unused_variable_detection.rs 29 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236
  1. // SPDX-License-Identifier: Apache-2.0
  2. use solang::file_resolver::FileResolver;
  3. use solang::sema::ast;
  4. use solang::{parse_and_resolve, Target};
  5. use std::ffi::OsStr;
  6. fn parse(src: &'static str) -> ast::Namespace {
  7. let mut cache = FileResolver::default();
  8. cache.set_file_contents("test.sol", src.to_string());
  9. parse_and_resolve(OsStr::new("test.sol"), &mut cache, Target::EVM)
  10. }
  11. fn parse_two_files(src1: &'static str, src2: &'static str) -> ast::Namespace {
  12. let mut cache = FileResolver::default();
  13. cache.set_file_contents("test.sol", src1.to_string());
  14. cache.set_file_contents("test2.sol", src2.to_string());
  15. parse_and_resolve(OsStr::new("test.sol"), &mut cache, Target::EVM)
  16. }
  17. #[test]
  18. fn emit_event() {
  19. //Used event
  20. let case_1 = r#"
  21. contract usedEvent {
  22. event Hey(uint8 n);
  23. function emitEvent(uint8 n) public {
  24. emit Hey(n);
  25. }
  26. }
  27. "#;
  28. let ns = parse(case_1);
  29. assert_eq!(ns.diagnostics.count_warnings(), 0);
  30. // Unused event
  31. let case_2 = r#"
  32. event Hey(uint8 n);
  33. contract usedEvent {
  34. event Hey(uint8 n);
  35. event Hello(uint8 n);
  36. function emitEvent(uint8 n) public {
  37. emit Hey(n);
  38. }
  39. }
  40. "#;
  41. let ns = parse(case_2);
  42. assert_eq!(ns.diagnostics.count_warnings(), 1);
  43. assert_eq!(
  44. ns.diagnostics.first_warning().message,
  45. "event 'Hello' has never been emitted"
  46. );
  47. // Unused event
  48. let case_2 = r#"
  49. contract F {
  50. event Hey(uint8 n);
  51. event Hello(uint8 n);
  52. }
  53. contract usedEvent is F {
  54. event Hey(uint8 n);
  55. function emitEvent(uint8 n) public {
  56. emit Hey(n);
  57. }
  58. }
  59. "#;
  60. let ns = parse(case_2);
  61. assert_eq!(ns.diagnostics.count_warnings(), 1);
  62. assert_eq!(
  63. ns.diagnostics.first_warning().message,
  64. "event 'Hello' has never been emitted"
  65. );
  66. // Unused event
  67. let case_2 = r#"
  68. contract F {
  69. event Hey(uint8 n);
  70. }
  71. contract usedEvent is F {
  72. event Hey(uint8 n);
  73. function emitEvent(uint8 n) public {
  74. // reference event in contract F, so our event decl is not used
  75. emit F.Hey(n);
  76. }
  77. }
  78. "#;
  79. let ns = parse(case_2);
  80. assert_eq!(ns.diagnostics.count_warnings(), 1);
  81. assert_eq!(
  82. ns.diagnostics.first_warning().message,
  83. "event 'Hey' has never been emitted"
  84. );
  85. // make sure we don't complain about interfaces or abstract contracts
  86. let case_3 = r#"
  87. abstract contract F {
  88. event Hey(uint8 n);
  89. }
  90. interface G {
  91. event Hey(uint8 n);
  92. }
  93. "#;
  94. let ns = parse(case_3);
  95. assert_eq!(ns.diagnostics.count_warnings(), 0);
  96. }
  97. #[test]
  98. fn constant_variable() {
  99. let file_2 = r#"
  100. uint32 constant outside = 2;
  101. "#;
  102. let file_1 = r#"
  103. import "test2.sol";
  104. contract Testing {
  105. uint32 test;
  106. uint32 constant cte = 5;
  107. constructor() {
  108. test = outside;
  109. test = cte;
  110. }
  111. function get() public view returns (uint32) {
  112. return test;
  113. }
  114. }
  115. "#;
  116. //Constant properly read
  117. let ns = parse_two_files(file_1, file_2);
  118. assert_eq!(ns.diagnostics.count_warnings(), 0);
  119. let file_1 = r#"
  120. import "test2.sol";
  121. contract Testing {
  122. uint32 test;
  123. uint32 constant cte = 5;
  124. constructor() {
  125. test = 45;
  126. }
  127. function get() public view returns (uint32) {
  128. return test;
  129. }
  130. }
  131. "#;
  132. let ns = parse_two_files(file_1, file_2);
  133. assert_eq!(ns.diagnostics.count_warnings(), 2);
  134. assert!(ns
  135. .diagnostics
  136. .warning_contains("storage variable 'cte' has been assigned, but never read"));
  137. assert!(ns
  138. .diagnostics
  139. .warning_contains("global constant 'outside' has never been used"));
  140. }
  141. #[test]
  142. fn storage_variable() {
  143. let file = r#"
  144. contract Test {
  145. string str = "This is a test";
  146. string str2;
  147. constructor() {
  148. str = "This is another test";
  149. }
  150. }
  151. "#;
  152. let ns = parse(file);
  153. let warnings = ns.diagnostics.warnings();
  154. assert_eq!(warnings.len(), 2);
  155. assert_eq!(
  156. warnings[0].message,
  157. "storage variable 'str' has been assigned, but never read"
  158. );
  159. assert_eq!(
  160. warnings[1].message,
  161. "storage variable 'str2' has never been used"
  162. );
  163. let file = r#"
  164. contract Test {
  165. string str = "This is a test";
  166. string str2;
  167. constructor() {
  168. str = "This is another test";
  169. str2 = str;
  170. }
  171. }
  172. "#;
  173. let ns = parse(file);
  174. assert_eq!(ns.diagnostics.count_warnings(), 1);
  175. assert_eq!(
  176. ns.diagnostics.first_warning().message,
  177. "storage variable 'str2' has been assigned, but never read"
  178. );
  179. let file = r#"
  180. contract Test {
  181. string str = "This is a test";
  182. constructor() {
  183. str = "This is another test";
  184. }
  185. }
  186. contract Test2 is Test {
  187. function get() public view returns (string) {
  188. return str;
  189. }
  190. }
  191. "#;
  192. let ns = parse(file);
  193. assert_eq!(ns.diagnostics.count_warnings(), 0);
  194. }
  195. #[test]
  196. fn state_variable() {
  197. let file = r#"
  198. contract Test {
  199. function get() public pure {
  200. uint32 a = 1;
  201. uint32 b;
  202. b = 1;
  203. uint32 c;
  204. uint32 d;
  205. d = 1;
  206. uint32 e;
  207. e = d*5;
  208. d = e/5;
  209. }
  210. }
  211. "#;
  212. let ns = parse(file);
  213. assert_eq!(ns.diagnostics.count_warnings(), 3);
  214. assert!(ns
  215. .diagnostics
  216. .warning_contains("local variable 'b' has been assigned, but never read"));
  217. assert!(ns
  218. .diagnostics
  219. .warning_contains("local variable 'a' is unused"));
  220. assert!(ns
  221. .diagnostics
  222. .warning_contains("local variable 'c' is unused"));
  223. }
  224. #[test]
  225. fn struct_usage() {
  226. let file = r#"
  227. struct testing {
  228. uint8 it;
  229. bool tf;
  230. }
  231. contract Test {
  232. testing t1;
  233. testing t4;
  234. testing t6;
  235. constructor() {
  236. t1 = testing(8, false);
  237. }
  238. function modify() public returns (uint8) {
  239. testing memory t2;
  240. t2.it = 4;
  241. t4 = testing(1, true);
  242. testing storage t3 = t4;
  243. uint8 k = 2*4/t3.it;
  244. testing t5;
  245. return k;
  246. }
  247. }
  248. "#;
  249. let ns = parse(file);
  250. assert_eq!(ns.diagnostics.count_warnings(), 4);
  251. assert!(ns
  252. .diagnostics
  253. .warning_contains("local variable 't2' has been assigned, but never read"));
  254. assert!(ns
  255. .diagnostics
  256. .warning_contains("storage variable 't1' has been assigned, but never read"));
  257. assert!(ns
  258. .diagnostics
  259. .warning_contains("local variable 't5' is unused"));
  260. assert!(ns
  261. .diagnostics
  262. .warning_contains("storage variable 't6' has never been used"));
  263. }
  264. #[test]
  265. fn subscript() {
  266. let file = r#"
  267. contract Test {
  268. int[] arr1;
  269. int[4] arr2;
  270. int[4] arr3;
  271. bytes byteArr;
  272. uint constant e = 1;
  273. function get() public {
  274. uint8 a = 1;
  275. uint8 b = 2;
  276. arr1[a] = 1;
  277. arr2[a+b] = 2;
  278. uint8 c = 1;
  279. uint8 d = 1;
  280. int[] memory arr4;
  281. arr4[0] = 1;
  282. int[4] storage arr5 = arr3;
  283. arr5[c*d] = 1;
  284. byteArr[e] = 0x05;
  285. }
  286. }
  287. "#;
  288. let ns = parse(file);
  289. assert_eq!(ns.diagnostics.count_warnings(), 4);
  290. assert!(ns
  291. .diagnostics
  292. .warning_contains("local variable 'arr4' has been assigned, but never read"));
  293. assert!(ns
  294. .diagnostics
  295. .warning_contains("storage variable 'arr1' has been assigned, but never read"));
  296. assert!(ns
  297. .diagnostics
  298. .warning_contains("storage variable 'arr2' has been assigned, but never read"));
  299. assert!(ns
  300. .diagnostics
  301. .warning_contains("storage variable 'byteArr' has been assigned, but never read"));
  302. let file = r#"
  303. contract Test {
  304. int[] arr1;
  305. int[4] arr2;
  306. int[4] arr3;
  307. bytes byteArr;
  308. uint constant e = 1;
  309. function get() public {
  310. uint8 a = 1;
  311. uint8 b = 2;
  312. arr1[a] = 1;
  313. arr2[a+b] = 2;
  314. assert(arr1[a] == arr2[b]);
  315. uint8 c = 1;
  316. uint8 d = 1;
  317. int[] memory arr4;
  318. arr4[0] = 1;
  319. int[4] storage arr5 = arr3;
  320. arr5[c*d] = 1;
  321. assert(arr4[c] == arr5[d]);
  322. assert(arr3[c] == arr5[d]);
  323. byteArr[e] = 0x05;
  324. assert(byteArr[e] == byteArr[e]);
  325. }
  326. }
  327. "#;
  328. let ns = parse(file);
  329. assert_eq!(ns.diagnostics.count_warnings(), 0);
  330. }
  331. #[test]
  332. fn assign_trunc_cast() {
  333. //This covers ZeroExt as well
  334. let file = r#"
  335. contract Test {
  336. bytes byteArr;
  337. bytes32 baRR;
  338. function get() public {
  339. string memory s = "Test";
  340. byteArr = bytes(s);
  341. uint16 a = 1;
  342. uint8 b;
  343. b = uint8(a);
  344. uint256 c;
  345. c = b;
  346. bytes32 b32;
  347. bytes memory char = bytes(bytes32(uint(a) * 2 ** (8 * b)));
  348. baRR = bytes32(c);
  349. bytes32 cdr = bytes32(char);
  350. assert(b32 == baRR);
  351. if(b32 != cdr) {
  352. }
  353. }
  354. }
  355. "#;
  356. let ns = parse(file);
  357. assert_eq!(ns.diagnostics.count_warnings(), 1);
  358. assert!(ns
  359. .diagnostics
  360. .warning_contains("storage variable 'byteArr' has been assigned, but never read"));
  361. }
  362. #[test]
  363. fn array_length() {
  364. let file = r#"
  365. contract Test {
  366. int[5] arr1;
  367. int[] arr2;
  368. function get() public view returns (bool) {
  369. int[5] memory arr3;
  370. int[] memory arr4;
  371. bool test = false;
  372. if(arr1.length == arr2.length) {
  373. test = true;
  374. }
  375. else if(arr3.length != arr4.length) {
  376. test = false;
  377. }
  378. return test;
  379. }
  380. }
  381. "#;
  382. let ns = parse(file);
  383. assert_eq!(ns.diagnostics.count_warnings(), 0);
  384. }
  385. #[test]
  386. fn sign_ext_storage_load() {
  387. let file = r#"
  388. contract Test {
  389. bytes a;
  390. function use(bytes memory b) pure public {
  391. assert(b[0] == b[1]);
  392. }
  393. function get() public pure returns (int16 ret) {
  394. use(a);
  395. int8 b = 1;
  396. int16 c = 1;
  397. int16 d;
  398. d = c << b;
  399. ret = d;
  400. }
  401. }
  402. "#;
  403. let ns = parse(file);
  404. assert_eq!(ns.diagnostics.count_warnings(), 0);
  405. }
  406. #[test]
  407. fn statements() {
  408. let file = r#"
  409. contract AddNumbers { function add(uint256 a, uint256 b) external pure returns (uint256 c) {c = b;} }
  410. contract Example {
  411. AddNumbers addContract;
  412. event StringFailure(string stringFailure);
  413. event BytesFailure(bytes bytesFailure);
  414. function exampleFunction(uint256 _a, uint256 _b) public returns (uint256 _c) {
  415. try addContract.add(_a, _b) returns (uint256 _value) {
  416. return (_value);
  417. } catch Error(string memory _err) {
  418. // This may occur if there is an overflow with the two numbers and the `AddNumbers` contract explicitly fails with a `revert()`
  419. emit StringFailure(_err);
  420. } catch (bytes memory _err) {
  421. emit BytesFailure(_err);
  422. }
  423. }
  424. function testFunction() pure public {
  425. int three = 3;
  426. {
  427. int test = 2;
  428. int c = test*3;
  429. while(c != test) {
  430. c -= three;
  431. }
  432. }
  433. int four = 4;
  434. int test = 3;
  435. do {
  436. int ct = 2;
  437. } while(four > test);
  438. }
  439. function bytesToUInt(uint v) public pure returns (uint ret) {
  440. if (v == 0) {
  441. ret = 0;
  442. }
  443. else {
  444. while (v > 0) {
  445. ret = uint(uint(ret) / (2 ** 8));
  446. ret |= uint(((v % 10) + 48) * 2 ** (8 * 31));
  447. v /= 10;
  448. }
  449. }
  450. return ret;
  451. }
  452. function stringToUint(string s) public pure returns (uint result) {
  453. bytes memory b = bytes(s);
  454. uint i;
  455. result = 0;
  456. for (i = 0; i < b.length; i++) {
  457. uint c = uint(b[i]);
  458. if (c >= 48 && c <= 57) {
  459. result = result * 10 + (c - 48);
  460. }
  461. }
  462. }
  463. }
  464. "#;
  465. let ns = parse(file);
  466. assert_eq!(ns.diagnostics.count_warnings(), 2);
  467. assert!(ns
  468. .diagnostics
  469. .warning_contains("function parameter 'a' is unused"));
  470. assert!(ns
  471. .diagnostics
  472. .warning_contains("local variable 'ct' is unused"));
  473. }
  474. #[test]
  475. fn function_call() {
  476. let file = r#"
  477. contract Test1 {
  478. uint32 public a;
  479. constructor(uint32 b) {
  480. a = b;
  481. }
  482. }
  483. contract Test2{
  484. function test(uint32 v1, uint32 v2) private returns (uint32) {
  485. uint32 v = 1;
  486. Test1 t = new Test1(v);
  487. uint32[2] memory vec = [v2, v1];
  488. return vec[0] + t.a();
  489. }
  490. function callTest() public {
  491. uint32 ta = 1;
  492. uint32 tb = 2;
  493. ta = test(ta, tb);
  494. }
  495. }
  496. contract C {
  497. uint public data;
  498. function x() public returns (uint) {
  499. data = 3;
  500. return this.data();
  501. }
  502. }
  503. "#;
  504. let ns = parse(file);
  505. assert_eq!(ns.diagnostics.count_warnings(), 0);
  506. let file = r#"
  507. contract Test1 {
  508. uint32 public a;
  509. constructor(uint32 b) {
  510. a = b;
  511. }
  512. }
  513. contract Test2 is Test1{
  514. constructor(uint32 val) Test1(val) {}
  515. function test(uint32 v1, uint32 v2) private returns (uint32) {
  516. uint32 v = 1;
  517. Test1 t = new Test1(v);
  518. uint32[2] memory vec = [v2, v1];
  519. return vec[0] + t.a();
  520. }
  521. function callTest() public {
  522. uint32 ta = 1;
  523. uint32 tb = 2;
  524. ta = test(ta, tb);
  525. }
  526. }
  527. "#;
  528. let ns = parse(file);
  529. assert_eq!(ns.diagnostics.count_warnings(), 0);
  530. }
  531. #[test]
  532. fn array_push_pop() {
  533. let file = r#"
  534. contract Test1 {
  535. uint32[] vec1;
  536. function testVec() public {
  537. uint32 a = 1;
  538. uint32 b = 2;
  539. uint32[] memory vec2;
  540. vec1.push(a);
  541. vec2.push(b);
  542. }
  543. }
  544. "#;
  545. let ns = parse(file);
  546. assert_eq!(ns.diagnostics.count_warnings(), 2);
  547. assert!(ns
  548. .diagnostics
  549. .warning_contains("local variable 'vec2' has been assigned, but never read"));
  550. assert!(ns
  551. .diagnostics
  552. .warning_contains("storage variable 'vec1' has been assigned, but never read"));
  553. let file = r#"
  554. contract Test1 {
  555. uint32[] vec1;
  556. function testVec() public {
  557. uint32 a = 1;
  558. uint32 b = 2;
  559. uint32[] memory vec2;
  560. vec1.push(a);
  561. vec2.push(b);
  562. vec1.pop();
  563. vec2.pop();
  564. }
  565. }
  566. "#;
  567. let ns = parse(file);
  568. assert_eq!(ns.diagnostics.count_warnings(), 2);
  569. assert!(ns
  570. .diagnostics
  571. .warning_contains("storage variable 'vec1' has been assigned, but never read"));
  572. assert!(ns
  573. .diagnostics
  574. .warning_contains("local variable 'vec2' has been assigned, but never read"));
  575. let file = r#"
  576. contract Test1 {
  577. function test_storage(uint64[] storage arr1, uint128[] storage arr2) private {
  578. arr1.push(32);
  579. arr2.pop();
  580. }
  581. function arg_ptr(uint64[] memory arr1, uint16[] memory arr2) private pure {
  582. arr1.push(422);
  583. arr2.pop();
  584. }
  585. }
  586. "#;
  587. let ns = parse(file);
  588. assert_eq!(ns.diagnostics.count_warnings(), 0);
  589. let file = r#"
  590. contract Test1 {
  591. function test_storage(uint64[] storage arr1) private pure {
  592. }
  593. function arg_ptr(uint64[] memory arr2) private pure {
  594. }
  595. }
  596. "#;
  597. let ns = parse(file);
  598. assert_eq!(ns.diagnostics.count_warnings(), 2);
  599. assert!(ns
  600. .diagnostics
  601. .warning_contains("function parameter 'arr1' is unused"));
  602. assert!(ns
  603. .diagnostics
  604. .warning_contains("function parameter 'arr2' is unused"));
  605. }
  606. #[test]
  607. fn return_variable() {
  608. let file = r#"
  609. contract Test1 {
  610. string testing;
  611. function test1() public pure returns (uint32 ret, string memory ret2) {
  612. return (2, "Testing is fun");
  613. }
  614. function test2() public returns (uint32 hey) {
  615. (uint32 a, string memory t) = test1();
  616. testing = t;
  617. }
  618. }
  619. "#;
  620. let ns = parse(file);
  621. assert_eq!(ns.diagnostics.count_warnings(), 3);
  622. assert!(ns
  623. .diagnostics
  624. .warning_contains("destructure variable 'a' has never been used"));
  625. assert!(ns
  626. .diagnostics
  627. .warning_contains("return variable 'hey' has never been assigned"));
  628. assert!(ns
  629. .diagnostics
  630. .warning_contains("storage variable 'testing' has been assigned, but never read"));
  631. }
  632. #[test]
  633. fn try_catch() {
  634. let file = r#"
  635. contract CalledContract {}
  636. contract TryCatcher {
  637. event SuccessEvent(bool t);
  638. event CatchEvent(bool t);
  639. function execute() public {
  640. try new CalledContract() returns(CalledContract returnedInstance) {
  641. emit SuccessEvent(true);
  642. } catch Error(string memory revertReason) {
  643. emit CatchEvent(true);
  644. } catch (bytes memory returnData) {
  645. emit CatchEvent(false);
  646. }
  647. }
  648. }
  649. "#;
  650. let ns = parse(file);
  651. assert_eq!(ns.diagnostics.count_warnings(), 3);
  652. assert!(ns
  653. .diagnostics
  654. .warning_contains("try-catch error bytes 'returnData' has never been used"));
  655. assert!(ns
  656. .diagnostics
  657. .warning_contains("try-catch returns variable 'returnedInstance' has never been read"));
  658. assert!(ns
  659. .diagnostics
  660. .warning_contains("try-catch error string 'revertReason' has never been used"));
  661. let file = r#"
  662. contract CalledContract {
  663. bool public ok = true;
  664. bool private notOk = false;
  665. }
  666. contract TryCatcher {
  667. event SuccessEvent(bool t);
  668. event CatchEvent(string t);
  669. event CatchBytes(bytes t);
  670. function execute() public {
  671. try new CalledContract() returns(CalledContract returnedInstance) {
  672. // returnedInstance can be used to obtain the address of the newly deployed contract
  673. emit SuccessEvent(returnedInstance.ok());
  674. } catch Error(string memory revertReason) {
  675. emit CatchEvent(revertReason);
  676. } catch (bytes memory returnData) {
  677. emit CatchBytes(returnData);
  678. }
  679. }
  680. }
  681. "#;
  682. let ns = parse(file);
  683. assert_eq!(ns.diagnostics.count_warnings(), 1);
  684. assert!(ns
  685. .diagnostics
  686. .warning_contains("storage variable 'notOk' has been assigned, but never read"));
  687. let file = r#"
  688. contract CalledContract {
  689. bool public ok;
  690. }
  691. "#;
  692. let ns = parse(file);
  693. assert_eq!(ns.diagnostics.count_warnings(), 0);
  694. }
  695. #[test]
  696. fn destructure() {
  697. let file = r#"
  698. contract Test2{
  699. function callTest() public view returns (uint32 ret) {
  700. uint32 ta = 1;
  701. uint32 tb = 2;
  702. uint32 te = 3;
  703. string memory tc = "hey";
  704. bytes memory td = bytes(tc);
  705. address nameReg = address(this);
  706. (bool tf,) = nameReg.call(td);
  707. ta = tf? tb : te;
  708. uint8 tg = 1;
  709. uint8 th = 2;
  710. (tg, th) = (th, tg);
  711. return ta;
  712. }
  713. }
  714. "#;
  715. let ns = parse(file);
  716. assert_eq!(ns.diagnostics.count_warnings(), 0);
  717. }
  718. #[test]
  719. fn struct_initialization() {
  720. let file = r#"
  721. contract Test1{
  722. struct Test2{
  723. uint8 a;
  724. uint8 b;
  725. }
  726. function callTest() public pure returns (uint32 ret) {
  727. uint8 tg = 1;
  728. uint8 th = 2;
  729. Test2 memory t2;
  730. t2 = Test2(tg, th);
  731. ret = t2.a;
  732. }
  733. }
  734. "#;
  735. let ns = parse(file);
  736. assert_eq!(ns.diagnostics.count_warnings(), 0);
  737. }
  738. #[test]
  739. fn subarray_mapping_struct_literal() {
  740. let file = r#"
  741. contract T {
  742. int p;
  743. constructor(int b) {
  744. p = b;
  745. }
  746. function sum(int a, int b) virtual public returns (int){
  747. uint8 v1 = 1;
  748. uint8 v2 = 2;
  749. uint8 v3 = 3;
  750. uint8 v4 = 4;
  751. uint8[2][2] memory v = [[v1, v2], [v3, v4]];
  752. return a + b * p/v[0][1];
  753. }
  754. }
  755. contract Test is T(2){
  756. struct fooStruct {
  757. int foo;
  758. int figther;
  759. }
  760. mapping(string => int) public mp;
  761. enum FreshJuiceSize{ SMALL, MEDIUM, LARGE }
  762. FreshJuiceSize choice;
  763. function sum(int a, int b) override public returns (int) {
  764. choice = FreshJuiceSize.LARGE;
  765. return a*b;
  766. }
  767. function test() public returns (int){
  768. int a = 1;
  769. int b = 2;
  770. int c = super.sum(a, b);
  771. int d = 3;
  772. fooStruct memory myStruct = fooStruct({foo: c, figther: d});
  773. string memory t = "Do some tests";
  774. mp[t] = myStruct.figther;
  775. return mp[t];
  776. }
  777. }
  778. "#;
  779. let ns = parse(file);
  780. assert_eq!(ns.diagnostics.count_warnings(), 1);
  781. assert!(ns
  782. .diagnostics
  783. .warning_contains("storage variable 'choice' has been assigned, but never read"));
  784. }
  785. #[test]
  786. fn builtin_call_destructure() {
  787. let file = r#"
  788. contract Test {
  789. function test() public returns(bool p) {
  790. uint128 b = 1;
  791. uint64 g = 2;
  792. address payable ad = payable(address(this));
  793. bytes memory by = hex"AB2";
  794. (p, ) = ad.call{value: b, gas: g}(by);
  795. uint c = 1;
  796. abi.encodeWithSignature("hey", c);
  797. uint128 amount = 2;
  798. ad.send(amount);
  799. uint128 amount2 = 1;
  800. ad.transfer(amount2);
  801. }
  802. }
  803. "#;
  804. let ns = parse(file);
  805. assert_eq!(ns.diagnostics.count_warnings(), 0);
  806. }
  807. #[test]
  808. fn delete_statement() {
  809. let file = r#"
  810. pragma solidity 0;
  811. contract Test1{
  812. int test8var;
  813. function test8() public {
  814. delete test8var;
  815. test8var = 2;
  816. }
  817. }
  818. "#;
  819. let ns = parse(file);
  820. assert_eq!(ns.diagnostics.count_warnings(), 0);
  821. }
  822. #[test]
  823. fn load_length() {
  824. let file = r#"
  825. contract foo {
  826. function f(uint i1) public pure returns (int) {
  827. int[8] bar = [ int(10), 20, 30, 4, 5, 6, 7, 8 ];
  828. bar[2] = 0x7_f;
  829. return bar[i1];
  830. }
  831. function barfunc() public pure returns (uint) {
  832. uint[2][3][4] array;
  833. return array.length;
  834. }
  835. }
  836. "#;
  837. let ns = parse(file);
  838. assert_eq!(ns.diagnostics.count_warnings(), 0);
  839. }
  840. #[test]
  841. fn address_selector() {
  842. let file = r#"
  843. contract ctc {
  844. function foo(int32 a) public pure returns (bool) {
  845. return a==1;
  846. }
  847. function test() public view {
  848. function(int32) external returns (bool) func = this.foo;
  849. assert(address(this) == func.address);
  850. assert(func.selector == hex"42761137");
  851. }
  852. }
  853. "#;
  854. let ns = parse(file);
  855. assert_eq!(ns.diagnostics.count_warnings(), 0);
  856. }
  857. #[test]
  858. fn load_storage_load() {
  859. let file = r#"
  860. struct X {
  861. uint32 f1;
  862. bool f2;
  863. }
  864. contract foo {
  865. function get() public pure returns (X[4] f) {
  866. f[1].f1 = 102;
  867. f[1].f2 = true;
  868. }
  869. }
  870. "#;
  871. let ns = parse(file);
  872. assert_eq!(ns.diagnostics.count_warnings(), 0);
  873. }
  874. #[test]
  875. fn variable_function() {
  876. let file = r#"
  877. contract ft is Arith {
  878. function test(bool action, int32 a, int32 b) public returns (int32) {
  879. function(int32,int32) internal returns (int32) func;
  880. if (action) {
  881. func = Arith.mul;
  882. } else {
  883. func = Arith.add;
  884. }
  885. return func(a, b);
  886. }
  887. }
  888. contract Arith {
  889. function mul(int32 a, int32 b) internal pure returns (int32) {
  890. return a * b;
  891. }
  892. function add(int32 a, int32 b) internal pure returns (int32) {
  893. return a + b;
  894. }
  895. }
  896. "#;
  897. let ns = parse(file);
  898. assert_eq!(ns.diagnostics.count_warnings(), 0);
  899. let file = r#"
  900. contract ft {
  901. function test() public {
  902. function(int32) external returns (uint64) func = this.foo;
  903. assert(func(102) == 0xabbaabba);
  904. }
  905. function foo(int32) public pure returns (uint64) {
  906. return 0xabbaabba;
  907. }
  908. }
  909. "#;
  910. let ns = parse(file);
  911. assert_eq!(ns.diagnostics.count_warnings(), 0);
  912. let file = r#"
  913. contract ft {
  914. function(int32,int32) internal returns (int32) func;
  915. function mul(int32 a, int32 b) internal pure returns (int32) {
  916. return a * b;
  917. }
  918. function add(int32 a, int32 b) internal pure returns (int32) {
  919. return a + b;
  920. }
  921. function set_op(bool action) public {
  922. if (action) {
  923. func = mul;
  924. } else {
  925. func = add;
  926. }
  927. }
  928. function test(int32 a, int32 b) public returns (int32) {
  929. return func(a, b);
  930. }
  931. }
  932. "#;
  933. let ns = parse(file);
  934. assert_eq!(ns.diagnostics.count_warnings(), 0);
  935. let file = r#"
  936. contract ft {
  937. function mul(int32 a, int32 b) internal pure returns (int32) {
  938. return a * b;
  939. }
  940. function add(int32 a, int32 b) internal pure returns (int32) {
  941. return a + b;
  942. }
  943. function test(bool action, int32 a, int32 b) public returns (int32) {
  944. function(int32,int32) internal returns (int32) func;
  945. if (action) {
  946. func = mul;
  947. } else {
  948. func = add;
  949. }
  950. return func(a, b);
  951. }
  952. }
  953. "#;
  954. let ns = parse(file);
  955. assert_eq!(ns.diagnostics.count_warnings(), 0);
  956. let file = r#"
  957. contract ft is Arith {
  958. function mul(int32 a, int32 b) internal pure override returns (int32) {
  959. return a * b * 10;
  960. }
  961. function add(int32 a, int32 b) internal pure override returns (int32) {
  962. return a + b + 10;
  963. }
  964. }
  965. contract Arith {
  966. function test(bool action, int32 a, int32 b) public returns (int32) {
  967. function(int32,int32) internal returns (int32) func;
  968. if (action) {
  969. func = mul;
  970. } else {
  971. func = add;
  972. }
  973. return func(a, b);
  974. }
  975. function mul(int32 a, int32 b) internal virtual returns (int32) {
  976. return a * b;
  977. }
  978. function add(int32 a, int32 b) internal virtual returns (int32) {
  979. return a + b;
  980. }
  981. }
  982. "#;
  983. let ns = parse(file);
  984. assert_eq!(ns.diagnostics.count_warnings(), 0);
  985. let file = r#"
  986. function global_function() pure returns (uint32) {
  987. return 102;
  988. }
  989. function global_function2() pure returns (uint32) {
  990. return global_function() + 5;
  991. }
  992. contract c {
  993. function test() public {
  994. function() internal returns (uint32) ftype = global_function2;
  995. uint64 x = ftype();
  996. assert(x == 107);
  997. }
  998. }
  999. "#;
  1000. let ns = parse(file);
  1001. assert_eq!(ns.diagnostics.count_warnings(), 0);
  1002. }
  1003. #[test]
  1004. fn format_string() {
  1005. let file = r#"
  1006. contract foo {
  1007. constructor() {
  1008. int x = 21847450052839212624230656502990235142567050104912751880812823948662932355201;
  1009. print("x = {}".format(x));
  1010. }
  1011. }
  1012. "#;
  1013. let ns = parse(file);
  1014. assert_eq!(ns.diagnostics.count_warnings(), 0);
  1015. }
  1016. #[test]
  1017. fn balance() {
  1018. let file = r#"
  1019. contract foo {
  1020. function test(address payable addr) public pure returns (bool) {
  1021. bool p;
  1022. p = addr.balance == 2;
  1023. return p;
  1024. }
  1025. }
  1026. "#;
  1027. let ns = parse(file);
  1028. assert_eq!(ns.diagnostics.count_warnings(), 0);
  1029. }