slither.vyper_parsing.type_parsing
1from typing import Union 2from slither.core.solidity_types.elementary_type import ( 3 ElementaryType, 4 ElementaryTypeName, 5) # TODO rename solidity type 6from slither.core.solidity_types.array_type import ArrayType 7from slither.core.solidity_types.mapping_type import MappingType 8from slither.core.solidity_types.user_defined_type import UserDefinedType 9from slither.core.declarations import FunctionContract, Contract 10from slither.vyper_parsing.ast.types import Name, Subscript, Call, Index, Tuple 11from slither.solc_parsing.exceptions import ParsingError 12 13# pylint: disable=too-many-branches,too-many-return-statements,import-outside-toplevel,too-many-locals 14def parse_type( 15 annotation: Union[Name, Subscript, Call, Tuple], 16 caller_context: Union[FunctionContract, Contract], 17): 18 from slither.vyper_parsing.expressions.expression_parsing import parse_expression 19 20 if isinstance(caller_context, FunctionContract): 21 contract = caller_context.contract 22 else: 23 contract = caller_context 24 25 assert isinstance(annotation, (Name, Subscript, Call, Tuple)) 26 27 if isinstance(annotation, Name): 28 name = annotation.id 29 lname = name.lower() # map `String` to string 30 if lname in ElementaryTypeName: 31 return ElementaryType(lname) 32 33 if name in contract.structures_as_dict: 34 return UserDefinedType(contract.structures_as_dict[name]) 35 36 if name in contract.enums_as_dict: 37 return UserDefinedType(contract.enums_as_dict[name]) 38 39 if name in contract.file_scope.contracts: 40 return UserDefinedType(contract.file_scope.contracts[name]) 41 42 if name in contract.file_scope.structures: 43 return UserDefinedType(contract.file_scope.structures[name]) 44 elif isinstance(annotation, Subscript): 45 assert isinstance(annotation.slice, Index) 46 # This is also a strange construct... https://github.com/vyperlang/vyper/issues/3577 47 if isinstance(annotation.slice.value, Tuple): 48 assert isinstance(annotation.value, Name) 49 if annotation.value.id == "DynArray": 50 type_ = parse_type(annotation.slice.value.elements[0], caller_context) 51 length = parse_expression(annotation.slice.value.elements[1], caller_context) 52 return ArrayType(type_, length) 53 if annotation.value.id == "HashMap": 54 type_from = parse_type(annotation.slice.value.elements[0], caller_context) 55 type_to = parse_type(annotation.slice.value.elements[1], caller_context) 56 57 return MappingType(type_from, type_to) 58 59 elif isinstance(annotation.value, Subscript): 60 type_ = parse_type(annotation.value, caller_context) 61 62 elif isinstance(annotation.value, Name): 63 # TODO it is weird that the ast_type is `Index` when it's a type annotation and not an expression, so we grab the value. https://github.com/vyperlang/vyper/issues/3577 64 type_ = parse_type(annotation.value, caller_context) 65 if annotation.value.id == "String": 66 # This is an elementary type 67 return type_ 68 69 length = parse_expression(annotation.slice.value, caller_context) 70 return ArrayType(type_, length) 71 72 elif isinstance(annotation, Call): 73 # TODO event variable represented as Call https://github.com/vyperlang/vyper/issues/3579 74 return parse_type(annotation.args[0], caller_context) 75 76 elif isinstance(annotation, Tuple): 77 # Vyper has tuple types like python x = f() where f() -> (y,z) 78 # and tuple elements can be unpacked like x[0]: y and x[1]: z. 79 # We model these as a struct and unpack each index into a field 80 # e.g. accessing the 0th element is translated as x._0 81 from slither.core.declarations.structure import Structure 82 from slither.core.variables.structure_variable import StructureVariable 83 84 st = Structure(caller_context.compilation_unit) 85 st.set_offset("-1:-1:-1", caller_context.compilation_unit) 86 st.name = "FAKE_TUPLE" 87 for idx, elem_info in enumerate(annotation.elements): 88 elem = StructureVariable() 89 elem.type = parse_type(elem_info, caller_context) 90 elem.name = f"_{idx}" 91 elem.set_structure(st) 92 elem.set_offset("-1:-1:-1", caller_context.compilation_unit) 93 st.elems[elem.name] = elem 94 st.add_elem_in_order(elem.name) 95 st.name += elem.name 96 97 return UserDefinedType(st) 98 99 raise ParsingError(f"Type name not found {name} context {caller_context}")
def
parse_type( annotation: Union[slither.vyper_parsing.ast.types.Name, slither.vyper_parsing.ast.types.Subscript, slither.vyper_parsing.ast.types.Call, slither.vyper_parsing.ast.types.Tuple], caller_context: Union[slither.core.declarations.function_contract.FunctionContract, slither.core.declarations.contract.Contract]):
15def parse_type( 16 annotation: Union[Name, Subscript, Call, Tuple], 17 caller_context: Union[FunctionContract, Contract], 18): 19 from slither.vyper_parsing.expressions.expression_parsing import parse_expression 20 21 if isinstance(caller_context, FunctionContract): 22 contract = caller_context.contract 23 else: 24 contract = caller_context 25 26 assert isinstance(annotation, (Name, Subscript, Call, Tuple)) 27 28 if isinstance(annotation, Name): 29 name = annotation.id 30 lname = name.lower() # map `String` to string 31 if lname in ElementaryTypeName: 32 return ElementaryType(lname) 33 34 if name in contract.structures_as_dict: 35 return UserDefinedType(contract.structures_as_dict[name]) 36 37 if name in contract.enums_as_dict: 38 return UserDefinedType(contract.enums_as_dict[name]) 39 40 if name in contract.file_scope.contracts: 41 return UserDefinedType(contract.file_scope.contracts[name]) 42 43 if name in contract.file_scope.structures: 44 return UserDefinedType(contract.file_scope.structures[name]) 45 elif isinstance(annotation, Subscript): 46 assert isinstance(annotation.slice, Index) 47 # This is also a strange construct... https://github.com/vyperlang/vyper/issues/3577 48 if isinstance(annotation.slice.value, Tuple): 49 assert isinstance(annotation.value, Name) 50 if annotation.value.id == "DynArray": 51 type_ = parse_type(annotation.slice.value.elements[0], caller_context) 52 length = parse_expression(annotation.slice.value.elements[1], caller_context) 53 return ArrayType(type_, length) 54 if annotation.value.id == "HashMap": 55 type_from = parse_type(annotation.slice.value.elements[0], caller_context) 56 type_to = parse_type(annotation.slice.value.elements[1], caller_context) 57 58 return MappingType(type_from, type_to) 59 60 elif isinstance(annotation.value, Subscript): 61 type_ = parse_type(annotation.value, caller_context) 62 63 elif isinstance(annotation.value, Name): 64 # TODO it is weird that the ast_type is `Index` when it's a type annotation and not an expression, so we grab the value. https://github.com/vyperlang/vyper/issues/3577 65 type_ = parse_type(annotation.value, caller_context) 66 if annotation.value.id == "String": 67 # This is an elementary type 68 return type_ 69 70 length = parse_expression(annotation.slice.value, caller_context) 71 return ArrayType(type_, length) 72 73 elif isinstance(annotation, Call): 74 # TODO event variable represented as Call https://github.com/vyperlang/vyper/issues/3579 75 return parse_type(annotation.args[0], caller_context) 76 77 elif isinstance(annotation, Tuple): 78 # Vyper has tuple types like python x = f() where f() -> (y,z) 79 # and tuple elements can be unpacked like x[0]: y and x[1]: z. 80 # We model these as a struct and unpack each index into a field 81 # e.g. accessing the 0th element is translated as x._0 82 from slither.core.declarations.structure import Structure 83 from slither.core.variables.structure_variable import StructureVariable 84 85 st = Structure(caller_context.compilation_unit) 86 st.set_offset("-1:-1:-1", caller_context.compilation_unit) 87 st.name = "FAKE_TUPLE" 88 for idx, elem_info in enumerate(annotation.elements): 89 elem = StructureVariable() 90 elem.type = parse_type(elem_info, caller_context) 91 elem.name = f"_{idx}" 92 elem.set_structure(st) 93 elem.set_offset("-1:-1:-1", caller_context.compilation_unit) 94 st.elems[elem.name] = elem 95 st.add_elem_in_order(elem.name) 96 st.name += elem.name 97 98 return UserDefinedType(st) 99 100 raise ParsingError(f"Type name not found {name} context {caller_context}")