imports.rs 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706
  1. // SPDX-License-Identifier: Apache-2.0
  2. use solang::file_resolver::FileResolver;
  3. use solang::Target;
  4. use std::ffi::OsStr;
  5. #[test]
  6. fn enum_import() {
  7. let mut cache = FileResolver::new();
  8. cache.set_file_contents(
  9. "a.sol",
  10. r#"
  11. import "b.sol";
  12. abstract contract foo {
  13. enum_b bar;
  14. }
  15. "#
  16. .to_string(),
  17. );
  18. cache.set_file_contents(
  19. "b.sol",
  20. r#"
  21. enum enum_b { b1 }
  22. "#
  23. .to_string(),
  24. );
  25. let ns =
  26. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  27. assert!(!ns.diagnostics.any_errors());
  28. let mut cache = FileResolver::new();
  29. cache.set_file_contents(
  30. "a.sol",
  31. r#"
  32. import { enum_b } from "b.sol";
  33. abstract contract foo {
  34. enum_b bar;
  35. }
  36. "#
  37. .to_string(),
  38. );
  39. cache.set_file_contents(
  40. "b.sol",
  41. r#"
  42. enum enum_b { b1 }
  43. "#
  44. .to_string(),
  45. );
  46. let ns =
  47. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  48. assert!(!ns.diagnostics.any_errors());
  49. let mut cache = FileResolver::new();
  50. cache.set_file_contents(
  51. "a.sol",
  52. r#"
  53. import { enum_b as foobar } from "b.sol";
  54. abstract contract foo {
  55. foobar bar;
  56. }
  57. "#
  58. .to_string(),
  59. );
  60. cache.set_file_contents(
  61. "b.sol",
  62. r#"
  63. enum enum_b { b1 }
  64. "#
  65. .to_string(),
  66. );
  67. let ns =
  68. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  69. assert!(!ns.diagnostics.any_errors());
  70. let mut cache = FileResolver::new();
  71. cache.set_file_contents(
  72. "a.sol",
  73. r#"
  74. import { enum_c } from "b.sol";
  75. "#
  76. .to_string(),
  77. );
  78. cache.set_file_contents(
  79. "b.sol",
  80. r#"
  81. enum enum_b { b1 }
  82. "#
  83. .to_string(),
  84. );
  85. let ns =
  86. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  87. assert_eq!(
  88. ns.diagnostics.first_error(),
  89. "import 'b.sol' does not export 'enum_c'"
  90. );
  91. // from has special handling to avoid making it a keyword
  92. let mut cache = FileResolver::new();
  93. cache.set_file_contents(
  94. "a.sol",
  95. r#"
  96. import { enum_c } frum "b.sol";
  97. "#
  98. .to_string(),
  99. );
  100. let ns =
  101. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  102. assert_eq!(
  103. ns.diagnostics.first_error(),
  104. "'frum' found where 'from' expected"
  105. );
  106. let mut cache = FileResolver::new();
  107. cache.set_file_contents(
  108. "a.sol",
  109. r#"
  110. import * as foo frum "b.sol";
  111. "#
  112. .to_string(),
  113. );
  114. let ns =
  115. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  116. assert_eq!(
  117. ns.diagnostics.first_error(),
  118. "'frum' found where 'from' expected"
  119. );
  120. }
  121. #[test]
  122. fn struct_import() {
  123. let mut cache = FileResolver::new();
  124. cache.set_file_contents(
  125. "a.sol",
  126. r#"
  127. import "b.sol";
  128. struct foo {
  129. struct_a bar;
  130. }
  131. "#
  132. .to_string(),
  133. );
  134. cache.set_file_contents(
  135. "b.sol",
  136. r#"
  137. struct struct_a { uint32 f1; }
  138. "#
  139. .to_string(),
  140. );
  141. let ns =
  142. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  143. assert!(!ns.diagnostics.any_errors());
  144. let mut cache = FileResolver::new();
  145. cache.set_file_contents(
  146. "a.sol",
  147. r#"
  148. import { struct_a as not_struct_a } from "b.sol";
  149. struct foo {
  150. struct_a bar;
  151. }
  152. "#
  153. .to_string(),
  154. );
  155. cache.set_file_contents(
  156. "b.sol",
  157. r#"
  158. struct struct_a { uint32 f1; }
  159. "#
  160. .to_string(),
  161. );
  162. let ns =
  163. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  164. assert_eq!(ns.diagnostics.first_error(), "type 'struct_a' not found");
  165. }
  166. #[test]
  167. fn contract_import() {
  168. let mut cache = FileResolver::new();
  169. cache.set_file_contents(
  170. "a.sol",
  171. r#"
  172. import "b.sol";
  173. contract a {
  174. function go() public {
  175. b x = new b();
  176. assert(x.test() == 102);
  177. }
  178. }
  179. "#
  180. .to_string(),
  181. );
  182. cache.set_file_contents(
  183. "b.sol",
  184. r#"
  185. contract b {
  186. function test() public returns (uint32) {
  187. return 102;
  188. }
  189. }
  190. "#
  191. .to_string(),
  192. );
  193. let ns =
  194. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  195. assert!(!ns.diagnostics.any_errors());
  196. // lets try a importing an import
  197. let mut cache = FileResolver::new();
  198. cache.set_file_contents(
  199. "a.sol",
  200. r#"
  201. import "b.sol";
  202. contract a {
  203. function go() public {
  204. c x = new c();
  205. assert(x.test() == 102);
  206. }
  207. }
  208. "#
  209. .to_string(),
  210. );
  211. cache.set_file_contents(
  212. "b.sol",
  213. r#"
  214. import "c.sol";
  215. "#
  216. .to_string(),
  217. );
  218. cache.set_file_contents(
  219. "c.sol",
  220. r#"
  221. contract c {
  222. function test() public returns (uint32) {
  223. return 102;
  224. }
  225. }
  226. "#
  227. .to_string(),
  228. );
  229. let ns =
  230. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  231. assert!(!ns.diagnostics.any_errors());
  232. // now let's rename an import in a chain
  233. let mut cache = FileResolver::new();
  234. cache.set_file_contents(
  235. "a.sol",
  236. r#"
  237. import "b.sol";
  238. contract a {
  239. function go() public {
  240. mr_c x = new mr_c();
  241. assert(x.test() == 102);
  242. }
  243. }
  244. "#
  245. .to_string(),
  246. );
  247. cache.set_file_contents(
  248. "b.sol",
  249. r#"
  250. import { c as mr_c } from "c.sol";
  251. "#
  252. .to_string(),
  253. );
  254. cache.set_file_contents(
  255. "c.sol",
  256. r#"
  257. contract c {
  258. function test() public returns (uint32) {
  259. return 102;
  260. }
  261. }
  262. "#
  263. .to_string(),
  264. );
  265. let ns =
  266. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  267. assert!(!ns.diagnostics.any_errors());
  268. }
  269. #[test]
  270. fn circular_import() {
  271. let mut cache = FileResolver::new();
  272. cache.set_file_contents(
  273. "self.sol",
  274. r#"
  275. import { foo } from "self.sol";
  276. enum foo { foo1, foo2 }
  277. contract c {
  278. foo public f1;
  279. }
  280. "#
  281. .to_string(),
  282. );
  283. let ns = solang::parse_and_resolve(
  284. OsStr::new("self.sol"),
  285. &mut cache,
  286. Target::default_substrate(),
  287. );
  288. assert!(!ns.diagnostics.any_errors());
  289. let mut cache = FileResolver::new();
  290. cache.set_file_contents(
  291. "a.sol",
  292. r#"
  293. import "b.sol";
  294. enum enum_a { f1, f2 }
  295. contract a {
  296. function go() public {
  297. b x = new b();
  298. assert(x.test() == 102);
  299. }
  300. }
  301. "#
  302. .to_string(),
  303. );
  304. cache.set_file_contents(
  305. "b.sol",
  306. r#"
  307. import "a.sol";
  308. contract b {
  309. function test() public returns (uint32) {
  310. return 102;
  311. }
  312. function test2() public returns (enum_a) {
  313. return enum_a.f1;
  314. }
  315. }
  316. "#
  317. .to_string(),
  318. );
  319. let ns =
  320. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  321. assert!(!ns.diagnostics.any_errors());
  322. }
  323. #[test]
  324. fn import_symbol() {
  325. // import struct via import symbol
  326. let mut cache = FileResolver::new();
  327. cache.set_file_contents(
  328. "a.sol",
  329. r#"
  330. import "b.sol" as foo;
  331. contract a {
  332. function go(foo.b_struct x) public returns (uint32) {
  333. return x.f1;
  334. }
  335. }
  336. "#
  337. .to_string(),
  338. );
  339. cache.set_file_contents(
  340. "b.sol",
  341. r#"
  342. struct b_struct {
  343. uint32 f1;
  344. }
  345. "#
  346. .to_string(),
  347. );
  348. let ns =
  349. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  350. assert!(!ns.diagnostics.any_errors());
  351. // import contract via import symbol
  352. let mut cache = FileResolver::new();
  353. cache.set_file_contents(
  354. "a.sol",
  355. r#"
  356. import "b.sol" as foo;
  357. contract a {
  358. function go() public returns (uint32) {
  359. foo.b x = new foo.b();
  360. return x.test();
  361. }
  362. }
  363. "#
  364. .to_string(),
  365. );
  366. cache.set_file_contents(
  367. "b.sol",
  368. r#"
  369. contract b {
  370. function test() public returns (uint32) {
  371. return 102;
  372. }
  373. }
  374. "#
  375. .to_string(),
  376. );
  377. let ns =
  378. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  379. assert!(!ns.diagnostics.any_errors());
  380. // import enum in contract via import symbol
  381. let mut cache = FileResolver::new();
  382. cache.set_file_contents(
  383. "a.sol",
  384. r#"
  385. import "b.sol" as foo;
  386. contract a {
  387. function go(foo.b.c x) public {
  388. assert(x == foo.b.c.c2);
  389. }
  390. }
  391. "#
  392. .to_string(),
  393. );
  394. cache.set_file_contents(
  395. "b.sol",
  396. r#"
  397. contract b {
  398. enum c { c1, c2 }
  399. function test() public returns (uint32) {
  400. return 102;
  401. }
  402. }
  403. "#
  404. .to_string(),
  405. );
  406. let ns =
  407. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  408. assert!(!ns.diagnostics.any_errors());
  409. // import struct in contract via import symbol chain
  410. let mut cache = FileResolver::new();
  411. cache.set_file_contents(
  412. "a.sol",
  413. r#"
  414. import "b.sol" as foo;
  415. contract a {
  416. function go(foo.bar.c.k x) public returns (int32) {
  417. return x.f1;
  418. }
  419. }
  420. "#
  421. .to_string(),
  422. );
  423. cache.set_file_contents(
  424. "b.sol",
  425. r#"
  426. import "c.sol" as bar;
  427. "#
  428. .to_string(),
  429. );
  430. cache.set_file_contents(
  431. "c.sol",
  432. r#"
  433. contract c {
  434. struct k {
  435. int32 f1;
  436. }
  437. function test() public returns (uint32) {
  438. return 102;
  439. }
  440. }
  441. "#
  442. .to_string(),
  443. );
  444. let ns =
  445. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  446. assert!(!ns.diagnostics.any_errors());
  447. }
  448. #[test]
  449. fn enum_import_chain() {
  450. // import struct in contract via import symbol chain
  451. let mut cache = FileResolver::new();
  452. cache.set_file_contents(
  453. "a.sol",
  454. r#"
  455. import "b.sol" as foo;
  456. contract a {
  457. function go(foo.c_import.d_import.d.enum_d x) public returns (bool) {
  458. return foo.c_import.d_import.d.enum_d.d2 == x;
  459. }
  460. }
  461. "#
  462. .to_string(),
  463. );
  464. cache.set_file_contents(
  465. "b.sol",
  466. r#"
  467. import "c.sol" as c_import;
  468. "#
  469. .to_string(),
  470. );
  471. cache.set_file_contents(
  472. "c.sol",
  473. r#"
  474. import "d.sol" as d_import;
  475. "#
  476. .to_string(),
  477. );
  478. cache.set_file_contents(
  479. "d.sol",
  480. r#"
  481. abstract contract d {
  482. enum enum_d { d1, d2, d3 }
  483. }
  484. "#
  485. .to_string(),
  486. );
  487. let ns =
  488. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  489. assert!(!ns.diagnostics.any_errors());
  490. // now with error
  491. let mut cache = FileResolver::new();
  492. cache.set_file_contents(
  493. "a.sol",
  494. r#"
  495. import "b.sol" as foo;
  496. contract a {
  497. function go(foo.c_import.d_import.d.enum_d x) public returns (bool) {
  498. return foo.c_import.d_import.d.enum_d.d4 == x;
  499. }
  500. }
  501. "#
  502. .to_string(),
  503. );
  504. cache.set_file_contents(
  505. "b.sol",
  506. r#"
  507. import "c.sol" as c_import;
  508. "#
  509. .to_string(),
  510. );
  511. cache.set_file_contents(
  512. "c.sol",
  513. r#"
  514. import "d.sol" as d_import;
  515. "#
  516. .to_string(),
  517. );
  518. cache.set_file_contents(
  519. "d.sol",
  520. r#"
  521. abstract contract d {
  522. enum enum_d { d1, d2, d3 }
  523. }
  524. "#
  525. .to_string(),
  526. );
  527. let ns =
  528. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  529. assert_eq!(
  530. ns.diagnostics.first_error(),
  531. "enum d.enum_d does not have value d4"
  532. );
  533. }
  534. #[test]
  535. fn import_base_dir() {
  536. // if a imports x/b.sol then when x/b.sol imports, it should use x/ as a base
  537. let mut cache = FileResolver::new();
  538. cache.set_file_contents(
  539. "a.sol",
  540. r#"
  541. import "x/b.sol";
  542. contract a {
  543. function go() public {
  544. c x = new c();
  545. assert(x.test() == 102);
  546. }
  547. }
  548. "#
  549. .to_string(),
  550. );
  551. cache.set_file_contents(
  552. "x/b.sol",
  553. r#"
  554. import "c.sol";
  555. "#
  556. .to_string(),
  557. );
  558. cache.set_file_contents(
  559. "x/c.sol",
  560. r#"
  561. contract c {
  562. function test() public returns (uint32) {
  563. return 102;
  564. }
  565. }
  566. "#
  567. .to_string(),
  568. );
  569. let ns =
  570. solang::parse_and_resolve(OsStr::new("a.sol"), &mut cache, Target::default_substrate());
  571. assert!(!ns.diagnostics.any_errors());
  572. }