@@ -7,8 +7,13 @@ pub(super) fn build_from(structured_ast_model: &IrModel) -> ModelWithTransformer
77 unify_function_types ( & mut mutator) ;
88 flatten_function_attributes ( & mut mutator) ;
99 flatten_state_variable_attributes ( & mut mutator) ;
10+ transmute_constant_state_variables ( & mut mutator) ;
1011 collapse_redundant_node_types ( & mut mutator) ;
1112 simplify_string_literals ( & mut mutator) ;
13+ simplify_imports ( & mut mutator) ;
14+ simplify_variable_declarations ( & mut mutator) ;
15+ simplify_parameters ( & mut mutator) ;
16+ simplify_mapping_type_parameters ( & mut mutator) ;
1217
1318 mutator. into ( )
1419}
@@ -138,13 +143,17 @@ fn flatten_function_attributes(mutator: &mut IrModelMutator) {
138143}
139144
140145fn flatten_state_variable_attributes ( mutator : & mut IrModelMutator ) {
141- // Function visibility, computed from a subset of the attributes
146+ // State variable visibility, computed from a subset of the attributes
142147 mutator. add_enum_type (
143148 "StateVariableVisibility" ,
144149 & [ "Public" , "Private" , "Internal" ] ,
145150 ) ;
146151
147- // Function mutability, computed from a subset of the attributes
152+ // State variable mutability, computed from a subset of the attributes.
153+ // NB. Even though most constant declarations are transformed into
154+ // `ConstantDefinition`, those with `public` visibility need to generate a
155+ // getter and thus we still need to represent them using a
156+ // `StateVariableDefinition`.
148157 mutator. add_enum_type (
149158 "StateVariableMutability" ,
150159 & [ "Mutable" , "Constant" , "Immutable" , "Transient" ] ,
@@ -174,14 +183,35 @@ fn flatten_state_variable_attributes(mutator: &mut IrModelMutator) {
174183 mutator. remove_type ( "StateVariableAttribute" ) ;
175184}
176185
186+ fn transmute_constant_state_variables ( mutator : & mut IrModelMutator ) {
187+ // State variables that are marked constant and are not public will be
188+ // transformed into `ConstantDefinition` (ie. the type used for top-level
189+ // constant definitions). Public constant state variables *cannot* be
190+ // transformed because they generate a getter, so it makes more sense to
191+ // keep them as `StateVariableDefinition`
192+ mutator. add_choice_variant ( "ContractMember" , "ConstantDefinition" ) ;
193+
194+ // Modify `ConstantDefinition` to accomodate for constant state variables
195+ mutator. add_sequence_field (
196+ "ConstantDefinition" ,
197+ "visibility" ,
198+ "StateVariableVisibility" ,
199+ true ,
200+ ) ;
201+
202+ // ...and make the value optional because state variables may not define it
203+ // NOTE: this is not valid Solidity, but we still want to support the
204+ // representation until we have robust validation
205+ mutator. remove_sequence_field ( "ConstantDefinition" , "value" ) ;
206+ mutator. add_sequence_field ( "ConstantDefinition" , "value" , "Expression" , true ) ;
207+ }
208+
177209fn collapse_redundant_node_types ( mutator : & mut IrModelMutator ) {
178210 // Collapse redundant node types
179211 mutator. collapse_sequence ( "ParametersDeclaration" ) ;
180212 mutator. collapse_sequence ( "ReturnsDeclaration" ) ;
181213 mutator. collapse_sequence ( "YulParametersDeclaration" ) ;
182214 mutator. collapse_sequence ( "YulReturnsDeclaration" ) ;
183- mutator. collapse_sequence ( "EventParametersDeclaration" ) ;
184- mutator. collapse_sequence ( "ErrorParametersDeclaration" ) ;
185215 mutator. collapse_sequence ( "ImportAlias" ) ;
186216 mutator. collapse_sequence ( "ElseBranch" ) ;
187217 mutator. collapse_sequence ( "UsingAlias" ) ;
@@ -244,3 +274,78 @@ fn simplify_string_literals(mutator: &mut IrModelMutator) {
244274 mutator. add_sequence_field ( "AssemblyStatement" , "flags" , "AssemblyFlags" , false ) ;
245275 mutator. add_sequence_field ( "AssemblyStatement" , "label" , "StringLiteral" , true ) ;
246276}
277+
278+ fn simplify_imports ( mutator : & mut IrModelMutator ) {
279+ // Collapse `ImportDirective` which is only a container for the `ImportClause`
280+ mutator. collapse_sequence ( "ImportDirective" ) ;
281+ // Remove `NamedImport`, since it can be converted to the equivalent `PathImport`
282+ mutator. remove_type ( "NamedImport" ) ;
283+ // TODO: collapsing `ImportDirective` means that the `ImportClause` gets
284+ // lifted to the `SourceUnitMember` enum and its name is inconsistent with
285+ // the rest of the variants (eg. `PragmaDirective` or `UsingDirective`). We
286+ // want to either rename `ImportClause` to `ImportDirective` (this may lead
287+ // to confusion due to the difference against the CST) or find a new better
288+ // name.
289+ }
290+
291+ fn simplify_variable_declarations ( mutator : & mut IrModelMutator ) {
292+ // Collapse the `VariableDeclarationType` into the parent `VariableDeclarationStatement`
293+ mutator. remove_type ( "VariableDeclarationType" ) ;
294+ mutator. add_sequence_field (
295+ "VariableDeclarationStatement" ,
296+ "type_name" ,
297+ "TypeName" ,
298+ true ,
299+ ) ;
300+
301+ // Re-use `VariableDeclarationStatement` for variable declarations in tuple
302+ // deconstruction expressions. Remove `TupleMember` first.
303+ mutator. remove_type ( "UntypedTupleMember" ) ;
304+ mutator. remove_type ( "TypedTupleMember" ) ;
305+ mutator. remove_type ( "TupleMember" ) ;
306+ mutator. remove_type ( "TupleDeconstructionElements" ) ;
307+ mutator. remove_type ( "TupleDeconstructionElement" ) ;
308+
309+ // Create a `TupleDeconstructionMember` initially as an enum so that the
310+ // `None` variant has no child
311+ mutator. add_enum_type ( "TupleDeconstructionMember" , & [ "None" ] ) ;
312+ mutator. add_choice_variant ( "TupleDeconstructionMember" , "Identifier" ) ;
313+ mutator. add_choice_variant ( "TupleDeconstructionMember" , "VariableDeclarationStatement" ) ;
314+ mutator. add_collection_type ( "TupleDeconstructionMembers" , "TupleDeconstructionMember" ) ;
315+ mutator. add_sequence_field (
316+ "TupleDeconstructionStatement" ,
317+ "members" ,
318+ "TupleDeconstructionMembers" ,
319+ false ,
320+ ) ;
321+ // This refactor also means we don't need the `var_keyword` field in the
322+ // `TupleDeconstructionStatement` anymore
323+ mutator. remove_sequence_field ( "TupleDeconstructionStatement" , "var_keyword" ) ;
324+ }
325+
326+ fn simplify_parameters ( mutator : & mut IrModelMutator ) {
327+ // Replace `EventParameter` and `ErrorParameter` with `Parameter`. This
328+ // requires adding an `indexed` attribute (required for event parameters).
329+ mutator. add_sequence_field ( "Parameter" , "indexed" , "IndexedKeyword" , true ) ;
330+
331+ mutator. remove_type ( "EventParametersDeclaration" ) ;
332+ mutator. remove_type ( "EventParameters" ) ;
333+ mutator. remove_type ( "EventParameter" ) ;
334+ mutator. add_sequence_field ( "EventDefinition" , "parameters" , "Parameters" , false ) ;
335+
336+ mutator. remove_type ( "ErrorParametersDeclaration" ) ;
337+ mutator. remove_type ( "ErrorParameters" ) ;
338+ mutator. remove_type ( "ErrorParameter" ) ;
339+ mutator. add_sequence_field ( "ErrorDefinition" , "parameters" , "Parameters" , false ) ;
340+ }
341+
342+ fn simplify_mapping_type_parameters ( mutator : & mut IrModelMutator ) {
343+ // Replace `MappingKey` and `MappingValue` with regular `Parameter` types.
344+ // `MappingKeyType` is a subset of `TypeName` and can be removed as well.
345+ mutator. remove_type ( "MappingKeyType" ) ;
346+ mutator. remove_type ( "MappingKey" ) ;
347+ mutator. remove_type ( "MappingValue" ) ;
348+
349+ mutator. add_sequence_field ( "MappingType" , "key_type" , "Parameter" , false ) ;
350+ mutator. add_sequence_field ( "MappingType" , "value_type" , "Parameter" , false ) ;
351+ }
0 commit comments