solstat/analyzer/optimizations/
pack_storage_variables.rs1use std::collections::HashSet;
2
3use solang_parser::pt::{self, Loc};
4use solang_parser::{self, pt::SourceUnit};
5
6use crate::analyzer::ast::{self, Target};
7use crate::analyzer::utils;
8
9pub fn pack_storage_variables_optimization(source_unit: SourceUnit) -> HashSet<Loc> {
10 let mut optimization_locations: HashSet<Loc> = HashSet::new();
11
12 let target_nodes =
13 ast::extract_target_from_node(Target::ContractDefinition, source_unit.into());
14
15 for node in target_nodes {
16 let source_unit_part = node.source_unit_part().unwrap();
17
18 if let pt::SourceUnitPart::ContractDefinition(contract_definition) = source_unit_part {
19 let mut variable_sizes: Vec<u16> = vec![];
20
21 for part in contract_definition.clone().parts {
22 if let pt::ContractPart::VariableDefinition(box_variable_definition) = part {
23 variable_sizes.push(utils::get_type_size(box_variable_definition.ty));
24 }
25 }
26
27 let unordered_variable_sizes = variable_sizes.clone();
29
30 variable_sizes.sort();
32
33 if utils::storage_slots_used(unordered_variable_sizes)
35 > utils::storage_slots_used(variable_sizes)
36 {
37 optimization_locations.insert(contract_definition.loc);
38 }
39 }
40 }
41
42 optimization_locations
43}
44
45#[test]
46fn test_pack_storage_variables_optimization() {
47 let contract = r#"
49 contract Contract {
50 uint256 num0;
51 uint256 num1;
52 uint256 num2;
53 bool bool0;
54 bool bool1;
55 }
56 "#;
57
58 let source_unit = solang_parser::parse(contract, 0).unwrap().0;
59 let optimization_locations = pack_storage_variables_optimization(source_unit);
60 assert_eq!(optimization_locations.len(), 0);
61
62 let contract = r#"
64 contract Contract {
65 bytes24 b0;
66 uint256 num0;
67 bytes24 b1;
68 }
69 "#;
70
71 let source_unit = solang_parser::parse(contract, 0).unwrap().0;
72 let optimization_locations = pack_storage_variables_optimization(source_unit);
73 assert_eq!(optimization_locations.len(), 0);
74
75 let contract = r#"
77 contract Contract {
78 bytes28 b0;
79 uint8 num0;
80 uint8 num1;
81 uint8 num2;
82 bool bo0;
83 uint256 num3;
84 bool bo1;
85 }
86 "#;
87
88 let source_unit = solang_parser::parse(contract, 0).unwrap().0;
89 let optimization_locations = pack_storage_variables_optimization(source_unit);
90 assert_eq!(optimization_locations.len(), 0);
91
92 let contract = r#"
94 contract Contract {
95 uint256 num0;
96 uint256 num1;
97 bool bool0;
98 uint256 num2;
99 bool bool1;
100 }
101 "#;
102
103 let source_unit = solang_parser::parse(contract, 0).unwrap().0;
104 let optimization_locations = pack_storage_variables_optimization(source_unit);
105 assert_eq!(optimization_locations.len(), 1);
106
107 let contract = r#"
109 contract Contract {
110 address owner;
111 uint256 num0;
112 bool bool0;
113 }
114 "#;
115
116 let source_unit = solang_parser::parse(contract, 0).unwrap().0;
117 let optimization_locations = pack_storage_variables_optimization(source_unit);
118 assert_eq!(optimization_locations.len(), 1);
119
120 let contract = r#"
122 contract Contract {
123 address owner; // 160 bits
124 uint256 num0; // 256 bits
125 bytes4 b0; // 32 bits
126 uint64 num1; // 64 bits
127 }
128 "#;
129
130 let source_unit = solang_parser::parse(contract, 0).unwrap().0;
131 let optimization_locations = pack_storage_variables_optimization(source_unit);
132 assert_eq!(optimization_locations.len(), 1);
133}