From 5863c30747eee5440911fb21bb5cc396098a5c9a Mon Sep 17 00:00:00 2001 From: Feist Josselin Date: Tue, 22 Mar 2022 14:07:23 +0100 Subject: [PATCH] Add support for user defined types (#1135) * Add support for user defined types - Create a new core object TypeAlias (top level or contract) - Add support for wrap/unwrap - Add tests --- slither/core/scope/scope.py | 8 + slither/core/solidity_types/__init__.py | 1 + slither/core/solidity_types/type_alias.py | 41 +++++ slither/solc_parsing/declarations/contract.py | 26 +++ .../solc_parsing/expressions/find_variable.py | 5 + .../slither_compilation_unit_solc.py | 18 ++ .../solidity_types/type_parsing.py | 14 ++ .../visitors/slithir/expression_to_slithir.py | 165 +++++++++++------- .../user_defined_types.sol-0.8.10-compact.zip | Bin 0 -> 3215 bytes .../user_defined_types.sol-0.8.11-compact.zip | Bin 0 -> 3215 bytes .../user_defined_types.sol-0.8.12-compact.zip | Bin 0 -> 3217 bytes .../user_defined_types.sol-0.8.8-compact.zip | Bin 0 -> 3180 bytes ...user_defined_types.sol-0.8.10-compact.json | 10 ++ ...user_defined_types.sol-0.8.11-compact.json | 10 ++ ...user_defined_types.sol-0.8.12-compact.json | 10 ++ .../user_defined_types.sol-0.8.8-compact.json | 10 ++ tests/ast-parsing/user_defined_types.sol | 30 ++++ tests/test_ast_parsing.py | 2 + 18 files changed, 289 insertions(+), 61 deletions(-) create mode 100644 slither/core/solidity_types/type_alias.py create mode 100644 tests/ast-parsing/compile/user_defined_types.sol-0.8.10-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_types.sol-0.8.11-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_types.sol-0.8.12-compact.zip create mode 100644 tests/ast-parsing/compile/user_defined_types.sol-0.8.8-compact.zip create mode 100644 tests/ast-parsing/expected/user_defined_types.sol-0.8.10-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_types.sol-0.8.11-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_types.sol-0.8.12-compact.json create mode 100644 tests/ast-parsing/expected/user_defined_types.sol-0.8.8-compact.json create mode 100644 tests/ast-parsing/user_defined_types.sol diff --git a/slither/core/scope/scope.py b/slither/core/scope/scope.py index dd755de94..c6d18556e 100644 --- a/slither/core/scope/scope.py +++ b/slither/core/scope/scope.py @@ -6,6 +6,7 @@ from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel from slither.core.declarations.enum_top_level import EnumTopLevel from slither.core.declarations.function_top_level import FunctionTopLevel from slither.core.declarations.structure_top_level import StructureTopLevel +from slither.core.solidity_types import TypeAlias from slither.core.variables.top_level_variable import TopLevelVariable from slither.slithir.variables import Constant @@ -44,6 +45,10 @@ class FileScope: # local name -> original name (A -> B) self.renaming: Dict[str, str] = {} + # User defined types + # Name -> type alias + self.user_defined_types: Dict[str, TypeAlias] = {} + def add_accesible_scopes(self) -> bool: """ Add information from accessible scopes. Return true if new information was obtained @@ -82,6 +87,9 @@ class FileScope: if not _dict_contain(new_scope.renaming, self.renaming): self.renaming.update(new_scope.renaming) learn_something = True + if not _dict_contain(new_scope.user_defined_types, self.user_defined_types): + self.user_defined_types.update(new_scope.user_defined_types) + learn_something = True return learn_something diff --git a/slither/core/solidity_types/__init__.py b/slither/core/solidity_types/__init__.py index 13b1efefb..a6de75bf5 100644 --- a/slither/core/solidity_types/__init__.py +++ b/slither/core/solidity_types/__init__.py @@ -5,3 +5,4 @@ from .mapping_type import MappingType from .user_defined_type import UserDefinedType from .type import Type from .type_information import TypeInformation +from .type_alias import TypeAlias, TypeAliasTopLevel, TypeAliasContract diff --git a/slither/core/solidity_types/type_alias.py b/slither/core/solidity_types/type_alias.py new file mode 100644 index 000000000..06aa06a8b --- /dev/null +++ b/slither/core/solidity_types/type_alias.py @@ -0,0 +1,41 @@ +from typing import TYPE_CHECKING, Tuple + +from slither.core.children.child_contract import ChildContract +from slither.core.declarations.top_level import TopLevel +from slither.core.solidity_types import Type + +if TYPE_CHECKING: + from slither.core.declarations import Contract + from slither.core.scope.scope import FileScope + + +class TypeAlias(Type): + def __init__(self, underlying_type: Type, name: str): + super().__init__() + self.name = name + self.underlying_type = underlying_type + + @property + def storage_size(self) -> Tuple[int, bool]: + return self.underlying_type.storage_size + + def __hash__(self): + return hash(str(self)) + + +class TypeAliasTopLevel(TypeAlias, TopLevel): + def __init__(self, underlying_type: Type, name: str, scope: "FileScope"): + super().__init__(underlying_type, name) + self.file_scope: "FileScope" = scope + + def __str__(self): + return self.name + + +class TypeAliasContract(TypeAlias, ChildContract): + def __init__(self, underlying_type: Type, name: str, contract: "Contract"): + super().__init__(underlying_type, name) + self._contract: "Contract" = contract + + def __str__(self): + return self.contract.name + "." + self.name diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index 0cdb5d848..efc53f2aa 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -5,6 +5,7 @@ from slither.core.declarations import Modifier, Event, EnumContract, StructureCo from slither.core.declarations.contract import Contract from slither.core.declarations.custom_error_contract import CustomErrorContract from slither.core.declarations.function_contract import FunctionContract +from slither.core.solidity_types import ElementaryType, TypeAliasContract from slither.core.variables.state_variable import StateVariable from slither.solc_parsing.declarations.caller_context import CallerContextExpression from slither.solc_parsing.declarations.custom_error import CustomErrorSolc @@ -230,6 +231,7 @@ class ContractSolc(CallerContextExpression): self.baseConstructorContractsCalled.append(referencedDeclaration) def _parse_contract_items(self): + # pylint: disable=too-many-branches if not self.get_children() in self._data: # empty contract return for item in self._data[self.get_children()]: @@ -253,10 +255,34 @@ class ContractSolc(CallerContextExpression): self._usingForNotParsed.append(item) elif item[self.get_key()] == "ErrorDefinition": self._customErrorParsed.append(item) + elif item[self.get_key()] == "UserDefinedValueTypeDefinition": + self._parse_type_alias(item) else: raise ParsingError("Unknown contract item: " + item[self.get_key()]) return + def _parse_type_alias(self, item: Dict) -> None: + assert "name" in item + assert "underlyingType" in item + underlying_type = item["underlyingType"] + assert "nodeType" in underlying_type and underlying_type["nodeType"] == "ElementaryTypeName" + assert "name" in underlying_type + + original_type = ElementaryType(underlying_type["name"]) + + # For user defined types defined at the contract level the lookup can be done + # Using the name or the canonical name + # For example during the type parsing the canonical name + # Note that Solidity allows shadowing of user defined types + # Between top level and contract definitions + alias = item["name"] + alias_canonical = self._contract.name + "." + item["name"] + + user_defined_type = TypeAliasContract(original_type, alias, self.underlying_contract) + user_defined_type.set_offset(item["src"], self.compilation_unit) + self._contract.file_scope.user_defined_types[alias] = user_defined_type + self._contract.file_scope.user_defined_types[alias_canonical] = user_defined_type + def _parse_struct(self, struct: Dict): st = StructureContract(self._contract.compilation_unit) diff --git a/slither/solc_parsing/expressions/find_variable.py b/slither/solc_parsing/expressions/find_variable.py index b88d97782..f3f9a2d99 100644 --- a/slither/solc_parsing/expressions/find_variable.py +++ b/slither/solc_parsing/expressions/find_variable.py @@ -18,6 +18,7 @@ from slither.core.solidity_types import ( ArrayType, FunctionType, MappingType, + TypeAlias, ) from slither.core.variables.top_level_variable import TopLevelVariable from slither.core.variables.variable import Variable @@ -292,6 +293,7 @@ def find_variable( Enum, Structure, CustomError, + TypeAlias, ], bool, ]: @@ -337,6 +339,9 @@ def find_variable( if var_name in current_scope.renaming: var_name = current_scope.renaming[var_name] + if var_name in current_scope.user_defined_types: + return current_scope.user_defined_types[var_name], False + # Use ret0/ret1 to help mypy ret0 = _find_variable_from_ref_declaration( referenced_declaration, direct_contracts, direct_functions diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 5a1d08392..b7a9d4467 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -15,6 +15,7 @@ from slither.core.declarations.import_directive import Import from slither.core.declarations.pragma_directive import Pragma from slither.core.declarations.structure_top_level import StructureTopLevel from slither.core.scope.scope import FileScope +from slither.core.solidity_types import ElementaryType, TypeAliasTopLevel from slither.core.variables.top_level_variable import TopLevelVariable from slither.exceptions import SlitherException from slither.solc_parsing.declarations.contract import ContractSolc @@ -298,6 +299,23 @@ class SlitherCompilationUnitSolc: 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") diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index 206985d9f..f052bba05 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -6,6 +6,7 @@ from slither.core.declarations.custom_error_contract import CustomErrorContract from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel from slither.core.declarations.function_contract import FunctionContract from slither.core.expressions.literal import Literal +from slither.core.solidity_types import TypeAlias from slither.core.solidity_types.array_type import ArrayType from slither.core.solidity_types.elementary_type import ( ElementaryType, @@ -224,6 +225,7 @@ def parse_type( 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 ( @@ -234,11 +236,13 @@ def parse_type( 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] @@ -274,6 +278,7 @@ def parse_type( 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 @@ -302,6 +307,7 @@ def parse_type( 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)}") @@ -315,6 +321,8 @@ def parse_type( 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, @@ -335,6 +343,8 @@ def parse_type( 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, @@ -351,6 +361,8 @@ def parse_type( 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, @@ -367,6 +379,8 @@ def parse_type( 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, diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index c4fb780a8..0029c29ed 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -1,10 +1,13 @@ import logging +from typing import List + from slither.core.declarations import ( Function, SolidityVariable, SolidityVariableComposed, SolidityFunction, + Contract, ) from slither.core.expressions import ( AssignmentOperationType, @@ -13,8 +16,9 @@ from slither.core.expressions import ( ElementaryTypeNameExpression, CallExpression, Identifier, + MemberAccess, ) -from slither.core.solidity_types import ArrayType, ElementaryType +from slither.core.solidity_types import ArrayType, ElementaryType, TypeAlias from slither.core.solidity_types.type import Type from slither.core.variables.local_variable_init_from_tuple import LocalVariableInitFromTuple from slither.core.variables.variable import Variable @@ -33,6 +37,7 @@ from slither.slithir.operations import ( Unpack, Return, SolidityCall, + Operation, ) from slither.slithir.tmp_operations.argument import Argument from slither.slithir.tmp_operations.tmp_call import TmpCall @@ -59,6 +64,10 @@ def get(expression): return val +def get_without_removing(expression): + return expression.context[key] + + def set_val(expression, val): expression.context[key] = val @@ -127,7 +136,7 @@ class ExpressionToSlithIR(ExpressionVisitor): self._expression = expression self._node = node - self._result = [] + self._result: List[Operation] = [] self._visit_expression(self.expression) if node.type == NodeType.RETURN: r = Return(get(self.expression)) @@ -240,8 +249,13 @@ class ExpressionToSlithIR(ExpressionVisitor): def _post_call_expression( self, expression - ): # pylint: disable=too-many-branches,too-many-statements - called = get(expression.called) + ): # pylint: disable=too-many-branches,too-many-statements,too-many-locals + + assert isinstance(expression, CallExpression) + + expression_called = expression.called + called = get(expression_called) + args = [get(a) for a in expression.arguments if a] for arg in args: arg_ = Argument(arg) @@ -259,66 +273,81 @@ class ExpressionToSlithIR(ExpressionVisitor): internal_call.set_expression(expression) self._result.append(internal_call) set_val(expression, val) + + # User defined types + elif ( + isinstance(called, TypeAlias) + and isinstance(expression_called, MemberAccess) + and expression_called.member_name in ["wrap", "unwrap"] + and len(args) == 1 + ): + val = TemporaryVariable(self._node) + var = TypeConversion(val, args[0], called) + var.set_expression(expression) + val.set_type(called) + self._result.append(var) + set_val(expression, val) + + # yul things + elif called.name == "caller()": + val = TemporaryVariable(self._node) + var = Assignment(val, SolidityVariableComposed("msg.sender"), "uint256") + self._result.append(var) + set_val(expression, val) + elif called.name == "origin()": + val = TemporaryVariable(self._node) + var = Assignment(val, SolidityVariableComposed("tx.origin"), "uint256") + self._result.append(var) + set_val(expression, val) + elif called.name == "extcodesize(uint256)": + val = ReferenceVariable(self._node) + var = Member(args[0], Constant("codesize"), val) + self._result.append(var) + set_val(expression, val) + elif called.name == "selfbalance()": + val = TemporaryVariable(self._node) + var = TypeConversion(val, SolidityVariable("this"), ElementaryType("address")) + val.set_type(ElementaryType("address")) + self._result.append(var) + + val1 = ReferenceVariable(self._node) + var1 = Member(val, Constant("balance"), val1) + self._result.append(var1) + set_val(expression, val1) + elif called.name == "address()": + val = TemporaryVariable(self._node) + var = TypeConversion(val, SolidityVariable("this"), ElementaryType("address")) + val.set_type(ElementaryType("address")) + self._result.append(var) + set_val(expression, val) + elif called.name == "callvalue()": + val = TemporaryVariable(self._node) + var = Assignment(val, SolidityVariableComposed("msg.value"), "uint256") + self._result.append(var) + set_val(expression, val) + else: - # yul things - if called.name == "caller()": - val = TemporaryVariable(self._node) - var = Assignment(val, SolidityVariableComposed("msg.sender"), "uint256") - self._result.append(var) - set_val(expression, val) - elif called.name == "origin()": - val = TemporaryVariable(self._node) - var = Assignment(val, SolidityVariableComposed("tx.origin"), "uint256") - self._result.append(var) - set_val(expression, val) - elif called.name == "extcodesize(uint256)": - val = ReferenceVariable(self._node) - var = Member(args[0], Constant("codesize"), val) - self._result.append(var) - set_val(expression, val) - elif called.name == "selfbalance()": - val = TemporaryVariable(self._node) - var = TypeConversion(val, SolidityVariable("this"), ElementaryType("address")) - val.set_type(ElementaryType("address")) - self._result.append(var) - - val1 = ReferenceVariable(self._node) - var1 = Member(val, Constant("balance"), val1) - self._result.append(var1) - set_val(expression, val1) - elif called.name == "address()": - val = TemporaryVariable(self._node) - var = TypeConversion(val, SolidityVariable("this"), ElementaryType("address")) - val.set_type(ElementaryType("address")) - self._result.append(var) - set_val(expression, val) - elif called.name == "callvalue()": - val = TemporaryVariable(self._node) - var = Assignment(val, SolidityVariableComposed("msg.value"), "uint256") - self._result.append(var) - set_val(expression, val) + # If tuple + if expression.type_call.startswith("tuple(") and expression.type_call != "tuple()": + val = TupleVariable(self._node) else: - # If tuple - if expression.type_call.startswith("tuple(") and expression.type_call != "tuple()": - val = TupleVariable(self._node) - else: - val = TemporaryVariable(self._node) + val = TemporaryVariable(self._node) - message_call = TmpCall(called, len(args), val, expression.type_call) - message_call.set_expression(expression) - # Gas/value are only accessible here if the syntax {gas: , value: } - # Is used over .gas().value() - if expression.call_gas: - call_gas = get(expression.call_gas) - message_call.call_gas = call_gas - if expression.call_value: - call_value = get(expression.call_value) - message_call.call_value = call_value - if expression.call_salt: - call_salt = get(expression.call_salt) - message_call.call_salt = call_salt - self._result.append(message_call) - set_val(expression, val) + message_call = TmpCall(called, len(args), val, expression.type_call) + message_call.set_expression(expression) + # Gas/value are only accessible here if the syntax {gas: , value: } + # Is used over .gas().value() + if expression.call_gas: + call_gas = get(expression.call_gas) + message_call.call_gas = call_gas + if expression.call_value: + call_value = get(expression.call_value) + message_call.call_value = call_value + if expression.call_salt: + call_salt = get(expression.call_salt) + message_call.call_salt = call_salt + self._result.append(message_call) + set_val(expression, val) def _post_conditional_expression(self, expression): raise Exception(f"Ternary operator are not convertible to SlithIR {expression}") @@ -413,6 +442,20 @@ class ExpressionToSlithIR(ExpressionVisitor): set_val(expression, val) return + if isinstance(expr, TypeAlias) and expression.member_name in ["wrap", "unwrap"]: + # The logic is be handled by _post_call_expression + set_val(expression, expr) + return + + # Early lookup to detect user defined types from other contracts definitions + # contract A { type MyInt is int} + # contract B { function f() public{ A.MyInt test = A.MyInt.wrap(1);}} + # The logic is handled by _post_call_expression + if isinstance(expr, Contract): + if expression.member_name in expr.file_scope.user_defined_types: + set_val(expression, expr.file_scope.user_defined_types[expression.member_name]) + return + val = ReferenceVariable(self._node) member = Member(expr, Constant(expression.member_name), val) member.set_expression(expression) diff --git a/tests/ast-parsing/compile/user_defined_types.sol-0.8.10-compact.zip b/tests/ast-parsing/compile/user_defined_types.sol-0.8.10-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..245529e6b77aa572359813a25dc4f242f759cd74 GIT binary patch literal 3215 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 literal 0 HcmV?d00001 diff --git a/tests/ast-parsing/compile/user_defined_types.sol-0.8.8-compact.zip b/tests/ast-parsing/compile/user_defined_types.sol-0.8.8-compact.zip new file mode 100644 index 0000000000000000000000000000000000000000..36924b8c2c904640651d8fb697001be94eda7f5c GIT binary patch literal 3180 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\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n}\n" + }, + "D": {}, + "C": { + "f(Left[])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/user_defined_types.sol-0.8.11-compact.json b/tests/ast-parsing/expected/user_defined_types.sol-0.8.11-compact.json new file mode 100644 index 000000000..06367c7cd --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_types.sol-0.8.11-compact.json @@ -0,0 +1,10 @@ +{ + "B": { + "u()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n", + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n}\n" + }, + "D": {}, + "C": { + "f(Left[])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/user_defined_types.sol-0.8.12-compact.json b/tests/ast-parsing/expected/user_defined_types.sol-0.8.12-compact.json new file mode 100644 index 000000000..06367c7cd --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_types.sol-0.8.12-compact.json @@ -0,0 +1,10 @@ +{ + "B": { + "u()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n", + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n}\n" + }, + "D": {}, + "C": { + "f(Left[])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/expected/user_defined_types.sol-0.8.8-compact.json b/tests/ast-parsing/expected/user_defined_types.sol-0.8.8-compact.json new file mode 100644 index 000000000..06367c7cd --- /dev/null +++ b/tests/ast-parsing/expected/user_defined_types.sol-0.8.8-compact.json @@ -0,0 +1,10 @@ +{ + "B": { + "u()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n}\n", + "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n}\n" + }, + "D": {}, + "C": { + "f(Left[])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: RETURN 1\n\"];\n}\n" + } +} \ No newline at end of file diff --git a/tests/ast-parsing/user_defined_types.sol b/tests/ast-parsing/user_defined_types.sol new file mode 100644 index 000000000..d05bdf396 --- /dev/null +++ b/tests/ast-parsing/user_defined_types.sol @@ -0,0 +1,30 @@ +type MyInt is uint; + +contract B { + type MyInt is int; + + function u() internal returns(int) {} + + function f() public{ + MyInt mi = MyInt.wrap(u()); + } +} + +function f(MyInt a) pure returns (MyInt b) { + b = MyInt(a); +} + +contract D +{ + B.MyInt x = B.MyInt.wrap(int(1)); +} + +contract C { + function f(Left[] memory a) internal returns(Left){ + return a[0]; + } +} +type Left is bytes2; + +MyInt constant x = MyInt.wrap(20); + diff --git a/tests/test_ast_parsing.py b/tests/test_ast_parsing.py index 234fdd2d1..68e0aebca 100644 --- a/tests/test_ast_parsing.py +++ b/tests/test_ast_parsing.py @@ -401,6 +401,8 @@ ALL_TESTS = [ ), Test("custom_error_with_state_variable.sol", make_version(8, 4, 12)), Test("complex_imports/import_aliases/test.sol", VERSIONS_08), + # 0.8.9 crashes on our testcase + Test("user_defined_types.sol", ["0.8.8"] + make_version(8, 10, 12)), ] # create the output folder if needed try: