def _analyze_struct_events(self, contract: ContractSolc): contract.analyze_constant_state_variables() # Struct can refer to enum, or state variables contract.analyze_structs() # Event can refer to struct contract.analyze_events() contract.analyze_using_for() contract.set_is_analyzed(True)
def _analyze_variables_modifiers_functions(self, contract: ContractSolc): # State variables, modifiers and functions can refer to anything contract.analyze_params_modifiers() contract.analyze_params_functions() contract.analyze_state_variables() contract.analyze_content_modifiers() contract.analyze_content_functions() contract.set_is_analyzed(True)
def _parse_struct_var_modifiers_functions(self, contract: ContractSolc): contract.parse_structs() # struct can refer another struct contract.parse_state_variables() contract.parse_modifiers() contract.parse_functions() contract.set_is_analyzed(True)
def _analyze_enums(self, contract: ContractSolc): # Enum must be analyzed first contract.analyze_enums() contract.set_is_analyzed(True)
def parse_contracts_from_loaded_json( self, data_loaded: Dict, filename: str ): # pylint: disable=too-many-branches if "nodeType" in data_loaded: self._is_compact_ast = True if "sourcePaths" in data_loaded: for sourcePath in data_loaded["sourcePaths"]: if os.path.isfile(sourcePath): self._core.add_source_code(sourcePath) if data_loaded[self.get_key()] == "root": self._core.solc_version = "0.3" logger.error("solc <0.4 is not supported") return if data_loaded[self.get_key()] == "SourceUnit": self._core.solc_version = "0.4" self._parse_source_unit(data_loaded, filename) else: logger.error("solc version is not supported") return for contract_data in data_loaded[self.get_children()]: assert contract_data[self.get_key()] in [ "ContractDefinition", "PragmaDirective", "ImportDirective", "StructDefinition", "EnumDefinition", ] if contract_data[self.get_key()] == "ContractDefinition": contract = Contract() contract_parser = ContractSolc(self, contract, contract_data) if "src" in contract_data: contract.set_offset(contract_data["src"], self._core) self._underlying_contract_to_parser[contract] = contract_parser elif contract_data[self.get_key()] == "PragmaDirective": if self._is_compact_ast: pragma = Pragma(contract_data["literals"]) else: pragma = Pragma(contract_data["attributes"]["literals"]) pragma.set_offset(contract_data["src"], self._core) self._core.pragma_directives.append(pragma) elif contract_data[self.get_key()] == "ImportDirective": if self.is_compact_ast: import_directive = Import(contract_data["absolutePath"]) else: import_directive = Import(contract_data["attributes"].get("absolutePath", "")) import_directive.set_offset(contract_data["src"], self._core) self._core.import_directives.append(import_directive) elif contract_data[self.get_key()] in [ "StructDefinition", "EnumDefinition", ]: # This can only happen for top-level structure and enum # They were introduced with 0.6.5 assert self._is_compact_ast # Do not support top level definition for legacy AST fake_contract_data = { "name": f"SlitherInternalTopLevelContract{self._top_level_contracts_counter}", "id": -1000 + self._top_level_contracts_counter, # TODO: determine if collission possible "linearizedBaseContracts": [], "fullyImplemented": True, "contractKind": "SLitherInternal", } self._top_level_contracts_counter += 1 contract = Contract() top_level_contract = ContractSolc(self, contract, fake_contract_data) contract.is_top_level = True contract.set_offset(contract_data["src"], self._core) if contract_data[self.get_key()] == "StructDefinition": top_level_contract.structures_not_parsed.append( contract_data ) # Todo add proper setters else: top_level_contract.enums_not_parsed.append( contract_data ) # Todo add proper setters self._underlying_contract_to_parser[contract] = top_level_contract
def parse_top_level_from_loaded_json( self, data_loaded: Dict, filename: str ): # pylint: disable=too-many-branches,too-many-statements if "nodeType" in data_loaded: self._is_compact_ast = True if "sourcePaths" in data_loaded: for sourcePath in data_loaded["sourcePaths"]: if os.path.isfile(sourcePath): self._compilation_unit.core.add_source_code(sourcePath) if data_loaded[self.get_key()] == "root": logger.error("solc <0.4 is not supported") return if data_loaded[self.get_key()] == "SourceUnit": self._parse_source_unit(data_loaded, filename) else: logger.error("solc version is not supported") return for top_level_data in data_loaded[self.get_children()]: if top_level_data[self.get_key()] == "ContractDefinition": contract = Contract(self._compilation_unit) contract_parser = ContractSolc(self, contract, top_level_data) if "src" in top_level_data: contract.set_offset(top_level_data["src"], self._compilation_unit) self._underlying_contract_to_parser[contract] = contract_parser elif top_level_data[self.get_key()] == "PragmaDirective": if self._is_compact_ast: pragma = Pragma(top_level_data["literals"]) else: pragma = Pragma(top_level_data["attributes"]["literals"]) pragma.set_offset(top_level_data["src"], self._compilation_unit) self._compilation_unit.pragma_directives.append(pragma) elif top_level_data[self.get_key()] == "ImportDirective": if self.is_compact_ast: import_directive = Import(top_level_data["absolutePath"]) # TODO investigate unitAlias in version < 0.7 and legacy ast if "unitAlias" in top_level_data: import_directive.alias = top_level_data["unitAlias"] else: import_directive = Import(top_level_data["attributes"].get("absolutePath", "")) import_directive.set_offset(top_level_data["src"], self._compilation_unit) self._compilation_unit.import_directives.append(import_directive) elif top_level_data[self.get_key()] == "StructDefinition": st = StructureTopLevel() st.set_offset(top_level_data["src"], self._compilation_unit) st_parser = StructureTopLevelSolc(st, top_level_data, self) self._compilation_unit.structures_top_level.append(st) self._structures_top_level_parser.append(st_parser) elif top_level_data[self.get_key()] == "EnumDefinition": # Note enum don't need a complex parser, so everything is directly done self._parse_enum(top_level_data) elif top_level_data[self.get_key()] == "VariableDeclaration": var = TopLevelVariable() var_parser = TopLevelVariableSolc(var, top_level_data) var.set_offset(top_level_data["src"], self._compilation_unit) self._compilation_unit.variables_top_level.append(var) self._variables_top_level_parser.append(var_parser) elif top_level_data[self.get_key()] == "FunctionDefinition": func = FunctionTopLevel(self._compilation_unit) func_parser = FunctionSolc(func, top_level_data, None, self) self._compilation_unit.functions_top_level.append(func) self._functions_top_level_parser.append(func_parser) self.add_function_or_modifier_parser(func_parser) else: raise SlitherException(f"Top level {top_level_data[self.get_key()]} not supported")
def parse_top_level_from_loaded_json(self, data_loaded: Dict, filename: str): # pylint: disable=too-many-branches,too-many-statements,too-many-locals if "nodeType" in data_loaded: self._is_compact_ast = True if "sourcePaths" in data_loaded: for sourcePath in data_loaded["sourcePaths"]: if os.path.isfile(sourcePath): self._compilation_unit.core.add_source_code(sourcePath) if data_loaded[self.get_key()] == "root": logger.error("solc <0.4 is not supported") return if data_loaded[self.get_key()] == "SourceUnit": self._parse_source_unit(data_loaded, filename) else: logger.error("solc version is not supported") return if self.get_children() not in data_loaded: return scope = self.compilation_unit.get_scope(filename) for top_level_data in data_loaded[self.get_children()]: if top_level_data[self.get_key()] == "ContractDefinition": contract = Contract(self._compilation_unit, scope) contract_parser = ContractSolc(self, contract, top_level_data) scope.contracts[contract.name] = contract if "src" in top_level_data: contract.set_offset(top_level_data["src"], self._compilation_unit) self._underlying_contract_to_parser[contract] = contract_parser elif top_level_data[self.get_key()] == "PragmaDirective": if self._is_compact_ast: pragma = Pragma(top_level_data["literals"], scope) scope.pragmas.add(pragma) else: pragma = Pragma(top_level_data["attributes"]["literals"], scope) scope.pragmas.add(pragma) pragma.set_offset(top_level_data["src"], self._compilation_unit) self._compilation_unit.pragma_directives.append(pragma) elif top_level_data[self.get_key()] == "ImportDirective": if self.is_compact_ast: import_directive = Import( Path(top_level_data["absolutePath"], ), scope, ) scope.imports.add(import_directive) # TODO investigate unitAlias in version < 0.7 and legacy ast if "unitAlias" in top_level_data: import_directive.alias = top_level_data["unitAlias"] if "symbolAliases" in top_level_data: symbol_aliases = top_level_data["symbolAliases"] _handle_import_aliases(symbol_aliases, import_directive, scope) else: import_directive = Import( Path( top_level_data["attributes"].get( "absolutePath", ""), ), scope, ) scope.imports.add(import_directive) # TODO investigate unitAlias in version < 0.7 and legacy ast if ("attributes" in top_level_data and "unitAlias" in top_level_data["attributes"]): import_directive.alias = top_level_data["attributes"][ "unitAlias"] import_directive.set_offset(top_level_data["src"], self._compilation_unit) self._compilation_unit.import_directives.append( import_directive) get_imported_scope = self.compilation_unit.get_scope( import_directive.filename) scope.accessible_scopes.append(get_imported_scope) elif top_level_data[self.get_key()] == "StructDefinition": scope = self.compilation_unit.get_scope(filename) st = StructureTopLevel(self.compilation_unit, scope) st.set_offset(top_level_data["src"], self._compilation_unit) st_parser = StructureTopLevelSolc(st, top_level_data, self) scope.structures[st.name] = st self._compilation_unit.structures_top_level.append(st) self._structures_top_level_parser.append(st_parser) elif top_level_data[self.get_key()] == "EnumDefinition": # Note enum don't need a complex parser, so everything is directly done self._parse_enum(top_level_data, filename) elif top_level_data[self.get_key()] == "VariableDeclaration": var = TopLevelVariable(scope) var_parser = TopLevelVariableSolc(var, top_level_data, self) var.set_offset(top_level_data["src"], self._compilation_unit) self._compilation_unit.variables_top_level.append(var) self._variables_top_level_parser.append(var_parser) scope.variables[var.name] = var elif top_level_data[self.get_key()] == "FunctionDefinition": scope = self.compilation_unit.get_scope(filename) func = FunctionTopLevel(self._compilation_unit, scope) scope.functions.add(func) func.set_offset(top_level_data["src"], self._compilation_unit) func_parser = FunctionSolc(func, top_level_data, None, self) self._compilation_unit.functions_top_level.append(func) self._functions_top_level_parser.append(func_parser) self.add_function_or_modifier_parser(func_parser) elif top_level_data[self.get_key()] == "ErrorDefinition": scope = self.compilation_unit.get_scope(filename) custom_error = CustomErrorTopLevel(self._compilation_unit, scope) custom_error.set_offset(top_level_data["src"], self._compilation_unit) custom_error_parser = CustomErrorSolc(custom_error, top_level_data, self) scope.custom_errors.add(custom_error) self._compilation_unit.custom_errors.append(custom_error) self._custom_error_parser.append(custom_error_parser) elif top_level_data[ self.get_key()] == "UserDefinedValueTypeDefinition": assert "name" in top_level_data alias = top_level_data["name"] assert "underlyingType" in top_level_data underlying_type = top_level_data["underlyingType"] assert ("nodeType" in underlying_type and underlying_type["nodeType"] == "ElementaryTypeName") assert "name" in underlying_type original_type = ElementaryType(underlying_type["name"]) user_defined_type = TypeAliasTopLevel(original_type, alias, scope) user_defined_type.set_offset(top_level_data["src"], self._compilation_unit) scope.user_defined_types[alias] = user_defined_type else: raise SlitherException( f"Top level {top_level_data[self.get_key()]} not supported" )