solstat/analyzer/optimizations/
cache_array_length.rs1use std::collections::HashSet;
2
3use solang_parser::pt::{self, Loc};
4use solang_parser::{self, pt::SourceUnit};
5
6use crate::analyzer::ast::{self, Target};
7
8pub fn cache_array_length_optimization(source_unit: SourceUnit) -> HashSet<Loc> {
9 let mut optimization_locations: HashSet<Loc> = HashSet::new();
11
12 let target_nodes = ast::extract_target_from_node(Target::For, source_unit.into());
14
15 for node in target_nodes {
17 let statement = node.statement().unwrap();
19
20 if let pt::Statement::For(_, _, option_box_expression, _, _) = statement {
21 if option_box_expression.is_some() {
23 let box_expression = option_box_expression.unwrap();
24
25 let member_access_nodes =
26 ast::extract_target_from_node(Target::MemberAccess, box_expression.into());
27
28 for node in member_access_nodes {
29 let member_access = node.expression().unwrap();
31 if let pt::Expression::MemberAccess(loc, _, identifier) = member_access {
32 if identifier.name == "length" {
33 optimization_locations.insert(loc);
34 }
35 }
36 }
37 }
38 }
39 }
40
41 optimization_locations
43}
44
45#[test]
46fn test_cache_array_length_optimization() {
47 let file_contents = r#"
48
49 contract Contract1 {
50
51
52 //loop with i++
53 function memoryArray(uint256[] memory arr) public {
54 uint256 j;
55 for (uint256 i; i < arr.length; i++) {
56 j = arr[i] + 10;
57 }
58 }
59
60 //loop with i++
61 function calldataArray(uint256[] calldata arr) public {
62 uint256 j;
63 for (uint256 i; i < 100; i++) {
64 j = arr[i] + arr.length;
65 }
66 }
67
68 //loop with i++
69 function memoryArray(uint256[] memory arr) public {
70 uint256 j;
71 for (uint256 i; arr.length<1000; i++) {
72 arr[i] = 10;
73 }
74 }
75
76 }
77 "#;
78
79 let source_unit = solang_parser::parse(file_contents, 0).unwrap().0;
80
81 let optimization_locations = cache_array_length_optimization(source_unit);
82
83 assert_eq!(optimization_locations.len(), 2)
84}