def analyze_expressions(self, caller_context): if self.type == NodeType.VARIABLE and not self._expression: self._expression = self.variable_declaration.expression if self._unparsed_expression: expression = parse_expression(self._unparsed_expression, caller_context) self._expression = expression self._unparsed_expression = None if self.expression: expression = self.expression pp = ReadVar(expression) self._expression_vars_read = pp.result() vars_read = [ExportValues(v).result() for v in self._expression_vars_read] self._vars_read = [item for sublist in vars_read for item in sublist] self._state_vars_read = [x for x in self.variables_read if\ isinstance(x, (StateVariable))] self._solidity_vars_read = [x for x in self.variables_read if\ isinstance(x, (SolidityVariable))] pp = WriteVar(expression) self._expression_vars_written = pp.result() vars_written = [ExportValues(v).result() for v in self._expression_vars_written] self._vars_written = [item for sublist in vars_written for item in sublist] self._state_vars_written = [x for x in self.variables_written if\ isinstance(x, StateVariable)] pp = FindCalls(expression) self._expression_calls = pp.result() calls = [ExportValues(c).result() for c in self.calls_as_expression] calls = [item for sublist in calls for item in sublist] self._internal_calls = [c for c in calls if isinstance(c, (Function, SolidityFunction))] self._external_calls = [c for c in self.calls_as_expression if not isinstance(c.called, Identifier)]
def _parse_modifier(self, modifier): m = parse_expression(modifier, self) self._expression_modifiers.append(m) for m in ExportValues(m).result(): if isinstance(m, Function): self._modifiers.append(m) elif isinstance(m, Contract): self._explicit_base_constructor_calls.append(m)
def analyze(self, caller_context): # Can be re-analyzed due to inheritance if self._was_analyzed: return self._was_analyzed = True if self._elem_to_parse: self._type = parse_type(self._elem_to_parse, caller_context) self._elem_to_parse = None if self._initialized: self._initial_expression = parse_expression(self._initializedNotParsed, caller_context) self._initializedNotParsed = None
def analyze_expressions(self, caller_context): if self.type == NodeType.VARIABLE and not self._expression: self._expression = self.variable_declaration.expression if self._unparsed_expression: expression = parse_expression(self._unparsed_expression, caller_context) self._expression = expression self._unparsed_expression = None if self.expression: if self.type == NodeType.VARIABLE: # Update the expression to be an assignement to the variable #print(self.variable_declaration) _expression = AssignmentOperation( Identifier(self.variable_declaration), self.expression, AssignmentOperationType.ASSIGN, self.variable_declaration.type) _expression.set_offset(self.expression.source_mapping, self.slither) self._expression = _expression expression = self.expression pp = ReadVar(expression) self._expression_vars_read = pp.result() # self._vars_read = [item for sublist in vars_read for item in sublist] # self._state_vars_read = [x for x in self.variables_read if\ # isinstance(x, (StateVariable))] # self._solidity_vars_read = [x for x in self.variables_read if\ # isinstance(x, (SolidityVariable))] pp = WriteVar(expression) self._expression_vars_written = pp.result() # self._vars_written = [item for sublist in vars_written for item in sublist] # self._state_vars_written = [x for x in self.variables_written if\ # isinstance(x, StateVariable)] pp = FindCalls(expression) self._expression_calls = pp.result() self._external_calls_as_expressions = [ c for c in self.calls_as_expression if not isinstance(c.called, Identifier) ] self._internal_calls_as_expressions = [ c for c in self.calls_as_expression if isinstance(c.called, Identifier) ]
def _parse_modifier(self, modifier): m = parse_expression(modifier, self) self._expression_modifiers.append(m) for m in ExportValues(m).result(): if isinstance(m, Function): entry_point = self._new_node(NodeType.OTHER_ENTRYPOINT, modifier['src']) node = self._new_node(NodeType.EXPRESSION, modifier['src']) node.add_unparsed_expression(modifier) link_nodes(entry_point, node) self._modifiers.append(ModifierStatements(modifier=m, entry_point=entry_point, nodes=[entry_point, node])) elif isinstance(m, Contract): entry_point = self._new_node(NodeType.OTHER_ENTRYPOINT, modifier['src']) node = self._new_node(NodeType.EXPRESSION, modifier['src']) node.add_unparsed_expression(modifier) link_nodes(entry_point, node) self._explicit_base_constructor_calls.append(ModifierStatements(modifier=m, entry_point=entry_point, nodes=[entry_point, node]))
def analyze_expressions(self, caller_context): if self._node.type == NodeType.VARIABLE and not self._node.expression: self._node.add_expression( self._node.variable_declaration.expression) if self._unparsed_expression: expression = parse_expression(self._unparsed_expression, caller_context) self._node.add_expression(expression) # self._unparsed_expression = None if self._node.expression: if self._node.type == NodeType.VARIABLE: # Update the expression to be an assignement to the variable _expression = AssignmentOperation( Identifier(self._node.variable_declaration), self._node.expression, AssignmentOperationType.ASSIGN, self._node.variable_declaration.type, ) _expression.set_offset(self._node.expression.source_mapping, self._node.slither) self._node.add_expression(_expression, bypass_verif_empty=True) expression = self._node.expression read_var = ReadVar(expression) self._node.variables_read_as_expression = read_var.result() write_var = WriteVar(expression) self._node.variables_written_as_expression = write_var.result() find_call = FindCalls(expression) self._node.calls_as_expression = find_call.result() self._node.external_calls_as_expressions = [ c for c in self._node.calls_as_expression if not isinstance(c.called, Identifier) ] self._node.internal_calls_as_expressions = [ c for c in self._node.calls_as_expression if isinstance(c.called, Identifier) ]
def _parse_modifier(self, modifier): m = parse_expression(modifier, self) self._expression_modifiers.append(m) # Do not parse modifier nodes for interfaces if not self._is_implemented: return for m in ExportValues(m).result(): if isinstance(m, Function): node = self._new_node(NodeType.EXPRESSION, modifier['src']) node.add_unparsed_expression(modifier) # The latest entry point is the entry point, or the latest modifier call if self._modifiers: latest_entry_point = self._modifiers[-1].nodes[-1] else: latest_entry_point = self.entry_point insert_node(latest_entry_point, node) self._modifiers.append( ModifierStatements(modifier=m, entry_point=latest_entry_point, nodes=[latest_entry_point, node])) elif isinstance(m, Contract): node = self._new_node(NodeType.EXPRESSION, modifier['src']) node.add_unparsed_expression(modifier) # The latest entry point is the entry point, or the latest constructor call if self._explicit_base_constructor_calls: latest_entry_point = self._explicit_base_constructor_calls[ -1].nodes[-1] else: latest_entry_point = self.entry_point insert_node(latest_entry_point, node) self._explicit_base_constructor_calls.append( ModifierStatements(modifier=m, entry_point=latest_entry_point, nodes=[latest_entry_point, node]))
def parse_type(t, caller_context): # local import to avoid circular dependency from slither.solc_parsing.expressions.expression_parsing import parse_expression from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc if isinstance(caller_context, Contract): contract = caller_context elif isinstance(caller_context, Function): contract = caller_context.contract else: raise ParsingError('Incorrect caller context') is_compact_ast = caller_context.is_compact_ast if is_compact_ast: key = 'nodeType' else: key = 'name' structures = contract.structures enums = contract.enums contracts = contract.slither.contracts if isinstance(t, UnknownType): return _find_from_type_name(t.name, contract, contracts, structures, enums) elif t[key] == 'ElementaryTypeName': if is_compact_ast: return ElementaryType(t['name']) return ElementaryType(t['attributes'][key]) elif t[key] == 'UserDefinedTypeName': if is_compact_ast: return _find_from_type_name(t['typeDescriptions']['typeString'], contract, contracts, structures, enums) # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type'). type_name_key = 'type' if 'type' in t['attributes'] else key return _find_from_type_name(t['attributes'][type_name_key], contract, contracts, structures, enums) elif t[key] == 'ArrayTypeName': length = None if is_compact_ast: if t['length']: length = parse_expression(t['length'], caller_context) array_type = parse_type(t['baseType'], contract) else: if len(t['children']) == 2: length = parse_expression(t['children'][1], caller_context) else: assert len(t['children']) == 1 array_type = parse_type(t['children'][0], contract) return ArrayType(array_type, length) elif t[key] == 'Mapping': if is_compact_ast: mappingFrom = parse_type(t['keyType'], contract) mappingTo = parse_type(t['valueType'], contract) else: assert len(t['children']) == 2 mappingFrom = parse_type(t['children'][0], contract) mappingTo = parse_type(t['children'][1], contract) return MappingType(mappingFrom, mappingTo) elif t[key] == 'FunctionTypeName': if is_compact_ast: params = t['parameterTypes'] return_values = t['returnParameterTypes'] index = 'parameters' else: assert len(t['children']) == 2 params = t['children'][0] return_values = t['children'][1] index = 'children' assert params[key] == 'ParameterList' assert return_values[key] == 'ParameterList' params_vars = [] return_values_vars = [] for p in params[index]: var = FunctionTypeVariableSolc(p) var.set_offset(p['src'], caller_context.slither) var.analyze(caller_context) params_vars.append(var) for p in return_values[index]: var = FunctionTypeVariableSolc(p) var.set_offset(p['src'], caller_context.slither) var.analyze(caller_context) return_values_vars.append(var) return FunctionType(params_vars, return_values_vars) raise ParsingError('Type name not found ' + str(t))
def _parse_modifier(self, modifier): m = parse_expression(modifier, self) self._expression_modifiers.append(m) self._modifiers += [ m for m in ExportValues(m).result() if isinstance(m, Function) ]
def parse_type(t: Union[Dict, UnknownType], caller_context): # local import to avoid circular dependency # pylint: disable=too-many-locals,too-many-branches,too-many-statements # pylint: disable=import-outside-toplevel from slither.solc_parsing.expressions.expression_parsing import parse_expression from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.slitherSolc import SlitherSolc # Note: for convenicence top level functions use the same parser than function in contract # but contract_parser is set to None if isinstance(caller_context, SlitherSolc) or ( isinstance(caller_context, FunctionSolc) and caller_context.contract_parser is None ): if isinstance(caller_context, SlitherSolc): sl = caller_context.core next_context = caller_context else: assert isinstance(caller_context, FunctionSolc) sl = caller_context.underlying_function.slither next_context = caller_context.slither_parser structures_direct_access = sl.structures_top_level all_structuress = [c.structures for c in sl.contracts] all_structures = [item for sublist in all_structuress for item in sublist] all_structures += structures_direct_access enums_direct_access = sl.enums_top_level all_enumss = [c.enums for c in sl.contracts] all_enums = [item for sublist in all_enumss for item in sublist] all_enums += enums_direct_access contracts = sl.contracts functions = [] elif isinstance(caller_context, (ContractSolc, FunctionSolc)): if isinstance(caller_context, FunctionSolc): underlying_func = caller_context.underlying_function # If contract_parser is set to None, then underlying_function is a functionContract # See note above assert isinstance(underlying_func, FunctionContract) contract = underlying_func.contract next_context = caller_context.contract_parser else: contract = caller_context.underlying_contract next_context = caller_context structures_direct_access = contract.structures + contract.slither.structures_top_level all_structuress = [c.structures for c in contract.slither.contracts] all_structures = [item for sublist in all_structuress for item in sublist] all_structures += contract.slither.structures_top_level enums_direct_access = contract.enums + contract.slither.enums_top_level all_enumss = [c.enums for c in contract.slither.contracts] all_enums = [item for sublist in all_enumss for item in sublist] all_enums += contract.slither.enums_top_level contracts = contract.slither.contracts functions = contract.functions + contract.modifiers else: raise ParsingError(f"Incorrect caller context: {type(caller_context)}") is_compact_ast = caller_context.is_compact_ast if is_compact_ast: key = "nodeType" else: key = "name" if isinstance(t, UnknownType): return _find_from_type_name( t.name, functions, contracts, structures_direct_access, all_structures, enums_direct_access, all_enums, ) if t[key] == "ElementaryTypeName": if is_compact_ast: return ElementaryType(t["name"]) return ElementaryType(t["attributes"][key]) if t[key] == "UserDefinedTypeName": if is_compact_ast: return _find_from_type_name( t["typeDescriptions"]["typeString"], functions, contracts, structures_direct_access, all_structures, enums_direct_access, all_enums, ) # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type'). type_name_key = "type" if "type" in t["attributes"] else key return _find_from_type_name( t["attributes"][type_name_key], functions, contracts, structures_direct_access, all_structures, enums_direct_access, all_enums, ) if t[key] == "ArrayTypeName": length = None if is_compact_ast: if t.get("length", None): length = parse_expression(t["length"], caller_context) array_type = parse_type(t["baseType"], next_context) else: if len(t["children"]) == 2: length = parse_expression(t["children"][1], caller_context) else: assert len(t["children"]) == 1 array_type = parse_type(t["children"][0], next_context) return ArrayType(array_type, length) if t[key] == "Mapping": if is_compact_ast: mappingFrom = parse_type(t["keyType"], next_context) mappingTo = parse_type(t["valueType"], next_context) else: assert len(t["children"]) == 2 mappingFrom = parse_type(t["children"][0], next_context) mappingTo = parse_type(t["children"][1], next_context) return MappingType(mappingFrom, mappingTo) if t[key] == "FunctionTypeName": if is_compact_ast: params = t["parameterTypes"] return_values = t["returnParameterTypes"] index = "parameters" else: assert len(t["children"]) == 2 params = t["children"][0] return_values = t["children"][1] index = "children" assert params[key] == "ParameterList" assert return_values[key] == "ParameterList" params_vars: List[FunctionTypeVariable] = [] return_values_vars: List[FunctionTypeVariable] = [] for p in params[index]: var = FunctionTypeVariable() var.set_offset(p["src"], caller_context.slither) var_parser = FunctionTypeVariableSolc(var, p) var_parser.analyze(caller_context) params_vars.append(var) for p in return_values[index]: var = FunctionTypeVariable() var.set_offset(p["src"], caller_context.slither) var_parser = FunctionTypeVariableSolc(var, p) var_parser.analyze(caller_context) return_values_vars.append(var) return FunctionType(params_vars, return_values_vars) raise ParsingError("Type name not found " + str(t))
def parse_type(t: Union[Dict, UnknownType], caller_context): # local import to avoid circular dependency # pylint: disable=too-many-locals,too-many-branches,too-many-statements # pylint: disable=import-outside-toplevel from slither.solc_parsing.expressions.expression_parsing import parse_expression from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.function import FunctionSolc if isinstance(caller_context, ContractSolc): contract = caller_context.underlying_contract contract_parser = caller_context is_compact_ast = caller_context.is_compact_ast elif isinstance(caller_context, FunctionSolc): contract = caller_context.underlying_function.contract contract_parser = caller_context.contract_parser is_compact_ast = caller_context.is_compact_ast else: raise ParsingError(f"Incorrect caller context: {type(caller_context)}") if is_compact_ast: key = "nodeType" else: key = "name" structures = contract.structures + contract.slither.top_level_structures enums = contract.enums + contract.slither.top_level_enums contracts = contract.slither.contracts if isinstance(t, UnknownType): return _find_from_type_name(t.name, contract, contracts, structures, enums) if t[key] == "ElementaryTypeName": if is_compact_ast: return ElementaryType(t["name"]) return ElementaryType(t["attributes"][key]) if t[key] == "UserDefinedTypeName": if is_compact_ast: return _find_from_type_name( t["typeDescriptions"]["typeString"], contract, contracts, structures, enums, ) # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type'). type_name_key = "type" if "type" in t["attributes"] else key return _find_from_type_name( t["attributes"][type_name_key], contract, contracts, structures, enums ) if t[key] == "ArrayTypeName": length = None if is_compact_ast: if t.get("length", None): length = parse_expression(t["length"], caller_context) array_type = parse_type(t["baseType"], contract_parser) else: if len(t["children"]) == 2: length = parse_expression(t["children"][1], caller_context) else: assert len(t["children"]) == 1 array_type = parse_type(t["children"][0], contract_parser) return ArrayType(array_type, length) if t[key] == "Mapping": if is_compact_ast: mappingFrom = parse_type(t["keyType"], contract_parser) mappingTo = parse_type(t["valueType"], contract_parser) else: assert len(t["children"]) == 2 mappingFrom = parse_type(t["children"][0], contract_parser) mappingTo = parse_type(t["children"][1], contract_parser) return MappingType(mappingFrom, mappingTo) if t[key] == "FunctionTypeName": if is_compact_ast: params = t["parameterTypes"] return_values = t["returnParameterTypes"] index = "parameters" else: assert len(t["children"]) == 2 params = t["children"][0] return_values = t["children"][1] index = "children" assert params[key] == "ParameterList" assert return_values[key] == "ParameterList" params_vars: List[FunctionTypeVariable] = [] return_values_vars: List[FunctionTypeVariable] = [] for p in params[index]: var = FunctionTypeVariable() var.set_offset(p["src"], caller_context.slither) var_parser = FunctionTypeVariableSolc(var, p) var_parser.analyze(caller_context) params_vars.append(var) for p in return_values[index]: var = FunctionTypeVariable() var.set_offset(p["src"], caller_context.slither) var_parser = FunctionTypeVariableSolc(var, p) var_parser.analyze(caller_context) return_values_vars.append(var) return FunctionType(params_vars, return_values_vars) raise ParsingError("Type name not found " + str(t))
def parse_type( t: Union[Dict, UnknownType], caller_context: Union[CallerContextExpression, "SlitherCompilationUnitSolc"], ) -> Type: """ caller_context can be a SlitherCompilationUnitSolc because we recursively call the function and go up in the context's scope. If we are really lost we just go over the SlitherCompilationUnitSolc :param t: :type t: :param caller_context: :type caller_context: :return: :rtype: """ # local import to avoid circular dependency # pylint: disable=too-many-locals,too-many-branches,too-many-statements # pylint: disable=import-outside-toplevel from slither.solc_parsing.expressions.expression_parsing import parse_expression from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.custom_error import CustomErrorSolc from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc sl: "SlitherCompilationUnit" renaming: Dict[str, str] user_defined_types: Dict[str, TypeAlias] # Note: for convenicence top level functions use the same parser than function in contract # but contract_parser is set to None if isinstance(caller_context, SlitherCompilationUnitSolc) or ( isinstance(caller_context, FunctionSolc) and caller_context.contract_parser is None): structures_direct_access: List["Structure"] if isinstance(caller_context, SlitherCompilationUnitSolc): sl = caller_context.compilation_unit next_context = caller_context renaming = {} user_defined_types = {} else: assert isinstance(caller_context, FunctionSolc) sl = caller_context.underlying_function.compilation_unit next_context = caller_context.slither_parser renaming = caller_context.underlying_function.file_scope.renaming user_defined_types = caller_context.underlying_function.file_scope.user_defined_types structures_direct_access = sl.structures_top_level all_structuress = [c.structures for c in sl.contracts] all_structures = [ item for sublist in all_structuress for item in sublist ] all_structures += structures_direct_access enums_direct_access = sl.enums_top_level all_enumss = [c.enums for c in sl.contracts] all_enums = [item for sublist in all_enumss for item in sublist] all_enums += enums_direct_access contracts = sl.contracts functions = [] elif isinstance( caller_context, (StructureTopLevelSolc, CustomErrorSolc, TopLevelVariableSolc)): if isinstance(caller_context, StructureTopLevelSolc): scope = caller_context.underlying_structure.file_scope elif isinstance(caller_context, TopLevelVariableSolc): scope = caller_context.underlying_variable.file_scope else: assert isinstance(caller_context, CustomErrorSolc) custom_error = caller_context.underlying_custom_error if isinstance(custom_error, CustomErrorTopLevel): scope = custom_error.file_scope else: assert isinstance(custom_error, CustomErrorContract) scope = custom_error.contract.file_scope next_context = caller_context.slither_parser structures_direct_access = list(scope.structures.values()) all_structuress = [c.structures for c in scope.contracts.values()] all_structures = [ item for sublist in all_structuress for item in sublist ] all_structures += structures_direct_access enums_direct_access = [] all_enums = scope.enums.values() contracts = scope.contracts.values() functions = list(scope.functions) renaming = scope.renaming user_defined_types = scope.user_defined_types elif isinstance(caller_context, (ContractSolc, FunctionSolc)): if isinstance(caller_context, FunctionSolc): underlying_func = caller_context.underlying_function # If contract_parser is set to None, then underlying_function is a functionContract # See note above assert isinstance(underlying_func, FunctionContract) contract = underlying_func.contract next_context = caller_context.contract_parser scope = caller_context.underlying_function.file_scope else: contract = caller_context.underlying_contract next_context = caller_context scope = caller_context.underlying_contract.file_scope structures_direct_access = contract.structures structures_direct_access += contract.file_scope.structures.values() all_structuress = [ c.structures for c in contract.file_scope.contracts.values() ] all_structures = [ item for sublist in all_structuress for item in sublist ] all_structures += contract.file_scope.structures.values() enums_direct_access: List["Enum"] = contract.enums enums_direct_access += contract.file_scope.enums.values() all_enumss = [c.enums for c in contract.file_scope.contracts.values()] all_enums = [item for sublist in all_enumss for item in sublist] all_enums += contract.file_scope.enums.values() contracts = contract.file_scope.contracts.values() functions = contract.functions + contract.modifiers renaming = scope.renaming user_defined_types = scope.user_defined_types else: raise ParsingError(f"Incorrect caller context: {type(caller_context)}") is_compact_ast = caller_context.is_compact_ast if is_compact_ast: key = "nodeType" else: key = "name" if isinstance(t, UnknownType): name = t.name if name in renaming: name = renaming[name] if name in user_defined_types: return user_defined_types[name] return _find_from_type_name( name, functions, contracts, structures_direct_access, all_structures, enums_direct_access, all_enums, ) if t[key] == "ElementaryTypeName": if is_compact_ast: return ElementaryType(t["name"]) return ElementaryType(t["attributes"][key]) if t[key] == "UserDefinedTypeName": if is_compact_ast: name = t["typeDescriptions"]["typeString"] if name in renaming: name = renaming[name] if name in user_defined_types: return user_defined_types[name] return _find_from_type_name( name, functions, contracts, structures_direct_access, all_structures, enums_direct_access, all_enums, ) # Determine if we have a type node (otherwise we use the name node, as some older solc did not have 'type'). type_name_key = "type" if "type" in t["attributes"] else key name = t["attributes"][type_name_key] if name in renaming: name = renaming[name] if name in user_defined_types: return user_defined_types[name] return _find_from_type_name( name, functions, contracts, structures_direct_access, all_structures, enums_direct_access, all_enums, ) # Introduced with Solidity 0.8 if t[key] == "IdentifierPath": if is_compact_ast: name = t["name"] if name in renaming: name = renaming[name] if name in user_defined_types: return user_defined_types[name] return _find_from_type_name( name, functions, contracts, structures_direct_access, all_structures, enums_direct_access, all_enums, ) raise SlitherError("Solidity 0.8 not supported with the legacy AST") if t[key] == "ArrayTypeName": length = None if is_compact_ast: if t.get("length", None): length = parse_expression(t["length"], caller_context) array_type = parse_type(t["baseType"], next_context) else: if len(t["children"]) == 2: length = parse_expression(t["children"][1], caller_context) else: assert len(t["children"]) == 1 array_type = parse_type(t["children"][0], next_context) return ArrayType(array_type, length) if t[key] == "Mapping": if is_compact_ast: mappingFrom = parse_type(t["keyType"], next_context) mappingTo = parse_type(t["valueType"], next_context) else: assert len(t["children"]) == 2 mappingFrom = parse_type(t["children"][0], next_context) mappingTo = parse_type(t["children"][1], next_context) return MappingType(mappingFrom, mappingTo) if t[key] == "FunctionTypeName": if is_compact_ast: params = t["parameterTypes"] return_values = t["returnParameterTypes"] index = "parameters" else: assert len(t["children"]) == 2 params = t["children"][0] return_values = t["children"][1] index = "children" assert params[key] == "ParameterList" assert return_values[key] == "ParameterList" params_vars: List[FunctionTypeVariable] = [] return_values_vars: List[FunctionTypeVariable] = [] for p in params[index]: var = FunctionTypeVariable() var.set_offset(p["src"], caller_context.compilation_unit) var_parser = FunctionTypeVariableSolc(var, p) var_parser.analyze(caller_context) params_vars.append(var) for p in return_values[index]: var = FunctionTypeVariable() var.set_offset(p["src"], caller_context.compilation_unit) var_parser = FunctionTypeVariableSolc(var, p) var_parser.analyze(caller_context) return_values_vars.append(var) return FunctionType(params_vars, return_values_vars) raise ParsingError("Type name not found " + str(t))
def parse_type(t, caller_context): # local import to avoid circular dependency from slither.solc_parsing.expressions.expression_parsing import parse_expression from slither.solc_parsing.variables.function_type_variable import FunctionTypeVariableSolc if isinstance(caller_context, Contract): contract = caller_context elif isinstance(caller_context, Function): contract = caller_context.contract else: logger.error('Incorrect caller context') exit(-1) structures = contract.structures enums = contract.enums contracts = contract.slither.contracts if isinstance(t, UnknownType): return _find_from_type_name(t.name, contract, contracts, structures, enums) elif t['name'] == 'ElementaryTypeName': return ElementaryType(t['attributes']['name']) elif t['name'] == 'UserDefinedTypeName': return _find_from_type_name(t['attributes']['name'], contract, contracts, structures, enums) elif t['name'] == 'ArrayTypeName': length = None if len(t['children']) == 2: length = parse_expression(t['children'][1], caller_context) else: assert len(t['children']) == 1 array_type = parse_type(t['children'][0], contract) return ArrayType(array_type, length) elif t['name'] == 'Mapping': assert len(t['children']) == 2 mappingFrom = parse_type(t['children'][0], contract) mappingTo = parse_type(t['children'][1], contract) return MappingType(mappingFrom, mappingTo) elif t['name'] == 'FunctionTypeName': assert len(t['children']) == 2 params = t['children'][0] return_values = t['children'][1] assert params['name'] == 'ParameterList' assert return_values['name'] == 'ParameterList' params_vars = [] return_values_vars = [] for p in params['children']: var = FunctionTypeVariableSolc(p) var.set_offset(p['src'], caller_context.slither) var.analyze(caller_context) params_vars.append(var) for p in return_values['children']: var = FunctionTypeVariableSolc(p) var.set_offset(p['src'], caller_context.slither) var.analyze(caller_context) return_values_vars.append(var) return FunctionType(params_vars, return_values_vars) logger.error('Type name not found ' + str(t)) exit(-1)