pull/1640/head
Feist Josselin 2 years ago
parent b57be52818
commit d4e2f3681c
  1. 49
      slither/core/cfg/node.py
  2. 2
      slither/core/cfg/scope.py
  3. 4
      slither/core/children/child_contract.py
  4. 2
      slither/core/children/child_event.py
  5. 4
      slither/core/children/child_expression.py
  6. 4
      slither/core/children/child_inheritance.py
  7. 4
      slither/core/children/child_node.py
  8. 4
      slither/core/children/child_structure.py
  9. 16
      slither/core/compilation_unit.py
  10. 26
      slither/core/declarations/contract.py
  11. 8
      slither/core/declarations/custom_error.py
  12. 4
      slither/core/declarations/enum.py
  13. 2
      slither/core/declarations/enum_top_level.py
  14. 2
      slither/core/declarations/event.py
  15. 52
      slither/core/declarations/function.py
  16. 6
      slither/core/declarations/function_contract.py
  17. 6
      slither/core/declarations/function_top_level.py
  18. 2
      slither/core/declarations/import_directive.py
  19. 2
      slither/core/declarations/pragma_directive.py
  20. 9
      slither/core/declarations/solidity_import_placeholder.py
  21. 36
      slither/core/declarations/solidity_variables.py
  22. 2
      slither/core/declarations/structure_top_level.py
  23. 2
      slither/core/declarations/using_for_top_level.py
  24. 12
      slither/core/dominators/utils.py
  25. 2
      slither/core/expressions/assignment_operation.py
  26. 6
      slither/core/expressions/call_expression.py
  27. 11
      slither/core/expressions/conditional_expression.py
  28. 5
      slither/core/expressions/elementary_type_name_expression.py
  29. 8
      slither/core/expressions/index_access.py
  30. 2
      slither/core/expressions/literal.py
  31. 4
      slither/core/expressions/member_access.py
  32. 9
      slither/core/expressions/new_array.py
  33. 4
      slither/core/expressions/new_contract.py
  34. 14
      slither/core/expressions/type_conversion.py
  35. 9
      slither/core/expressions/unary_operation.py
  36. 2
      slither/core/scope/scope.py
  37. 2
      slither/core/slither_core.py
  38. 21
      slither/core/solidity_types/array_type.py
  39. 6
      slither/core/solidity_types/elementary_type.py
  40. 5
      slither/core/solidity_types/function_type.py
  41. 11
      slither/core/solidity_types/mapping_type.py
  42. 12
      slither/core/solidity_types/type_alias.py
  43. 5
      slither/core/solidity_types/type_information.py
  44. 12
      slither/core/solidity_types/user_defined_type.py
  45. 2
      slither/core/variables/event_variable.py
  46. 2
      slither/core/variables/state_variable.py
  47. 2
      slither/core/variables/top_level_variable.py
  48. 2
      slither/core/variables/variable.py
  49. 7
      slither/printers/guidance/echidna.py
  50. 3
      slither/slither.py
  51. 76
      slither/slithir/convert.py
  52. 9
      slither/slithir/operations/assignment.py
  53. 17
      slither/slithir/operations/binary.py
  54. 10
      slither/slithir/operations/condition.py
  55. 11
      slither/slithir/operations/delete.py
  56. 8
      slither/slithir/operations/event_call.py
  57. 20
      slither/slithir/operations/high_level_call.py
  58. 17
      slither/slithir/operations/index.py
  59. 10
      slither/slithir/operations/init_array.py
  60. 21
      slither/slithir/operations/internal_call.py
  61. 15
      slither/slithir/operations/internal_dynamic_call.py
  62. 13
      slither/slithir/operations/length.py
  63. 2
      slither/slithir/operations/library_call.py
  64. 19
      slither/slithir/operations/low_level_call.py
  65. 2
      slither/slithir/operations/lvalue.py
  66. 11
      slither/slithir/operations/member.py
  67. 16
      slither/slithir/operations/new_array.py
  68. 12
      slither/slithir/operations/new_contract.py
  69. 11
      slither/slithir/operations/new_structure.py
  70. 3
      slither/slithir/operations/operation.py
  71. 13
      slither/slithir/operations/phi.py
  72. 14
      slither/slithir/operations/phi_callback.py
  73. 10
      slither/slithir/operations/return_operation.py
  74. 14
      slither/slithir/operations/send.py
  75. 15
      slither/slithir/operations/solidity_call.py
  76. 12
      slither/slithir/operations/transfer.py
  77. 16
      slither/slithir/operations/type_conversion.py
  78. 15
      slither/slithir/operations/unary.py
  79. 6
      slither/slithir/tmp_operations/argument.py
  80. 17
      slither/slithir/tmp_operations/tmp_call.py
  81. 10
      slither/slithir/tmp_operations/tmp_new_array.py
  82. 3
      slither/slithir/tmp_operations/tmp_new_contract.py
  83. 97
      slither/slithir/utils/ssa.py
  84. 5
      slither/slithir/utils/utils.py
  85. 13
      slither/slithir/variables/constant.py
  86. 7
      slither/slithir/variables/local_variable.py
  87. 10
      slither/slithir/variables/reference.py
  88. 2
      slither/slithir/variables/reference_ssa.py
  89. 4
      slither/slithir/variables/state_variable.py
  90. 8
      slither/slithir/variables/temporary.py
  91. 7
      slither/slithir/variables/temporary_ssa.py
  92. 8
      slither/slithir/variables/tuple.py
  93. 2
      slither/slithir/variables/tuple_ssa.py
  94. 2
      slither/slithir/variables/variable.py
  95. 12
      slither/solc_parsing/cfg/node.py
  96. 70
      slither/solc_parsing/declarations/contract.py
  97. 6
      slither/solc_parsing/declarations/custom_error.py
  98. 4
      slither/solc_parsing/declarations/event.py
  99. 23
      slither/solc_parsing/declarations/function.py
  100. 6
      slither/solc_parsing/declarations/modifier.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -42,6 +42,7 @@ from slither.all_exceptions import SlitherException
from slither.core.declarations import Contract, Function from slither.core.declarations import Contract, Function
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
import slither.slithir.operations.operation
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.slithir.variables.variable import SlithIRVariable from slither.slithir.variables.variable import SlithIRVariable
@ -104,7 +105,7 @@ class NodeType(Enum):
OTHER_ENTRYPOINT = 0x60 OTHER_ENTRYPOINT = 0x60
# @staticmethod # @staticmethod
def __str__(self): def __str__(self) -> str:
if self == NodeType.ENTRYPOINT: if self == NodeType.ENTRYPOINT:
return "ENTRY_POINT" return "ENTRY_POINT"
if self == NodeType.EXPRESSION: if self == NodeType.EXPRESSION:
@ -158,7 +159,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
node_id: int, node_id: int,
scope: Union["Scope", "Function"], scope: Union["Scope", "Function"],
file_scope: "FileScope", file_scope: "FileScope",
): ) -> None:
super().__init__() super().__init__()
self._node_type = node_type self._node_type = node_type
@ -513,11 +514,11 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
return self._expression return self._expression
def add_expression(self, expression: Expression, bypass_verif_empty: bool = False): def add_expression(self, expression: Expression, bypass_verif_empty: bool = False) -> None:
assert self._expression is None or bypass_verif_empty assert self._expression is None or bypass_verif_empty
self._expression = expression self._expression = expression
def add_variable_declaration(self, var: LocalVariable): def add_variable_declaration(self, var: LocalVariable) -> None:
assert self._variable_declaration is None assert self._variable_declaration is None
self._variable_declaration = var self._variable_declaration = var
if var.expression: if var.expression:
@ -550,7 +551,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
for c in self.internal_calls for c in self.internal_calls
) )
def contains_if(self, include_loop=True) -> bool: def contains_if(self, include_loop: bool=True) -> bool:
""" """
Check if the node is a IF node Check if the node is a IF node
Returns: Returns:
@ -560,7 +561,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
return self.type in [NodeType.IF, NodeType.IFLOOP] return self.type in [NodeType.IF, NodeType.IFLOOP]
return self.type == NodeType.IF return self.type == NodeType.IF
def is_conditional(self, include_loop=True) -> bool: def is_conditional(self, include_loop: bool=True) -> bool:
""" """
Check if the node is a conditional node Check if the node is a conditional node
A conditional node is either a IF or a require/assert or a RETURN bool A conditional node is either a IF or a require/assert or a RETURN bool
@ -589,7 +590,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
def inline_asm(self) -> Optional[Union[str, Dict]]: def inline_asm(self) -> Optional[Union[str, Dict]]:
return self._asm_source_code return self._asm_source_code
def add_inline_asm(self, asm: Union[str, Dict]): def add_inline_asm(self, asm: Union[str, Dict]) -> None:
self._asm_source_code = asm self._asm_source_code = asm
# endregion # endregion
@ -599,7 +600,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def add_father(self, father: "Node"): def add_father(self, father: "Node") -> None:
"""Add a father node """Add a father node
Args: Args:
@ -624,7 +625,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
return list(self._fathers) return list(self._fathers)
def remove_father(self, father: "Node"): def remove_father(self, father: "Node") -> None:
"""Remove the father node. Do nothing if the node is not a father """Remove the father node. Do nothing if the node is not a father
Args: Args:
@ -632,7 +633,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
self._fathers = [x for x in self._fathers if x.node_id != father.node_id] self._fathers = [x for x in self._fathers if x.node_id != father.node_id]
def remove_son(self, son: "Node"): def remove_son(self, son: "Node") -> None:
"""Remove the son node. Do nothing if the node is not a son """Remove the son node. Do nothing if the node is not a son
Args: Args:
@ -640,7 +641,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
self._sons = [x for x in self._sons if x.node_id != son.node_id] self._sons = [x for x in self._sons if x.node_id != son.node_id]
def add_son(self, son: "Node"): def add_son(self, son: "Node") -> None:
"""Add a son node """Add a son node
Args: Args:
@ -648,7 +649,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
self._sons.append(son) self._sons.append(son)
def set_sons(self, sons: List["Node"]): def set_sons(self, sons: List["Node"]) -> None:
"""Set the son nodes """Set the son nodes
Args: Args:
@ -706,14 +707,14 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
def irs_ssa(self, irs): def irs_ssa(self, irs):
self._irs_ssa = irs self._irs_ssa = irs
def add_ssa_ir(self, ir: Operation): def add_ssa_ir(self, ir: Operation) -> None:
""" """
Use to place phi operation Use to place phi operation
""" """
ir.set_node(self) ir.set_node(self)
self._irs_ssa.append(ir) self._irs_ssa.append(ir)
def slithir_generation(self): def slithir_generation(self) -> None:
if self.expression: if self.expression:
expression = self.expression expression = self.expression
self._irs = convert_expression(expression, self) self._irs = convert_expression(expression, self)
@ -730,11 +731,11 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
return self._all_slithir_operations return self._all_slithir_operations
@staticmethod @staticmethod
def _is_non_slithir_var(var: Variable): def _is_non_slithir_var(var: Variable) -> bool:
return not isinstance(var, (Constant, ReferenceVariable, TemporaryVariable, TupleVariable)) return not isinstance(var, (Constant, ReferenceVariable, TemporaryVariable, TupleVariable))
@staticmethod @staticmethod
def _is_valid_slithir_var(var: Variable): def _is_valid_slithir_var(var: Variable) -> bool:
return isinstance(var, (ReferenceVariable, TemporaryVariable, TupleVariable)) return isinstance(var, (ReferenceVariable, TemporaryVariable, TupleVariable))
# endregion # endregion
@ -785,7 +786,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
self._dominance_frontier = doms self._dominance_frontier = doms
@property @property
def dominator_successors(self): def dominator_successors(self) -> Set["Node"]:
return self._dom_successors return self._dom_successors
@property @property
@ -827,14 +828,14 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
# def phi_origin_member_variables(self) -> Dict[str, Tuple[MemberVariable, Set["Node"]]]: # def phi_origin_member_variables(self) -> Dict[str, Tuple[MemberVariable, Set["Node"]]]:
# return self._phi_origins_member_variables # return self._phi_origins_member_variables
def add_phi_origin_local_variable(self, variable: LocalVariable, node: "Node"): def add_phi_origin_local_variable(self, variable: LocalVariable, node: "Node") -> None:
if variable.name not in self._phi_origins_local_variables: if variable.name not in self._phi_origins_local_variables:
self._phi_origins_local_variables[variable.name] = (variable, set()) self._phi_origins_local_variables[variable.name] = (variable, set())
(v, nodes) = self._phi_origins_local_variables[variable.name] (v, nodes) = self._phi_origins_local_variables[variable.name]
assert v == variable assert v == variable
nodes.add(node) nodes.add(node)
def add_phi_origin_state_variable(self, variable: StateVariable, node: "Node"): def add_phi_origin_state_variable(self, variable: StateVariable, node: "Node") -> None:
if variable.canonical_name not in self._phi_origins_state_variables: if variable.canonical_name not in self._phi_origins_state_variables:
self._phi_origins_state_variables[variable.canonical_name] = ( self._phi_origins_state_variables[variable.canonical_name] = (
variable, variable,
@ -858,7 +859,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _find_read_write_call(self): # pylint: disable=too-many-statements def _find_read_write_call(self) -> None: # pylint: disable=too-many-statements
for ir in self.irs: for ir in self.irs:
@ -934,7 +935,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
self._low_level_calls = list(set(self._low_level_calls)) self._low_level_calls = list(set(self._low_level_calls))
@staticmethod @staticmethod
def _convert_ssa(v: Variable): def _convert_ssa(v: Variable) -> Optional[Union[StateVariable, LocalVariable]]:
if isinstance(v, StateIRVariable): if isinstance(v, StateIRVariable):
contract = v.contract contract = v.contract
non_ssa_var = contract.get_state_variable_from_name(v.name) non_ssa_var = contract.get_state_variable_from_name(v.name)
@ -944,7 +945,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
non_ssa_var = function.get_local_variable_from_name(v.name) non_ssa_var = function.get_local_variable_from_name(v.name)
return non_ssa_var return non_ssa_var
def update_read_write_using_ssa(self): def update_read_write_using_ssa(self) -> None:
if not self.expression: if not self.expression:
return return
for ir in self.irs_ssa: for ir in self.irs_ssa:
@ -1026,12 +1027,12 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
################################################################################### ###################################################################################
def link_nodes(node1: Node, node2: Node): def link_nodes(node1: Node, node2: Node) -> None:
node1.add_son(node2) node1.add_son(node2)
node2.add_father(node1) node2.add_father(node1)
def insert_node(origin: Node, node_inserted: Node): def insert_node(origin: Node, node_inserted: Node) -> None:
sons = origin.sons sons = origin.sons
link_nodes(origin, node_inserted) link_nodes(origin, node_inserted)
for son in sons: for son in sons:

@ -7,7 +7,7 @@ if TYPE_CHECKING:
# pylint: disable=too-few-public-methods # pylint: disable=too-few-public-methods
class Scope: class Scope:
def __init__(self, is_checked: bool, is_yul: bool, scope: Union["Scope", "Function"]): def __init__(self, is_checked: bool, is_yul: bool, scope: Union["Scope", "Function"]) -> None:
self.nodes: List["Node"] = [] self.nodes: List["Node"] = []
self.is_checked = is_checked self.is_checked = is_checked
self.is_yul = is_yul self.is_yul = is_yul

@ -7,11 +7,11 @@ if TYPE_CHECKING:
class ChildContract(SourceMapping): class ChildContract(SourceMapping):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._contract = None self._contract = None
def set_contract(self, contract: "Contract"): def set_contract(self, contract: "Contract") -> None:
self._contract = contract self._contract = contract
@property @property

@ -5,7 +5,7 @@ if TYPE_CHECKING:
class ChildEvent: class ChildEvent:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._event = None self._event = None

@ -5,11 +5,11 @@ if TYPE_CHECKING:
class ChildExpression: class ChildExpression:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._expression = None self._expression = None
def set_expression(self, expression: "Expression"): def set_expression(self, expression: "Expression") -> None:
self._expression = expression self._expression = expression
@property @property

@ -5,11 +5,11 @@ if TYPE_CHECKING:
class ChildInheritance: class ChildInheritance:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._contract_declarer = None self._contract_declarer = None
def set_contract_declarer(self, contract: "Contract"): def set_contract_declarer(self, contract: "Contract") -> None:
self._contract_declarer = contract self._contract_declarer = contract
@property @property

@ -7,11 +7,11 @@ if TYPE_CHECKING:
class ChildNode: class ChildNode:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._node = None self._node = None
def set_node(self, node: "Node"): def set_node(self, node: "Node") -> None:
self._node = node self._node = node
@property @property

@ -5,11 +5,11 @@ if TYPE_CHECKING:
class ChildStructure: class ChildStructure:
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._structure = None self._structure = None
def set_structure(self, structure: "Structure"): def set_structure(self, structure: "Structure") -> None:
self._structure = structure self._structure = structure
@property @property

@ -24,6 +24,12 @@ from slither.core.variables.state_variable import StateVariable
from slither.core.variables.top_level_variable import TopLevelVariable from slither.core.variables.top_level_variable import TopLevelVariable
from slither.slithir.operations import InternalCall from slither.slithir.operations import InternalCall
from slither.slithir.variables import Constant from slither.slithir.variables import Constant
import crytic_compile.compilation_unit
import slither.core.declarations.contract
import slither.core.declarations.function
import slither.core.declarations.import_directive
import slither.core.declarations.modifier
import slither.core.declarations.pragma_directive
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.slither_core import SlitherCore from slither.core.slither_core import SlitherCore
@ -31,7 +37,7 @@ if TYPE_CHECKING:
# pylint: disable=too-many-instance-attributes,too-many-public-methods # pylint: disable=too-many-instance-attributes,too-many-public-methods
class SlitherCompilationUnit(Context): class SlitherCompilationUnit(Context):
def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit): def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None:
super().__init__() super().__init__()
self._core = core self._core = core
@ -150,21 +156,21 @@ class SlitherCompilationUnit(Context):
def functions(self) -> List[Function]: def functions(self) -> List[Function]:
return list(self._all_functions) return list(self._all_functions)
def add_function(self, func: Function): def add_function(self, func: Function) -> None:
self._all_functions.add(func) self._all_functions.add(func)
@property @property
def modifiers(self) -> List[Modifier]: def modifiers(self) -> List[Modifier]:
return list(self._all_modifiers) return list(self._all_modifiers)
def add_modifier(self, modif: Modifier): def add_modifier(self, modif: Modifier) -> None:
self._all_modifiers.add(modif) self._all_modifiers.add(modif)
@property @property
def functions_and_modifiers(self) -> List[Function]: def functions_and_modifiers(self) -> List[Function]:
return self.functions + self.modifiers return self.functions + self.modifiers
def propagate_function_calls(self): def propagate_function_calls(self) -> None:
for f in self.functions_and_modifiers: for f in self.functions_and_modifiers:
for node in f.nodes: for node in f.nodes:
for ir in node.irs_ssa: for ir in node.irs_ssa:
@ -256,7 +262,7 @@ class SlitherCompilationUnit(Context):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def compute_storage_layout(self): def compute_storage_layout(self) -> None:
for contract in self.contracts_derived: for contract in self.contracts_derived:
self._storage_layouts[contract.name] = {} self._storage_layouts[contract.name] = {}

@ -55,7 +55,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
Contract class Contract class
""" """
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__() super().__init__()
self._name: Optional[str] = None self._name: Optional[str] = None
@ -366,7 +366,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
""" """
return list(self._variables_ordered) return list(self._variables_ordered)
def add_variables_ordered(self, new_vars: List["StateVariable"]): def add_variables_ordered(self, new_vars: List["StateVariable"]) -> None:
self._variables_ordered += new_vars self._variables_ordered += new_vars
@property @property
@ -534,7 +534,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def add_function(self, func: "FunctionContract"): def add_function(self, func: "FunctionContract"):
self._functions[func.canonical_name] = func self._functions[func.canonical_name] = func
def set_functions(self, functions: Dict[str, "FunctionContract"]): def set_functions(self, functions: Dict[str, "FunctionContract"]) -> None:
""" """
Set the functions Set the functions
@ -578,7 +578,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def available_modifiers_as_dict(self) -> Dict[str, "Modifier"]: def available_modifiers_as_dict(self) -> Dict[str, "Modifier"]:
return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed} return {m.full_name: m for m in self._modifiers.values() if not m.is_shadowed}
def set_modifiers(self, modifiers: Dict[str, "Modifier"]): def set_modifiers(self, modifiers: Dict[str, "Modifier"]) -> None:
""" """
Set the modifiers Set the modifiers
@ -688,7 +688,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
inheritance: List["Contract"], inheritance: List["Contract"],
immediate_inheritance: List["Contract"], immediate_inheritance: List["Contract"],
called_base_constructor_contracts: List["Contract"], called_base_constructor_contracts: List["Contract"],
): ) -> None:
self._inheritance = inheritance self._inheritance = inheritance
self._immediate_inheritance = immediate_inheritance self._immediate_inheritance = immediate_inheritance
self._explicit_base_constructor_calls = called_base_constructor_contracts self._explicit_base_constructor_calls = called_base_constructor_contracts
@ -1216,7 +1216,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def update_read_write_using_ssa(self): def update_read_write_using_ssa(self) -> None:
for function in self.functions + self.modifiers: for function in self.functions + self.modifiers:
function.update_read_write_using_ssa() function.update_read_write_using_ssa()
@ -1311,7 +1311,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def is_incorrectly_constructed(self, incorrect: bool): def is_incorrectly_constructed(self, incorrect: bool):
self._is_incorrectly_parsed = incorrect self._is_incorrectly_parsed = incorrect
def add_constructor_variables(self): def add_constructor_variables(self) -> None:
from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.function_contract import FunctionContract
if self.state_variables: if self.state_variables:
@ -1380,7 +1380,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def _create_node( def _create_node(
self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function] self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]
): ) -> "Node":
from slither.core.cfg.node import Node, NodeType from slither.core.cfg.node import Node, NodeType
from slither.core.expressions import ( from slither.core.expressions import (
AssignmentOperationType, AssignmentOperationType,
@ -1412,7 +1412,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def convert_expression_to_slithir_ssa(self): def convert_expression_to_slithir_ssa(self) -> None:
""" """
Assume generate_slithir_and_analyze was called on all functions Assume generate_slithir_and_analyze was called on all functions
@ -1437,7 +1437,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
for func in self.functions + self.modifiers: for func in self.functions + self.modifiers:
func.generate_slithir_ssa(all_ssa_state_variables_instances) func.generate_slithir_ssa(all_ssa_state_variables_instances)
def fix_phi(self): def fix_phi(self) -> None:
last_state_variables_instances = {} last_state_variables_instances = {}
initial_state_variables_instances = {} initial_state_variables_instances = {}
for v in self._initial_state_variables: for v in self._initial_state_variables:
@ -1459,7 +1459,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def __eq__(self, other): def __eq__(self, other: SourceMapping):
if isinstance(other, str): if isinstance(other, str):
return other == self.name return other == self.name
return NotImplemented return NotImplemented
@ -1469,10 +1469,10 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
return other != self.name return other != self.name
return NotImplemented return NotImplemented
def __str__(self): def __str__(self) -> str:
return self.name return self.name
def __hash__(self): def __hash__(self) -> int:
return self._id return self._id
# endregion # endregion

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class CustomError(SourceMapping): class CustomError(SourceMapping):
def __init__(self, compilation_unit: "SlitherCompilationUnit"): def __init__(self, compilation_unit: "SlitherCompilationUnit") -> None:
super().__init__() super().__init__()
self._name: str = "" self._name: str = ""
self._parameters: List[LocalVariable] = [] self._parameters: List[LocalVariable] = []
@ -30,7 +30,7 @@ class CustomError(SourceMapping):
def parameters(self) -> List[LocalVariable]: def parameters(self) -> List[LocalVariable]:
return self._parameters return self._parameters
def add_parameters(self, p: "LocalVariable"): def add_parameters(self, p: "LocalVariable") -> None:
self._parameters.append(p) self._parameters.append(p)
@property @property
@ -42,7 +42,7 @@ class CustomError(SourceMapping):
################################################################################### ###################################################################################
@staticmethod @staticmethod
def _convert_type_for_solidity_signature(t: Optional[Union[Type, List[Type]]]): def _convert_type_for_solidity_signature(t: Optional[Union[Type, List[Type]]]) -> str:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from slither.core.declarations import Contract from slither.core.declarations import Contract
@ -92,5 +92,5 @@ class CustomError(SourceMapping):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def __str__(self): def __str__(self) -> str:
return "revert " + self.solidity_signature return "revert " + self.solidity_signature

@ -4,7 +4,7 @@ from slither.core.source_mapping.source_mapping import SourceMapping
class Enum(SourceMapping): class Enum(SourceMapping):
def __init__(self, name: str, canonical_name: str, values: List[str]): def __init__(self, name: str, canonical_name: str, values: List[str]) -> None:
super().__init__() super().__init__()
self._name = name self._name = name
self._canonical_name = canonical_name self._canonical_name = canonical_name
@ -33,5 +33,5 @@ class Enum(SourceMapping):
def max(self) -> int: def max(self) -> int:
return self._max return self._max
def __str__(self): def __str__(self) -> str:
return self.name return self.name

@ -8,6 +8,6 @@ if TYPE_CHECKING:
class EnumTopLevel(Enum, TopLevel): class EnumTopLevel(Enum, TopLevel):
def __init__(self, name: str, canonical_name: str, values: List[str], scope: "FileScope"): def __init__(self, name: str, canonical_name: str, values: List[str], scope: "FileScope") -> None:
super().__init__(name, canonical_name, values) super().__init__(name, canonical_name, values)
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class Event(ChildContract, SourceMapping): class Event(ChildContract, SourceMapping):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._name = None self._name = None
self._elems: List[EventVariable] = [] self._elems: List[EventVariable] = []

@ -6,7 +6,7 @@ from abc import abstractmethod, ABCMeta
from collections import namedtuple from collections import namedtuple
from enum import Enum from enum import Enum
from itertools import groupby from itertools import groupby
from typing import Dict, TYPE_CHECKING, List, Optional, Set, Union, Callable, Tuple from typing import Any, Dict, TYPE_CHECKING, List, Optional, Set, Union, Callable, Tuple
from slither.core.cfg.scope import Scope from slither.core.cfg.scope import Scope
from slither.core.declarations.solidity_variables import ( from slither.core.declarations.solidity_variables import (
@ -27,6 +27,7 @@ from slither.core.variables.state_variable import StateVariable
from slither.utils.type import convert_type_for_solidity_signature_to_string from slither.utils.type import convert_type_for_solidity_signature_to_string
from slither.utils.utils import unroll from slither.utils.utils import unroll
# pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines # pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines
if TYPE_CHECKING: if TYPE_CHECKING:
@ -45,6 +46,7 @@ if TYPE_CHECKING:
from slither.slithir.operations import Operation from slither.slithir.operations import Operation
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
LOGGER = logging.getLogger("Function") LOGGER = logging.getLogger("Function")
ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"]) ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"])
@ -56,7 +58,7 @@ class ModifierStatements:
modifier: Union["Contract", "Function"], modifier: Union["Contract", "Function"],
entry_point: "Node", entry_point: "Node",
nodes: List["Node"], nodes: List["Node"],
): ) -> None:
self._modifier = modifier self._modifier = modifier
self._entry_point = entry_point self._entry_point = entry_point
self._nodes = nodes self._nodes = nodes
@ -116,7 +118,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
Function class Function class
""" """
def __init__(self, compilation_unit: "SlitherCompilationUnit"): def __init__(self, compilation_unit: "SlitherCompilationUnit") -> None:
super().__init__() super().__init__()
self._internal_scope: List[str] = [] self._internal_scope: List[str] = []
self._name: Optional[str] = None self._name: Optional[str] = None
@ -370,7 +372,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def set_function_type(self, t: FunctionType): def set_function_type(self, t: FunctionType) -> None:
assert isinstance(t, FunctionType) assert isinstance(t, FunctionType)
self._function_type = t self._function_type = t
@ -455,7 +457,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def visibility(self, v: str): def visibility(self, v: str):
self._visibility = v self._visibility = v
def set_visibility(self, v: str): def set_visibility(self, v: str) -> None:
self._visibility = v self._visibility = v
@property @property
@ -554,7 +556,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def entry_point(self, node: "Node"): def entry_point(self, node: "Node"):
self._entry_point = node self._entry_point = node
def add_node(self, node: "Node"): def add_node(self, node: "Node") -> None:
if not self._entry_point: if not self._entry_point:
self._entry_point = node self._entry_point = node
self._nodes.append(node) self._nodes.append(node)
@ -598,7 +600,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._parameters) return list(self._parameters)
def add_parameters(self, p: "LocalVariable"): def add_parameters(self, p: "LocalVariable") -> None:
self._parameters.append(p) self._parameters.append(p)
@property @property
@ -608,7 +610,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._parameters_ssa) return list(self._parameters_ssa)
def add_parameter_ssa(self, var: "LocalIRVariable"): def add_parameter_ssa(self, var: "LocalIRVariable") -> None:
self._parameters_ssa.append(var) self._parameters_ssa.append(var)
def parameters_src(self) -> SourceMapping: def parameters_src(self) -> SourceMapping:
@ -651,7 +653,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._returns) return list(self._returns)
def add_return(self, r: "LocalVariable"): def add_return(self, r: "LocalVariable") -> None:
self._returns.append(r) self._returns.append(r)
@property @property
@ -661,7 +663,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return list(self._returns_ssa) return list(self._returns_ssa)
def add_return_ssa(self, var: "LocalIRVariable"): def add_return_ssa(self, var: "LocalIRVariable") -> None:
self._returns_ssa.append(var) self._returns_ssa.append(var)
# endregion # endregion
@ -680,7 +682,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
""" """
return [c.modifier for c in self._modifiers] return [c.modifier for c in self._modifiers]
def add_modifier(self, modif: "ModifierStatements"): def add_modifier(self, modif: "ModifierStatements") -> None:
self._modifiers.append(modif) self._modifiers.append(modif)
@property @property
@ -714,7 +716,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
# This is a list of contracts internally, so we convert it to a list of constructor functions. # This is a list of contracts internally, so we convert it to a list of constructor functions.
return list(self._explicit_base_constructor_calls) return list(self._explicit_base_constructor_calls)
def add_explicit_base_constructor_calls_statements(self, modif: ModifierStatements): def add_explicit_base_constructor_calls_statements(self, modif: ModifierStatements) -> None:
self._explicit_base_constructor_calls.append(modif) self._explicit_base_constructor_calls.append(modif)
# endregion # endregion
@ -1057,7 +1059,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
self._all_reachable_from_functions = functions self._all_reachable_from_functions = functions
return self._all_reachable_from_functions return self._all_reachable_from_functions
def add_reachable_from_node(self, n: "Node", ir: "Operation"): def add_reachable_from_node(self, n: "Node", ir: "Operation") -> None:
self._reachable_from_nodes.add(ReacheableNode(n, ir)) self._reachable_from_nodes.add(ReacheableNode(n, ir))
self._reachable_from_functions.add(n.function) self._reachable_from_functions.add(n.function)
@ -1068,7 +1070,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _explore_functions(self, f_new_values: Callable[["Function"], List]): def _explore_functions(self, f_new_values: Callable[["Function"], List]) -> List[Any]:
values = f_new_values(self) values = f_new_values(self)
explored = [self] explored = [self]
to_explore = [ to_explore = [
@ -1218,11 +1220,11 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
func: "Function", func: "Function",
f: Callable[["Node"], List[SolidityVariable]], f: Callable[["Node"], List[SolidityVariable]],
include_loop: bool, include_loop: bool,
): ) -> List[Any]:
ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)] ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)]
return [item for sublist in ret for item in sublist] return [item for sublist in ret for item in sublist]
def all_conditional_solidity_variables_read(self, include_loop=True) -> List[SolidityVariable]: def all_conditional_solidity_variables_read(self, include_loop: bool=True) -> List[SolidityVariable]:
""" """
Return the Soldiity variables directly used in a condtion Return the Soldiity variables directly used in a condtion
@ -1258,7 +1260,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return [var for var in ret if isinstance(var, SolidityVariable)] return [var for var in ret if isinstance(var, SolidityVariable)]
@staticmethod @staticmethod
def _explore_func_nodes(func: "Function", f: Callable[["Node"], List[SolidityVariable]]): def _explore_func_nodes(func: "Function", f: Callable[["Node"], List[SolidityVariable]]) -> List[Union[Any, SolidityVariableComposed]]:
ret = [f(n) for n in func.nodes] ret = [f(n) for n in func.nodes]
return [item for sublist in ret for item in sublist] return [item for sublist in ret for item in sublist]
@ -1367,7 +1369,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
with open(filename, "w", encoding="utf8") as f: with open(filename, "w", encoding="utf8") as f:
f.write(content) f.write(content)
def slithir_cfg_to_dot_str(self, skip_expressions=False) -> str: def slithir_cfg_to_dot_str(self, skip_expressions: bool=False) -> str:
""" """
Export the CFG to a DOT format. The nodes includes the Solidity expressions and the IRs Export the CFG to a DOT format. The nodes includes the Solidity expressions and the IRs
:return: the DOT content :return: the DOT content
@ -1512,7 +1514,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _analyze_read_write(self): def _analyze_read_write(self) -> None:
"""Compute variables read/written/...""" """Compute variables read/written/..."""
write_var = [x.variables_written_as_expression for x in self.nodes] write_var = [x.variables_written_as_expression for x in self.nodes]
write_var = [x for x in write_var if x] write_var = [x for x in write_var if x]
@ -1570,7 +1572,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
slithir_variables = [x for x in slithir_variables if x] slithir_variables = [x for x in slithir_variables if x]
self._slithir_variables = [item for sublist in slithir_variables for item in sublist] self._slithir_variables = [item for sublist in slithir_variables for item in sublist]
def _analyze_calls(self): def _analyze_calls(self) -> None:
calls = [x.calls_as_expression for x in self.nodes] calls = [x.calls_as_expression for x in self.nodes]
calls = [x for x in calls if x] calls = [x for x in calls if x]
calls = [item for sublist in calls for item in sublist] calls = [item for sublist in calls for item in sublist]
@ -1702,7 +1704,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return self._get_last_ssa_variable_instances(target_state=False, target_local=True) return self._get_last_ssa_variable_instances(target_state=False, target_local=True)
@staticmethod @staticmethod
def _unchange_phi(ir: "Operation"): def _unchange_phi(ir: "Operation") -> bool:
from slither.slithir.operations import Phi, PhiCallback from slither.slithir.operations import Phi, PhiCallback
if not isinstance(ir, (Phi, PhiCallback)) or len(ir.rvalues) > 1: if not isinstance(ir, (Phi, PhiCallback)) or len(ir.rvalues) > 1:
@ -1711,7 +1713,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return True return True
return ir.rvalues[0] == ir.lvalue return ir.rvalues[0] == ir.lvalue
def fix_phi(self, last_state_variables_instances, initial_state_variables_instances): def fix_phi(self, last_state_variables_instances: Dict[str, Union[List[Any], List[Union[Any, "StateIRVariable"]], List[ "StateIRVariable"]]], initial_state_variables_instances: Dict[str, "StateIRVariable"]) -> None:
from slither.slithir.operations import InternalCall, PhiCallback from slither.slithir.operations import InternalCall, PhiCallback
from slither.slithir.variables import Constant, StateIRVariable from slither.slithir.variables import Constant, StateIRVariable
@ -1745,7 +1747,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
node.irs_ssa = [ir for ir in node.irs_ssa if not self._unchange_phi(ir)] node.irs_ssa = [ir for ir in node.irs_ssa if not self._unchange_phi(ir)]
def generate_slithir_and_analyze(self): def generate_slithir_and_analyze(self) -> None:
for node in self.nodes: for node in self.nodes:
node.slithir_generation() node.slithir_generation()
@ -1756,7 +1758,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def generate_slithir_ssa(self, all_ssa_state_variables_instances): def generate_slithir_ssa(self, all_ssa_state_variables_instances):
pass pass
def update_read_write_using_ssa(self): def update_read_write_using_ssa(self) -> None:
for node in self.nodes: for node in self.nodes:
node.update_read_write_using_ssa() node.update_read_write_using_ssa()
self._analyze_read_write() self._analyze_read_write()
@ -1767,7 +1769,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def __str__(self): def __str__(self) -> str:
return self.name return self.name
# endregion # endregion

@ -1,17 +1,19 @@
""" """
Function module Function module
""" """
from typing import TYPE_CHECKING, List, Tuple from typing import Dict, TYPE_CHECKING, List, Tuple
from slither.core.children.child_contract import ChildContract from slither.core.children.child_contract import ChildContract
from slither.core.children.child_inheritance import ChildInheritance from slither.core.children.child_inheritance import ChildInheritance
from slither.core.declarations import Function from slither.core.declarations import Function
# pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines # pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.declarations import Contract from slither.core.declarations import Contract
from slither.core.scope.scope import FileScope from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
class FunctionContract(Function, ChildContract, ChildInheritance): class FunctionContract(Function, ChildContract, ChildInheritance):
@ -96,7 +98,7 @@ class FunctionContract(Function, ChildContract, ChildInheritance):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def generate_slithir_ssa(self, all_ssa_state_variables_instances): def generate_slithir_ssa(self, all_ssa_state_variables_instances: Dict[str, "StateIRVariable"]) -> None:
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import ( from slither.core.dominators.utils import (
compute_dominance_frontier, compute_dominance_frontier,

@ -1,7 +1,7 @@
""" """
Function module Function module
""" """
from typing import List, Tuple, TYPE_CHECKING from typing import Any, Dict, List, Tuple, TYPE_CHECKING
from slither.core.declarations import Function from slither.core.declarations import Function
from slither.core.declarations.top_level import TopLevel from slither.core.declarations.top_level import TopLevel
@ -12,7 +12,7 @@ if TYPE_CHECKING:
class FunctionTopLevel(Function, TopLevel): class FunctionTopLevel(Function, TopLevel):
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__(compilation_unit) super().__init__(compilation_unit)
self._scope: "FileScope" = scope self._scope: "FileScope" = scope
@ -78,7 +78,7 @@ class FunctionTopLevel(Function, TopLevel):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def generate_slithir_ssa(self, all_ssa_state_variables_instances): def generate_slithir_ssa(self, all_ssa_state_variables_instances: Dict[Any, Any]) -> None:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import ( from slither.core.dominators.utils import (

@ -8,7 +8,7 @@ if TYPE_CHECKING:
class Import(SourceMapping): class Import(SourceMapping):
def __init__(self, filename: Path, scope: "FileScope"): def __init__(self, filename: Path, scope: "FileScope") -> None:
super().__init__() super().__init__()
self._filename: Path = filename self._filename: Path = filename
self._alias: Optional[str] = None self._alias: Optional[str] = None

@ -7,7 +7,7 @@ if TYPE_CHECKING:
class Pragma(SourceMapping): class Pragma(SourceMapping):
def __init__(self, directive: List[str], scope: "FileScope"): def __init__(self, directive: List[str], scope: "FileScope") -> None:
super().__init__() super().__init__()
self._directive = directive self._directive = directive
self.scope: "FileScope" = scope self.scope: "FileScope" = scope

@ -4,6 +4,11 @@ Special variable to model import with renaming
from slither.core.declarations import Import from slither.core.declarations import Import
from slither.core.solidity_types import ElementaryType from slither.core.solidity_types import ElementaryType
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
import slither.core.declarations.import_directive
import slither.core.solidity_types.elementary_type
from slither.core.declarations.contract import Contract
from slither.core.declarations.solidity_variables import SolidityVariable
from typing import Union
class SolidityImportPlaceHolder(Variable): class SolidityImportPlaceHolder(Variable):
@ -13,7 +18,7 @@ class SolidityImportPlaceHolder(Variable):
In the long term we should remove this and better integrate import aliases In the long term we should remove this and better integrate import aliases
""" """
def __init__(self, import_directive: Import): def __init__(self, import_directive: Import) -> None:
super().__init__() super().__init__()
assert import_directive.alias is not None assert import_directive.alias is not None
self._import_directive = import_directive self._import_directive = import_directive
@ -27,7 +32,7 @@ class SolidityImportPlaceHolder(Variable):
def type(self) -> ElementaryType: def type(self) -> ElementaryType:
return ElementaryType("string") return ElementaryType("string")
def __eq__(self, other): def __eq__(self, other: Union[Contract, SolidityVariable]) -> bool:
return ( return (
self.__class__ == other.__class__ self.__class__ == other.__class__
and self._import_directive.filename == self._import_directive.filename and self._import_directive.filename == self._import_directive.filename

@ -1,13 +1,11 @@
# https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html # https://solidity.readthedocs.io/en/v0.4.24/units-and-global-variables.html
from typing import List, Dict, Union, TYPE_CHECKING from typing import List, Dict, Union, Any
from slither.core.declarations.custom_error import CustomError from slither.core.declarations.custom_error import CustomError
from slither.core.solidity_types import ElementaryType, TypeInformation from slither.core.solidity_types import ElementaryType, TypeInformation
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
from slither.exceptions import SlitherException from slither.exceptions import SlitherException
if TYPE_CHECKING:
pass
SOLIDITY_VARIABLES = { SOLIDITY_VARIABLES = {
"now": "uint256", "now": "uint256",
@ -98,13 +96,13 @@ def solidity_function_signature(name):
class SolidityVariable(SourceMapping): class SolidityVariable(SourceMapping):
def __init__(self, name: str): def __init__(self, name: str) -> None:
super().__init__() super().__init__()
self._check_name(name) self._check_name(name)
self._name = name self._name = name
# dev function, will be removed once the code is stable # dev function, will be removed once the code is stable
def _check_name(self, name: str): # pylint: disable=no-self-use def _check_name(self, name: str) -> None: # pylint: disable=no-self-use
assert name in SOLIDITY_VARIABLES or name.endswith(("_slot", "_offset")) assert name in SOLIDITY_VARIABLES or name.endswith(("_slot", "_offset"))
@property @property
@ -124,18 +122,18 @@ class SolidityVariable(SourceMapping):
def type(self) -> ElementaryType: def type(self) -> ElementaryType:
return ElementaryType(SOLIDITY_VARIABLES[self.name]) return ElementaryType(SOLIDITY_VARIABLES[self.name])
def __str__(self): def __str__(self) -> str:
return self._name return self._name
def __eq__(self, other): def __eq__(self, other: SourceMapping) -> bool:
return self.__class__ == other.__class__ and self.name == other.name return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self): def __hash__(self) -> int:
return hash(self.name) return hash(self.name)
class SolidityVariableComposed(SolidityVariable): class SolidityVariableComposed(SolidityVariable):
def _check_name(self, name: str): def _check_name(self, name: str) -> None:
assert name in SOLIDITY_VARIABLES_COMPOSED assert name in SOLIDITY_VARIABLES_COMPOSED
@property @property
@ -146,13 +144,13 @@ class SolidityVariableComposed(SolidityVariable):
def type(self) -> ElementaryType: def type(self) -> ElementaryType:
return ElementaryType(SOLIDITY_VARIABLES_COMPOSED[self.name]) return ElementaryType(SOLIDITY_VARIABLES_COMPOSED[self.name])
def __str__(self): def __str__(self) -> str:
return self._name return self._name
def __eq__(self, other): def __eq__(self, other: Any) -> bool:
return self.__class__ == other.__class__ and self.name == other.name return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self): def __hash__(self) -> int:
return hash(self.name) return hash(self.name)
@ -162,7 +160,7 @@ class SolidityFunction(SourceMapping):
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information # https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
# As a result, we set return_type during the Ir conversion # As a result, we set return_type during the Ir conversion
def __init__(self, name: str): def __init__(self, name: str) -> None:
super().__init__() super().__init__()
assert name in SOLIDITY_FUNCTIONS assert name in SOLIDITY_FUNCTIONS
self._name = name self._name = name
@ -187,28 +185,28 @@ class SolidityFunction(SourceMapping):
def return_type(self, r: List[Union[TypeInformation, ElementaryType]]): def return_type(self, r: List[Union[TypeInformation, ElementaryType]]):
self._return_type = r self._return_type = r
def __str__(self): def __str__(self) -> str:
return self._name return self._name
def __eq__(self, other): def __eq__(self, other: "SolidityFunction") -> bool:
return self.__class__ == other.__class__ and self.name == other.name return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self): def __hash__(self) -> int:
return hash(self.name) return hash(self.name)
class SolidityCustomRevert(SolidityFunction): class SolidityCustomRevert(SolidityFunction):
def __init__(self, custom_error: CustomError): # pylint: disable=super-init-not-called def __init__(self, custom_error: CustomError) -> None: # pylint: disable=super-init-not-called
self._name = "revert " + custom_error.solidity_signature self._name = "revert " + custom_error.solidity_signature
self._custom_error = custom_error self._custom_error = custom_error
self._return_type: List[Union[TypeInformation, ElementaryType]] = [] self._return_type: List[Union[TypeInformation, ElementaryType]] = []
def __eq__(self, other): def __eq__(self, other: Union["SolidityCustomRevert", SolidityFunction]) -> bool:
return ( return (
self.__class__ == other.__class__ self.__class__ == other.__class__
and self.name == other.name and self.name == other.name
and self._custom_error == other._custom_error and self._custom_error == other._custom_error
) )
def __hash__(self): def __hash__(self) -> int:
return hash(hash(self.name) + hash(self._custom_error)) return hash(hash(self.name) + hash(self._custom_error))

@ -9,6 +9,6 @@ if TYPE_CHECKING:
class StructureTopLevel(Structure, TopLevel): class StructureTopLevel(Structure, TopLevel):
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__(compilation_unit) super().__init__(compilation_unit)
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope

@ -8,7 +8,7 @@ if TYPE_CHECKING:
class UsingForTopLevel(TopLevel): class UsingForTopLevel(TopLevel):
def __init__(self, scope: "FileScope"): def __init__(self, scope: "FileScope") -> None:
super().__init__() super().__init__()
self._using_for: Dict[Union[str, Type], List[Type]] = {} self._using_for: Dict[Union[str, Type], List[Type]] = {}
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope

@ -1,4 +1,4 @@
from typing import List, TYPE_CHECKING from typing import Set, List, TYPE_CHECKING
from slither.core.cfg.node import NodeType from slither.core.cfg.node import NodeType
@ -6,7 +6,7 @@ if TYPE_CHECKING:
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
def intersection_predecessor(node: "Node"): def intersection_predecessor(node: "Node") -> Set[Node]:
if not node.fathers: if not node.fathers:
return set() return set()
ret = node.fathers[0].dominators ret = node.fathers[0].dominators
@ -15,7 +15,7 @@ def intersection_predecessor(node: "Node"):
return ret return ret
def _compute_dominators(nodes: List["Node"]): def _compute_dominators(nodes: List["Node"]) -> None:
changed = True changed = True
while changed: while changed:
@ -28,7 +28,7 @@ def _compute_dominators(nodes: List["Node"]):
changed = True changed = True
def _compute_immediate_dominators(nodes: List["Node"]): def _compute_immediate_dominators(nodes: List["Node"]) -> None:
for node in nodes: for node in nodes:
idom_candidates = set(node.dominators) idom_candidates = set(node.dominators)
idom_candidates.remove(node) idom_candidates.remove(node)
@ -58,7 +58,7 @@ def _compute_immediate_dominators(nodes: List["Node"]):
idom.dominator_successors.add(node) idom.dominator_successors.add(node)
def compute_dominators(nodes: List["Node"]): def compute_dominators(nodes: List["Node"]) -> None:
""" """
Naive implementation of Cooper, Harvey, Kennedy algo Naive implementation of Cooper, Harvey, Kennedy algo
See 'A Simple,Fast Dominance Algorithm' See 'A Simple,Fast Dominance Algorithm'
@ -74,7 +74,7 @@ def compute_dominators(nodes: List["Node"]):
_compute_immediate_dominators(nodes) _compute_immediate_dominators(nodes)
def compute_dominance_frontier(nodes: List["Node"]): def compute_dominance_frontier(nodes: List["Node"]) -> None:
""" """
Naive implementation of Cooper, Harvey, Kennedy algo Naive implementation of Cooper, Harvey, Kennedy algo
See 'A Simple,Fast Dominance Algorithm' See 'A Simple,Fast Dominance Algorithm'

@ -85,7 +85,7 @@ class AssignmentOperation(ExpressionTyped):
right_expression: Expression, right_expression: Expression,
expression_type: AssignmentOperationType, expression_type: AssignmentOperationType,
expression_return_type: Optional["Type"], expression_return_type: Optional["Type"],
): ) -> None:
assert isinstance(left_expression, Expression) assert isinstance(left_expression, Expression)
assert isinstance(right_expression, Expression) assert isinstance(right_expression, Expression)
super().__init__() super().__init__()

@ -1,10 +1,10 @@
from typing import Optional, List from typing import Any, Optional, List
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
class CallExpression(Expression): # pylint: disable=too-many-instance-attributes class CallExpression(Expression): # pylint: disable=too-many-instance-attributes
def __init__(self, called, arguments, type_call): def __init__(self, called: Expression, arguments: List[Any], type_call: str) -> None:
assert isinstance(called, Expression) assert isinstance(called, Expression)
super().__init__() super().__init__()
self._called: Expression = called self._called: Expression = called
@ -53,7 +53,7 @@ class CallExpression(Expression): # pylint: disable=too-many-instance-attribute
def type_call(self) -> str: def type_call(self) -> str:
return self._type_call return self._type_call
def __str__(self): def __str__(self) -> str:
txt = str(self._called) txt = str(self._called)
if self.call_gas or self.call_value: if self.call_gas or self.call_value:
gas = f"gas: {self.call_gas}" if self.call_gas else "" gas = f"gas: {self.call_gas}" if self.call_gas else ""

@ -1,10 +1,17 @@
from typing import List from typing import Union, List
from .expression import Expression from .expression import Expression
from slither.core.expressions.binary_operation import BinaryOperation
from slither.core.expressions.expression import Expression
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.literal import Literal
from slither.core.expressions.tuple_expression import TupleExpression
from slither.core.expressions.type_conversion import TypeConversion
from slither.core.expressions.unary_operation import UnaryOperation
class ConditionalExpression(Expression): class ConditionalExpression(Expression):
def __init__(self, if_expression, then_expression, else_expression): def __init__(self, if_expression: Union[BinaryOperation, Identifier, Literal], then_expression: Union["ConditionalExpression", TypeConversion, Literal, TupleExpression, Identifier], else_expression: Union[TupleExpression, UnaryOperation, Identifier, Literal]) -> None:
assert isinstance(if_expression, Expression) assert isinstance(if_expression, Expression)
assert isinstance(then_expression, Expression) assert isinstance(then_expression, Expression)
assert isinstance(else_expression, Expression) assert isinstance(else_expression, Expression)

@ -3,10 +3,11 @@
""" """
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.solidity_types.elementary_type import ElementaryType
class ElementaryTypeNameExpression(Expression): class ElementaryTypeNameExpression(Expression):
def __init__(self, t): def __init__(self, t: ElementaryType) -> None:
assert isinstance(t, Type) assert isinstance(t, Type)
super().__init__() super().__init__()
self._type = t self._type = t
@ -20,5 +21,5 @@ class ElementaryTypeNameExpression(Expression):
assert isinstance(new_type, Type) assert isinstance(new_type, Type)
self._type = new_type self._type = new_type
def __str__(self): def __str__(self) -> str:
return str(self._type) return str(self._type)

@ -1,6 +1,8 @@
from typing import List, TYPE_CHECKING from typing import Union, List, TYPE_CHECKING
from slither.core.expressions.expression_typed import ExpressionTyped from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.literal import Literal
if TYPE_CHECKING: if TYPE_CHECKING:
@ -9,7 +11,7 @@ if TYPE_CHECKING:
class IndexAccess(ExpressionTyped): class IndexAccess(ExpressionTyped):
def __init__(self, left_expression, right_expression, index_type): def __init__(self, left_expression: Union["IndexAccess", Identifier], right_expression: Union[Literal, Identifier], index_type: str) -> None:
super().__init__() super().__init__()
self._expressions = [left_expression, right_expression] self._expressions = [left_expression, right_expression]
# TODO type of undexAccess is not always a Type # TODO type of undexAccess is not always a Type
@ -32,5 +34,5 @@ class IndexAccess(ExpressionTyped):
def type(self) -> "Type": def type(self) -> "Type":
return self._type return self._type
def __str__(self): def __str__(self) -> str:
return str(self.expression_left) + "[" + str(self.expression_right) + "]" return str(self.expression_left) + "[" + str(self.expression_right) + "]"

@ -12,7 +12,7 @@ if TYPE_CHECKING:
class Literal(Expression): class Literal(Expression):
def __init__( def __init__(
self, value: Union[int, str], custom_type: "Type", subdenomination: Optional[str] = None self, value: Union[int, str], custom_type: "Type", subdenomination: Optional[str] = None
): ) -> None:
super().__init__() super().__init__()
self._value = value self._value = value
self._type = custom_type self._type = custom_type

@ -5,7 +5,7 @@ from slither.core.solidity_types.type import Type
class MemberAccess(ExpressionTyped): class MemberAccess(ExpressionTyped):
def __init__(self, member_name, member_type, expression): def __init__(self, member_name: str, member_type: str, expression: Expression) -> None:
# assert isinstance(member_type, Type) # assert isinstance(member_type, Type)
# TODO member_type is not always a Type # TODO member_type is not always a Type
assert isinstance(expression, Expression) assert isinstance(expression, Expression)
@ -26,5 +26,5 @@ class MemberAccess(ExpressionTyped):
def type(self) -> Type: def type(self) -> Type:
return self._type return self._type
def __str__(self): def __str__(self) -> str:
return str(self.expression) + "." + self.member_name return str(self.expression) + "." + self.member_name

@ -1,11 +1,18 @@
from typing import Union, TYPE_CHECKING
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
class NewArray(Expression): class NewArray(Expression):
# note: dont conserve the size of the array if provided # note: dont conserve the size of the array if provided
def __init__(self, depth, array_type): def __init__(self, depth: int, array_type: Union["TypeAliasTopLevel", "ElementaryType"]) -> None:
super().__init__() super().__init__()
assert isinstance(array_type, Type) assert isinstance(array_type, Type)
self._depth: int = depth self._depth: int = depth

@ -2,7 +2,7 @@ from slither.core.expressions.expression import Expression
class NewContract(Expression): class NewContract(Expression):
def __init__(self, contract_name): def __init__(self, contract_name: str) -> None:
super().__init__() super().__init__()
self._contract_name: str = contract_name self._contract_name: str = contract_name
self._gas = None self._gas = None
@ -29,5 +29,5 @@ class NewContract(Expression):
def call_salt(self, salt): def call_salt(self, salt):
self._salt = salt self._salt = salt
def __str__(self): def __str__(self) -> str:
return "new " + str(self._contract_name) return "new " + str(self._contract_name)

@ -1,10 +1,20 @@
from typing import Union, TYPE_CHECKING
from slither.core.expressions.expression_typed import ExpressionTyped from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.expressions.call_expression import CallExpression
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.literal import Literal
from slither.core.expressions.member_access import MemberAccess
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasContract
from slither.core.solidity_types.user_defined_type import UserDefinedType
class TypeConversion(ExpressionTyped): class TypeConversion(ExpressionTyped):
def __init__(self, expression, expression_type): def __init__(self, expression: Union["MemberAccess", "Literal", "CallExpression", "TypeConversion", "Identifier"], expression_type: Union["ElementaryType", "UserDefinedType", "TypeAliasContract"]) -> None:
super().__init__() super().__init__()
assert isinstance(expression, Expression) assert isinstance(expression, Expression)
assert isinstance(expression_type, Type) assert isinstance(expression_type, Type)
@ -15,5 +25,5 @@ class TypeConversion(ExpressionTyped):
def expression(self) -> Expression: def expression(self) -> Expression:
return self._expression return self._expression
def __str__(self): def __str__(self) -> str:
return str(self.type) + "(" + str(self.expression) + ")" return str(self.type) + "(" + str(self.expression) + ")"

@ -4,6 +4,11 @@ from enum import Enum
from slither.core.expressions.expression_typed import ExpressionTyped from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.exceptions import SlitherCoreError from slither.core.exceptions import SlitherCoreError
from slither.core.expressions.identifier import Identifier
from slither.core.expressions.index_access import IndexAccess
from slither.core.expressions.literal import Literal
from slither.core.expressions.tuple_expression import TupleExpression
from typing import Union
logger = logging.getLogger("UnaryOperation") logger = logging.getLogger("UnaryOperation")
@ -20,7 +25,7 @@ class UnaryOperationType(Enum):
MINUS_PRE = 8 # for stuff like uint(-1) MINUS_PRE = 8 # for stuff like uint(-1)
@staticmethod @staticmethod
def get_type(operation_type, isprefix): def get_type(operation_type: str, isprefix: bool) -> "UnaryOperationType":
if isprefix: if isprefix:
if operation_type == "!": if operation_type == "!":
return UnaryOperationType.BANG return UnaryOperationType.BANG
@ -86,7 +91,7 @@ class UnaryOperationType(Enum):
class UnaryOperation(ExpressionTyped): class UnaryOperation(ExpressionTyped):
def __init__(self, expression, expression_type): def __init__(self, expression: Union[Literal, Identifier, IndexAccess, TupleExpression], expression_type: UnaryOperationType) -> None:
assert isinstance(expression, Expression) assert isinstance(expression, Expression)
super().__init__() super().__init__()
self._expression: Expression = expression self._expression: Expression = expression

@ -25,7 +25,7 @@ def _dict_contain(d1: Dict, d2: Dict) -> bool:
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
class FileScope: class FileScope:
def __init__(self, filename: Filename): def __init__(self, filename: Filename) -> None:
self.filename = filename self.filename = filename
self.accessible_scopes: List[FileScope] = [] self.accessible_scopes: List[FileScope] = []

@ -40,7 +40,7 @@ class SlitherCore(Context):
Slither static analyzer Slither static analyzer
""" """
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._filename: Optional[str] = None self._filename: Optional[str] = None

@ -1,13 +1,20 @@
from typing import Optional, Tuple from typing import Union, Optional, Tuple, Any, TYPE_CHECKING
from slither.core.expressions import Literal
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.visitors.expression.constants_folding import ConstantFolding from slither.visitors.expression.constants_folding import ConstantFolding
if TYPE_CHECKING:
from slither.core.expressions.literal import Literal
from slither.core.expressions.binary_operation import BinaryOperation
from slither.core.expressions.identifier import Identifier
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.function_type import FunctionType
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
class ArrayType(Type): class ArrayType(Type):
def __init__(self, t, length): def __init__(self, t: Union["TypeAliasTopLevel", "ArrayType", "FunctionType", "ElementaryType"], length: Optional[Union["Identifier", "Literal", "BinaryOperation"]]) -> None:
assert isinstance(t, Type) assert isinstance(t, Type)
if length: if length:
if isinstance(length, int): if isinstance(length, int):
@ -38,7 +45,7 @@ class ArrayType(Type):
return self._length return self._length
@property @property
def length_value(self) -> Optional[Literal]: def length_value(self) -> Optional["Literal"]:
return self._length_value return self._length_value
@property @property
@ -56,15 +63,15 @@ class ArrayType(Type):
return elem_size * int(str(self._length_value)), True return elem_size * int(str(self._length_value)), True
return 32, True return 32, True
def __str__(self): def __str__(self) -> str:
if self._length: if self._length:
return str(self._type) + f"[{str(self._length_value)}]" return str(self._type) + f"[{str(self._length_value)}]"
return str(self._type) + "[]" return str(self._type) + "[]"
def __eq__(self, other): def __eq__(self, other: Any) -> bool:
if not isinstance(other, ArrayType): if not isinstance(other, ArrayType):
return False return False
return self._type == other.type and self.length == other.length return self._type == other.type and self.length == other.length
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -216,13 +216,13 @@ class ElementaryType(Type):
return MaxValues[self.name] return MaxValues[self.name]
raise SlitherException(f"{self.name} does not have a max value") raise SlitherException(f"{self.name} does not have a max value")
def __str__(self): def __str__(self) -> str:
return self._type return self._type
def __eq__(self, other): def __eq__(self, other) -> bool:
if not isinstance(other, ElementaryType): if not isinstance(other, ElementaryType):
return False return False
return self.type == other.type return self.type == other.type
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -2,6 +2,7 @@ from typing import List, Tuple
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.variables.function_type_variable import FunctionTypeVariable from slither.core.variables.function_type_variable import FunctionTypeVariable
from slither.core.solidity_types.elementary_type import ElementaryType
class FunctionType(Type): class FunctionType(Type):
@ -9,7 +10,7 @@ class FunctionType(Type):
self, self,
params: List[FunctionTypeVariable], params: List[FunctionTypeVariable],
return_values: List[FunctionTypeVariable], return_values: List[FunctionTypeVariable],
): ) -> None:
assert all(isinstance(x, FunctionTypeVariable) for x in params) assert all(isinstance(x, FunctionTypeVariable) for x in params)
assert all(isinstance(x, FunctionTypeVariable) for x in return_values) assert all(isinstance(x, FunctionTypeVariable) for x in return_values)
super().__init__() super().__init__()
@ -68,7 +69,7 @@ class FunctionType(Type):
return f"({params}) returns({return_values})" return f"({params}) returns({return_values})"
return f"({params})" return f"({params})"
def __eq__(self, other): def __eq__(self, other: ElementaryType) -> bool:
if not isinstance(other, FunctionType): if not isinstance(other, FunctionType):
return False return False
return self.params == other.params and self.return_values == other.return_values return self.params == other.params and self.return_values == other.return_values

@ -1,10 +1,13 @@
from typing import Tuple from typing import Union, Tuple, TYPE_CHECKING
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
class MappingType(Type): class MappingType(Type):
def __init__(self, type_from, type_to): def __init__(self, type_from: "ElementaryType", type_to: Union["MappingType", "TypeAliasTopLevel", "ElementaryType"]) -> None:
assert isinstance(type_from, Type) assert isinstance(type_from, Type)
assert isinstance(type_to, Type) assert isinstance(type_to, Type)
super().__init__() super().__init__()
@ -27,7 +30,7 @@ class MappingType(Type):
def is_dynamic(self) -> bool: def is_dynamic(self) -> bool:
return True return True
def __str__(self): def __str__(self) -> str:
return f"mapping({str(self._from)} => {str(self._to)})" return f"mapping({str(self._from)} => {str(self._to)})"
def __eq__(self, other): def __eq__(self, other):
@ -35,5 +38,5 @@ class MappingType(Type):
return False return False
return self.type_from == other.type_from and self.type_to == other.type_to return self.type_from == other.type_from and self.type_to == other.type_to
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -10,7 +10,7 @@ if TYPE_CHECKING:
class TypeAlias(Type): class TypeAlias(Type):
def __init__(self, underlying_type: Type, name: str): def __init__(self, underlying_type: Type, name: str) -> None:
super().__init__() super().__init__()
self.name = name self.name = name
self.underlying_type = underlying_type self.underlying_type = underlying_type
@ -31,7 +31,7 @@ class TypeAlias(Type):
def storage_size(self) -> Tuple[int, bool]: def storage_size(self) -> Tuple[int, bool]:
return self.underlying_type.storage_size return self.underlying_type.storage_size
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))
@property @property
@ -40,18 +40,18 @@ class TypeAlias(Type):
class TypeAliasTopLevel(TypeAlias, TopLevel): class TypeAliasTopLevel(TypeAlias, TopLevel):
def __init__(self, underlying_type: Type, name: str, scope: "FileScope"): def __init__(self, underlying_type: Type, name: str, scope: "FileScope") -> None:
super().__init__(underlying_type, name) super().__init__(underlying_type, name)
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope
def __str__(self): def __str__(self) -> str:
return self.name return self.name
class TypeAliasContract(TypeAlias, ChildContract): class TypeAliasContract(TypeAlias, ChildContract):
def __init__(self, underlying_type: Type, name: str, contract: "Contract"): def __init__(self, underlying_type: Type, name: str, contract: "Contract") -> None:
super().__init__(underlying_type, name) super().__init__(underlying_type, name)
self._contract: "Contract" = contract self._contract: "Contract" = contract
def __str__(self): def __str__(self) -> str:
return self.contract.name + "." + self.name return self.contract.name + "." + self.name

@ -1,16 +1,17 @@
from typing import TYPE_CHECKING, Tuple from typing import Union, TYPE_CHECKING, Tuple
from slither.core.solidity_types import ElementaryType from slither.core.solidity_types import ElementaryType
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.enum_top_level import EnumTopLevel
# Use to model the Type(X) function, which returns an undefined type # 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 # https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
class TypeInformation(Type): class TypeInformation(Type):
def __init__(self, c): def __init__(self, c: Union[ElementaryType, "Contract", "EnumTopLevel"]) -> None:
# pylint: disable=import-outside-toplevel # pylint: disable=import-outside-toplevel
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.enum import Enum from slither.core.declarations.enum import Enum

@ -1,4 +1,4 @@
from typing import Union, TYPE_CHECKING, Tuple from typing import Union, TYPE_CHECKING, Tuple, Any
import math import math
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
@ -8,10 +8,12 @@ if TYPE_CHECKING:
from slither.core.declarations.structure import Structure from slither.core.declarations.structure import Structure
from slither.core.declarations.enum import Enum from slither.core.declarations.enum import Enum
from slither.core.declarations.contract import Contract 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 # pylint: disable=import-outside-toplevel
class UserDefinedType(Type): class UserDefinedType(Type):
def __init__(self, t): def __init__(self, t: Union["EnumContract", "StructureTopLevel", "Contract", "StructureContract"]) -> None:
from slither.core.declarations.structure import Structure from slither.core.declarations.structure import Structure
from slither.core.declarations.enum import Enum from slither.core.declarations.enum import Enum
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
@ -62,7 +64,7 @@ class UserDefinedType(Type):
to_log = f"{self} does not have storage size" to_log = f"{self} does not have storage size"
raise SlitherException(to_log) raise SlitherException(to_log)
def __str__(self): def __str__(self) -> str:
from slither.core.declarations.structure_contract import StructureContract from slither.core.declarations.structure_contract import StructureContract
from slither.core.declarations.enum_contract import EnumContract from slither.core.declarations.enum_contract import EnumContract
@ -71,10 +73,10 @@ class UserDefinedType(Type):
return str(type_used.contract) + "." + str(type_used.name) return str(type_used.contract) + "." + str(type_used.name)
return str(type_used.name) return str(type_used.name)
def __eq__(self, other): def __eq__(self, other: Any) -> bool:
if not isinstance(other, UserDefinedType): if not isinstance(other, UserDefinedType):
return False return False
return self.type == other.type return self.type == other.type
def __hash__(self): def __hash__(self) -> int:
return hash(str(self)) return hash(str(self))

@ -3,7 +3,7 @@ from slither.core.children.child_event import ChildEvent
class EventVariable(ChildEvent, Variable): class EventVariable(ChildEvent, Variable):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._indexed = False self._indexed = False

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class StateVariable(ChildContract, Variable): class StateVariable(ChildContract, Variable):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._node_initialization: Optional["Node"] = None self._node_initialization: Optional["Node"] = None

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class TopLevelVariable(TopLevel, Variable): class TopLevelVariable(TopLevel, Variable):
def __init__(self, scope: "FileScope"): def __init__(self, scope: "FileScope") -> None:
super().__init__() super().__init__()
self._node_initialization: Optional["Node"] = None self._node_initialization: Optional["Node"] = None
self.file_scope = scope self.file_scope = scope

@ -12,7 +12,7 @@ if TYPE_CHECKING:
# pylint: disable=too-many-instance-attributes # pylint: disable=too-many-instance-attributes
class Variable(SourceMapping): class Variable(SourceMapping):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._name: Optional[str] = None self._name: Optional[str] = None
self._initial_expression: Optional["Expression"] = None self._initial_expression: Optional["Expression"] = None

@ -31,6 +31,9 @@ from slither.slithir.operations import (
from slither.slithir.operations.binary import Binary from slither.slithir.operations.binary import Binary
from slither.slithir.variables import Constant from slither.slithir.variables import Constant
from slither.visitors.expression.constants_folding import ConstantFolding from slither.visitors.expression.constants_folding import ConstantFolding
import slither.core.declarations.function
import slither.slithir.operations.operation
from slither.utils.output import Output
def _get_name(f: Union[Function, Variable]) -> str: def _get_name(f: Union[Function, Variable]) -> str:
@ -168,7 +171,7 @@ def _extract_constants_from_irs( # pylint: disable=too-many-branches,too-many-n
all_cst_used: List[ConstantValue], all_cst_used: List[ConstantValue],
all_cst_used_in_binary: Dict[str, List[ConstantValue]], all_cst_used_in_binary: Dict[str, List[ConstantValue]],
context_explored: Set[Node], context_explored: Set[Node],
): ) -> None:
for ir in irs: for ir in irs:
if isinstance(ir, Binary): if isinstance(ir, Binary):
for r in ir.read: for r in ir.read:
@ -364,7 +367,7 @@ class Echidna(AbstractPrinter):
WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#echidna" WIKI = "https://github.com/trailofbits/slither/wiki/Printer-documentation#echidna"
def output(self, filename): # pylint: disable=too-many-locals def output(self, filename: str) -> Output: # pylint: disable=too-many-locals
""" """
Output the inheritance relation Output the inheritance relation

@ -12,6 +12,7 @@ from slither.exceptions import SlitherError
from slither.printers.abstract_printer import AbstractPrinter from slither.printers.abstract_printer import AbstractPrinter
from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc
from slither.utils.output import Output from slither.utils.output import Output
import crytic_compile.crytic_compile
logger = logging.getLogger("Slither") logger = logging.getLogger("Slither")
logging.basicConfig() logging.basicConfig()
@ -49,7 +50,7 @@ def _update_file_scopes(candidates: ValuesView[FileScope]):
class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes class Slither(SlitherCore): # pylint: disable=too-many-instance-attributes
def __init__(self, target: Union[str, CryticCompile], **kwargs): def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None:
""" """
Args: Args:
target (str | CryticCompile) target (str | CryticCompile)

@ -1,6 +1,6 @@
import logging import logging
from pathlib import Path from pathlib import Path
from typing import List, TYPE_CHECKING, Union, Optional from typing import Any, List, TYPE_CHECKING, Union, Optional
# pylint: disable= too-many-lines,import-outside-toplevel,too-many-branches,too-many-statements,too-many-nested-blocks # pylint: disable= too-many-lines,import-outside-toplevel,too-many-branches,too-many-statements,too-many-nested-blocks
from slither.core.declarations import ( from slither.core.declarations import (
@ -34,7 +34,7 @@ from slither.core.solidity_types.elementary_type import (
MaxValues, MaxValues,
) )
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.solidity_types.type_alias import TypeAlias from slither.core.solidity_types.type_alias import TypeAliasTopLevel, TypeAlias
from slither.core.variables.function_type_variable import FunctionTypeVariable from slither.core.variables.function_type_variable import FunctionTypeVariable
from slither.core.variables.state_variable import StateVariable from slither.core.variables.state_variable import StateVariable
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
@ -83,6 +83,28 @@ from slither.slithir.variables import TupleVariable
from slither.utils.function import get_function_id from slither.utils.function import get_function_id
from slither.utils.type import export_nested_types_from_variable from slither.utils.type import export_nested_types_from_variable
from slither.visitors.slithir.expression_to_slithir import ExpressionToSlithIR from slither.visitors.slithir.expression_to_slithir import ExpressionToSlithIR
import slither.core.declarations.contract
import slither.core.declarations.function
import slither.core.solidity_types.elementary_type
import slither.core.solidity_types.function_type
import slither.core.solidity_types.user_defined_type
import slither.slithir.operations.assignment
import slither.slithir.operations.binary
import slither.slithir.operations.call
import slither.slithir.operations.high_level_call
import slither.slithir.operations.index
import slither.slithir.operations.init_array
import slither.slithir.operations.internal_call
import slither.slithir.operations.length
import slither.slithir.operations.library_call
import slither.slithir.operations.low_level_call
import slither.slithir.operations.member
import slither.slithir.operations.operation
import slither.slithir.operations.send
import slither.slithir.operations.solidity_call
import slither.slithir.operations.transfer
import slither.slithir.variables.temporary
from slither.core.expressions.expression import Expression
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
@ -91,7 +113,7 @@ if TYPE_CHECKING:
logger = logging.getLogger("ConvertToIR") logger = logging.getLogger("ConvertToIR")
def convert_expression(expression, node): def convert_expression(expression: Expression, node: "Node") -> List[Any]:
# handle standlone expression # handle standlone expression
# such as return true; # such as return true;
from slither.core.cfg.node import NodeType from slither.core.cfg.node import NodeType
@ -143,7 +165,7 @@ def convert_expression(expression, node):
################################################################################### ###################################################################################
def is_value(ins): def is_value(ins: slither.slithir.operations.operation.Operation) -> bool:
if isinstance(ins, TmpCall): if isinstance(ins, TmpCall):
if isinstance(ins.ori, Member): if isinstance(ins.ori, Member):
if ins.ori.variable_right == "value": if ins.ori.variable_right == "value":
@ -151,7 +173,7 @@ def is_value(ins):
return False return False
def is_gas(ins): def is_gas(ins: slither.slithir.operations.operation.Operation) -> bool:
if isinstance(ins, TmpCall): if isinstance(ins, TmpCall):
if isinstance(ins.ori, Member): if isinstance(ins.ori, Member):
if ins.ori.variable_right == "gas": if ins.ori.variable_right == "gas":
@ -159,7 +181,7 @@ def is_gas(ins):
return False return False
def _fits_under_integer(val: int, can_be_int: bool, can_be_uint) -> List[str]: def _fits_under_integer(val: int, can_be_int: bool, can_be_uint: bool) -> List[str]:
""" """
Return the list of uint/int that can contain val Return the list of uint/int that can contain val
@ -271,7 +293,7 @@ def _find_function_from_parameter(
return None return None
def is_temporary(ins): def is_temporary(ins: slither.slithir.operations.operation.Operation) -> bool:
return isinstance( return isinstance(
ins, ins,
(Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure), (Argument, TmpNewElementaryType, TmpNewContract, TmpNewArray, TmpNewStructure),
@ -300,7 +322,7 @@ def _make_function_type(func: Function) -> FunctionType:
################################################################################### ###################################################################################
def integrate_value_gas(result): def integrate_value_gas(result: List[Any]) -> List[Any]:
""" """
Integrate value and gas temporary arguments to call instruction Integrate value and gas temporary arguments to call instruction
""" """
@ -504,7 +526,7 @@ def _convert_type_contract(ir: Member) -> Assignment:
raise SlithIRError(f"type({contract.name}).{ir.variable_right} is unknown") raise SlithIRError(f"type({contract.name}).{ir.variable_right} is unknown")
def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals def propagate_types(ir: slither.slithir.operations.operation.Operation, node: "Node"): # pylint: disable=too-many-locals
# propagate the type # propagate the type
node_function = node.function node_function = node.function
using_for = ( using_for = (
@ -813,7 +835,7 @@ def propagate_types(ir, node: "Node"): # pylint: disable=too-many-locals
return None return None
def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]): # pylint: disable=too-many-locals def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> slither.slithir.operations.call.Call: # pylint: disable=too-many-locals
assert isinstance(ins, TmpCall) assert isinstance(ins, TmpCall)
if isinstance(ins.called, Variable) and isinstance(ins.called.type, FunctionType): if isinstance(ins.called, Variable) and isinstance(ins.called.type, FunctionType):
# If the call is made to a variable member, where the member is this # If the call is made to a variable member, where the member is this
@ -1114,7 +1136,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]): # pylint: dis
################################################################################### ###################################################################################
def can_be_low_level(ir): def can_be_low_level(ir: slither.slithir.operations.high_level_call.HighLevelCall) -> bool:
return ir.function_name in [ return ir.function_name in [
"transfer", "transfer",
"send", "send",
@ -1125,7 +1147,7 @@ def can_be_low_level(ir):
] ]
def convert_to_low_level(ir): def convert_to_low_level(ir: slither.slithir.operations.high_level_call.HighLevelCall) -> Union[slither.slithir.operations.send.Send, slither.slithir.operations.low_level_call.LowLevelCall, slither.slithir.operations.transfer.Transfer]:
""" """
Convert to a transfer/send/or low level call Convert to a transfer/send/or low level call
The funciton assume to receive a correct IR The funciton assume to receive a correct IR
@ -1165,7 +1187,7 @@ def convert_to_low_level(ir):
raise SlithIRError(f"Incorrect conversion to low level {ir}") raise SlithIRError(f"Incorrect conversion to low level {ir}")
def can_be_solidity_func(ir) -> bool: def can_be_solidity_func(ir: slither.slithir.operations.high_level_call.HighLevelCall) -> bool:
if not isinstance(ir, HighLevelCall): if not isinstance(ir, HighLevelCall):
return False return False
return ir.destination.name == "abi" and ir.function_name in [ return ir.destination.name == "abi" and ir.function_name in [
@ -1178,7 +1200,7 @@ def can_be_solidity_func(ir) -> bool:
] ]
def convert_to_solidity_func(ir): def convert_to_solidity_func(ir: slither.slithir.operations.high_level_call.HighLevelCall) -> slither.slithir.operations.solidity_call.SolidityCall:
""" """
Must be called after can_be_solidity_func Must be called after can_be_solidity_func
:param ir: :param ir:
@ -1214,7 +1236,7 @@ def convert_to_solidity_func(ir):
return new_ir return new_ir
def convert_to_push_expand_arr(ir, node, ret): def convert_to_push_expand_arr(ir: slither.slithir.operations.high_level_call.HighLevelCall, node: "Node", ret: List[Any]) -> slither.slithir.variables.temporary.TemporaryVariable:
arr = ir.destination arr = ir.destination
length = ReferenceVariable(node) length = ReferenceVariable(node)
@ -1249,7 +1271,7 @@ def convert_to_push_expand_arr(ir, node, ret):
return length_val return length_val
def convert_to_push_set_val(ir, node, length_val, ret): def convert_to_push_set_val(ir: slither.slithir.operations.high_level_call.HighLevelCall, node: "Node", length_val: slither.slithir.variables.temporary.TemporaryVariable, ret: List[Union[slither.slithir.operations.length.Length, slither.slithir.operations.assignment.Assignment, slither.slithir.operations.binary.Binary]]) -> None:
arr = ir.destination arr = ir.destination
new_type = ir.destination.type.type new_type = ir.destination.type.type
@ -1284,7 +1306,7 @@ def convert_to_push_set_val(ir, node, length_val, ret):
ret.append(ir_assign_value) ret.append(ir_assign_value)
def convert_to_push(ir, node): def convert_to_push(ir: slither.slithir.operations.high_level_call.HighLevelCall, node: "Node") -> List[Union[slither.slithir.operations.length.Length, slither.slithir.operations.assignment.Assignment, slither.slithir.operations.binary.Binary, slither.slithir.operations.index.Index, slither.slithir.operations.init_array.InitArray]]:
""" """
Convert a call to a series of operations to push a new value onto the array Convert a call to a series of operations to push a new value onto the array
@ -1358,7 +1380,7 @@ def convert_to_pop(ir, node):
return ret return ret
def look_for_library_or_top_level(contract, ir, using_for, t): def look_for_library_or_top_level(contract: slither.core.declarations.contract.Contract, ir: slither.slithir.operations.high_level_call.HighLevelCall, using_for, t: Union[slither.core.solidity_types.user_defined_type.UserDefinedType, slither.core.solidity_types.elementary_type.ElementaryType, str, TypeAliasTopLevel]) -> Optional[Union[slither.slithir.operations.library_call.LibraryCall, slither.slithir.operations.internal_call.InternalCall]]:
for destination in using_for[t]: for destination in using_for[t]:
if isinstance(destination, FunctionTopLevel) and destination.name == ir.function_name: if isinstance(destination, FunctionTopLevel) and destination.name == ir.function_name:
arguments = [ir.destination] + ir.arguments arguments = [ir.destination] + ir.arguments
@ -1403,7 +1425,7 @@ def look_for_library_or_top_level(contract, ir, using_for, t):
return None return None
def convert_to_library_or_top_level(ir, node, using_for): def convert_to_library_or_top_level(ir: slither.slithir.operations.high_level_call.HighLevelCall, node: "Node", using_for) -> Optional[Union[slither.slithir.operations.library_call.LibraryCall, slither.slithir.operations.internal_call.InternalCall]]:
# We use contract_declarer, because Solidity resolve the library # We use contract_declarer, because Solidity resolve the library
# before resolving the inheritance. # before resolving the inheritance.
# Though we could use .contract as libraries cannot be shadowed # Though we could use .contract as libraries cannot be shadowed
@ -1422,7 +1444,7 @@ def convert_to_library_or_top_level(ir, node, using_for):
return None return None
def get_type(t): def get_type(t: Union[slither.core.solidity_types.user_defined_type.UserDefinedType, slither.core.solidity_types.elementary_type.ElementaryType]) -> str:
""" """
Convert a type to a str Convert a type to a str
If the instance is a Contract, return 'address' instead If the instance is a Contract, return 'address' instead
@ -1441,7 +1463,7 @@ def _can_be_implicitly_converted(source: str, target: str) -> bool:
return source == target return source == target
def convert_type_library_call(ir: HighLevelCall, lib_contract: Contract): def convert_type_library_call(ir: HighLevelCall, lib_contract: Contract) -> Optional[slither.slithir.operations.library_call.LibraryCall]:
func = None func = None
candidates = [ candidates = [
f f
@ -1652,7 +1674,7 @@ def convert_type_of_high_and_internal_level_call(
################################################################################### ###################################################################################
def find_references_origin(irs): def find_references_origin(irs: List[Any]) -> None:
""" """
Make lvalue of each Index, Member operation Make lvalue of each Index, Member operation
points to the left variable points to the left variable
@ -1689,7 +1711,7 @@ def remove_temporary(result):
return result return result
def remove_unused(result): def remove_unused(result: List[Any]) -> List[Any]:
removed = True removed = True
if not result: if not result:
@ -1736,7 +1758,7 @@ def remove_unused(result):
################################################################################### ###################################################################################
def convert_constant_types(irs): def convert_constant_types(irs: List[Any]) -> None:
""" """
late conversion of uint -> type for constant (Literal) late conversion of uint -> type for constant (Literal)
:param irs: :param irs:
@ -1812,7 +1834,7 @@ def convert_constant_types(irs):
################################################################################### ###################################################################################
def convert_delete(irs): def convert_delete(irs: List[Any]) -> None:
""" """
Convert the lvalue of the Delete to point to the variable removed Convert the lvalue of the Delete to point to the variable removed
This can only be done after find_references_origin is called This can only be done after find_references_origin is called
@ -1833,7 +1855,7 @@ def convert_delete(irs):
################################################################################### ###################################################################################
def _find_source_mapping_references(irs: List[Operation]): def _find_source_mapping_references(irs: List[Operation]) -> None:
for ir in irs: for ir in irs:
if isinstance(ir, NewContract): if isinstance(ir, NewContract):
@ -1848,7 +1870,7 @@ def _find_source_mapping_references(irs: List[Operation]):
################################################################################### ###################################################################################
def apply_ir_heuristics(irs: List[Operation], node: "Node"): def apply_ir_heuristics(irs: List[Operation], node: "Node") -> List[Any]:
""" """
Apply a set of heuristic to improve slithIR Apply a set of heuristic to improve slithIR
""" """

@ -4,12 +4,15 @@ from slither.core.declarations.function import Function
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.variables import TupleVariable, ReferenceVariable from slither.slithir.variables import TupleVariable, ReferenceVariable
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.variable import Variable
from typing import List
logger = logging.getLogger("AssignmentOperationIR") logger = logging.getLogger("AssignmentOperationIR")
class Assignment(OperationWithLValue): class Assignment(OperationWithLValue):
def __init__(self, left_variable, right_variable, variable_return_type): def __init__(self, left_variable: Variable, right_variable: SourceMapping, variable_return_type) -> None:
assert is_valid_lvalue(left_variable) assert is_valid_lvalue(left_variable)
assert is_valid_rvalue(right_variable) or isinstance( assert is_valid_rvalue(right_variable) or isinstance(
right_variable, (Function, TupleVariable) right_variable, (Function, TupleVariable)
@ -25,7 +28,7 @@ class Assignment(OperationWithLValue):
return list(self._variables) return list(self._variables)
@property @property
def read(self): def read(self) -> List[SourceMapping]:
return [self.rvalue] return [self.rvalue]
@property @property
@ -33,7 +36,7 @@ class Assignment(OperationWithLValue):
return self._variable_return_type return self._variable_return_type
@property @property
def rvalue(self): def rvalue(self) -> SourceMapping:
return self._rvalue return self._rvalue
def __str__(self): def __str__(self):

@ -7,6 +7,9 @@ from slither.slithir.exceptions import SlithIRError
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.variables import ReferenceVariable from slither.slithir.variables import ReferenceVariable
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.variable import Variable
from typing import List
logger = logging.getLogger("BinaryOperationIR") logger = logging.getLogger("BinaryOperationIR")
@ -33,7 +36,7 @@ class BinaryType(Enum):
OROR = 18 # || OROR = 18 # ||
@staticmethod @staticmethod
def return_bool(operation_type): def return_bool(operation_type: "BinaryType") -> bool:
return operation_type in [ return operation_type in [
BinaryType.OROR, BinaryType.OROR,
BinaryType.ANDAND, BinaryType.ANDAND,
@ -98,7 +101,7 @@ class BinaryType(Enum):
BinaryType.DIVISION, BinaryType.DIVISION,
] ]
def __str__(self): # pylint: disable=too-many-branches def __str__(self) -> str: # pylint: disable=too-many-branches
if self == BinaryType.POWER: if self == BinaryType.POWER:
return "**" return "**"
if self == BinaryType.MULTIPLICATION: if self == BinaryType.MULTIPLICATION:
@ -141,7 +144,7 @@ class BinaryType(Enum):
class Binary(OperationWithLValue): class Binary(OperationWithLValue):
def __init__(self, result, left_variable, right_variable, operation_type: BinaryType): def __init__(self, result: Variable, left_variable: SourceMapping, right_variable: Variable, operation_type: BinaryType) -> None:
assert is_valid_rvalue(left_variable) or isinstance(left_variable, Function) assert is_valid_rvalue(left_variable) or isinstance(left_variable, Function)
assert is_valid_rvalue(right_variable) or isinstance(right_variable, Function) assert is_valid_rvalue(right_variable) or isinstance(right_variable, Function)
assert is_valid_lvalue(result) assert is_valid_lvalue(result)
@ -156,7 +159,7 @@ class Binary(OperationWithLValue):
result.set_type(left_variable.type) result.set_type(left_variable.type)
@property @property
def read(self): def read(self) -> List[SourceMapping]:
return [self.variable_left, self.variable_right] return [self.variable_left, self.variable_right]
@property @property
@ -164,15 +167,15 @@ class Binary(OperationWithLValue):
return self._variables return self._variables
@property @property
def variable_left(self): def variable_left(self) -> SourceMapping:
return self._variables[0] return self._variables[0]
@property @property
def variable_right(self): def variable_right(self) -> Variable:
return self._variables[1] return self._variables[1]
@property @property
def type(self): def type(self) -> BinaryType:
return self._type return self._type
@property @property

@ -1,6 +1,12 @@
from slither.slithir.operations.operation import Operation from slither.slithir.operations.operation import Operation
from slither.slithir.utils.utils import is_valid_rvalue from slither.slithir.utils.utils import is_valid_rvalue
from slither.core.variables.local_variable import LocalVariable
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import List, Union
class Condition(Operation): class Condition(Operation):
@ -9,13 +15,13 @@ class Condition(Operation):
Only present as last operation in conditional node Only present as last operation in conditional node
""" """
def __init__(self, value): def __init__(self, value: Union[LocalVariable, TemporaryVariableSSA, TemporaryVariable, Constant, LocalIRVariable]) -> None:
assert is_valid_rvalue(value) assert is_valid_rvalue(value)
super().__init__() super().__init__()
self._value = value self._value = value
@property @property
def read(self): def read(self) -> List[Union[LocalIRVariable, Constant, LocalVariable, TemporaryVariableSSA, TemporaryVariable]]:
return [self.value] return [self.value]
@property @property

@ -1,6 +1,11 @@
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
from slither.core.variables.state_variable import StateVariable
from slither.slithir.variables.reference import ReferenceVariable
from slither.slithir.variables.reference_ssa import ReferenceVariableSSA
from slither.slithir.variables.state_variable import StateIRVariable
from typing import List, Union
class Delete(OperationWithLValue): class Delete(OperationWithLValue):
@ -9,18 +14,18 @@ class Delete(OperationWithLValue):
of its operand of its operand
""" """
def __init__(self, lvalue, variable): def __init__(self, lvalue: Union[StateIRVariable, StateVariable, ReferenceVariable], variable: Union[StateIRVariable, StateVariable, ReferenceVariable, ReferenceVariableSSA]) -> None:
assert is_valid_lvalue(variable) assert is_valid_lvalue(variable)
super().__init__() super().__init__()
self._variable = variable self._variable = variable
self._lvalue = lvalue self._lvalue = lvalue
@property @property
def read(self): def read(self) -> List[Union[StateIRVariable, ReferenceVariable, ReferenceVariableSSA, StateVariable]]:
return [self.variable] return [self.variable]
@property @property
def variable(self): def variable(self) -> Union[StateIRVariable, StateVariable, ReferenceVariable, ReferenceVariableSSA]:
return self._variable return self._variable
def __str__(self): def __str__(self):

@ -1,18 +1,20 @@
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.slithir.variables.constant import Constant
from typing import Any, List, Union
class EventCall(Call): class EventCall(Call):
def __init__(self, name): def __init__(self, name: Union[str, Constant]) -> None:
super().__init__() super().__init__()
self._name = name self._name = name
# todo add instance of the Event # todo add instance of the Event
@property @property
def name(self): def name(self) -> Union[str, Constant]:
return self._name return self._name
@property @property
def read(self): def read(self) -> List[Any]:
return self._unroll(self.arguments) return self._unroll(self.arguments)
def __str__(self): def __str__(self):

@ -1,4 +1,4 @@
from typing import Union from typing import List, Optional, Union
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
@ -8,6 +8,10 @@ from slither.core.declarations.function import Function
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
from slither.slithir.variables.constant import Constant from slither.slithir.variables.constant import Constant
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from slither.slithir.variables.tuple import TupleVariable
class HighLevelCall(Call, OperationWithLValue): class HighLevelCall(Call, OperationWithLValue):
@ -16,7 +20,7 @@ class HighLevelCall(Call, OperationWithLValue):
""" """
# pylint: disable=too-many-arguments,too-many-instance-attributes # pylint: disable=too-many-arguments,too-many-instance-attributes
def __init__(self, destination, function_name, nbr_arguments, result, type_call): def __init__(self, destination: SourceMapping, function_name: Constant, nbr_arguments: int, result: Optional[Union[TemporaryVariable, TupleVariable, TemporaryVariableSSA]], type_call: str) -> None:
assert isinstance(function_name, Constant) assert isinstance(function_name, Constant)
assert is_valid_lvalue(result) or result is None assert is_valid_lvalue(result) or result is None
self._check_destination(destination) self._check_destination(destination)
@ -34,7 +38,7 @@ class HighLevelCall(Call, OperationWithLValue):
# Development function, to be removed once the code is stable # Development function, to be removed once the code is stable
# It is ovveride by LbraryCall # It is ovveride by LbraryCall
def _check_destination(self, destination): # pylint: disable=no-self-use def _check_destination(self, destination: SourceMapping) -> None: # pylint: disable=no-self-use
assert isinstance(destination, (Variable, SolidityVariable)) assert isinstance(destination, (Variable, SolidityVariable))
@property @property
@ -62,17 +66,17 @@ class HighLevelCall(Call, OperationWithLValue):
self._call_gas = v self._call_gas = v
@property @property
def read(self): def read(self) -> List[SourceMapping]:
all_read = [self.destination, self.call_gas, self.call_value] + self._unroll(self.arguments) all_read = [self.destination, self.call_gas, self.call_value] + self._unroll(self.arguments)
# remove None # remove None
return [x for x in all_read if x] + [self.destination] return [x for x in all_read if x] + [self.destination]
@property @property
def destination(self): def destination(self) -> SourceMapping:
return self._destination return self._destination
@property @property
def function_name(self): def function_name(self) -> Constant:
return self._function_name return self._function_name
@property @property
@ -84,11 +88,11 @@ class HighLevelCall(Call, OperationWithLValue):
self._function_instance = function self._function_instance = function
@property @property
def nbr_arguments(self): def nbr_arguments(self) -> int:
return self._nbr_arguments return self._nbr_arguments
@property @property
def type_call(self): def type_call(self) -> str:
return self._type_call return self._type_call
################################################################################### ###################################################################################

@ -2,10 +2,15 @@ from slither.core.declarations import SolidityVariableComposed
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.variables.reference import ReferenceVariable from slither.slithir.variables.reference import ReferenceVariable
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.variable import Variable
from slither.slithir.variables.reference_ssa import ReferenceVariableSSA
from typing import List, Union
class Index(OperationWithLValue): class Index(OperationWithLValue):
def __init__(self, result, left_variable, right_variable, index_type): def __init__(self, result: Union[ReferenceVariable, ReferenceVariableSSA], left_variable: Variable, right_variable: SourceMapping, index_type: Union[ElementaryType, str]) -> None:
super().__init__() super().__init__()
assert is_valid_lvalue(left_variable) or left_variable == SolidityVariableComposed( assert is_valid_lvalue(left_variable) or left_variable == SolidityVariableComposed(
"msg.data" "msg.data"
@ -17,23 +22,23 @@ class Index(OperationWithLValue):
self._lvalue = result self._lvalue = result
@property @property
def read(self): def read(self) -> List[SourceMapping]:
return list(self.variables) return list(self.variables)
@property @property
def variables(self): def variables(self) -> List[SourceMapping]:
return self._variables return self._variables
@property @property
def variable_left(self): def variable_left(self) -> Variable:
return self._variables[0] return self._variables[0]
@property @property
def variable_right(self): def variable_right(self) -> SourceMapping:
return self._variables[1] return self._variables[1]
@property @property
def index_type(self): def index_type(self) -> Union[ElementaryType, str]:
return self._type return self._type
def __str__(self): def __str__(self):

@ -1,9 +1,13 @@
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_rvalue from slither.slithir.utils.utils import is_valid_rvalue
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import List, Union
class InitArray(OperationWithLValue): class InitArray(OperationWithLValue):
def __init__(self, init_values, lvalue): def __init__(self, init_values: List[Constant], lvalue: Union[TemporaryVariableSSA, TemporaryVariable]) -> None:
# init_values can be an array of n dimension # init_values can be an array of n dimension
# reduce was removed in py3 # reduce was removed in py3
super().__init__() super().__init__()
@ -24,11 +28,11 @@ class InitArray(OperationWithLValue):
self._lvalue = lvalue self._lvalue = lvalue
@property @property
def read(self): def read(self) -> List[Constant]:
return self._unroll(self.init_values) return self._unroll(self.init_values)
@property @property
def init_values(self): def init_values(self) -> List[Constant]:
return list(self._init_values) return list(self._init_values)
def __str__(self): def __str__(self):

@ -1,15 +1,20 @@
from typing import Union, Tuple, List, Optional from typing import Any, Union, Tuple, List, Optional
from slither.core.declarations import Modifier from slither.core.declarations import Modifier
from slither.core.declarations.function import Function from slither.core.declarations.function import Function
from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.function_contract import FunctionContract
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from slither.slithir.variables.tuple import TupleVariable
from slither.slithir.variables.tuple_ssa import TupleVariableSSA
class InternalCall(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes class InternalCall(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes
def __init__( def __init__(
self, function: Union[Function, Tuple[str, str]], nbr_arguments, result, type_call self, function: Union[Function, Tuple[str, str]], nbr_arguments: int, result: Optional[Union[TupleVariableSSA, TemporaryVariableSSA, TupleVariable, TemporaryVariable]], type_call: str
): ) -> None:
super().__init__() super().__init__()
self._contract_name = "" self._contract_name = ""
if isinstance(function, Function): if isinstance(function, Function):
@ -30,7 +35,7 @@ class InternalCall(Call, OperationWithLValue): # pylint: disable=too-many-insta
self.function_candidates: Optional[List[Function]] = None self.function_candidates: Optional[List[Function]] = None
@property @property
def read(self): def read(self) -> List[Any]:
return list(self._unroll(self.arguments)) return list(self._unroll(self.arguments))
@property @property
@ -42,19 +47,19 @@ class InternalCall(Call, OperationWithLValue): # pylint: disable=too-many-insta
self._function = f self._function = f
@property @property
def function_name(self): def function_name(self) -> Constant:
return self._function_name return self._function_name
@property @property
def contract_name(self): def contract_name(self) -> str:
return self._contract_name return self._contract_name
@property @property
def nbr_arguments(self): def nbr_arguments(self) -> int:
return self._nbr_arguments return self._nbr_arguments
@property @property
def type_call(self): def type_call(self) -> str:
return self._type_call return self._type_call
@property @property

@ -3,12 +3,19 @@ from slither.core.variables.variable import Variable
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
import slither.core.solidity_types.function_type
from slither.core.variables.local_variable import LocalVariable
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import List, Optional, Union
class InternalDynamicCall( class InternalDynamicCall(
Call, OperationWithLValue Call, OperationWithLValue
): # pylint: disable=too-many-instance-attributes ): # pylint: disable=too-many-instance-attributes
def __init__(self, lvalue, function, function_type): def __init__(self, lvalue: Optional[Union[TemporaryVariableSSA, TemporaryVariable]], function: Union[LocalVariable, LocalIRVariable], function_type: slither.core.solidity_types.function_type.FunctionType) -> None:
assert isinstance(function_type, FunctionType) assert isinstance(function_type, FunctionType)
assert isinstance(function, Variable) assert isinstance(function, Variable)
assert is_valid_lvalue(lvalue) or lvalue is None assert is_valid_lvalue(lvalue) or lvalue is None
@ -22,15 +29,15 @@ class InternalDynamicCall(
self._call_gas = None self._call_gas = None
@property @property
def read(self): def read(self) -> List[Union[Constant, LocalIRVariable, LocalVariable]]:
return self._unroll(self.arguments) + [self.function] return self._unroll(self.arguments) + [self.function]
@property @property
def function(self): def function(self) -> Union[LocalVariable, LocalIRVariable]:
return self._function return self._function
@property @property
def function_type(self): def function_type(self) -> slither.core.solidity_types.function_type.FunctionType:
return self._function_type return self._function_type
@property @property

@ -1,10 +1,17 @@
from slither.core.solidity_types import ElementaryType from slither.core.solidity_types import ElementaryType
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.reference import ReferenceVariable
from slither.slithir.variables.reference_ssa import ReferenceVariableSSA
from slither.slithir.variables.state_variable import StateIRVariable
from typing import List, Union
class Length(OperationWithLValue): class Length(OperationWithLValue):
def __init__(self, value, lvalue): def __init__(self, value: Union[StateVariable, LocalIRVariable, LocalVariable, StateIRVariable], lvalue: Union[ReferenceVariable, ReferenceVariableSSA]) -> None:
super().__init__() super().__init__()
assert is_valid_rvalue(value) assert is_valid_rvalue(value)
assert is_valid_lvalue(lvalue) assert is_valid_lvalue(lvalue)
@ -13,11 +20,11 @@ class Length(OperationWithLValue):
lvalue.set_type(ElementaryType("uint256")) lvalue.set_type(ElementaryType("uint256"))
@property @property
def read(self): def read(self) -> List[Union[LocalVariable, StateVariable, LocalIRVariable, StateIRVariable]]:
return [self._value] return [self._value]
@property @property
def value(self): def value(self) -> Union[StateVariable, LocalVariable]:
return self._value return self._value
def __str__(self): def __str__(self):

@ -9,7 +9,7 @@ class LibraryCall(HighLevelCall):
""" """
# Development function, to be removed once the code is stable # Development function, to be removed once the code is stable
def _check_destination(self, destination): def _check_destination(self, destination: Contract) -> None:
assert isinstance(destination, Contract) assert isinstance(destination, Contract)
def can_reenter(self, callstack=None): def can_reenter(self, callstack=None):

@ -4,6 +4,13 @@ from slither.core.variables.variable import Variable
from slither.core.declarations.solidity_variables import SolidityVariable from slither.core.declarations.solidity_variables import SolidityVariable
from slither.slithir.variables.constant import Constant from slither.slithir.variables.constant import Constant
from slither.core.variables.local_variable import LocalVariable
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from slither.slithir.variables.tuple import TupleVariable
from slither.slithir.variables.tuple_ssa import TupleVariableSSA
from typing import List, Union
class LowLevelCall(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes class LowLevelCall(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes
@ -11,7 +18,7 @@ class LowLevelCall(Call, OperationWithLValue): # pylint: disable=too-many-insta
High level message call High level message call
""" """
def __init__(self, destination, function_name, nbr_arguments, result, type_call): def __init__(self, destination: Union[LocalVariable, LocalIRVariable, TemporaryVariableSSA, TemporaryVariable], function_name: Constant, nbr_arguments: int, result: Union[TupleVariable, TupleVariableSSA], type_call: str) -> None:
# pylint: disable=too-many-arguments # pylint: disable=too-many-arguments
assert isinstance(destination, (Variable, SolidityVariable)) assert isinstance(destination, (Variable, SolidityVariable))
assert isinstance(function_name, Constant) assert isinstance(function_name, Constant)
@ -51,7 +58,7 @@ class LowLevelCall(Call, OperationWithLValue): # pylint: disable=too-many-insta
self._call_gas = v self._call_gas = v
@property @property
def read(self): def read(self) -> List[Union[LocalIRVariable, Constant, LocalVariable, TemporaryVariableSSA, TemporaryVariable]]:
all_read = [self.destination, self.call_gas, self.call_value] + self.arguments all_read = [self.destination, self.call_gas, self.call_value] + self.arguments
# remove None # remove None
return self._unroll([x for x in all_read if x]) return self._unroll([x for x in all_read if x])
@ -73,19 +80,19 @@ class LowLevelCall(Call, OperationWithLValue): # pylint: disable=too-many-insta
return self._call_value is not None return self._call_value is not None
@property @property
def destination(self): def destination(self) -> Union[LocalVariable, LocalIRVariable, TemporaryVariableSSA, TemporaryVariable]:
return self._destination return self._destination
@property @property
def function_name(self): def function_name(self) -> Constant:
return self._function_name return self._function_name
@property @property
def nbr_arguments(self): def nbr_arguments(self) -> int:
return self._nbr_arguments return self._nbr_arguments
@property @property
def type_call(self): def type_call(self) -> str:
return self._type_call return self._type_call
def __str__(self): def __str__(self):

@ -6,7 +6,7 @@ class OperationWithLValue(Operation):
Operation with a lvalue Operation with a lvalue
""" """
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._lvalue = None self._lvalue = None

@ -7,10 +7,13 @@ from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_rvalue from slither.slithir.utils.utils import is_valid_rvalue
from slither.slithir.variables.constant import Constant from slither.slithir.variables.constant import Constant
from slither.slithir.variables.reference import ReferenceVariable from slither.slithir.variables.reference import ReferenceVariable
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.slithir.variables.reference_ssa import ReferenceVariableSSA
from typing import List, Union
class Member(OperationWithLValue): class Member(OperationWithLValue):
def __init__(self, variable_left, variable_right, result): def __init__(self, variable_left: SourceMapping, variable_right: Constant, result: Union[ReferenceVariable, ReferenceVariableSSA]) -> None:
# Function can happen for something like # Function can happen for something like
# library FunctionExtensions { # library FunctionExtensions {
# function h(function() internal _t, uint8) internal { } # function h(function() internal _t, uint8) internal { }
@ -38,15 +41,15 @@ class Member(OperationWithLValue):
self._value = None self._value = None
@property @property
def read(self): def read(self) -> List[SourceMapping]:
return [self.variable_left, self.variable_right] return [self.variable_left, self.variable_right]
@property @property
def variable_left(self): def variable_left(self) -> SourceMapping:
return self._variable_left return self._variable_left
@property @property
def variable_right(self): def variable_right(self) -> Constant:
return self._variable_right return self._variable_right
@property @property

@ -1,10 +1,18 @@
from typing import List, Union, TYPE_CHECKING
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
if TYPE_CHECKING:
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
class NewArray(Call, OperationWithLValue): class NewArray(Call, OperationWithLValue):
def __init__(self, depth, array_type, lvalue): def __init__(self, depth: int, array_type: "TypeAliasTopLevel",
lvalue: Union["TemporaryVariableSSA", "TemporaryVariable"]) -> None:
super().__init__() super().__init__()
assert isinstance(array_type, Type) assert isinstance(array_type, Type)
self._depth = depth self._depth = depth
@ -13,15 +21,15 @@ class NewArray(Call, OperationWithLValue):
self._lvalue = lvalue self._lvalue = lvalue
@property @property
def array_type(self): def array_type(self) -> "TypeAliasTopLevel":
return self._array_type return self._array_type
@property @property
def read(self): def read(self) -> List["Constant"]:
return self._unroll(self.arguments) return self._unroll(self.arguments)
@property @property
def depth(self): def depth(self) -> int:
return self._depth return self._depth
def __str__(self): def __str__(self):

@ -1,10 +1,14 @@
from slither.slithir.operations import Call, OperationWithLValue from slither.slithir.operations import Call, OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
from slither.slithir.variables.constant import Constant from slither.slithir.variables.constant import Constant
from slither.core.declarations.contract import Contract
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import Any, List, Union
class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes
def __init__(self, contract_name, lvalue): def __init__(self, contract_name: Constant, lvalue: Union[TemporaryVariableSSA, TemporaryVariable]) -> None:
assert isinstance(contract_name, Constant) assert isinstance(contract_name, Constant)
assert is_valid_lvalue(lvalue) assert is_valid_lvalue(lvalue)
super().__init__() super().__init__()
@ -40,15 +44,15 @@ class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instan
self._call_salt = s self._call_salt = s
@property @property
def contract_name(self): def contract_name(self) -> Constant:
return self._contract_name return self._contract_name
@property @property
def read(self): def read(self) -> List[Any]:
return self._unroll(self.arguments) return self._unroll(self.arguments)
@property @property
def contract_created(self): def contract_created(self) -> Contract:
contract_name = self.contract_name contract_name = self.contract_name
contract_instance = self.node.file_scope.get_contract_from_name(contract_name) contract_instance = self.node.file_scope.get_contract_from_name(contract_name)
return contract_instance return contract_instance

@ -4,10 +4,15 @@ from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
from slither.core.declarations.structure import Structure from slither.core.declarations.structure import Structure
from slither.core.declarations.structure_contract import StructureContract
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import List, Union
class NewStructure(Call, OperationWithLValue): class NewStructure(Call, OperationWithLValue):
def __init__(self, structure, lvalue): def __init__(self, structure: StructureContract, lvalue: Union[TemporaryVariableSSA, TemporaryVariable]) -> None:
super().__init__() super().__init__()
assert isinstance(structure, Structure) assert isinstance(structure, Structure)
assert is_valid_lvalue(lvalue) assert is_valid_lvalue(lvalue)
@ -16,11 +21,11 @@ class NewStructure(Call, OperationWithLValue):
self._lvalue = lvalue self._lvalue = lvalue
@property @property
def read(self): def read(self) -> List[Union[TemporaryVariableSSA, TemporaryVariable, Constant]]:
return self._unroll(self.arguments) return self._unroll(self.arguments)
@property @property
def structure(self): def structure(self) -> StructureContract:
return self._structure return self._structure
@property @property

@ -3,6 +3,7 @@ from slither.core.context.context import Context
from slither.core.children.child_expression import ChildExpression from slither.core.children.child_expression import ChildExpression
from slither.core.children.child_node import ChildNode from slither.core.children.child_node import ChildNode
from slither.utils.utils import unroll from slither.utils.utils import unroll
from typing import Any, List
class AbstractOperation(abc.ABC): class AbstractOperation(abc.ABC):
@ -33,5 +34,5 @@ class Operation(Context, ChildExpression, ChildNode, AbstractOperation):
# if array inside the parameters # if array inside the parameters
@staticmethod @staticmethod
def _unroll(l): def _unroll(l: List[Any]) -> List[Any]:
return unroll(l) return unroll(l)

@ -1,9 +1,16 @@
from typing import List, Set, Union, TYPE_CHECKING
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
from slither.core.declarations.solidity_variables import SolidityVariableComposed
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.state_variable import StateIRVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
if TYPE_CHECKING:
from slither.core.cfg.node import Node
class Phi(OperationWithLValue): class Phi(OperationWithLValue):
def __init__(self, left_variable, nodes): def __init__(self, left_variable: Union[LocalIRVariable, StateIRVariable], nodes: Set["Node" ]) -> None:
# When Phi operations are created the # When Phi operations are created the
# correct indexes of the variables are not yet computed # correct indexes of the variables are not yet computed
# We store the nodes where the variables are written # We store the nodes where the variables are written
@ -17,7 +24,7 @@ class Phi(OperationWithLValue):
self._nodes = nodes self._nodes = nodes
@property @property
def read(self): def read(self) -> List[Union[SolidityVariableComposed, LocalIRVariable, TemporaryVariableSSA, StateIRVariable]]:
return self.rvalues return self.rvalues
@property @property
@ -29,7 +36,7 @@ class Phi(OperationWithLValue):
self._rvalues = vals self._rvalues = vals
@property @property
def nodes(self): def nodes(self) -> Set["Node"]:
return self._nodes return self._nodes
def __str__(self): def __str__(self):

@ -1,9 +1,17 @@
from typing import List, Set, Union, TYPE_CHECKING
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
from slither.slithir.operations.phi import Phi from slither.slithir.operations.phi import Phi
from slither.slithir.operations.high_level_call import HighLevelCall
from slither.slithir.operations.internal_call import InternalCall
from slither.slithir.variables.state_variable import StateIRVariable
if TYPE_CHECKING:
from slither.core.cfg.node import Node
class PhiCallback(Phi): class PhiCallback(Phi):
def __init__(self, left_variable, nodes, call_ir, rvalue): def __init__(self, left_variable: StateIRVariable, nodes: Set["Node"], call_ir: Union[InternalCall, HighLevelCall], rvalue: StateIRVariable) -> None:
assert is_valid_lvalue(left_variable) assert is_valid_lvalue(left_variable)
assert isinstance(nodes, set) assert isinstance(nodes, set)
super().__init__(left_variable, nodes) super().__init__(left_variable, nodes)
@ -12,11 +20,11 @@ class PhiCallback(Phi):
self._rvalue_no_callback = rvalue self._rvalue_no_callback = rvalue
@property @property
def callee_ir(self): def callee_ir(self) -> Union[InternalCall, HighLevelCall]:
return self._call_ir return self._call_ir
@property @property
def read(self): def read(self) -> List[StateIRVariable]:
return self.rvalues return self.rvalues
@property @property

@ -3,6 +3,8 @@ from slither.slithir.operations.operation import Operation
from slither.slithir.variables.tuple import TupleVariable from slither.slithir.variables.tuple import TupleVariable
from slither.slithir.utils.utils import is_valid_rvalue from slither.slithir.utils.utils import is_valid_rvalue
from slither.core.variables.variable import Variable
from typing import List
class Return(Operation): class Return(Operation):
@ -11,7 +13,7 @@ class Return(Operation):
Only present as last operation in RETURN node Only present as last operation in RETURN node
""" """
def __init__(self, values): def __init__(self, values) -> None:
# Note: Can return None # Note: Can return None
# ex: return call() # ex: return call()
# where call() dont return # where call() dont return
@ -35,7 +37,7 @@ class Return(Operation):
super().__init__() super().__init__()
self._values = values self._values = values
def _valid_value(self, value): def _valid_value(self, value) -> bool:
if isinstance(value, list): if isinstance(value, list):
assert all(self._valid_value(v) for v in value) assert all(self._valid_value(v) for v in value)
else: else:
@ -43,11 +45,11 @@ class Return(Operation):
return True return True
@property @property
def read(self): def read(self) -> List[Variable]:
return self._unroll(self.values) return self._unroll(self.values)
@property @property
def values(self): def values(self) -> List[Variable]:
return self._unroll(self._values) return self._unroll(self._values)
def __str__(self): def __str__(self):

@ -3,10 +3,16 @@ from slither.core.variables.variable import Variable
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue from slither.slithir.utils.utils import is_valid_lvalue
from slither.core.variables.local_variable import LocalVariable
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import List, Union
class Send(Call, OperationWithLValue): class Send(Call, OperationWithLValue):
def __init__(self, destination, value, result): def __init__(self, destination: Union[LocalVariable, LocalIRVariable], value: Constant, result: Union[TemporaryVariable, TemporaryVariableSSA]) -> None:
assert is_valid_lvalue(result) assert is_valid_lvalue(result)
assert isinstance(destination, (Variable, SolidityVariable)) assert isinstance(destination, (Variable, SolidityVariable))
super().__init__() super().__init__()
@ -19,15 +25,15 @@ class Send(Call, OperationWithLValue):
return True return True
@property @property
def call_value(self): def call_value(self) -> Constant:
return self._call_value return self._call_value
@property @property
def read(self): def read(self) -> List[Union[Constant, LocalIRVariable, LocalVariable]]:
return [self.destination, self.call_value] return [self.destination, self.call_value]
@property @property
def destination(self): def destination(self) -> Union[LocalVariable, LocalIRVariable]:
return self._destination return self._destination
def __str__(self): def __str__(self):

@ -1,10 +1,13 @@
from slither.core.declarations.solidity_variables import SolidityFunction from slither.core.declarations.solidity_variables import SolidityCustomRevert, SolidityFunction
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.children.child_node import ChildNode
from slither.core.solidity_types.elementary_type import ElementaryType
from typing import Any, List, Union
class SolidityCall(Call, OperationWithLValue): class SolidityCall(Call, OperationWithLValue):
def __init__(self, function, nbr_arguments, result, type_call): def __init__(self, function: Union[SolidityCustomRevert, SolidityFunction], nbr_arguments: int, result: ChildNode, type_call: Union[str, List[ElementaryType]]) -> None:
assert isinstance(function, SolidityFunction) assert isinstance(function, SolidityFunction)
super().__init__() super().__init__()
self._function = function self._function = function
@ -13,19 +16,19 @@ class SolidityCall(Call, OperationWithLValue):
self._lvalue = result self._lvalue = result
@property @property
def read(self): def read(self) -> List[Any]:
return self._unroll(self.arguments) return self._unroll(self.arguments)
@property @property
def function(self): def function(self) -> Union[SolidityCustomRevert, SolidityFunction]:
return self._function return self._function
@property @property
def nbr_arguments(self): def nbr_arguments(self) -> int:
return self._nbr_arguments return self._nbr_arguments
@property @property
def type_call(self): def type_call(self) -> Union[str, List[ElementaryType]]:
return self._type_call return self._type_call
def __str__(self): def __str__(self):

@ -1,10 +1,14 @@
from slither.slithir.operations.call import Call from slither.slithir.operations.call import Call
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.core.declarations.solidity_variables import SolidityVariable from slither.core.declarations.solidity_variables import SolidityVariable
from slither.core.variables.local_variable import LocalVariable
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.local_variable import LocalIRVariable
from typing import List, Union
class Transfer(Call): class Transfer(Call):
def __init__(self, destination, value): def __init__(self, destination: Union[LocalVariable, LocalIRVariable], value: Constant) -> None:
assert isinstance(destination, (Variable, SolidityVariable)) assert isinstance(destination, (Variable, SolidityVariable))
self._destination = destination self._destination = destination
super().__init__() super().__init__()
@ -15,15 +19,15 @@ class Transfer(Call):
return True return True
@property @property
def call_value(self): def call_value(self) -> Constant:
return self._call_value return self._call_value
@property @property
def read(self): def read(self) -> List[Union[Constant, LocalIRVariable, LocalVariable]]:
return [self.destination, self.call_value] return [self.destination, self.call_value]
@property @property
def destination(self): def destination(self) -> Union[LocalVariable, LocalIRVariable]:
return self._destination return self._destination
def __str__(self): def __str__(self):

@ -2,10 +2,18 @@ from slither.core.declarations import Contract
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
import slither.core.declarations.contract
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasContract, TypeAliasTopLevel
from slither.core.solidity_types.user_defined_type import UserDefinedType
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import List, Union
class TypeConversion(OperationWithLValue): class TypeConversion(OperationWithLValue):
def __init__(self, result, variable, variable_type): def __init__(self, result: Union[TemporaryVariableSSA, TemporaryVariable], variable: SourceMapping, variable_type: Union[TypeAliasContract, UserDefinedType, ElementaryType, TypeAliasTopLevel]) -> None:
super().__init__() super().__init__()
assert is_valid_rvalue(variable) or isinstance(variable, Contract) assert is_valid_rvalue(variable) or isinstance(variable, Contract)
assert is_valid_lvalue(result) assert is_valid_lvalue(result)
@ -16,15 +24,15 @@ class TypeConversion(OperationWithLValue):
self._lvalue = result self._lvalue = result
@property @property
def variable(self): def variable(self) -> SourceMapping:
return self._variable return self._variable
@property @property
def type(self): def type(self) -> Union[TypeAliasContract, TypeAliasTopLevel, slither.core.declarations.contract.Contract, UserDefinedType, ElementaryType]:
return self._type return self._type
@property @property
def read(self): def read(self) -> List[SourceMapping]:
return [self.variable] return [self.variable]
def __str__(self): def __str__(self):

@ -4,6 +4,13 @@ from enum import Enum
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue
from slither.slithir.exceptions import SlithIRError from slither.slithir.exceptions import SlithIRError
from slither.core.expressions.unary_operation import UnaryOperationType
from slither.core.variables.local_variable import LocalVariable
from slither.slithir.variables.constant import Constant
from slither.slithir.variables.local_variable import LocalIRVariable
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.temporary_ssa import TemporaryVariableSSA
from typing import List, Union
logger = logging.getLogger("BinaryOperationIR") logger = logging.getLogger("BinaryOperationIR")
@ -31,7 +38,7 @@ class UnaryType(Enum):
class Unary(OperationWithLValue): class Unary(OperationWithLValue):
def __init__(self, result, variable, operation_type): def __init__(self, result: Union[TemporaryVariableSSA, TemporaryVariable], variable: Union[Constant, LocalIRVariable, LocalVariable], operation_type: UnaryOperationType) -> None:
assert is_valid_rvalue(variable) assert is_valid_rvalue(variable)
assert is_valid_lvalue(result) assert is_valid_lvalue(result)
super().__init__() super().__init__()
@ -40,15 +47,15 @@ class Unary(OperationWithLValue):
self._lvalue = result self._lvalue = result
@property @property
def read(self): def read(self) -> List[Union[Constant, LocalIRVariable, LocalVariable]]:
return [self._variable] return [self._variable]
@property @property
def rvalue(self): def rvalue(self) -> Union[Constant, LocalVariable]:
return self._variable return self._variable
@property @property
def type(self): def type(self) -> UnaryOperationType:
return self._type return self._type
@property @property

@ -10,7 +10,7 @@ class ArgumentType(Enum):
class Argument(Operation): class Argument(Operation):
def __init__(self, argument): def __init__(self, argument) -> None:
super().__init__() super().__init__()
self._argument = argument self._argument = argument
self._type = ArgumentType.CALL self._type = ArgumentType.CALL
@ -32,11 +32,11 @@ class Argument(Operation):
def read(self): def read(self):
return [self.argument] return [self.argument]
def set_type(self, t): def set_type(self, t: ArgumentType) -> None:
assert isinstance(t, ArgumentType) assert isinstance(t, ArgumentType)
self._type = t self._type = t
def get_type(self): def get_type(self) -> ArgumentType:
return self._type return self._type
def __str__(self): def __str__(self):

@ -8,10 +8,17 @@ from slither.core.declarations import (
from slither.core.declarations.custom_error import CustomError from slither.core.declarations.custom_error import CustomError
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.slithir.operations.member import Member
from slither.slithir.tmp_operations.tmp_new_array import TmpNewArray
from slither.slithir.tmp_operations.tmp_new_contract import TmpNewContract
from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.tuple import TupleVariable
from typing import Optional, Union
class TmpCall(OperationWithLValue): # pylint: disable=too-many-instance-attributes class TmpCall(OperationWithLValue): # pylint: disable=too-many-instance-attributes
def __init__(self, called, nbr_arguments, result, type_call): def __init__(self, called: SourceMapping, nbr_arguments: int, result: Union[TupleVariable, TemporaryVariable], type_call: str) -> None:
assert isinstance( assert isinstance(
called, called,
( (
@ -80,18 +87,18 @@ class TmpCall(OperationWithLValue): # pylint: disable=too-many-instance-attribu
self._called = c self._called = c
@property @property
def nbr_arguments(self): def nbr_arguments(self) -> int:
return self._nbr_arguments return self._nbr_arguments
@property @property
def type_call(self): def type_call(self) -> str:
return self._type_call return self._type_call
@property @property
def ori(self): def ori(self) -> Optional[Union[TmpNewContract, TmpNewArray, "TmpCall", Member]]:
return self._ori return self._ori
def set_ori(self, ori): def set_ori(self, ori: Union["TmpCall", TmpNewContract, TmpNewArray, Member]) -> None:
self._ori = ori self._ori = ori
def __str__(self): def __str__(self):

@ -1,9 +1,13 @@
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
from slither.slithir.variables.temporary import TemporaryVariable
from typing import Union
class TmpNewArray(OperationWithLValue): class TmpNewArray(OperationWithLValue):
def __init__(self, depth, array_type, lvalue): def __init__(self, depth: int, array_type: Union[TypeAliasTopLevel, ElementaryType], lvalue: TemporaryVariable) -> None:
super().__init__() super().__init__()
assert isinstance(array_type, Type) assert isinstance(array_type, Type)
self._depth = depth self._depth = depth
@ -11,7 +15,7 @@ class TmpNewArray(OperationWithLValue):
self._lvalue = lvalue self._lvalue = lvalue
@property @property
def array_type(self): def array_type(self) -> TypeAliasTopLevel:
return self._array_type return self._array_type
@property @property
@ -19,7 +23,7 @@ class TmpNewArray(OperationWithLValue):
return [] return []
@property @property
def depth(self): def depth(self) -> int:
return self._depth return self._depth
def __str__(self): def __str__(self):

@ -1,8 +1,9 @@
from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.operations.lvalue import OperationWithLValue
from slither.slithir.variables.temporary import TemporaryVariable
class TmpNewContract(OperationWithLValue): class TmpNewContract(OperationWithLValue):
def __init__(self, contract_name, lvalue): def __init__(self, contract_name: str, lvalue: TemporaryVariable) -> None:
super().__init__() super().__init__()
self._contract_name = contract_name self._contract_name = contract_name
self._lvalue = lvalue self._lvalue = lvalue

@ -1,6 +1,6 @@
import logging import logging
from slither.core.cfg.node import NodeType from slither.core.cfg.node import Node, NodeType
from slither.core.declarations import ( from slither.core.declarations import (
Contract, Contract,
Enum, Enum,
@ -58,6 +58,21 @@ from slither.slithir.variables import (
TupleVariableSSA, TupleVariableSSA,
) )
from slither.slithir.exceptions import SlithIRError from slither.slithir.exceptions import SlithIRError
import slither.slithir.operations.init_array
import slither.slithir.operations.new_array
import slither.slithir.operations.return_operation
import slither.slithir.variables.local_variable
import slither.slithir.variables.reference_ssa
import slither.slithir.variables.state_variable
import slither.slithir.variables.temporary_ssa
import slither.slithir.variables.tuple_ssa
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.modifier import Modifier
from slither.core.variables.variable import Variable
from slither.slithir.operations.call import Call
from slither.slithir.operations.operation import Operation
from typing import Any, Callable, Dict, List, Tuple, Union
logger = logging.getLogger("SSA_Conversion") logger = logging.getLogger("SSA_Conversion")
@ -68,7 +83,7 @@ logger = logging.getLogger("SSA_Conversion")
################################################################################### ###################################################################################
def transform_slithir_vars_to_ssa(function): def transform_slithir_vars_to_ssa(function: Union[FunctionContract, Modifier, FunctionTopLevel]) -> None:
""" """
Transform slithIR vars to SSA (TemporaryVariable, ReferenceVariable, TupleVariable) Transform slithIR vars to SSA (TemporaryVariable, ReferenceVariable, TupleVariable)
""" """
@ -98,7 +113,7 @@ def transform_slithir_vars_to_ssa(function):
# pylint: disable=too-many-arguments,too-many-locals,too-many-nested-blocks,too-many-statements,too-many-branches # pylint: disable=too-many-arguments,too-many-locals,too-many-nested-blocks,too-many-statements,too-many-branches
def add_ssa_ir(function, all_state_variables_instances): def add_ssa_ir(function: Union[FunctionContract, Modifier, FunctionTopLevel], all_state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable]) -> None:
""" """
Add SSA version of the IR Add SSA version of the IR
Args: Args:
@ -199,14 +214,14 @@ def add_ssa_ir(function, all_state_variables_instances):
def generate_ssa_irs( def generate_ssa_irs(
node, node: Node,
local_variables_instances, local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
all_local_variables_instances, all_local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
state_variables_instances, state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
all_state_variables_instances, all_state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
init_local_variables_instances, init_local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
visited, visited: List[Union[Node, Any]],
): ) -> None:
if node in visited: if node in visited:
return return
@ -323,7 +338,7 @@ def generate_ssa_irs(
################################################################################### ###################################################################################
def last_name(n, var, init_vars): def last_name(n: Node, var: Union[slither.slithir.variables.state_variable.StateIRVariable, slither.slithir.variables.local_variable.LocalIRVariable], init_vars: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable]) -> Union[slither.slithir.variables.state_variable.StateIRVariable, slither.slithir.variables.local_variable.LocalIRVariable]:
candidates = [] candidates = []
# Todo optimize by creating a variables_ssa_written attribute # Todo optimize by creating a variables_ssa_written attribute
for ir_ssa in n.irs_ssa: for ir_ssa in n.irs_ssa:
@ -342,7 +357,7 @@ def last_name(n, var, init_vars):
return max(candidates, key=lambda v: v.index) return max(candidates, key=lambda v: v.index)
def is_used_later(initial_node, variable): def is_used_later(initial_node: Node, variable: Union[slither.slithir.variables.state_variable.StateIRVariable, LocalVariable]) -> bool:
# TODO: does not handle the case where its read and written in the declaration node # TODO: does not handle the case where its read and written in the declaration node
# It can be problematic if this happens in a loop/if structure # It can be problematic if this happens in a loop/if structure
# Ex: # Ex:
@ -389,13 +404,13 @@ def is_used_later(initial_node, variable):
def update_lvalue( def update_lvalue(
new_ir, new_ir: Operation,
node, node: Node,
local_variables_instances, local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
all_local_variables_instances, all_local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
state_variables_instances, state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
all_state_variables_instances, all_state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
): ) -> None:
if isinstance(new_ir, OperationWithLValue): if isinstance(new_ir, OperationWithLValue):
lvalue = new_ir.lvalue lvalue = new_ir.lvalue
update_through_ref = False update_through_ref = False
@ -437,8 +452,8 @@ def update_lvalue(
def initiate_all_local_variables_instances( def initiate_all_local_variables_instances(
nodes, local_variables_instances, all_local_variables_instances nodes: List[Node], local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable], all_local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable]
): ) -> None:
for node in nodes: for node in nodes:
if node.variable_declaration: if node.variable_declaration:
new_var = LocalIRVariable(node.variable_declaration) new_var = LocalIRVariable(node.variable_declaration)
@ -457,13 +472,13 @@ def initiate_all_local_variables_instances(
def fix_phi_rvalues_and_storage_ref( def fix_phi_rvalues_and_storage_ref(
node, node: Node,
local_variables_instances, local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
all_local_variables_instances, all_local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
state_variables_instances, state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
all_state_variables_instances, all_state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
init_local_variables_instances, init_local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
): ) -> None:
for ir in node.irs_ssa: for ir in node.irs_ssa:
if isinstance(ir, (Phi)) and not ir.rvalues: if isinstance(ir, (Phi)) and not ir.rvalues:
variables = [ variables = [
@ -506,7 +521,7 @@ def fix_phi_rvalues_and_storage_ref(
) )
def add_phi_origins(node, local_variables_definition, state_variables_definition): def add_phi_origins(node: Node, local_variables_definition: Dict[str, Tuple[LocalVariable, Node]], state_variables_definition: Dict[str, Tuple[StateVariable, Node]]) -> None:
# Add new key to local_variables_definition # Add new key to local_variables_definition
# The key is the variable_name # The key is the variable_name
@ -557,12 +572,12 @@ def add_phi_origins(node, local_variables_definition, state_variables_definition
def get( def get(
variable, variable,
local_variables_instances, local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
state_variables_instances, state_variables_instances: Dict[str, slither.slithir.variables.state_variable.StateIRVariable],
temporary_variables_instances, temporary_variables_instances: Dict[int, slither.slithir.variables.temporary_ssa.TemporaryVariableSSA],
reference_variables_instances, reference_variables_instances: Dict[int, slither.slithir.variables.reference_ssa.ReferenceVariableSSA],
tuple_variables_instances, tuple_variables_instances: Dict[int, slither.slithir.variables.tuple_ssa.TupleVariableSSA],
all_local_variables_instances, all_local_variables_instances: Dict[str, slither.slithir.variables.local_variable.LocalIRVariable],
): ):
# variable can be None # variable can be None
# for example, on LowLevelCall, ir.lvalue can be none # for example, on LowLevelCall, ir.lvalue can be none
@ -623,14 +638,14 @@ def get(
return variable return variable
def get_variable(ir, f, *instances): def get_variable(ir: Operation, f: Callable, *instances):
# pylint: disable=no-value-for-parameter # pylint: disable=no-value-for-parameter
variable = f(ir) variable = f(ir)
variable = get(variable, *instances) variable = get(variable, *instances)
return variable return variable
def _get_traversal(values, *instances): def _get_traversal(values: List[Any], *instances) -> List[Any]:
ret = [] ret = []
# pylint: disable=no-value-for-parameter # pylint: disable=no-value-for-parameter
for v in values: for v in values:
@ -642,11 +657,11 @@ def _get_traversal(values, *instances):
return ret return ret
def get_arguments(ir, *instances): def get_arguments(ir: Call, *instances) -> List[Any]:
return _get_traversal(ir.arguments, *instances) return _get_traversal(ir.arguments, *instances)
def get_rec_values(ir, f, *instances): def get_rec_values(ir: Union[slither.slithir.operations.init_array.InitArray, slither.slithir.operations.return_operation.Return, slither.slithir.operations.new_array.NewArray], f: Callable, *instances) -> List[Variable]:
# Use by InitArray and NewArray # Use by InitArray and NewArray
# Potential recursive array(s) # Potential recursive array(s)
ori_init_values = f(ir) ori_init_values = f(ir)
@ -654,7 +669,7 @@ def get_rec_values(ir, f, *instances):
return _get_traversal(ori_init_values, *instances) return _get_traversal(ori_init_values, *instances)
def copy_ir(ir, *instances): def copy_ir(ir: Operation, *instances) -> Operation:
""" """
Args: Args:
ir (Operation) ir (Operation)

@ -8,9 +8,10 @@ from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.constant import Constant from slither.slithir.variables.constant import Constant
from slither.slithir.variables.reference import ReferenceVariable from slither.slithir.variables.reference import ReferenceVariable
from slither.slithir.variables.tuple import TupleVariable from slither.slithir.variables.tuple import TupleVariable
from slither.core.source_mapping.source_mapping import SourceMapping
def is_valid_rvalue(v): def is_valid_rvalue(v: SourceMapping) -> bool:
return isinstance( return isinstance(
v, v,
( (
@ -25,7 +26,7 @@ def is_valid_rvalue(v):
) )
def is_valid_lvalue(v): def is_valid_lvalue(v) -> bool:
return isinstance( return isinstance(
v, v,
( (

@ -4,13 +4,14 @@ from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uin
from slither.slithir.variables.variable import SlithIRVariable from slither.slithir.variables.variable import SlithIRVariable
from slither.utils.arithmetic import convert_subdenomination from slither.utils.arithmetic import convert_subdenomination
from slither.utils.integer_conversion import convert_string_to_int from slither.utils.integer_conversion import convert_string_to_int
from typing import Optional, Union
@total_ordering @total_ordering
class Constant(SlithIRVariable): class Constant(SlithIRVariable):
def __init__( def __init__(
self, val, constant_type=None, subdenomination=None self, val: str, constant_type: Optional[ElementaryType]=None, subdenomination: Optional[str]=None
): # pylint: disable=too-many-branches ) -> None: # pylint: disable=too-many-branches
super().__init__() super().__init__()
assert isinstance(val, str) assert isinstance(val, str)
@ -38,7 +39,7 @@ class Constant(SlithIRVariable):
self._val = val self._val = val
@property @property
def value(self): def value(self) -> Union[bool, int, str]:
""" """
Return the value. Return the value.
If the expression was an hexadecimal delcared as hex'...' If the expression was an hexadecimal delcared as hex'...'
@ -56,14 +57,14 @@ class Constant(SlithIRVariable):
""" """
return self._original_value return self._original_value
def __str__(self): def __str__(self) -> str:
return str(self.value) return str(self.value)
@property @property
def name(self): def name(self) -> str:
return str(self) return str(self)
def __eq__(self, other): def __eq__(self, other: Union["Constant", str]) -> bool:
return self.value == other return self.value == other
def __ne__(self, other): def __ne__(self, other):

@ -1,12 +1,13 @@
from slither.core.variables.local_variable import LocalVariable from slither.core.variables.local_variable import LocalVariable
from slither.slithir.variables.temporary import TemporaryVariable from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.variable import SlithIRVariable from slither.slithir.variables.variable import SlithIRVariable
from slither.slithir.variables.state_variable import StateIRVariable
class LocalIRVariable( class LocalIRVariable(
LocalVariable, SlithIRVariable LocalVariable, SlithIRVariable
): # pylint: disable=too-many-instance-attributes ): # pylint: disable=too-many-instance-attributes
def __init__(self, local_variable): def __init__(self, local_variable: LocalVariable) -> None:
assert isinstance(local_variable, LocalVariable) assert isinstance(local_variable, LocalVariable)
super().__init__() super().__init__()
@ -57,10 +58,10 @@ class LocalIRVariable(
self._refers_to = variables self._refers_to = variables
@property @property
def non_ssa_version(self): def non_ssa_version(self) -> LocalVariable:
return self._non_ssa_version return self._non_ssa_version
def add_refers_to(self, variable): def add_refers_to(self, variable: StateIRVariable) -> None:
# It is a temporaryVariable if its the return of a new .. # It is a temporaryVariable if its the return of a new ..
# ex: string[] memory dynargs = new string[](1); # ex: string[] memory dynargs = new string[](1);
assert isinstance(variable, (SlithIRVariable, TemporaryVariable)) assert isinstance(variable, (SlithIRVariable, TemporaryVariable))

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from slither.core.children.child_node import ChildNode from slither.core.children.child_node import ChildNode
from slither.core.declarations import Contract, Enum, SolidityVariable, Function from slither.core.declarations import Contract, Enum, SolidityVariable, Function
@ -9,7 +9,7 @@ if TYPE_CHECKING:
class ReferenceVariable(ChildNode, Variable): class ReferenceVariable(ChildNode, Variable):
def __init__(self, node: "Node", index=None): def __init__(self, node: "Node", index: Optional[int]=None) -> None:
super().__init__() super().__init__()
if index is None: if index is None:
self._index = node.compilation_unit.counter_slithir_reference self._index = node.compilation_unit.counter_slithir_reference
@ -56,17 +56,17 @@ class ReferenceVariable(ChildNode, Variable):
self._points_to = points_to self._points_to = points_to
@property @property
def name(self): def name(self) -> str:
return f"REF_{self.index}" return f"REF_{self.index}"
# overide of core.variables.variables # overide of core.variables.variables
# reference can have Function has a type # reference can have Function has a type
# to handle the function selector # to handle the function selector
def set_type(self, t): def set_type(self, t) -> None:
if not isinstance(t, Function): if not isinstance(t, Function):
super().set_type(t) super().set_type(t)
else: else:
self._type = t self._type = t
def __str__(self): def __str__(self) -> str:
return self.name return self.name

@ -7,7 +7,7 @@ from slither.slithir.variables.reference import ReferenceVariable
class ReferenceVariableSSA(ReferenceVariable): # pylint: disable=too-few-public-methods class ReferenceVariableSSA(ReferenceVariable): # pylint: disable=too-few-public-methods
def __init__(self, reference): def __init__(self, reference: ReferenceVariable) -> None:
super().__init__(reference.node, reference.index) super().__init__(reference.node, reference.index)
self._non_ssa_version = reference self._non_ssa_version = reference

@ -5,7 +5,7 @@ from slither.slithir.variables.variable import SlithIRVariable
class StateIRVariable( class StateIRVariable(
StateVariable, SlithIRVariable StateVariable, SlithIRVariable
): # pylint: disable=too-many-instance-attributes ): # pylint: disable=too-many-instance-attributes
def __init__(self, state_variable): def __init__(self, state_variable: StateVariable) -> None:
assert isinstance(state_variable, StateVariable) assert isinstance(state_variable, StateVariable)
super().__init__() super().__init__()
@ -38,7 +38,7 @@ class StateIRVariable(
self._index = idx self._index = idx
@property @property
def non_ssa_version(self): def non_ssa_version(self) -> StateVariable:
return self._non_ssa_version return self._non_ssa_version
@property @property

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from slither.core.children.child_node import ChildNode from slither.core.children.child_node import ChildNode
from slither.core.variables.variable import Variable from slither.core.variables.variable import Variable
@ -8,7 +8,7 @@ if TYPE_CHECKING:
class TemporaryVariable(ChildNode, Variable): class TemporaryVariable(ChildNode, Variable):
def __init__(self, node: "Node", index=None): def __init__(self, node: "Node", index: Optional[int]=None) -> None:
super().__init__() super().__init__()
if index is None: if index is None:
self._index = node.compilation_unit.counter_slithir_temporary self._index = node.compilation_unit.counter_slithir_temporary
@ -26,8 +26,8 @@ class TemporaryVariable(ChildNode, Variable):
self._index = idx self._index = idx
@property @property
def name(self): def name(self) -> str:
return f"TMP_{self.index}" return f"TMP_{self.index}"
def __str__(self): def __str__(self) -> str:
return self.name return self.name

@ -4,14 +4,17 @@
as the TemporaryVariable are in SSA form in both version as the TemporaryVariable are in SSA form in both version
""" """
from slither.slithir.variables.temporary import TemporaryVariable from slither.slithir.variables.temporary import TemporaryVariable
from slither.slithir.variables.reference import ReferenceVariable
from slither.slithir.variables.tuple import TupleVariable
from typing import Union
class TemporaryVariableSSA(TemporaryVariable): # pylint: disable=too-few-public-methods class TemporaryVariableSSA(TemporaryVariable): # pylint: disable=too-few-public-methods
def __init__(self, temporary): def __init__(self, temporary: TemporaryVariable) -> None:
super().__init__(temporary.node, temporary.index) super().__init__(temporary.node, temporary.index)
self._non_ssa_version = temporary self._non_ssa_version = temporary
@property @property
def non_ssa_version(self): def non_ssa_version(self) -> Union[TemporaryVariable, TupleVariable, ReferenceVariable]:
return self._non_ssa_version return self._non_ssa_version

@ -1,4 +1,4 @@
from typing import TYPE_CHECKING from typing import Optional, TYPE_CHECKING
from slither.core.children.child_node import ChildNode from slither.core.children.child_node import ChildNode
from slither.slithir.variables.variable import SlithIRVariable from slither.slithir.variables.variable import SlithIRVariable
@ -8,7 +8,7 @@ if TYPE_CHECKING:
class TupleVariable(ChildNode, SlithIRVariable): class TupleVariable(ChildNode, SlithIRVariable):
def __init__(self, node: "Node", index=None): def __init__(self, node: "Node", index: Optional[int]=None) -> None:
super().__init__() super().__init__()
if index is None: if index is None:
self._index = node.compilation_unit.counter_slithir_tuple self._index = node.compilation_unit.counter_slithir_tuple
@ -27,8 +27,8 @@ class TupleVariable(ChildNode, SlithIRVariable):
self._index = idx self._index = idx
@property @property
def name(self): def name(self) -> str:
return f"TUPLE_{self.index}" return f"TUPLE_{self.index}"
def __str__(self): def __str__(self) -> str:
return self.name return self.name

@ -7,7 +7,7 @@ from slither.slithir.variables.tuple import TupleVariable
class TupleVariableSSA(TupleVariable): # pylint: disable=too-few-public-methods class TupleVariableSSA(TupleVariable): # pylint: disable=too-few-public-methods
def __init__(self, t): def __init__(self, t: TupleVariable) -> None:
super().__init__(t.node, t.index) super().__init__(t.node, t.index)
self._non_ssa_version = t self._non_ssa_version = t

@ -2,7 +2,7 @@ from slither.core.variables.variable import Variable
class SlithIRVariable(Variable): class SlithIRVariable(Variable):
def __init__(self): def __init__(self) -> None:
super().__init__() super().__init__()
self._index = 0 self._index = 0

@ -1,4 +1,4 @@
from typing import Optional, Dict from typing import Union, Optional, Dict, TYPE_CHECKING
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
from slither.core.cfg.node import NodeType from slither.core.cfg.node import NodeType
@ -12,9 +12,13 @@ from slither.visitors.expression.find_calls import FindCalls
from slither.visitors.expression.read_var import ReadVar from slither.visitors.expression.read_var import ReadVar
from slither.visitors.expression.write_var import WriteVar from slither.visitors.expression.write_var import WriteVar
if TYPE_CHECKING:
from slither.solc_parsing.declarations.function import FunctionSolc
from slither.solc_parsing.declarations.modifier import ModifierSolc
class NodeSolc: class NodeSolc:
def __init__(self, node: Node): def __init__(self, node: Node) -> None:
self._unparsed_expression: Optional[Dict] = None self._unparsed_expression: Optional[Dict] = None
self._node = node self._node = node
@ -22,11 +26,11 @@ class NodeSolc:
def underlying_node(self) -> Node: def underlying_node(self) -> Node:
return self._node return self._node
def add_unparsed_expression(self, expression: Dict): def add_unparsed_expression(self, expression: Dict) -> None:
assert self._unparsed_expression is None assert self._unparsed_expression is None
self._unparsed_expression = expression self._unparsed_expression = expression
def analyze_expressions(self, caller_context): def analyze_expressions(self, caller_context: Union["FunctionSolc", "ModifierSolc"]) -> None:
if self._node.type == NodeType.VARIABLE and not self._node.expression: if self._node.type == NodeType.VARIABLE and not self._node.expression:
self._node.add_expression(self._node.variable_declaration.expression) self._node.add_expression(self._node.variable_declaration.expression)
if self._unparsed_expression: if self._unparsed_expression:

@ -1,6 +1,6 @@
import logging import logging
import re import re
from typing import List, Dict, Callable, TYPE_CHECKING, Union, Set from typing import Any, List, Dict, Callable, TYPE_CHECKING, Union, Set
from slither.core.declarations import Modifier, Event, EnumContract, StructureContract, Function from slither.core.declarations import Modifier, Event, EnumContract, StructureContract, Function
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
@ -17,19 +17,21 @@ from slither.solc_parsing.declarations.structure_contract import StructureContra
from slither.solc_parsing.exceptions import ParsingError, VariableNotFound from slither.solc_parsing.exceptions import ParsingError, VariableNotFound
from slither.solc_parsing.solidity_types.type_parsing import parse_type from slither.solc_parsing.solidity_types.type_parsing import parse_type
from slither.solc_parsing.variables.state_variable import StateVariableSolc from slither.solc_parsing.variables.state_variable import StateVariableSolc
import slither.core.declarations.function
import slither.core.declarations.modifier
import slither.core.solidity_types.type
LOGGER = logging.getLogger("ContractSolcParsing") LOGGER = logging.getLogger("ContractSolcParsing")
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc
from slither.core.slither_core import SlitherCore
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
# pylint: disable=too-many-instance-attributes,import-outside-toplevel,too-many-nested-blocks,too-many-public-methods # pylint: disable=too-many-instance-attributes,import-outside-toplevel,too-many-nested-blocks,too-many-public-methods
class ContractSolc(CallerContextExpression): class ContractSolc(CallerContextExpression):
def __init__(self, slither_parser: "SlitherCompilationUnitSolc", contract: Contract, data): def __init__(self, slither_parser: "SlitherCompilationUnitSolc", contract: Contract, data: Dict[str, Any]) -> None:
# assert slitherSolc.solc_version.startswith('0.4') # assert slitherSolc.solc_version.startswith('0.4')
self._contract = contract self._contract = contract
@ -86,7 +88,7 @@ class ContractSolc(CallerContextExpression):
def is_analyzed(self) -> bool: def is_analyzed(self) -> bool:
return self._is_analyzed return self._is_analyzed
def set_is_analyzed(self, is_analyzed: bool): def set_is_analyzed(self, is_analyzed: bool) -> None:
self._is_analyzed = is_analyzed self._is_analyzed = is_analyzed
@property @property
@ -130,7 +132,7 @@ class ContractSolc(CallerContextExpression):
def get_key(self) -> str: def get_key(self) -> str:
return self._slither_parser.get_key() return self._slither_parser.get_key()
def get_children(self, key="nodes") -> str: def get_children(self, key: str="nodes") -> str:
if self.is_compact_ast: if self.is_compact_ast:
return key return key
return "children" return "children"
@ -150,7 +152,7 @@ class ContractSolc(CallerContextExpression):
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _parse_contract_info(self): def _parse_contract_info(self) -> None:
if self.is_compact_ast: if self.is_compact_ast:
attributes = self._data attributes = self._data
else: else:
@ -178,7 +180,7 @@ class ContractSolc(CallerContextExpression):
"name" "name"
] ]
def _parse_base_contract_info(self): # pylint: disable=too-many-branches def _parse_base_contract_info(self) -> None: # pylint: disable=too-many-branches
# Parse base contracts (immediate, non-linearized) # Parse base contracts (immediate, non-linearized)
if self.is_compact_ast: if self.is_compact_ast:
# Parse base contracts + constructors in compact-ast # Parse base contracts + constructors in compact-ast
@ -236,7 +238,7 @@ class ContractSolc(CallerContextExpression):
): ):
self.baseConstructorContractsCalled.append(referencedDeclaration) self.baseConstructorContractsCalled.append(referencedDeclaration)
def _parse_contract_items(self): def _parse_contract_items(self) -> None:
# pylint: disable=too-many-branches # pylint: disable=too-many-branches
if not self.get_children() in self._data: # empty contract if not self.get_children() in self._data: # empty contract
return return
@ -289,7 +291,7 @@ class ContractSolc(CallerContextExpression):
self._contract.file_scope.user_defined_types[alias] = user_defined_type self._contract.file_scope.user_defined_types[alias] = user_defined_type
self._contract.file_scope.user_defined_types[alias_canonical] = user_defined_type self._contract.file_scope.user_defined_types[alias_canonical] = user_defined_type
def _parse_struct(self, struct: Dict): def _parse_struct(self, struct: Dict) -> None:
st = StructureContract(self._contract.compilation_unit) st = StructureContract(self._contract.compilation_unit)
st.set_contract(self._contract) st.set_contract(self._contract)
@ -299,7 +301,7 @@ class ContractSolc(CallerContextExpression):
self._contract.structures_as_dict[st.name] = st self._contract.structures_as_dict[st.name] = st
self._structures_parser.append(st_parser) self._structures_parser.append(st_parser)
def parse_structs(self): def parse_structs(self) -> None:
for father in self._contract.inheritance_reverse: for father in self._contract.inheritance_reverse:
self._contract.structures_as_dict.update(father.structures_as_dict) self._contract.structures_as_dict.update(father.structures_as_dict)
@ -307,7 +309,7 @@ class ContractSolc(CallerContextExpression):
self._parse_struct(struct) self._parse_struct(struct)
self._structuresNotParsed = None self._structuresNotParsed = None
def _parse_custom_error(self, custom_error: Dict): def _parse_custom_error(self, custom_error: Dict) -> None:
ce = CustomErrorContract(self.compilation_unit) ce = CustomErrorContract(self.compilation_unit)
ce.set_contract(self._contract) ce.set_contract(self._contract)
ce.set_offset(custom_error["src"], self.compilation_unit) ce.set_offset(custom_error["src"], self.compilation_unit)
@ -316,7 +318,7 @@ class ContractSolc(CallerContextExpression):
self._contract.custom_errors_as_dict[ce.name] = ce self._contract.custom_errors_as_dict[ce.name] = ce
self._custom_errors_parser.append(ce_parser) self._custom_errors_parser.append(ce_parser)
def parse_custom_errors(self): def parse_custom_errors(self) -> None:
for father in self._contract.inheritance_reverse: for father in self._contract.inheritance_reverse:
self._contract.custom_errors_as_dict.update(father.custom_errors_as_dict) self._contract.custom_errors_as_dict.update(father.custom_errors_as_dict)
@ -324,7 +326,7 @@ class ContractSolc(CallerContextExpression):
self._parse_custom_error(custom_error) self._parse_custom_error(custom_error)
self._customErrorParsed = None self._customErrorParsed = None
def parse_state_variables(self): def parse_state_variables(self) -> None:
for father in self._contract.inheritance_reverse: for father in self._contract.inheritance_reverse:
self._contract.variables_as_dict.update( self._contract.variables_as_dict.update(
{ {
@ -352,7 +354,7 @@ class ContractSolc(CallerContextExpression):
self._contract.variables_as_dict[var.name] = var self._contract.variables_as_dict[var.name] = var
self._contract.add_variables_ordered([var]) self._contract.add_variables_ordered([var])
def _parse_modifier(self, modifier_data: Dict): def _parse_modifier(self, modifier_data: Dict) -> None:
modif = Modifier(self._contract.compilation_unit) modif = Modifier(self._contract.compilation_unit)
modif.set_offset(modifier_data["src"], self._contract.compilation_unit) modif.set_offset(modifier_data["src"], self._contract.compilation_unit)
modif.set_contract(self._contract) modif.set_contract(self._contract)
@ -365,12 +367,12 @@ class ContractSolc(CallerContextExpression):
self._slither_parser.add_function_or_modifier_parser(modif_parser) self._slither_parser.add_function_or_modifier_parser(modif_parser)
def parse_modifiers(self): def parse_modifiers(self) -> None:
for modifier in self._modifiersNotParsed: for modifier in self._modifiersNotParsed:
self._parse_modifier(modifier) self._parse_modifier(modifier)
self._modifiersNotParsed = None self._modifiersNotParsed = None
def _parse_function(self, function_data: Dict): def _parse_function(self, function_data: Dict) -> None:
func = FunctionContract(self._contract.compilation_unit) func = FunctionContract(self._contract.compilation_unit)
func.set_offset(function_data["src"], self._contract.compilation_unit) func.set_offset(function_data["src"], self._contract.compilation_unit)
func.set_contract(self._contract) func.set_contract(self._contract)
@ -383,7 +385,7 @@ class ContractSolc(CallerContextExpression):
self._slither_parser.add_function_or_modifier_parser(func_parser) self._slither_parser.add_function_or_modifier_parser(func_parser)
def parse_functions(self): def parse_functions(self) -> None:
for function in self._functionsNotParsed: for function in self._functionsNotParsed:
self._parse_function(function) self._parse_function(function)
@ -403,21 +405,21 @@ class ContractSolc(CallerContextExpression):
LOGGER.error(error) LOGGER.error(error)
self._contract.is_incorrectly_constructed = True self._contract.is_incorrectly_constructed = True
def analyze_content_modifiers(self): def analyze_content_modifiers(self) -> None:
try: try:
for modifier_parser in self._modifiers_parser: for modifier_parser in self._modifiers_parser:
modifier_parser.analyze_content() modifier_parser.analyze_content()
except (VariableNotFound, KeyError) as e: except (VariableNotFound, KeyError) as e:
self.log_incorrect_parsing(f"Missing modifier {e}") self.log_incorrect_parsing(f"Missing modifier {e}")
def analyze_content_functions(self): def analyze_content_functions(self) -> None:
try: try:
for function_parser in self._functions_parser: for function_parser in self._functions_parser:
function_parser.analyze_content() function_parser.analyze_content()
except (VariableNotFound, KeyError, ParsingError) as e: except (VariableNotFound, KeyError, ParsingError) as e:
self.log_incorrect_parsing(f"Missing function {e}") self.log_incorrect_parsing(f"Missing function {e}")
def analyze_params_modifiers(self): def analyze_params_modifiers(self) -> None:
try: try:
elements_no_params = self._modifiers_no_params elements_no_params = self._modifiers_no_params
getter = lambda c: c.modifiers_parser getter = lambda c: c.modifiers_parser
@ -437,7 +439,7 @@ class ContractSolc(CallerContextExpression):
self.log_incorrect_parsing(f"Missing params {e}") self.log_incorrect_parsing(f"Missing params {e}")
self._modifiers_no_params = [] self._modifiers_no_params = []
def analyze_params_functions(self): def analyze_params_functions(self) -> None:
try: try:
elements_no_params = self._functions_no_params elements_no_params = self._functions_no_params
getter = lambda c: c.functions_parser getter = lambda c: c.functions_parser
@ -465,7 +467,7 @@ class ContractSolc(CallerContextExpression):
explored_reference_id: Set[str], explored_reference_id: Set[str],
parser: List[FunctionSolc], parser: List[FunctionSolc],
all_elements: Dict[str, Function], all_elements: Dict[str, Function],
): ) -> None:
elem = Cls(self._contract.compilation_unit) elem = Cls(self._contract.compilation_unit)
elem.set_contract(self._contract) elem.set_contract(self._contract)
underlying_function = element_parser.underlying_function underlying_function = element_parser.underlying_function
@ -566,7 +568,7 @@ class ContractSolc(CallerContextExpression):
self.log_incorrect_parsing(f"Missing params {e}") self.log_incorrect_parsing(f"Missing params {e}")
return all_elements return all_elements
def analyze_constant_state_variables(self): def analyze_constant_state_variables(self) -> None:
for var_parser in self._variables_parser: for var_parser in self._variables_parser:
if var_parser.underlying_variable.is_constant: if var_parser.underlying_variable.is_constant:
# cant parse constant expression based on function calls # cant parse constant expression based on function calls
@ -575,7 +577,7 @@ class ContractSolc(CallerContextExpression):
except (VariableNotFound, KeyError) as e: except (VariableNotFound, KeyError) as e:
LOGGER.error(e) LOGGER.error(e)
def analyze_state_variables(self): def analyze_state_variables(self) -> None:
try: try:
for var_parser in self._variables_parser: for var_parser in self._variables_parser:
var_parser.analyze(self) var_parser.analyze(self)
@ -583,7 +585,7 @@ class ContractSolc(CallerContextExpression):
except (VariableNotFound, KeyError) as e: except (VariableNotFound, KeyError) as e:
self.log_incorrect_parsing(f"Missing state variable {e}") self.log_incorrect_parsing(f"Missing state variable {e}")
def analyze_using_for(self): # pylint: disable=too-many-branches def analyze_using_for(self) -> None: # pylint: disable=too-many-branches
try: try:
for father in self._contract.inheritance: for father in self._contract.inheritance:
self._contract.using_for.update(father.using_for) self._contract.using_for.update(father.using_for)
@ -620,7 +622,7 @@ class ContractSolc(CallerContextExpression):
except (VariableNotFound, KeyError) as e: except (VariableNotFound, KeyError) as e:
self.log_incorrect_parsing(f"Missing using for {e}") self.log_incorrect_parsing(f"Missing using for {e}")
def _analyze_function_list(self, function_list: List, type_name: Type): def _analyze_function_list(self, function_list: List, type_name: Type) -> None:
for f in function_list: for f in function_list:
full_name_split = f["function"]["name"].split(".") full_name_split = f["function"]["name"].split(".")
if len(full_name_split) == 1: if len(full_name_split) == 1:
@ -639,7 +641,7 @@ class ContractSolc(CallerContextExpression):
function_name = full_name_split[2] function_name = full_name_split[2]
self._analyze_library_function(library_name, function_name, type_name) self._analyze_library_function(library_name, function_name, type_name)
def _check_aliased_import(self, first_part: str, function_name: str, type_name: Type): def _check_aliased_import(self, first_part: str, function_name: str, type_name: Type) -> None:
# We check if the first part appear as alias for an import # We check if the first part appear as alias for an import
# if it is then function_name must be a top level function # if it is then function_name must be a top level function
# otherwise it's a library function # otherwise it's a library function
@ -649,7 +651,7 @@ class ContractSolc(CallerContextExpression):
return return
self._analyze_library_function(first_part, function_name, type_name) self._analyze_library_function(first_part, function_name, type_name)
def _analyze_top_level_function(self, function_name: str, type_name: Type): def _analyze_top_level_function(self, function_name: str, type_name: Type) -> None:
for tl_function in self.compilation_unit.functions_top_level: for tl_function in self.compilation_unit.functions_top_level:
if tl_function.name == function_name: if tl_function.name == function_name:
self._contract.using_for[type_name].append(tl_function) self._contract.using_for[type_name].append(tl_function)
@ -673,7 +675,7 @@ class ContractSolc(CallerContextExpression):
f"Contract level using for: Library {library_name} - function {function_name} not found" f"Contract level using for: Library {library_name} - function {function_name} not found"
) )
def analyze_enums(self): def analyze_enums(self) -> None:
try: try:
for father in self._contract.inheritance: for father in self._contract.inheritance:
self._contract.enums_as_dict.update(father.enums_as_dict) self._contract.enums_as_dict.update(father.enums_as_dict)
@ -686,7 +688,7 @@ class ContractSolc(CallerContextExpression):
except (VariableNotFound, KeyError) as e: except (VariableNotFound, KeyError) as e:
self.log_incorrect_parsing(f"Missing enum {e}") self.log_incorrect_parsing(f"Missing enum {e}")
def _analyze_enum(self, enum): def _analyze_enum(self, enum: Dict[str, Union[str, int, List[Dict[str, Union[int, str]]], Dict[str, str], List[Dict[str, Union[Dict[str, str], int, str]]]]]) -> None:
# Enum can be parsed in one pass # Enum can be parsed in one pass
if self.is_compact_ast: if self.is_compact_ast:
name = enum["name"] name = enum["name"]
@ -710,21 +712,21 @@ class ContractSolc(CallerContextExpression):
new_enum.set_offset(enum["src"], self._contract.compilation_unit) new_enum.set_offset(enum["src"], self._contract.compilation_unit)
self._contract.enums_as_dict[canonicalName] = new_enum self._contract.enums_as_dict[canonicalName] = new_enum
def _analyze_struct(self, struct: StructureContractSolc): # pylint: disable=no-self-use def _analyze_struct(self, struct: StructureContractSolc) -> None: # pylint: disable=no-self-use
struct.analyze() struct.analyze()
def analyze_structs(self): def analyze_structs(self) -> None:
try: try:
for struct in self._structures_parser: for struct in self._structures_parser:
self._analyze_struct(struct) self._analyze_struct(struct)
except (VariableNotFound, KeyError) as e: except (VariableNotFound, KeyError) as e:
self.log_incorrect_parsing(f"Missing struct {e}") self.log_incorrect_parsing(f"Missing struct {e}")
def analyze_custom_errors(self): def analyze_custom_errors(self) -> None:
for custom_error in self._custom_errors_parser: for custom_error in self._custom_errors_parser:
custom_error.analyze_params() custom_error.analyze_params()
def analyze_events(self): def analyze_events(self) -> None:
try: try:
for father in self._contract.inheritance_reverse: for father in self._contract.inheritance_reverse:
self._contract.events_as_dict.update(father.events_as_dict) self._contract.events_as_dict.update(father.events_as_dict)

@ -22,7 +22,7 @@ class CustomErrorSolc(CallerContextExpression):
custom_error: CustomError, custom_error: CustomError,
custom_error_data: dict, custom_error_data: dict,
slither_parser: "SlitherCompilationUnitSolc", slither_parser: "SlitherCompilationUnitSolc",
): ) -> None:
self._slither_parser: "SlitherCompilationUnitSolc" = slither_parser self._slither_parser: "SlitherCompilationUnitSolc" = slither_parser
self._custom_error = custom_error self._custom_error = custom_error
custom_error.name = custom_error_data["name"] custom_error.name = custom_error_data["name"]
@ -32,7 +32,7 @@ class CustomErrorSolc(CallerContextExpression):
custom_error_data = custom_error_data["attributes"] custom_error_data = custom_error_data["attributes"]
self._custom_error_data = custom_error_data self._custom_error_data = custom_error_data
def analyze_params(self): def analyze_params(self) -> None:
# Can be re-analyzed due to inheritance # Can be re-analyzed due to inheritance
if self._params_was_analyzed: if self._params_was_analyzed:
return return
@ -68,7 +68,7 @@ class CustomErrorSolc(CallerContextExpression):
return key return key
return "children" return "children"
def _parse_params(self, params: Dict): def _parse_params(self, params: Dict) -> None:
assert params[self.get_key()] == "ParameterList" assert params[self.get_key()] == "ParameterList"
if self._slither_parser.is_compact_ast: if self._slither_parser.is_compact_ast:

@ -16,7 +16,7 @@ class EventSolc:
Event class Event class
""" """
def __init__(self, event: Event, event_data: Dict, contract_parser: "ContractSolc"): def __init__(self, event: Event, event_data: Dict, contract_parser: "ContractSolc") -> None:
self._event = event self._event = event
event.set_contract(contract_parser.underlying_contract) event.set_contract(contract_parser.underlying_contract)
@ -43,7 +43,7 @@ class EventSolc:
def is_compact_ast(self) -> bool: def is_compact_ast(self) -> bool:
return self._parser_contract.is_compact_ast return self._parser_contract.is_compact_ast
def analyze(self, contract: "ContractSolc"): def analyze(self, contract: "ContractSolc") -> None:
for elem_to_parse in self._elemsNotParsed: for elem_to_parse in self._elemsNotParsed:
elem = EventVariable() elem = EventVariable()
# Todo: check if the source offset is always here # Todo: check if the source offset is always here

@ -23,10 +23,10 @@ from slither.solc_parsing.variables.local_variable_init_from_tuple import (
LocalVariableInitFromTupleSolc, LocalVariableInitFromTupleSolc,
) )
from slither.solc_parsing.variables.variable_declaration import MultipleVariablesDeclaration from slither.solc_parsing.variables.variable_declaration import MultipleVariablesDeclaration
from slither.solc_parsing.yul.parse_yul import YulBlock
from slither.utils.expression_manipulations import SplitTernaryExpression from slither.utils.expression_manipulations import SplitTernaryExpression
from slither.visitors.expression.export_values import ExportValues from slither.visitors.expression.export_values import ExportValues
from slither.visitors.expression.has_conditional import HasConditional from slither.visitors.expression.has_conditional import HasConditional
from slither.solc_parsing.yul.parse_yul import YulBlock
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
@ -35,6 +35,7 @@ if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
LOGGER = logging.getLogger("FunctionSolc") LOGGER = logging.getLogger("FunctionSolc")
@ -55,7 +56,7 @@ class FunctionSolc(CallerContextExpression):
function_data: Dict, function_data: Dict,
contract_parser: Optional["ContractSolc"], contract_parser: Optional["ContractSolc"],
slither_parser: "SlitherCompilationUnitSolc", slither_parser: "SlitherCompilationUnitSolc",
): ) -> None:
self._slither_parser: "SlitherCompilationUnitSolc" = slither_parser self._slither_parser: "SlitherCompilationUnitSolc" = slither_parser
self._contract_parser = contract_parser self._contract_parser = contract_parser
self._function = function self._function = function
@ -143,7 +144,7 @@ class FunctionSolc(CallerContextExpression):
def _add_local_variable( def _add_local_variable(
self, local_var_parser: Union[LocalVariableSolc, LocalVariableInitFromTupleSolc] self, local_var_parser: Union[LocalVariableSolc, LocalVariableInitFromTupleSolc]
): ) -> None:
# If two local variables have the same name # If two local variables have the same name
# We add a suffix to the new variable # We add a suffix to the new variable
# This is done to prevent collision during SSA translation # This is done to prevent collision during SSA translation
@ -175,7 +176,7 @@ class FunctionSolc(CallerContextExpression):
def function_not_parsed(self) -> Dict: def function_not_parsed(self) -> Dict:
return self._functionNotParsed return self._functionNotParsed
def _analyze_type(self): def _analyze_type(self) -> None:
""" """
Analyz the type of the function Analyz the type of the function
Myst be called in the constructor as the name might change according to the function's type Myst be called in the constructor as the name might change according to the function's type
@ -201,7 +202,7 @@ class FunctionSolc(CallerContextExpression):
if self._function.name == self._function.contract_declarer.name: if self._function.name == self._function.contract_declarer.name:
self._function.function_type = FunctionType.CONSTRUCTOR self._function.function_type = FunctionType.CONSTRUCTOR
def _analyze_attributes(self): def _analyze_attributes(self) -> None:
if self.is_compact_ast: if self.is_compact_ast:
attributes = self._functionNotParsed attributes = self._functionNotParsed
else: else:
@ -1018,7 +1019,7 @@ class FunctionSolc(CallerContextExpression):
return node return node
def _parse_block(self, block: Dict, node: NodeSolc, check_arithmetic: bool = False): def _parse_block(self, block: Dict, node: NodeSolc, check_arithmetic: bool = False) -> NodeSolc:
""" """
Return: Return:
Node Node
@ -1053,7 +1054,7 @@ class FunctionSolc(CallerContextExpression):
node = self._parse_statement(statement, node, new_scope) node = self._parse_statement(statement, node, new_scope)
return node return node
def _parse_cfg(self, cfg: Dict): def _parse_cfg(self, cfg: Dict) -> None:
assert cfg[self.get_key()] == "Block" assert cfg[self.get_key()] == "Block"
@ -1118,7 +1119,7 @@ class FunctionSolc(CallerContextExpression):
return None return None
def _fix_break_node(self, node: Node): def _fix_break_node(self, node: Node) -> None:
end_node = self._find_end_loop(node, [], 0) end_node = self._find_end_loop(node, [], 0)
if not end_node: if not end_node:
@ -1134,7 +1135,7 @@ class FunctionSolc(CallerContextExpression):
node.set_sons([end_node]) node.set_sons([end_node])
end_node.add_father(node) end_node.add_father(node)
def _fix_continue_node(self, node: Node): def _fix_continue_node(self, node: Node) -> None:
start_node = self._find_start_loop(node, []) start_node = self._find_start_loop(node, [])
if not start_node: if not start_node:
@ -1145,14 +1146,14 @@ class FunctionSolc(CallerContextExpression):
node.set_sons([start_node]) node.set_sons([start_node])
start_node.add_father(node) start_node.add_father(node)
def _fix_try(self, node: Node): def _fix_try(self, node: Node) -> None:
end_node = next((son for son in node.sons if son.type != NodeType.CATCH), None) end_node = next((son for son in node.sons if son.type != NodeType.CATCH), None)
if end_node: if end_node:
for son in node.sons: for son in node.sons:
if son.type == NodeType.CATCH: if son.type == NodeType.CATCH:
self._fix_catch(son, end_node) self._fix_catch(son, end_node)
def _fix_catch(self, node: Node, end_node: Node): def _fix_catch(self, node: Node, end_node: Node) -> None:
if not node.sons: if not node.sons:
link_nodes(node, end_node) link_nodes(node, end_node)
else: else:

@ -23,7 +23,7 @@ class ModifierSolc(FunctionSolc):
function_data: Dict, function_data: Dict,
contract_parser: "ContractSolc", contract_parser: "ContractSolc",
slither_parser: "SlitherCompilationUnitSolc", slither_parser: "SlitherCompilationUnitSolc",
): ) -> None:
super().__init__(modifier, function_data, contract_parser, slither_parser) super().__init__(modifier, function_data, contract_parser, slither_parser)
# _modifier is equal to _function, but keep it here to prevent # _modifier is equal to _function, but keep it here to prevent
# confusion for mypy in underlying_function # confusion for mypy in underlying_function
@ -33,7 +33,7 @@ class ModifierSolc(FunctionSolc):
def underlying_function(self) -> Modifier: def underlying_function(self) -> Modifier:
return self._modifier return self._modifier
def analyze_params(self): def analyze_params(self) -> None:
# Can be re-analyzed due to inheritance # Can be re-analyzed due to inheritance
if self._params_was_analyzed: if self._params_was_analyzed:
return return
@ -55,7 +55,7 @@ class ModifierSolc(FunctionSolc):
if params: if params:
self._parse_params(params) self._parse_params(params)
def analyze_content(self): def analyze_content(self) -> None:
if self._content_was_analyzed: if self._content_was_analyzed:
return return

Some files were not shown because too many files have changed in this diff Show More

Loading…
Cancel
Save