diff --git a/slither/core/children/child_expression.py b/slither/core/children/child_expression.py index 102e267b3..0064658c0 100644 --- a/slither/core/children/child_expression.py +++ b/slither/core/children/child_expression.py @@ -1,7 +1,8 @@ -from typing import TYPE_CHECKING +from typing import TYPE_CHECKING, Union if TYPE_CHECKING: from slither.core.expressions.expression import Expression + from slither.slithir.operations import Operation class ChildExpression: @@ -9,9 +10,9 @@ class ChildExpression: super().__init__() self._expression = None - def set_expression(self, expression: "Expression") -> None: + def set_expression(self, expression: Union["Expression", "Operation"]) -> None: self._expression = expression @property - def expression(self) -> "Expression": + def expression(self) -> Union["Expression", "Operation"]: return self._expression diff --git a/slither/core/declarations/__init__.py b/slither/core/declarations/__init__.py index f891ad621..92e0b9eca 100644 --- a/slither/core/declarations/__init__.py +++ b/slither/core/declarations/__init__.py @@ -17,3 +17,4 @@ from .structure_contract import StructureContract from .structure_top_level import StructureTopLevel from .function_contract import FunctionContract from .function_top_level import FunctionTopLevel +from .custom_error_contract import CustomErrorContract diff --git a/slither/core/declarations/contract.py b/slither/core/declarations/contract.py index 6d787294f..2d2d10b04 100644 --- a/slither/core/declarations/contract.py +++ b/slither/core/declarations/contract.py @@ -38,13 +38,13 @@ if TYPE_CHECKING: EnumContract, StructureContract, FunctionContract, + CustomErrorContract, ) from slither.slithir.variables.variable import SlithIRVariable - from slither.core.variables.variable import Variable - from slither.core.variables.state_variable import StateVariable + from slither.core.variables import Variable, StateVariable from slither.core.compilation_unit import SlitherCompilationUnit - from slither.core.declarations.custom_error_contract import CustomErrorContract from slither.core.scope.scope import FileScope + from slither.core.cfg.node import Node LOGGER = logging.getLogger("Contract") @@ -803,23 +803,25 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods """ return next((v for v in self.state_variables if v.name == canonical_name), None) - def get_structure_from_name(self, structure_name: str) -> Optional["Structure"]: + def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]: """ Return a structure from a name Args: structure_name (str): name of the structure Returns: - Structure + StructureContract """ return next((st for st in self.structures if st.name == structure_name), None) - def get_structure_from_canonical_name(self, structure_name: str) -> Optional["Structure"]: + def get_structure_from_canonical_name( + self, structure_name: str + ) -> Optional["StructureContract"]: """ Return a structure from a canonical name Args: structure_name (str): canonical name of the structure Returns: - Structure + StructureContract """ return next((st for st in self.structures if st.canonical_name == structure_name), None) diff --git a/slither/core/declarations/using_for_top_level.py b/slither/core/declarations/using_for_top_level.py index 2c8dfc9b8..27d1f90e4 100644 --- a/slither/core/declarations/using_for_top_level.py +++ b/slither/core/declarations/using_for_top_level.py @@ -14,5 +14,5 @@ class UsingForTopLevel(TopLevel): self.file_scope: "FileScope" = scope @property - def using_for(self) -> Dict[Type, List[Type]]: + def using_for(self) -> Dict[Union[str, Type], List[Type]]: return self._using_for diff --git a/slither/core/slither_core.py b/slither/core/slither_core.py index ff6df04f0..e5f4e830a 100644 --- a/slither/core/slither_core.py +++ b/slither/core/slither_core.py @@ -8,7 +8,7 @@ import pathlib import posixpath import re from collections import defaultdict -from typing import Optional, Dict, List, Set, Union +from typing import Optional, Dict, List, Set, Union, Tuple from crytic_compile import CryticCompile from crytic_compile.utils.naming import Filename @@ -73,8 +73,8 @@ class SlitherCore(Context): # Maps from file to detector name to the start/end ranges for that detector. # Infinity is used to signal a detector has no end range. - self._ignore_ranges: defaultdict[str, defaultdict[str, List[(int, int)]]] = defaultdict( - lambda: defaultdict(lambda: []) + self._ignore_ranges: Dict[str, Dict[str, List[Tuple[int, ...]]]] = defaultdict( + lambda: defaultdict(lambda: [(-1, -1)]) ) self._compilation_units: List[SlitherCompilationUnit] = [] diff --git a/slither/core/solidity_types/array_type.py b/slither/core/solidity_types/array_type.py index c873c639a..9a0b12c00 100644 --- a/slither/core/solidity_types/array_type.py +++ b/slither/core/solidity_types/array_type.py @@ -17,7 +17,7 @@ class ArrayType(Type): def __init__( self, t: Union["TypeAliasTopLevel", "ArrayType", "FunctionType", "ElementaryType"], - length: Optional[Union["Identifier", Literal, "BinaryOperation"]], + length: Optional[Union["Identifier", Literal, "BinaryOperation", int]], ) -> None: assert isinstance(t, Type) if length: diff --git a/slither/core/solidity_types/function_type.py b/slither/core/solidity_types/function_type.py index 4682bcf19..b73d9fa84 100644 --- a/slither/core/solidity_types/function_type.py +++ b/slither/core/solidity_types/function_type.py @@ -1,4 +1,4 @@ -from typing import List, Tuple +from typing import List, Tuple, Any from slither.core.solidity_types.type import Type from slither.core.variables.function_type_variable import FunctionTypeVariable @@ -69,7 +69,7 @@ class FunctionType(Type): return f"({params}) returns({return_values})" return f"({params})" - def __eq__(self, other: ElementaryType) -> bool: + def __eq__(self, other: Any) -> bool: if not isinstance(other, FunctionType): return False return self.params == other.params and self.return_values == other.return_values diff --git a/slither/core/solidity_types/type_alias.py b/slither/core/solidity_types/type_alias.py index b202d3608..5b9ea0a37 100644 --- a/slither/core/solidity_types/type_alias.py +++ b/slither/core/solidity_types/type_alias.py @@ -2,7 +2,7 @@ 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 +from slither.core.solidity_types import Type, ElementaryType if TYPE_CHECKING: from slither.core.declarations import Contract @@ -10,13 +10,13 @@ if TYPE_CHECKING: class TypeAlias(Type): - def __init__(self, underlying_type: Type, name: str) -> None: + def __init__(self, underlying_type: ElementaryType, name: str) -> None: super().__init__() self.name = name self.underlying_type = underlying_type @property - def type(self) -> Type: + def type(self) -> ElementaryType: """ Return the underlying type. Alias for underlying_type diff --git a/slither/core/solidity_types/type_information.py b/slither/core/solidity_types/type_information.py index dd0aeec43..2af0b097a 100644 --- a/slither/core/solidity_types/type_information.py +++ b/slither/core/solidity_types/type_information.py @@ -5,13 +5,13 @@ from slither.core.solidity_types.type import Type if TYPE_CHECKING: from slither.core.declarations.contract import Contract - from slither.core.declarations.enum_top_level import EnumTopLevel + from slither.core.declarations.enum import Enum # Use to model the Type(X) function, which returns an undefined type # https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information class TypeInformation(Type): - def __init__(self, c: Union[ElementaryType, "Contract", "EnumTopLevel"]) -> None: + def __init__(self, c: Union[ElementaryType, "Contract", "Enum"]) -> None: # pylint: disable=import-outside-toplevel from slither.core.declarations.contract import Contract from slither.core.declarations.enum import Enum @@ -21,7 +21,7 @@ class TypeInformation(Type): self._type = c @property - def type(self) -> "Contract": + def type(self) -> Union["Contract", ElementaryType, "Enum"]: return self._type @property diff --git a/slither/core/solidity_types/user_defined_type.py b/slither/core/solidity_types/user_defined_type.py index a78497fd9..8de41116f 100644 --- a/slither/core/solidity_types/user_defined_type.py +++ b/slither/core/solidity_types/user_defined_type.py @@ -8,14 +8,10 @@ if TYPE_CHECKING: from slither.core.declarations.structure import Structure from slither.core.declarations.enum import Enum from slither.core.declarations.contract import Contract - from slither.core.declarations import EnumContract - from slither.core.declarations.structure_top_level import StructureTopLevel # pylint: disable=import-outside-toplevel class UserDefinedType(Type): - def __init__( - self, t: Union["EnumContract", "StructureTopLevel", "Contract", "StructureContract"] - ) -> None: + def __init__(self, t: Union["Enum", "Contract", "Structure"]) -> None: from slither.core.declarations.structure import Structure from slither.core.declarations.enum import Enum from slither.core.declarations.contract import Contract diff --git a/slither/core/variables/__init__.py b/slither/core/variables/__init__.py index e69de29bb..638f0f3a4 100644 --- a/slither/core/variables/__init__.py +++ b/slither/core/variables/__init__.py @@ -0,0 +1,2 @@ +from .state_variable import StateVariable +from .variable import Variable diff --git a/slither/slithir/operations/phi_callback.py b/slither/slithir/operations/phi_callback.py index 34a488f98..0c8994056 100644 --- a/slither/slithir/operations/phi_callback.py +++ b/slither/slithir/operations/phi_callback.py @@ -38,6 +38,10 @@ class PhiCallback(Phi): def rvalues(self): return self._rvalues + @rvalues.setter + def rvalues(self, vals): + self._rvalues = vals + @property def rvalue_no_callback(self): """ @@ -45,10 +49,6 @@ class PhiCallback(Phi): """ return self._rvalue_no_callback - @rvalues.setter - def rvalues(self, vals): - self._rvalues = vals - @property def nodes(self): return self._nodes diff --git a/slither/slithir/variables/constant.py b/slither/slithir/variables/constant.py index e787bc396..ddfc9e054 100644 --- a/slither/slithir/variables/constant.py +++ b/slither/slithir/variables/constant.py @@ -11,7 +11,7 @@ from slither.utils.integer_conversion import convert_string_to_int class Constant(SlithIRVariable): def __init__( self, - val: str, + val: Union[int, str], constant_type: Optional[ElementaryType] = None, subdenomination: Optional[str] = None, ) -> None: # pylint: disable=too-many-branches diff --git a/slither/slithir/variables/local_variable.py b/slither/slithir/variables/local_variable.py index 627629bc5..eb32d4024 100644 --- a/slither/slithir/variables/local_variable.py +++ b/slither/slithir/variables/local_variable.py @@ -1,3 +1,4 @@ +from typing import Set from slither.core.variables.local_variable import LocalVariable from slither.slithir.variables.temporary import TemporaryVariable from slither.slithir.variables.variable import SlithIRVariable @@ -31,7 +32,7 @@ class LocalIRVariable( # Additional field # points to state variables - self._refers_to = set() + self._refers_to: Set[StateIRVariable] = set() # keep un-ssa version if isinstance(local_variable, LocalIRVariable): diff --git a/slither/slithir/variables/reference.py b/slither/slithir/variables/reference.py index 978e4f737..95802b7e2 100644 --- a/slither/slithir/variables/reference.py +++ b/slither/slithir/variables/reference.py @@ -35,13 +35,6 @@ class ReferenceVariable(ChildNode, Variable): """ return self._points_to - @property - def points_to_origin(self): - points = self.points_to - while isinstance(points, ReferenceVariable): - points = points.points_to - return points - @points_to.setter def points_to(self, points_to): # Can only be a rvalue of @@ -55,6 +48,13 @@ class ReferenceVariable(ChildNode, Variable): self._points_to = points_to + @property + def points_to_origin(self): + points = self.points_to + while isinstance(points, ReferenceVariable): + points = points.points_to + return points + @property def name(self) -> str: return f"REF_{self.index}" diff --git a/slither/solc_parsing/declarations/function.py b/slither/solc_parsing/declarations/function.py index af9e14bb1..9671d9bbe 100644 --- a/slither/solc_parsing/declarations/function.py +++ b/slither/solc_parsing/declarations/function.py @@ -1,5 +1,5 @@ import logging -from typing import Dict, Optional, Union, List, TYPE_CHECKING +from typing import Dict, Optional, Union, List, TYPE_CHECKING, Tuple from slither.core.cfg.node import NodeType, link_nodes, insert_node, Node from slither.core.cfg.scope import Scope @@ -445,7 +445,7 @@ class FunctionSolc(CallerContextExpression): def _parse_for_compact_ast( # pylint: disable=no-self-use self, statement: Dict - ) -> (Optional[Dict], Optional[Dict], Optional[Dict], Dict): + ) -> Tuple[Optional[Dict], Optional[Dict], Optional[Dict], Dict]: body = statement["body"] init_expression = statement.get("initializationExpression", None) condition = statement.get("condition", None) @@ -455,7 +455,7 @@ class FunctionSolc(CallerContextExpression): def _parse_for_legacy_ast( self, statement: Dict - ) -> (Optional[Dict], Optional[Dict], Optional[Dict], Dict): + ) -> Tuple[Optional[Dict], Optional[Dict], Optional[Dict], Dict]: # if we're using an old version of solc (anything below and including 0.4.11) or if the user # explicitly enabled compact ast, we might need to make some best-effort guesses children = statement[self.get_children("children")] diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index e289090b1..7a52ddb0a 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -22,7 +22,7 @@ from slither.solc_parsing.exceptions import ParsingError from slither.solc_parsing.expressions.expression_parsing import CallerContextExpression if TYPE_CHECKING: - from slither.core.declarations import Structure, Enum + from slither.core.declarations import Structure, Enum, Function from slither.core.declarations.contract import Contract from slither.core.compilation_unit import SlitherCompilationUnit from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc @@ -233,6 +233,7 @@ def parse_type( sl: "SlitherCompilationUnit" renaming: Dict[str, str] user_defined_types: Dict[str, TypeAlias] + enums_direct_access: List["Enum"] = [] # 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 ( @@ -254,7 +255,7 @@ def parse_type( 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 + 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 @@ -316,7 +317,7 @@ def parse_type( 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.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] diff --git a/slither/solc_parsing/variables/variable_declaration.py b/slither/solc_parsing/variables/variable_declaration.py index 79f9f3dac..d21d89875 100644 --- a/slither/solc_parsing/variables/variable_declaration.py +++ b/slither/solc_parsing/variables/variable_declaration.py @@ -1,6 +1,6 @@ import logging import re -from typing import Dict +from typing import Dict, Optional from slither.solc_parsing.declarations.caller_context import CallerContextExpression from slither.solc_parsing.expressions.expression_parsing import parse_expression @@ -127,7 +127,7 @@ class VariableDeclarationSolc: self._variable.visibility = "internal" def _init_from_declaration( - self, var: Dict, init: bool + self, var: Dict, init: Optional[bool] ) -> None: # pylint: disable=too-many-branches if self._is_compact_ast: attributes = var diff --git a/slither/visitors/expression/constants_folding.py b/slither/visitors/expression/constants_folding.py index e42349a03..5f419ef99 100644 --- a/slither/visitors/expression/constants_folding.py +++ b/slither/visitors/expression/constants_folding.py @@ -8,6 +8,8 @@ from slither.core.expressions import ( Identifier, BinaryOperation, UnaryOperation, + TupleExpression, + TypeConversion, ) from slither.utils.integer_conversion import convert_string_to_fraction, convert_string_to_int @@ -23,7 +25,9 @@ class NotConstant(Exception): KEY = "ConstantFolding" -CONSTANT_TYPES_OPERATIONS = Union[Literal, BinaryOperation, UnaryOperation, Identifier] +CONSTANT_TYPES_OPERATIONS = Union[ + Literal, BinaryOperation, UnaryOperation, Identifier, TupleExpression, TypeConversion +] def get_val(expression: CONSTANT_TYPES_OPERATIONS) -> Union[bool, int, Fraction, str]: diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index b6f8313aa..46f11b016 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -1,7 +1,6 @@ import logging -from typing import Any, Union, List, TYPE_CHECKING +from typing import Any, Union, List, TYPE_CHECKING, TypeVar, Generic -import slither.slithir.variables.reference from slither.core.declarations import ( Function, SolidityVariable, @@ -67,13 +66,14 @@ from slither.visitors.expression.expression import ExpressionVisitor if TYPE_CHECKING: from slither.core.cfg.node import Node + from slither.slithir.operations import Operation logger = logging.getLogger("VISTIOR:ExpressionToSlithIR") key = "expressionToSlithIR" -def get(expression: Expression): +def get(expression: Union[Expression, Operation]): val = expression.context[key] # we delete the item to reduce memory use del expression.context[key] @@ -84,7 +84,7 @@ def get_without_removing(expression): return expression.context[key] -def set_val(expression: Expression, val) -> None: +def set_val(expression: Union[Expression, Operation], val) -> None: expression.context[key] = val @@ -121,7 +121,7 @@ _signed_to_unsigned = { def convert_assignment( left: Union[LocalVariable, StateVariable, ReferenceVariable], - right: SourceMapping, + right: Union[LocalVariable, StateVariable, ReferenceVariable], t: AssignmentOperationType, return_type, ) -> Union[Binary, Assignment]: @@ -417,9 +417,7 @@ class ExpressionToSlithIR(ExpressionVisitor): cst = Constant(expression.value, expression.type, expression.subdenomination) set_val(expression, cst) - def _post_member_access( - self, expression: slither.core.expressions.member_access.MemberAccess - ) -> None: + def _post_member_access(self, expression: MemberAccess) -> None: expr = get(expression.expression) # Look for type(X).max / min @@ -541,9 +539,7 @@ class ExpressionToSlithIR(ExpressionVisitor): val = expressions set_val(expression, val) - def _post_type_conversion( - self, expression: slither.core.expressions.type_conversion.TypeConversion - ) -> None: + def _post_type_conversion(self, expression: TypeConversion) -> None: expr = get(expression.expression) val = TemporaryVariable(self._node) operation = TypeConversion(val, expr, expression.type)