solstat/analyzer/optimizations/
cache_array_length.rs

1use 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    //Create a new hashset that stores the location of each optimization target identified
10    let mut optimization_locations: HashSet<Loc> = HashSet::new();
11
12    //Extract the target nodes from the source_unit
13    let target_nodes = ast::extract_target_from_node(Target::For, source_unit.into());
14
15    //For each target node that was extracted, check for the optimization patterns
16    for node in target_nodes {
17        //Can unwrap because Target::For will always be a statement
18        let statement = node.statement().unwrap();
19
20        if let pt::Statement::For(_, _, option_box_expression, _, _) = statement {
21            //get all of the .length in the for loop definition
22            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                    //Can unwrap because Target::MemberAccess will always be an expression
30                    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    //Return the identified optimization locations
42    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}