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_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: 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: 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, 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)