Merge pull request #1624 from crytic/dev-add-types

Add more types
pull/1665/head
Feist Josselin 2 years ago committed by GitHub
commit 20a79519f3
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 16
      slither/__main__.py
  2. 57
      slither/core/cfg/node.py
  3. 2
      slither/core/cfg/scope.py
  4. 4
      slither/core/children/child_contract.py
  5. 2
      slither/core/children/child_event.py
  6. 9
      slither/core/children/child_expression.py
  7. 4
      slither/core/children/child_inheritance.py
  8. 4
      slither/core/children/child_node.py
  9. 4
      slither/core/children/child_structure.py
  10. 14
      slither/core/compilation_unit.py
  11. 1
      slither/core/declarations/__init__.py
  12. 46
      slither/core/declarations/contract.py
  13. 8
      slither/core/declarations/custom_error.py
  14. 4
      slither/core/declarations/enum.py
  15. 4
      slither/core/declarations/enum_top_level.py
  16. 4
      slither/core/declarations/event.py
  17. 63
      slither/core/declarations/function.py
  18. 8
      slither/core/declarations/function_contract.py
  19. 9
      slither/core/declarations/function_top_level.py
  20. 2
      slither/core/declarations/import_directive.py
  21. 4
      slither/core/declarations/pragma_directive.py
  22. 8
      slither/core/declarations/solidity_import_placeholder.py
  23. 36
      slither/core/declarations/solidity_variables.py
  24. 2
      slither/core/declarations/structure_top_level.py
  25. 4
      slither/core/declarations/using_for_top_level.py
  26. 12
      slither/core/dominators/utils.py
  27. 2
      slither/core/expressions/assignment_operation.py
  28. 6
      slither/core/expressions/call_expression.py
  29. 19
      slither/core/expressions/conditional_expression.py
  30. 5
      slither/core/expressions/elementary_type_name_expression.py
  31. 13
      slither/core/expressions/index_access.py
  32. 2
      slither/core/expressions/literal.py
  33. 4
      slither/core/expressions/member_access.py
  34. 11
      slither/core/expressions/new_array.py
  35. 4
      slither/core/expressions/new_contract.py
  36. 21
      slither/core/expressions/type_conversion.py
  37. 20
      slither/core/expressions/unary_operation.py
  38. 2
      slither/core/scope/scope.py
  39. 14
      slither/core/slither_core.py
  40. 23
      slither/core/solidity_types/array_type.py
  41. 6
      slither/core/solidity_types/elementary_type.py
  42. 6
      slither/core/solidity_types/function_type.py
  43. 16
      slither/core/solidity_types/mapping_type.py
  44. 16
      slither/core/solidity_types/type_alias.py
  45. 7
      slither/core/solidity_types/type_information.py
  46. 10
      slither/core/solidity_types/user_defined_type.py
  47. 2
      slither/core/variables/__init__.py
  48. 2
      slither/core/variables/event_variable.py
  49. 2
      slither/core/variables/local_variable_init_from_tuple.py
  50. 2
      slither/core/variables/state_variable.py
  51. 2
      slither/core/variables/top_level_variable.py
  52. 2
      slither/core/variables/variable.py
  53. 4
      slither/detectors/abstract_detector.py
  54. 7
      slither/detectors/assembly/shift_parameter_mixup.py
  55. 4
      slither/detectors/attributes/const_functions_asm.py
  56. 4
      slither/detectors/attributes/const_functions_state.py
  57. 4
      slither/detectors/attributes/constant_pragma.py
  58. 9
      slither/detectors/attributes/incorrect_solc.py
  59. 7
      slither/detectors/attributes/locked_ether.py
  60. 12
      slither/detectors/attributes/unimplemented_interface.py
  61. 19
      slither/detectors/compiler_bugs/array_by_reference.py
  62. 9
      slither/detectors/compiler_bugs/enum_conversion.py
  63. 5
      slither/detectors/compiler_bugs/multiple_constructor_schemes.py
  64. 9
      slither/detectors/compiler_bugs/public_mapping_nested.py
  65. 18
      slither/detectors/compiler_bugs/reused_base_constructor.py
  66. 12
      slither/detectors/compiler_bugs/storage_ABIEncoderV2_array.py
  67. 4
      slither/detectors/compiler_bugs/storage_signed_integer_array.py
  68. 17
      slither/detectors/compiler_bugs/uninitialized_function_ptr_in_constructor.py
  69. 15
      slither/detectors/erc/erc20/arbitrary_send_erc20.py
  70. 11
      slither/detectors/erc/erc20/incorrect_erc20_interface.py
  71. 12
      slither/detectors/erc/incorrect_erc721_interface.py
  72. 11
      slither/detectors/erc/unindexed_event_parameters.py
  73. 5
      slither/detectors/examples/backdoor.py
  74. 12
      slither/detectors/functions/arbitrary_send_eth.py
  75. 3
      slither/detectors/functions/dead_code.py
  76. 11
      slither/detectors/functions/modifier.py
  77. 3
      slither/detectors/functions/permit_domain_signature_collision.py
  78. 4
      slither/detectors/functions/protected_variable.py
  79. 10
      slither/detectors/functions/suicidal.py
  80. 12
      slither/detectors/functions/unimplemented.py
  81. 15
      slither/detectors/naming_convention/naming_convention.py
  82. 3
      slither/detectors/operations/block_timestamp.py
  83. 14
      slither/detectors/operations/low_level_calls.py
  84. 17
      slither/detectors/operations/missing_events_access_control.py
  85. 20
      slither/detectors/operations/missing_events_arithmetic.py
  86. 25
      slither/detectors/operations/missing_zero_address_validation.py
  87. 3
      slither/detectors/operations/unchecked_low_level_return_values.py
  88. 3
      slither/detectors/operations/unchecked_send_return_value.py
  89. 3
      slither/detectors/operations/unchecked_transfer.py
  90. 15
      slither/detectors/operations/unused_return_values.py
  91. 5
      slither/detectors/operations/void_constructor.py
  92. 9
      slither/detectors/reentrancy/reentrancy_benign.py
  93. 8
      slither/detectors/reentrancy/reentrancy_events.py
  94. 15
      slither/detectors/reentrancy/reentrancy_no_gas.py
  95. 3
      slither/detectors/reentrancy/token.py
  96. 24
      slither/detectors/shadowing/builtin_symbols.py
  97. 33
      slither/detectors/shadowing/local.py
  98. 12
      slither/detectors/shadowing/state.py
  99. 7
      slither/detectors/slither/name_reused.py
  100. 6
      slither/detectors/source/rtlo.py
  101. Some files were not shown because too many files have changed in this diff Show More

@ -25,7 +25,13 @@ from slither.printers import all_printers
from slither.printers.abstract_printer import AbstractPrinter
from slither.slither import Slither
from slither.utils import codex
from slither.utils.output import output_to_json, output_to_zip, output_to_sarif, ZIP_TYPES_ACCEPTED
from slither.utils.output import (
output_to_json,
output_to_zip,
output_to_sarif,
ZIP_TYPES_ACCEPTED,
Output,
)
from slither.utils.output_capture import StandardOutputCapture
from slither.utils.colors import red, set_colorization_enabled
from slither.utils.command_line import (
@ -112,7 +118,7 @@ def _process(
slither: Slither,
detector_classes: List[Type[AbstractDetector]],
printer_classes: List[Type[AbstractPrinter]],
) -> Tuple[Slither, List[Dict], List[Dict], int]:
) -> Tuple[Slither, List[Dict], List[Output], int]:
for detector_cls in detector_classes:
slither.register_detector(detector_cls)
@ -125,9 +131,9 @@ def _process(
results_printers = []
if not printer_classes:
detector_results = slither.run_detectors()
detector_results = [x for x in detector_results if x] # remove empty results
detector_results = [item for sublist in detector_results for item in sublist] # flatten
detector_resultss = slither.run_detectors()
detector_resultss = [x for x in detector_resultss if x] # remove empty results
detector_results = [item for sublist in detector_resultss for item in sublist] # flatten
results_detectors.extend(detector_results)
else:

@ -4,16 +4,19 @@
from enum import Enum
from typing import Optional, List, Set, Dict, Tuple, Union, TYPE_CHECKING
from slither.all_exceptions import SlitherException
from slither.core.children.child_function import ChildFunction
from slither.core.declarations import Contract, Function
from slither.core.declarations.solidity_variables import (
SolidityVariable,
SolidityFunction,
)
from slither.core.expressions.expression import Expression
from slither.core.solidity_types import ElementaryType
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.variable import Variable
from slither.core.solidity_types import ElementaryType
from slither.slithir.convert import convert_expression
from slither.slithir.operations import (
HighLevelCall,
@ -38,10 +41,6 @@ from slither.slithir.variables import (
TemporaryVariable,
TupleVariable,
)
from slither.all_exceptions import SlitherException
from slither.core.declarations import Contract, Function
from slither.core.expressions.expression import Expression
if TYPE_CHECKING:
from slither.slithir.variables.variable import SlithIRVariable
@ -119,7 +118,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
node_id: int,
scope: Union["Scope", "Function"],
file_scope: "FileScope",
):
) -> None:
super().__init__()
self._node_type = node_type
@ -474,11 +473,11 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
"""
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
self._expression = expression
def add_variable_declaration(self, var: LocalVariable):
def add_variable_declaration(self, var: LocalVariable) -> None:
assert self._variable_declaration is None
self._variable_declaration = var
if var.expression:
@ -511,7 +510,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
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
Returns:
@ -521,7 +520,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
return self.type in [NodeType.IF, NodeType.IFLOOP]
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
A conditional node is either a IF or a require/assert or a RETURN bool
@ -550,7 +549,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
def inline_asm(self) -> Optional[Union[str, Dict]]:
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
# endregion
@ -560,7 +559,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
Args:
@ -585,7 +584,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
"""
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
Args:
@ -593,7 +592,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]
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
Args:
@ -601,7 +600,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]
def add_son(self, son: "Node"):
def add_son(self, son: "Node") -> None:
"""Add a son node
Args:
@ -609,7 +608,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
"""
self._sons.append(son)
def set_sons(self, sons: List["Node"]):
def set_sons(self, sons: List["Node"]) -> None:
"""Set the son nodes
Args:
@ -667,14 +666,14 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
def irs_ssa(self, 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
"""
ir.set_node(self)
self._irs_ssa.append(ir)
def slithir_generation(self):
def slithir_generation(self) -> None:
if self.expression:
expression = self.expression
self._irs = convert_expression(expression, self)
@ -691,11 +690,11 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
return self._all_slithir_operations
@staticmethod
def _is_non_slithir_var(var: Variable):
def _is_non_slithir_var(var: Variable) -> bool:
return not isinstance(var, (Constant, ReferenceVariable, TemporaryVariable, TupleVariable))
@staticmethod
def _is_valid_slithir_var(var: Variable):
def _is_valid_slithir_var(var: Variable) -> bool:
return isinstance(var, (ReferenceVariable, TemporaryVariable, TupleVariable))
# endregion
@ -746,7 +745,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
self._dominance_frontier = doms
@property
def dominator_successors(self):
def dominator_successors(self) -> Set["Node"]:
return self._dom_successors
@property
@ -788,14 +787,14 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
# def phi_origin_member_variables(self) -> Dict[str, Tuple[MemberVariable, Set["Node"]]]:
# 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:
self._phi_origins_local_variables[variable.name] = (variable, set())
(v, nodes) = self._phi_origins_local_variables[variable.name]
assert v == variable
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:
self._phi_origins_state_variables[variable.canonical_name] = (
variable,
@ -819,7 +818,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:
@ -895,7 +894,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
self._low_level_calls = list(set(self._low_level_calls))
@staticmethod
def _convert_ssa(v: Variable):
def _convert_ssa(v: Variable) -> Optional[Union[StateVariable, LocalVariable]]:
if isinstance(v, StateIRVariable):
contract = v.contract
non_ssa_var = contract.get_state_variable_from_name(v.name)
@ -905,7 +904,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
non_ssa_var = function.get_local_variable_from_name(v.name)
return non_ssa_var
def update_read_write_using_ssa(self):
def update_read_write_using_ssa(self) -> None:
if not self.expression:
return
for ir in self.irs_ssa:
@ -969,7 +968,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
###################################################################################
###################################################################################
def __str__(self):
def __str__(self) -> str:
additional_info = ""
if self.expression:
additional_info += " " + str(self.expression)
@ -987,12 +986,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)
node2.add_father(node1)
def insert_node(origin: Node, node_inserted: Node):
def insert_node(origin: Node, node_inserted: Node) -> None:
sons = origin.sons
link_nodes(origin, node_inserted)
for son in sons:

@ -7,7 +7,7 @@ if TYPE_CHECKING:
# pylint: disable=too-few-public-methods
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.is_checked = is_checked
self.is_yul = is_yul

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

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

@ -1,17 +1,18 @@
from typing import TYPE_CHECKING
from typing import TYPE_CHECKING, Union
if TYPE_CHECKING:
from slither.core.expressions.expression import Expression
from slither.slithir.operations import Operation
class ChildExpression:
def __init__(self):
def __init__(self) -> None:
super().__init__()
self._expression = None
def set_expression(self, expression: "Expression"):
def set_expression(self, expression: Union["Expression", "Operation"]) -> None:
self._expression = expression
@property
def expression(self) -> "Expression":
def expression(self) -> Union["Expression", "Operation"]:
return self._expression

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

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

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

@ -16,10 +16,10 @@ from slither.core.declarations import (
from slither.core.declarations.custom_error import CustomError
from slither.core.declarations.enum_top_level import EnumTopLevel
from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.using_for_top_level import UsingForTopLevel
from slither.core.declarations.structure_top_level import StructureTopLevel
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
from slither.core.declarations.using_for_top_level import UsingForTopLevel
from slither.core.scope.scope import FileScope
from slither.core.solidity_types.type_alias import TypeAliasTopLevel
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.top_level_variable import TopLevelVariable
from slither.slithir.operations import InternalCall
@ -31,7 +31,7 @@ if TYPE_CHECKING:
# pylint: disable=too-many-instance-attributes,too-many-public-methods
class SlitherCompilationUnit(Context):
def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit):
def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit) -> None:
super().__init__()
self._core = core
@ -150,21 +150,21 @@ class SlitherCompilationUnit(Context):
def functions(self) -> List[Function]:
return list(self._all_functions)
def add_function(self, func: Function):
def add_function(self, func: Function) -> None:
self._all_functions.add(func)
@property
def modifiers(self) -> List[Modifier]:
return list(self._all_modifiers)
def add_modifier(self, modif: Modifier):
def add_modifier(self, modif: Modifier) -> None:
self._all_modifiers.add(modif)
@property
def functions_and_modifiers(self) -> List[Function]:
return self.functions + self.modifiers
def propagate_function_calls(self):
def propagate_function_calls(self) -> None:
for f in self.functions_and_modifiers:
for node in f.nodes:
for ir in node.irs_ssa:
@ -256,7 +256,7 @@ class SlitherCompilationUnit(Context):
###################################################################################
###################################################################################
def compute_storage_layout(self):
def compute_storage_layout(self) -> None:
for contract in self.contracts_derived:
self._storage_layouts[contract.name] = {}

@ -17,3 +17,4 @@ from .structure_contract import StructureContract
from .structure_top_level import StructureTopLevel
from .function_contract import FunctionContract
from .function_top_level import FunctionTopLevel
from .custom_error_contract import CustomErrorContract

@ -4,7 +4,7 @@
import logging
from collections import defaultdict
from pathlib import Path
from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union, Set
from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union, Set, Any
from crytic_compile.platform import Type as PlatformType
@ -38,13 +38,13 @@ if TYPE_CHECKING:
EnumContract,
StructureContract,
FunctionContract,
CustomErrorContract,
)
from slither.slithir.variables.variable import SlithIRVariable
from slither.core.variables.variable import Variable
from slither.core.variables.state_variable import StateVariable
from slither.core.variables import Variable, StateVariable
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations.custom_error_contract import CustomErrorContract
from slither.core.scope.scope import FileScope
from slither.core.cfg.node import Node
LOGGER = logging.getLogger("Contract")
@ -55,7 +55,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
Contract class
"""
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"):
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__()
self._name: Optional[str] = None
@ -366,7 +366,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
"""
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
@property
@ -534,7 +534,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def add_function(self, func: "FunctionContract"):
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
@ -578,7 +578,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
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}
def set_modifiers(self, modifiers: Dict[str, "Modifier"]):
def set_modifiers(self, modifiers: Dict[str, "Modifier"]) -> None:
"""
Set the modifiers
@ -688,7 +688,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
inheritance: List["Contract"],
immediate_inheritance: List["Contract"],
called_base_constructor_contracts: List["Contract"],
):
) -> None:
self._inheritance = inheritance
self._immediate_inheritance = immediate_inheritance
self._explicit_base_constructor_calls = called_base_constructor_contracts
@ -803,23 +803,25 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
"""
return next((v for v in self.state_variables if v.name == canonical_name), None)
def get_structure_from_name(self, structure_name: str) -> Optional["Structure"]:
def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]:
"""
Return a structure from a name
Args:
structure_name (str): name of the structure
Returns:
Structure
StructureContract
"""
return next((st for st in self.structures if st.name == structure_name), None)
def get_structure_from_canonical_name(self, structure_name: str) -> Optional["Structure"]:
def get_structure_from_canonical_name(
self, structure_name: str
) -> Optional["StructureContract"]:
"""
Return a structure from a canonical name
Args:
structure_name (str): canonical name of the structure
Returns:
Structure
StructureContract
"""
return next((st for st in self.structures if st.canonical_name == structure_name), None)
@ -1216,7 +1218,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:
function.update_read_write_using_ssa()
@ -1311,7 +1313,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def is_incorrectly_constructed(self, incorrect: bool):
self._is_incorrectly_parsed = incorrect
def add_constructor_variables(self):
def add_constructor_variables(self) -> None:
from slither.core.declarations.function_contract import FunctionContract
if self.state_variables:
@ -1380,7 +1382,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
def _create_node(
self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]
):
) -> "Node":
from slither.core.cfg.node import Node, NodeType
from slither.core.expressions import (
AssignmentOperationType,
@ -1412,7 +1414,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
@ -1437,7 +1439,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
for func in self.functions + self.modifiers:
func.generate_slithir_ssa(all_ssa_state_variables_instances)
def fix_phi(self):
def fix_phi(self) -> None:
last_state_variables_instances = {}
initial_state_variables_instances = {}
for v in self._initial_state_variables:
@ -1459,20 +1461,20 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
###################################################################################
###################################################################################
def __eq__(self, other):
def __eq__(self, other: SourceMapping) -> bool:
if isinstance(other, str):
return other == self.name
return NotImplemented
def __neq__(self, other):
def __neq__(self, other: Any) -> bool:
if isinstance(other, str):
return other != self.name
return NotImplemented
def __str__(self):
def __str__(self) -> str:
return self.name
def __hash__(self):
def __hash__(self) -> int:
return self._id
# endregion

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class CustomError(SourceMapping):
def __init__(self, compilation_unit: "SlitherCompilationUnit"):
def __init__(self, compilation_unit: "SlitherCompilationUnit") -> None:
super().__init__()
self._name: str = ""
self._parameters: List[LocalVariable] = []
@ -30,7 +30,7 @@ class CustomError(SourceMapping):
def parameters(self) -> List[LocalVariable]:
return self._parameters
def add_parameters(self, p: "LocalVariable"):
def add_parameters(self, p: "LocalVariable") -> None:
self._parameters.append(p)
@property
@ -42,7 +42,7 @@ class CustomError(SourceMapping):
###################################################################################
@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
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

@ -4,7 +4,7 @@ from slither.core.source_mapping.source_mapping import 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__()
self._name = name
self._canonical_name = canonical_name
@ -33,5 +33,5 @@ class Enum(SourceMapping):
def max(self) -> int:
return self._max
def __str__(self):
def __str__(self) -> str:
return self.name

@ -8,6 +8,8 @@ if TYPE_CHECKING:
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)
self.file_scope: "FileScope" = scope

@ -9,7 +9,7 @@ if TYPE_CHECKING:
class Event(ChildContract, SourceMapping):
def __init__(self):
def __init__(self) -> None:
super().__init__()
self._name = None
self._elems: List[EventVariable] = []
@ -59,5 +59,5 @@ class Event(ChildContract, SourceMapping):
"""
return self.contract == contract
def __str__(self):
def __str__(self) -> str:
return self.name

@ -6,7 +6,7 @@ from abc import abstractmethod, ABCMeta
from collections import namedtuple
from enum import Enum
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.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.utils import unroll
# pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines
if TYPE_CHECKING:
@ -45,6 +46,8 @@ if TYPE_CHECKING:
from slither.slithir.operations import Operation
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
from slither.core.declarations.function_contract import FunctionContract
LOGGER = logging.getLogger("Function")
ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"])
@ -56,7 +59,7 @@ class ModifierStatements:
modifier: Union["Contract", "Function"],
entry_point: "Node",
nodes: List["Node"],
):
) -> None:
self._modifier = modifier
self._entry_point = entry_point
self._nodes = nodes
@ -116,7 +119,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
Function class
"""
def __init__(self, compilation_unit: "SlitherCompilationUnit"):
def __init__(self, compilation_unit: "SlitherCompilationUnit") -> None:
super().__init__()
self._internal_scope: List[str] = []
self._name: Optional[str] = None
@ -295,7 +298,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def contains_assembly(self, c: bool):
self._contains_assembly = c
def can_reenter(self, callstack=None) -> bool:
def can_reenter(self, callstack: Optional[List["FunctionContract"]] = None) -> bool:
"""
Check if the function can re-enter
Follow internal calls.
@ -370,7 +373,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)
self._function_type = t
@ -455,7 +458,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def visibility(self, v: str):
self._visibility = v
def set_visibility(self, v: str):
def set_visibility(self, v: str) -> None:
self._visibility = v
@property
@ -554,7 +557,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def entry_point(self, node: "Node"):
self._entry_point = node
def add_node(self, node: "Node"):
def add_node(self, node: "Node") -> None:
if not self._entry_point:
self._entry_point = node
self._nodes.append(node)
@ -598,7 +601,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
"""
return list(self._parameters)
def add_parameters(self, p: "LocalVariable"):
def add_parameters(self, p: "LocalVariable") -> None:
self._parameters.append(p)
@property
@ -608,7 +611,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
"""
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)
def parameters_src(self) -> SourceMapping:
@ -651,7 +654,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
"""
return list(self._returns)
def add_return(self, r: "LocalVariable"):
def add_return(self, r: "LocalVariable") -> None:
self._returns.append(r)
@property
@ -661,7 +664,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
"""
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)
# endregion
@ -680,7 +683,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
"""
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)
@property
@ -714,7 +717,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.
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)
# endregion
@ -1057,7 +1060,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
self._all_reachable_from_functions = 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_functions.add(n.function)
@ -1068,7 +1071,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)
explored = [self]
to_explore = [
@ -1218,11 +1221,13 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
func: "Function",
f: Callable[["Node"], List[SolidityVariable]],
include_loop: bool,
):
) -> List[Any]:
ret = [f(n) for n in func.nodes if n.is_conditional(include_loop)]
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
@ -1258,7 +1263,9 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return [var for var in ret if isinstance(var, SolidityVariable)]
@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]
return [item for sublist in ret for item in sublist]
@ -1367,7 +1374,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
with open(filename, "w", encoding="utf8") as f:
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
:return: the DOT content
@ -1512,7 +1519,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/..."""
write_var = [x.variables_written_as_expression for x in self.nodes]
write_var = [x for x in write_var if x]
@ -1570,7 +1577,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
slithir_variables = [x for x in slithir_variables if x]
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 for x in calls if x]
calls = [item for sublist in calls for item in sublist]
@ -1702,7 +1709,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return self._get_last_ssa_variable_instances(target_state=False, target_local=True)
@staticmethod
def _unchange_phi(ir: "Operation"):
def _unchange_phi(ir: "Operation") -> bool:
from slither.slithir.operations import Phi, PhiCallback
if not isinstance(ir, (Phi, PhiCallback)) or len(ir.rvalues) > 1:
@ -1711,7 +1718,11 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
return True
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, List["StateIRVariable"]],
initial_state_variables_instances: Dict[str, "StateIRVariable"],
) -> None:
from slither.slithir.operations import InternalCall, PhiCallback
from slither.slithir.variables import Constant, StateIRVariable
@ -1745,7 +1756,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)]
def generate_slithir_and_analyze(self):
def generate_slithir_and_analyze(self) -> None:
for node in self.nodes:
node.slithir_generation()
@ -1756,7 +1767,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
def generate_slithir_ssa(self, all_ssa_state_variables_instances):
pass
def update_read_write_using_ssa(self):
def update_read_write_using_ssa(self) -> None:
for node in self.nodes:
node.update_read_write_using_ssa()
self._analyze_read_write()
@ -1767,7 +1778,7 @@ class Function(SourceMapping, metaclass=ABCMeta): # pylint: disable=too-many-pu
###################################################################################
###################################################################################
def __str__(self):
def __str__(self) -> str:
return self.name
# endregion

@ -1,17 +1,19 @@
"""
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_inheritance import ChildInheritance
from slither.core.declarations import Function
# pylint: disable=import-outside-toplevel,too-many-instance-attributes,too-many-statements,too-many-lines
if TYPE_CHECKING:
from slither.core.declarations import Contract
from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
class FunctionContract(Function, ChildContract, ChildInheritance):
@ -96,7 +98,9 @@ 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.core.dominators.utils import (
compute_dominance_frontier,

@ -1,7 +1,7 @@
"""
Function module
"""
from typing import List, Tuple, TYPE_CHECKING
from typing import Dict, List, Tuple, TYPE_CHECKING
from slither.core.declarations import Function
from slither.core.declarations.top_level import TopLevel
@ -9,10 +9,11 @@ from slither.core.declarations.top_level import TopLevel
if TYPE_CHECKING:
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.scope.scope import FileScope
from slither.slithir.variables.state_variable import StateIRVariable
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)
self._scope: "FileScope" = scope
@ -78,7 +79,9 @@ 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[str, "StateIRVariable"]
) -> None:
# pylint: disable=import-outside-toplevel
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import (

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

@ -7,7 +7,7 @@ if TYPE_CHECKING:
class Pragma(SourceMapping):
def __init__(self, directive: List[str], scope: "FileScope"):
def __init__(self, directive: List[str], scope: "FileScope") -> None:
super().__init__()
self._directive = directive
self.scope: "FileScope" = scope
@ -39,5 +39,5 @@ class Pragma(SourceMapping):
return self._directive[0] == "experimental" and self._directive[1] == "ABIEncoderV2"
return False
def __str__(self):
def __str__(self) -> str:
return "pragma " + "".join(self.directive)

@ -1,7 +1,11 @@
"""
Special variable to model import with renaming
"""
from typing import Union
from slither.core.declarations import Import
from slither.core.declarations.contract import Contract
from slither.core.declarations.solidity_variables import SolidityVariable
from slither.core.solidity_types import ElementaryType
from slither.core.variables.variable import Variable
@ -13,7 +17,7 @@ class SolidityImportPlaceHolder(Variable):
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__()
assert import_directive.alias is not None
self._import_directive = import_directive
@ -27,7 +31,7 @@ class SolidityImportPlaceHolder(Variable):
def type(self) -> ElementaryType:
return ElementaryType("string")
def __eq__(self, other):
def __eq__(self, other: Union[Contract, SolidityVariable]) -> bool:
return (
self.__class__ == other.__class__
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
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.solidity_types import ElementaryType, TypeInformation
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.exceptions import SlitherException
if TYPE_CHECKING:
pass
SOLIDITY_VARIABLES = {
"now": "uint256",
@ -98,13 +96,13 @@ def solidity_function_signature(name):
class SolidityVariable(SourceMapping):
def __init__(self, name: str):
def __init__(self, name: str) -> None:
super().__init__()
self._check_name(name)
self._name = name
# 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"))
@property
@ -124,18 +122,18 @@ class SolidityVariable(SourceMapping):
def type(self) -> ElementaryType:
return ElementaryType(SOLIDITY_VARIABLES[self.name])
def __str__(self):
def __str__(self) -> str:
return self._name
def __eq__(self, other):
def __eq__(self, other: SourceMapping) -> bool:
return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self):
def __hash__(self) -> int:
return hash(self.name)
class SolidityVariableComposed(SolidityVariable):
def _check_name(self, name: str):
def _check_name(self, name: str) -> None:
assert name in SOLIDITY_VARIABLES_COMPOSED
@property
@ -146,13 +144,13 @@ class SolidityVariableComposed(SolidityVariable):
def type(self) -> ElementaryType:
return ElementaryType(SOLIDITY_VARIABLES_COMPOSED[self.name])
def __str__(self):
def __str__(self) -> str:
return self._name
def __eq__(self, other):
def __eq__(self, other: Any) -> bool:
return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self):
def __hash__(self) -> int:
return hash(self.name)
@ -162,7 +160,7 @@ class SolidityFunction(SourceMapping):
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
# As a result, we set return_type during the Ir conversion
def __init__(self, name: str):
def __init__(self, name: str) -> None:
super().__init__()
assert name in SOLIDITY_FUNCTIONS
self._name = name
@ -187,28 +185,28 @@ class SolidityFunction(SourceMapping):
def return_type(self, r: List[Union[TypeInformation, ElementaryType]]):
self._return_type = r
def __str__(self):
def __str__(self) -> str:
return self._name
def __eq__(self, other):
def __eq__(self, other: "SolidityFunction") -> bool:
return self.__class__ == other.__class__ and self.name == other.name
def __hash__(self):
def __hash__(self) -> int:
return hash(self.name)
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._custom_error = custom_error
self._return_type: List[Union[TypeInformation, ElementaryType]] = []
def __eq__(self, other):
def __eq__(self, other: Union["SolidityCustomRevert", SolidityFunction]) -> bool:
return (
self.__class__ == other.__class__
and self.name == other.name
and self._custom_error == other._custom_error
)
def __hash__(self):
def __hash__(self) -> int:
return hash(hash(self.name) + hash(self._custom_error))

@ -9,6 +9,6 @@ if TYPE_CHECKING:
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)
self.file_scope: "FileScope" = scope

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

@ -1,4 +1,4 @@
from typing import List, TYPE_CHECKING
from typing import Set, List, TYPE_CHECKING
from slither.core.cfg.node import NodeType
@ -6,7 +6,7 @@ if TYPE_CHECKING:
from slither.core.cfg.node import Node
def intersection_predecessor(node: "Node"):
def intersection_predecessor(node: "Node") -> Set["Node"]:
if not node.fathers:
return set()
ret = node.fathers[0].dominators
@ -15,7 +15,7 @@ def intersection_predecessor(node: "Node"):
return ret
def _compute_dominators(nodes: List["Node"]):
def _compute_dominators(nodes: List["Node"]) -> None:
changed = True
while changed:
@ -28,7 +28,7 @@ def _compute_dominators(nodes: List["Node"]):
changed = True
def _compute_immediate_dominators(nodes: List["Node"]):
def _compute_immediate_dominators(nodes: List["Node"]) -> None:
for node in nodes:
idom_candidates = set(node.dominators)
idom_candidates.remove(node)
@ -58,7 +58,7 @@ def _compute_immediate_dominators(nodes: List["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
See 'A Simple,Fast Dominance Algorithm'
@ -74,7 +74,7 @@ def compute_dominators(nodes: List["Node"]):
_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
See 'A Simple,Fast Dominance Algorithm'

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

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

@ -1,10 +1,23 @@
from typing import List
from typing import Union, List
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):
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(then_expression, Expression)
assert isinstance(else_expression, Expression)

@ -3,10 +3,11 @@
"""
from slither.core.expressions.expression import Expression
from slither.core.solidity_types.type import Type
from slither.core.solidity_types.elementary_type import ElementaryType
class ElementaryTypeNameExpression(Expression):
def __init__(self, t):
def __init__(self, t: ElementaryType) -> None:
assert isinstance(t, Type)
super().__init__()
self._type = t
@ -20,5 +21,5 @@ class ElementaryTypeNameExpression(Expression):
assert isinstance(new_type, Type)
self._type = new_type
def __str__(self):
def __str__(self) -> str:
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.identifier import Identifier
from slither.core.expressions.literal import Literal
if TYPE_CHECKING:
@ -9,7 +11,12 @@ if TYPE_CHECKING:
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__()
self._expressions = [left_expression, right_expression]
# TODO type of undexAccess is not always a Type
@ -32,5 +39,5 @@ class IndexAccess(ExpressionTyped):
def type(self) -> "Type":
return self._type
def __str__(self):
def __str__(self) -> str:
return str(self.expression_left) + "[" + str(self.expression_right) + "]"

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

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

@ -1,11 +1,20 @@
from typing import Union, TYPE_CHECKING
from slither.core.expressions.expression import Expression
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):
# 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__()
assert isinstance(array_type, Type)
self._depth: int = depth

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

@ -1,10 +1,27 @@
from typing import Union, TYPE_CHECKING
from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression
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):
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__()
assert isinstance(expression, Expression)
assert isinstance(expression_type, Type)
@ -15,5 +32,5 @@ class TypeConversion(ExpressionTyped):
def expression(self) -> Expression:
return self._expression
def __str__(self):
def __str__(self) -> str:
return str(self.type) + "(" + str(self.expression) + ")"

@ -1,9 +1,15 @@
import logging
from typing import Union
from enum import Enum
from slither.core.expressions.expression_typed import ExpressionTyped
from slither.core.expressions.expression import Expression
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
logger = logging.getLogger("UnaryOperation")
@ -20,7 +26,7 @@ class UnaryOperationType(Enum):
MINUS_PRE = 8 # for stuff like uint(-1)
@staticmethod
def get_type(operation_type, isprefix):
def get_type(operation_type: str, isprefix: bool) -> "UnaryOperationType":
if isprefix:
if operation_type == "!":
return UnaryOperationType.BANG
@ -43,7 +49,7 @@ class UnaryOperationType(Enum):
return UnaryOperationType.MINUSMINUS_POST
raise SlitherCoreError(f"get_type: Unknown operation type {operation_type}")
def __str__(self):
def __str__(self) -> str:
if self == UnaryOperationType.BANG:
return "!"
if self == UnaryOperationType.TILD:
@ -65,7 +71,7 @@ class UnaryOperationType(Enum):
raise SlitherCoreError(f"str: Unknown operation type {self}")
@staticmethod
def is_prefix(operation_type):
def is_prefix(operation_type: "UnaryOperationType") -> bool:
if operation_type in [
UnaryOperationType.BANG,
UnaryOperationType.TILD,
@ -86,7 +92,11 @@ class UnaryOperationType(Enum):
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)
super().__init__()
self._expression: Expression = expression
@ -114,7 +124,7 @@ class UnaryOperation(ExpressionTyped):
def is_prefix(self) -> bool:
return UnaryOperationType.is_prefix(self._type)
def __str__(self):
def __str__(self) -> str:
if self.is_prefix:
return str(self.type) + " " + str(self._expression)
return str(self._expression) + " " + str(self.type)

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

@ -8,7 +8,7 @@ import pathlib
import posixpath
import re
from collections import defaultdict
from typing import Optional, Dict, List, Set, Union
from typing import Optional, Dict, List, Set, Union, Tuple
from crytic_compile import CryticCompile
from crytic_compile.utils.naming import Filename
@ -40,7 +40,7 @@ class SlitherCore(Context):
Slither static analyzer
"""
def __init__(self):
def __init__(self) -> None:
super().__init__()
self._filename: Optional[str] = None
@ -73,8 +73,8 @@ class SlitherCore(Context):
# Maps from file to detector name to the start/end ranges for that detector.
# Infinity is used to signal a detector has no end range.
self._ignore_ranges: defaultdict[str, defaultdict[str, List[(int, int)]]] = defaultdict(
lambda: defaultdict(lambda: [])
self._ignore_ranges: Dict[str, Dict[str, List[Tuple[int, ...]]]] = defaultdict(
lambda: defaultdict(lambda: [(-1, -1)])
)
self._compilation_units: List[SlitherCompilationUnit] = []
@ -443,7 +443,7 @@ class SlitherCore(Context):
return True
def load_previous_results(self):
def load_previous_results(self) -> None:
filename = self._previous_results_filename
try:
if os.path.isfile(filename):
@ -456,7 +456,7 @@ class SlitherCore(Context):
except json.decoder.JSONDecodeError:
logger.error(red(f"Impossible to decode {filename}. Consider removing the file"))
def write_results_to_hide(self):
def write_results_to_hide(self) -> None:
if not self._results_to_hide:
return
filename = self._previous_results_filename
@ -464,7 +464,7 @@ class SlitherCore(Context):
results = self._results_to_hide + self._previous_results
json.dump(results, f)
def save_results_to_hide(self, results: List[Dict]):
def save_results_to_hide(self, results: List[Dict]) -> None:
self._results_to_hide += results
def add_path_to_filter(self, path: str):

@ -1,13 +1,24 @@
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.solidity_types.type import Type
from slither.visitors.expression.constants_folding import ConstantFolding
from slither.core.expressions.literal import Literal
if TYPE_CHECKING:
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):
def __init__(self, t, length):
def __init__(
self,
t: Union["TypeAliasTopLevel", "ArrayType", "FunctionType", "ElementaryType"],
length: Optional[Union["Identifier", Literal, "BinaryOperation", int]],
) -> None:
assert isinstance(t, Type)
if length:
if isinstance(length, int):
@ -56,15 +67,15 @@ class ArrayType(Type):
return elem_size * int(str(self._length_value)), True
return 32, True
def __str__(self):
def __str__(self) -> str:
if self._length:
return str(self._type) + f"[{str(self._length_value)}]"
return str(self._type) + "[]"
def __eq__(self, other):
def __eq__(self, other: Any) -> bool:
if not isinstance(other, ArrayType):
return False
return self._type == other.type and self.length == other.length
def __hash__(self):
def __hash__(self) -> int:
return hash(str(self))

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

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

@ -1,10 +1,18 @@
from typing import Tuple
from typing import Union, Tuple, TYPE_CHECKING
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):
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_to, Type)
super().__init__()
@ -27,7 +35,7 @@ class MappingType(Type):
def is_dynamic(self) -> bool:
return True
def __str__(self):
def __str__(self) -> str:
return f"mapping({str(self._from)} => {str(self._to)})"
def __eq__(self, other):
@ -35,5 +43,5 @@ class MappingType(Type):
return False
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))

@ -2,7 +2,7 @@ from typing import TYPE_CHECKING, Tuple
from slither.core.children.child_contract import ChildContract
from slither.core.declarations.top_level import TopLevel
from slither.core.solidity_types import Type
from slither.core.solidity_types import Type, ElementaryType
if TYPE_CHECKING:
from slither.core.declarations import Contract
@ -10,13 +10,13 @@ if TYPE_CHECKING:
class TypeAlias(Type):
def __init__(self, underlying_type: Type, name: str):
def __init__(self, underlying_type: ElementaryType, name: str) -> None:
super().__init__()
self.name = name
self.underlying_type = underlying_type
@property
def type(self) -> Type:
def type(self) -> ElementaryType:
"""
Return the underlying type. Alias for underlying_type
@ -31,7 +31,7 @@ class TypeAlias(Type):
def storage_size(self) -> Tuple[int, bool]:
return self.underlying_type.storage_size
def __hash__(self):
def __hash__(self) -> int:
return hash(str(self))
@property
@ -40,18 +40,18 @@ class TypeAlias(Type):
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)
self.file_scope: "FileScope" = scope
def __str__(self):
def __str__(self) -> str:
return self.name
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)
self._contract: "Contract" = contract
def __str__(self):
def __str__(self) -> str:
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.type import Type
if TYPE_CHECKING:
from slither.core.declarations.contract import Contract
from slither.core.declarations.enum import Enum
# Use to model the Type(X) function, which returns an undefined type
# https://solidity.readthedocs.io/en/latest/units-and-global-variables.html#type-information
class TypeInformation(Type):
def __init__(self, c):
def __init__(self, c: Union[ElementaryType, "Contract", "Enum"]) -> None:
# pylint: disable=import-outside-toplevel
from slither.core.declarations.contract import Contract
from slither.core.declarations.enum import Enum
@ -20,7 +21,7 @@ class TypeInformation(Type):
self._type = c
@property
def type(self) -> "Contract":
def type(self) -> Union["Contract", ElementaryType, "Enum"]:
return self._type
@property

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

@ -0,0 +1,2 @@
from .state_variable import StateVariable
from .variable import Variable

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

@ -13,7 +13,7 @@ class LocalVariableInitFromTuple(LocalVariable):
"""
def __init__(self):
def __init__(self) -> None:
super().__init__()
self._tuple_index: Optional[int] = None

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

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

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

@ -5,9 +5,9 @@ from typing import Optional, List, TYPE_CHECKING, Dict, Union, Callable
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations import Contract
from slither.utils.colors import green, yellow, red
from slither.formatters.exceptions import FormatImpossible
from slither.formatters.utils.patches import apply_patch, create_diff
from slither.utils.colors import green, yellow, red
from slither.utils.comparable_enum import ComparableEnum
from slither.utils.output import Output, SupportedOutput
@ -81,7 +81,7 @@ class AbstractDetector(metaclass=abc.ABCMeta):
def __init__(
self, compilation_unit: SlitherCompilationUnit, slither: "Slither", logger: Logger
):
) -> None:
self.compilation_unit: SlitherCompilationUnit = compilation_unit
self.contracts: List[Contract] = compilation_unit.contracts
self.slither: "Slither" = slither

@ -1,6 +1,9 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import Binary, BinaryType
from slither.slithir.variables import Constant
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class ShiftParameterMixup(AbstractDetector):
@ -36,7 +39,7 @@ The shift statement will right-shift the constant 8 by `a` bits"""
WIKI_RECOMMENDATION = "Swap the order of parameters."
def _check_function(self, f):
def _check_function(self, f: FunctionContract) -> List[Output]:
results = []
for node in f.nodes:
@ -52,7 +55,7 @@ The shift statement will right-shift the constant 8 by `a` bits"""
results.append(json)
return results
def _detect(self):
def _detect(self) -> List[Output]:
results = []
for c in self.contracts:
for f in c.functions:

@ -2,12 +2,14 @@
Module detecting constant functions
Recursively check the called functions
"""
from typing import List
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
ALL_SOLC_VERSIONS_04,
)
from slither.formatters.attributes.const_functions import custom_format
from slither.utils.output import Output
class ConstantFunctionsAsm(AbstractDetector):
@ -55,7 +57,7 @@ All the calls to `get` revert, breaking Bob's smart contract execution."""
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect the constant function using assembly code
Recursively visit the calls

@ -2,12 +2,14 @@
Module detecting constant functions
Recursively check the called functions
"""
from typing import List
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
ALL_SOLC_VERSIONS_04,
)
from slither.formatters.attributes.const_functions import custom_format
from slither.utils.output import Output
class ConstantFunctionsState(AbstractDetector):
@ -55,7 +57,7 @@ All the calls to `get` revert, breaking Bob's smart contract execution."""
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect the constant function changing the state
Recursively visit the calls

@ -1,9 +1,11 @@
"""
Check that the same pragma is used in all the files
"""
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.formatters.attributes.constant_pragma import custom_format
from slither.utils.output import Output
class ConstantPragma(AbstractDetector):
@ -22,7 +24,7 @@ class ConstantPragma(AbstractDetector):
WIKI_DESCRIPTION = "Detect whether different Solidity versions are used."
WIKI_RECOMMENDATION = "Use one Solidity version."
def _detect(self):
def _detect(self) -> List[Output]:
results = []
pragma = self.compilation_unit.pragma_directives
versions = [p.version for p in pragma if p.is_solidity_version]

@ -3,8 +3,11 @@
"""
import re
from typing import List, Optional, Tuple
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.formatters.attributes.incorrect_solc import custom_format
from slither.utils.output import Output
# group:
# 0: ^ > >= < <= (optional)
@ -83,7 +86,7 @@ Consider using the latest version of Solidity for testing."""
"^0.8.8",
]
def _check_version(self, version):
def _check_version(self, version: Tuple[str, str, str, str, str]) -> Optional[str]:
op = version[0]
if op and op not in [">", ">=", "^"]:
return self.LESS_THAN_TXT
@ -96,7 +99,7 @@ Consider using the latest version of Solidity for testing."""
return self.OLD_VERSION_TXT
return None
def _check_pragma(self, version):
def _check_pragma(self, version: str) -> Optional[str]:
if version in self.BUGGY_VERSIONS:
return self.BUGGY_VERSION_TXT
versions = PATTERN.findall(version)
@ -117,7 +120,7 @@ Consider using the latest version of Solidity for testing."""
return self._check_version(version_left)
return self.COMPLEX_PRAGMA_TXT
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detects pragma statements that allow for outdated solc versions.
:return: Returns the relevant JSON data for the findings.

@ -1,7 +1,9 @@
"""
Check if ethers are locked in the contract
"""
from typing import List
from slither.core.declarations.contract import Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import (
HighLevelCall,
@ -12,6 +14,7 @@ from slither.slithir.operations import (
LibraryCall,
InternalCall,
)
from slither.utils.output import Output
class LockedEther(AbstractDetector): # pylint: disable=too-many-nested-blocks
@ -41,7 +44,7 @@ Every Ether sent to `Locked` will be lost."""
WIKI_RECOMMENDATION = "Remove the payable attribute or add a withdraw function."
@staticmethod
def do_no_send_ether(contract):
def do_no_send_ether(contract: Contract) -> bool:
functions = contract.all_functions_called
to_explore = functions
explored = []
@ -73,7 +76,7 @@ Every Ether sent to `Locked` will be lost."""
return True
def _detect(self):
def _detect(self) -> List[Output]:
results = []
for contract in self.compilation_unit.contracts_derived:

@ -4,8 +4,10 @@ Module detecting unimplemented interfaces
Collect all the interfaces
Check for contracts which implement all interface functions but do not explicitly derive from those interfaces.
"""
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.utils.output import Output
class MissingInheritance(AbstractDetector):
@ -42,7 +44,9 @@ contract Something {
WIKI_RECOMMENDATION = "Inherit from the missing interface or contract."
@staticmethod
def detect_unimplemented_interface(contract, interfaces):
def detect_unimplemented_interface(
contract: Contract, interfaces: List[Contract]
) -> List[Contract]:
"""
Detects if contract intends to implement one of the interfaces but does not explicitly do so by deriving from it
:param contract: The contract to check
@ -50,7 +54,7 @@ contract Something {
:return: Interfaces likely intended to implement by the contract
"""
intended_interfaces = []
intended_interfaces: List[Contract] = []
sigs_contract = {f.full_name for f in contract.functions_entry_points}
if not sigs_contract:
@ -111,7 +115,7 @@ contract Something {
return intended_interfaces
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect unimplemented interfaces
Returns:
list: {'contract'}

@ -1,13 +1,17 @@
"""
Detects the passing of arrays located in memory to functions which expect to modify arrays via storage reference.
"""
from typing import List, Set, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.solidity_types.array_type import ArrayType
from slither.core.variables.state_variable import StateVariable
from slither.core.variables.local_variable import LocalVariable
from slither.slithir.operations.high_level_call import HighLevelCall
from slither.slithir.operations.internal_call import InternalCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class ArrayByReference(AbstractDetector):
@ -55,7 +59,7 @@ As a result, Bob's usage of the contract is incorrect."""
WIKI_RECOMMENDATION = "Ensure the correct usage of `memory` and `storage` in the function parameters. Make all the locations explicit."
@staticmethod
def get_funcs_modifying_array_params(contracts):
def get_funcs_modifying_array_params(contracts: List[Contract]) -> Set[FunctionContract]:
"""
Obtains a set of functions which take arrays not located in storage as parameters, and writes to them.
:param contracts: The collection of contracts to check functions in.
@ -83,7 +87,14 @@ As a result, Bob's usage of the contract is incorrect."""
return results
@staticmethod
def detect_calls_passing_ref_to_function(contracts, array_modifying_funcs):
def detect_calls_passing_ref_to_function(
contracts: List[Contract], array_modifying_funcs: Set[FunctionContract]
) -> List[
Union[
Tuple[Node, StateVariable, FunctionContract],
Tuple[Node, LocalVariable, FunctionContract],
]
]:
"""
Obtains all calls passing storage arrays by value to a function which cannot write to them successfully.
:param contracts: The collection of contracts to check for problematic calls in.
@ -134,7 +145,7 @@ As a result, Bob's usage of the contract is incorrect."""
results.append((node, arg, ir.function))
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detects passing of arrays located in memory to functions which expect to modify arrays via storage reference.
:return: The JSON results of the detector, which contains the calling_node, affected_argument_variable and

@ -1,7 +1,11 @@
"""
Module detecting dangerous conversion to enum
"""
from typing import List, Tuple
from slither.core.cfg.node import Node
from slither.core.declarations import Contract
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
@ -9,9 +13,10 @@ from slither.detectors.abstract_detector import (
)
from slither.slithir.operations import TypeConversion
from slither.core.declarations.enum import Enum
from slither.utils.output import Output
def _detect_dangerous_enum_conversions(contract):
def _detect_dangerous_enum_conversions(contract: Contract) -> List[Tuple[Node, SourceMapping]]:
"""Detect dangerous conversion to enum by checking IR
Args:
contract (Contract)
@ -61,7 +66,7 @@ Attackers can trigger unexpected behaviour by calling `bug(1)`."""
VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 0, 4)
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect dangerous conversion to enum"""
results = []

@ -1,4 +1,7 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class MultipleConstructorSchemes(AbstractDetector):
@ -43,7 +46,7 @@ In Solidity [0.4.22](https://github.com/ethereum/solidity/releases/tag/v0.4.23),
WIKI_RECOMMENDATION = "Only declare one constructor, preferably using the new scheme `constructor(...)` instead of `function <contractName>(...)`."
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detect multiple constructor schemes in the same contract
:return: Returns a list of contract JSON result, where each result contains all constructor definitions.

@ -1,7 +1,7 @@
"""
Module detecting public mappings with nested variables (returns incorrect values prior to 0.5.x)
"""
from typing import Any, List, Union
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
@ -10,9 +10,12 @@ from slither.detectors.abstract_detector import (
from slither.core.solidity_types.mapping_type import MappingType
from slither.core.solidity_types.user_defined_type import UserDefinedType
from slither.core.declarations.structure import Structure
from slither.core.declarations.contract import Contract
from slither.core.variables.state_variable import StateVariable
from slither.utils.output import Output
def detect_public_nested_mappings(contract):
def detect_public_nested_mappings(contract: Contract) -> List[Union[StateVariable, Any]]:
"""
Detect any state variables that are initialized from an immediate function call (prior to constructor run).
:param contract: The contract to detect state variable definitions for.
@ -68,7 +71,7 @@ class PublicMappingNested(AbstractDetector):
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detect public mappings with nested variables (returns incorrect values prior to 0.5.x)

@ -1,18 +1,24 @@
"""
Module detecting re-used base constructors in inheritance hierarchy.
"""
from typing import Any, Dict, List, Tuple, Union
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
ALL_SOLC_VERSIONS_04,
)
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
# Helper: adds explicitly called constructors with arguments to the results lookup.
def _add_constructors_with_args(
base_constructors, called_by_constructor, current_contract, results
):
base_constructors: List[Union[Any, FunctionContract]],
called_by_constructor: bool,
current_contract: Contract,
results: Dict[FunctionContract, List[Tuple[Contract, bool]]],
) -> None:
for explicit_base_constructor in base_constructors:
if len(explicit_base_constructor.parameters) > 0:
if explicit_base_constructor not in results:
@ -77,7 +83,9 @@ The constructor of `A` is called multiple times in `D` and `E`:
VULNERABLE_SOLC_VERSIONS = ALL_SOLC_VERSIONS_04
def _detect_explicitly_called_base_constructors(self, contract):
def _detect_explicitly_called_base_constructors(
self, contract: Contract
) -> Dict[FunctionContract, List[Tuple[Contract, bool]]]:
"""
Detects explicitly calls to base constructors with arguments in the inheritance hierarchy.
:param contract: The contract to detect explicit calls to a base constructor with arguments to.
@ -124,7 +132,7 @@ The constructor of `A` is called multiple times in `D` and `E`:
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detect reused base constructors.
:return: Returns a list of JSON results.

@ -1,7 +1,7 @@
"""
Module detecting ABIEncoderV2 array bug
"""
from typing import List, Set, Tuple
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
@ -16,6 +16,10 @@ from slither.core.declarations.solidity_variables import SolidityFunction
from slither.slithir.operations import EventCall
from slither.slithir.operations import HighLevelCall
from slither.utils.utils import unroll
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class ABIEncoderV2Array(AbstractDetector):
@ -55,7 +59,9 @@ contract A {
VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 7, 25) + make_solc_versions(5, 0, 9)
@staticmethod
def _detect_storage_abiencoderv2_arrays(contract):
def _detect_storage_abiencoderv2_arrays(
contract: Contract,
) -> Set[Tuple[FunctionContract, Node]]:
"""
Detects and returns all nodes with storage-allocated abiencoderv2 arrays of arrays/structs in abi.encode, events or external calls
:param contract: Contract to detect within
@ -98,7 +104,7 @@ contract A {
# Return the resulting set of tuples
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detect ABIEncoderV2 array bug
"""

@ -1,6 +1,7 @@
"""
Module detecting storage signed integer array bug
"""
from typing import List
from slither.detectors.abstract_detector import (
AbstractDetector,
@ -14,6 +15,7 @@ from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable
from slither.slithir.operations.assignment import Assignment
from slither.slithir.operations.init_array import InitArray
from slither.utils.output import Output
class StorageSignedIntegerArray(AbstractDetector):
@ -108,7 +110,7 @@ contract A {
# Return the resulting set of tuples
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detect storage signed integer array init/assignment
"""

@ -1,7 +1,7 @@
"""
Module detecting uninitialized function pointer calls in constructors
"""
from typing import Any, List, Union
from slither.detectors.abstract_detector import (
AbstractDetector,
DetectorClassification,
@ -10,9 +10,14 @@ from slither.detectors.abstract_detector import (
from slither.slithir.operations import InternalDynamicCall, OperationWithLValue
from slither.slithir.variables import ReferenceVariable
from slither.slithir.variables.variable import SlithIRVariable
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.slithir.variables.state_variable import StateIRVariable
from slither.utils.output import Output
def _get_variables_entrance(function):
def _get_variables_entrance(function: FunctionContract) -> List[Union[Any, StateIRVariable]]:
"""
Return the first SSA variables of the function
Catpure the phi operation at the entry point
@ -25,7 +30,7 @@ def _get_variables_entrance(function):
return ret
def _is_vulnerable(node, variables_entrance):
def _is_vulnerable(node: Node, variables_entrance: List[Union[Any, StateIRVariable]]) -> bool:
"""
Vulnerable if an IR ssa:
- It is an internal dynamic call
@ -84,7 +89,9 @@ The call to `a(10)` will lead to unexpected behavior because function pointer `a
VULNERABLE_SOLC_VERSIONS = make_solc_versions(4, 5, 25) + make_solc_versions(5, 0, 8)
@staticmethod
def _detect_uninitialized_function_ptr_in_constructor(contract):
def _detect_uninitialized_function_ptr_in_constructor(
contract: Contract,
) -> List[Union[Any, Node]]:
"""
Detect uninitialized function pointer calls in constructors
:param contract: The contract of interest for detection
@ -99,7 +106,7 @@ The call to `a(10)` will lead to unexpected behavior because function pointer `a
]
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detect uninitialized function pointer calls in constructors of contracts
Returns:

@ -1,16 +1,17 @@
from typing import List
from slither.analyses.data_dependency.data_dependency import is_dependent
from slither.core.cfg.node import Node
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations import Contract, Function, SolidityVariableComposed
from slither.core.declarations.solidity_variables import SolidityVariable
from slither.slithir.operations import HighLevelCall, LibraryCall
from slither.core.declarations import Contract, Function, SolidityVariableComposed
from slither.analyses.data_dependency.data_dependency import is_dependent
from slither.core.compilation_unit import SlitherCompilationUnit
class ArbitrarySendErc20:
"""Detects instances where ERC20 can be sent from an arbitrary from address."""
def __init__(self, compilation_unit: SlitherCompilationUnit):
def __init__(self, compilation_unit: SlitherCompilationUnit) -> None:
self._compilation_unit = compilation_unit
self._no_permit_results: List[Node] = []
self._permit_results: List[Node] = []
@ -27,7 +28,7 @@ class ArbitrarySendErc20:
def permit_results(self) -> List[Node]:
return self._permit_results
def _detect_arbitrary_from(self, contract: Contract):
def _detect_arbitrary_from(self, contract: Contract) -> None:
for f in contract.functions:
all_high_level_calls = [
f_called[1].solidity_signature
@ -48,7 +49,7 @@ class ArbitrarySendErc20:
ArbitrarySendErc20._arbitrary_from(f.nodes, self._no_permit_results)
@staticmethod
def _arbitrary_from(nodes: List[Node], results: List[Node]):
def _arbitrary_from(nodes: List[Node], results: List[Node]) -> None:
"""Finds instances of (safe)transferFrom that do not use msg.sender or address(this) as from parameter."""
for node in nodes:
for ir in node.irs:
@ -89,7 +90,7 @@ class ArbitrarySendErc20:
):
results.append(ir.node)
def detect(self):
def detect(self) -> None:
"""Detect transfers that use arbitrary `from` parameter."""
for c in self.compilation_unit.contracts_derived:
self._detect_arbitrary_from(c)

@ -2,7 +2,12 @@
Detect incorrect erc20 interface.
Some contracts do not return a bool on transfer/transferFrom/approve, which may lead to preventing the contract to be used with contracts compiled with recent solc (>0.4.22)
"""
from typing import List, Tuple
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class IncorrectERC20InterfaceDetection(AbstractDetector):
@ -36,7 +41,7 @@ contract Token{
)
@staticmethod
def incorrect_erc20_interface(signature):
def incorrect_erc20_interface(signature: Tuple[str, List[str], List[str]]) -> bool:
(name, parameters, returnVars) = signature
if name == "transfer" and parameters == ["address", "uint256"] and returnVars != ["bool"]:
@ -68,7 +73,7 @@ contract Token{
return False
@staticmethod
def detect_incorrect_erc20_interface(contract):
def detect_incorrect_erc20_interface(contract: Contract) -> List[FunctionContract]:
"""Detect incorrect ERC20 interface
Returns:
@ -93,7 +98,7 @@ contract Token{
return functions
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect incorrect erc20 interface
Returns:

@ -1,7 +1,11 @@
"""
Detect incorrect erc721 interface.
"""
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class IncorrectERC721InterfaceDetection(AbstractDetector):
@ -37,7 +41,9 @@ contract Token{
)
@staticmethod
def incorrect_erc721_interface(signature):
def incorrect_erc721_interface(
signature: Union[Tuple[str, List[str], List[str]], Tuple[str, List[str], List[Any]]]
) -> bool:
(name, parameters, returnVars) = signature
# ERC721
@ -83,7 +89,7 @@ contract Token{
return False
@staticmethod
def detect_incorrect_erc721_interface(contract):
def detect_incorrect_erc721_interface(contract: Contract) -> List[Union[FunctionContract, Any]]:
"""Detect incorrect ERC721 interface
Returns:
@ -102,7 +108,7 @@ contract Token{
]
return functions
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect incorrect erc721 interface
Returns:

@ -1,7 +1,12 @@
"""
Detect mistakenly un-indexed ERC20 event parameters
"""
from typing import Any, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.event import Event
from slither.core.variables.event_variable import EventVariable
from slither.utils.output import Output
class UnindexedERC20EventParameters(AbstractDetector):
@ -39,7 +44,9 @@ Failure to include these keywords will exclude the parameter data in the transac
STANDARD_JSON = False
@staticmethod
def detect_erc20_unindexed_event_params(contract):
def detect_erc20_unindexed_event_params(
contract: Contract,
) -> List[Union[Tuple[Event, EventVariable], Any]]:
"""
Detect un-indexed ERC20 event parameters in a given contract.
:param contract: The contract to check ERC20 events for un-indexed parameters in.
@ -68,7 +75,7 @@ Failure to include these keywords will exclude the parameter data in the transac
# Return the results.
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""
Detect un-indexed ERC20 event parameters in all contracts.
"""

@ -1,4 +1,7 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class Backdoor(AbstractDetector):
@ -17,7 +20,7 @@ class Backdoor(AbstractDetector):
WIKI_EXPLOIT_SCENARIO = ".."
WIKI_RECOMMENDATION = ".."
def _detect(self):
def _detect(self) -> List[Output]:
results = []
for contract in self.compilation_unit.contracts_derived:

@ -9,11 +9,12 @@
TODO: dont report if the value is tainted by msg.value
"""
from typing import List
from typing import Any, Tuple, Union, List
from slither.analyses.data_dependency.data_dependency import is_tainted, is_dependent
from slither.core.cfg.node import Node
from slither.core.declarations import Function, Contract
from slither.analyses.data_dependency.data_dependency import is_tainted, is_dependent
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.solidity_variables import (
SolidityFunction,
SolidityVariableComposed,
@ -28,12 +29,11 @@ from slither.slithir.operations import (
Transfer,
)
# pylint: disable=too-many-nested-blocks,too-many-branches
from slither.utils.output import Output
def arbitrary_send(func: Function):
def arbitrary_send(func: Function) -> Union[bool, List[Node]]:
if func.is_protected():
return []
@ -74,7 +74,9 @@ def arbitrary_send(func: Function):
return ret
def detect_arbitrary_send(contract: Contract):
def detect_arbitrary_send(
contract: Contract,
) -> List[Union[Tuple[FunctionContract, List[Node]], Any]]:
"""
Detect arbitrary send
Args:

@ -5,6 +5,7 @@ from typing import List, Tuple
from slither.core.declarations import Function, FunctionContract, Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class DeadCode(AbstractDetector):
@ -34,7 +35,7 @@ contract Contract{
WIKI_RECOMMENDATION = "Remove unused functions."
def _detect(self):
def _detect(self) -> List[Output]:
results = []

@ -5,18 +5,19 @@ Note that require()/assert() are not considered here. Even if they
are in the outermost scope, they do not guarantee a revert, so a
default value can still be returned.
"""
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.cfg.node import NodeType
from slither.core.cfg.node import Node, NodeType
from slither.utils.output import Output
def is_revert(node):
def is_revert(node: Node) -> bool:
return node.type == NodeType.THROW or any(
c.name in ["revert()", "revert(string"] for c in node.internal_calls
)
def _get_false_son(node):
def _get_false_son(node: Node) -> Node:
"""Select the son node corresponding to a false branch
Following this node stays on the outer scope of the function
"""
@ -60,7 +61,7 @@ If the condition in `myModif` is false, the execution of `get()` will return 0."
WIKI_RECOMMENDATION = "All the paths in a modifier must execute `_` or revert."
def _detect(self):
def _detect(self) -> List[Output]:
results = []
for c in self.contracts:
for mod in c.modifiers:

@ -8,6 +8,7 @@ from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.function import get_function_id
from slither.utils.output import Output
class DomainSeparatorCollision(AbstractDetector):
@ -39,7 +40,7 @@ contract Contract{
WIKI_RECOMMENDATION = "Remove or rename the function that collides with DOMAIN_SEPARATOR()."
def _detect(self):
def _detect(self) -> List[Output]:
domain_sig = get_function_id("DOMAIN_SEPARATOR()")
for contract in self.compilation_unit.contracts_derived:
if contract.is_erc20():

@ -5,8 +5,8 @@ A suicidal contract is an unprotected function that calls selfdestruct
"""
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations import Function, Contract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
@ -71,7 +71,7 @@ contract Buggy{
results.append(res)
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect the suicidal functions"""
results = []
for contract in self.compilation_unit.contracts_derived:

@ -3,8 +3,12 @@ Module detecting suicidal contract
A suicidal contract is an unprotected function that calls selfdestruct
"""
from typing import List
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class Suicidal(AbstractDetector):
@ -37,7 +41,7 @@ Bob calls `kill` and destructs the contract."""
WIKI_RECOMMENDATION = "Protect access to all sensitive functions."
@staticmethod
def detect_suicidal_func(func):
def detect_suicidal_func(func: FunctionContract) -> bool:
"""Detect if the function is suicidal
Detect the public functions calling suicide/selfdestruct without protection
@ -60,14 +64,14 @@ Bob calls `kill` and destructs the contract."""
return True
def detect_suicidal(self, contract):
def detect_suicidal(self, contract: Contract) -> List[FunctionContract]:
ret = []
for f in contract.functions_declared:
if self.detect_suicidal_func(f):
ret.append(f)
return ret
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect the suicidal functions"""
results = []
for c in self.contracts:

@ -7,8 +7,12 @@ Check for unimplemented functions that are never implemented
Consider public state variables as implemented functions
Do not consider fallback function or constructor
"""
from typing import List, Set
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
# Since 0.5.1, Solidity allows creating state variable matching a function signature.
older_solc_versions = ["0.5.0"] + ["0.4." + str(x) for x in range(0, 27)]
@ -55,10 +59,10 @@ All unimplemented functions must be implemented on a contract that is meant to b
WIKI_RECOMMENDATION = "Implement all unimplemented functions in any contract you intend to use directly (not simply inherit from)."
@staticmethod
def _match_state_variable(contract, f):
def _match_state_variable(contract: Contract, f: FunctionContract) -> bool:
return any(s.full_name == f.full_name for s in contract.state_variables)
def _detect_unimplemented_function(self, contract):
def _detect_unimplemented_function(self, contract: Contract) -> Set[FunctionContract]:
"""
Detects any function definitions which are not implemented in the given contract.
:param contract: The contract to search unimplemented functions for.
@ -87,7 +91,7 @@ All unimplemented functions must be implemented on a contract that is meant to b
unimplemented.add(f)
return unimplemented
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect unimplemented functions
Recursively visit the calls

@ -1,6 +1,8 @@
import re
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.formatters.naming_convention.naming_convention import custom_format
from slither.utils.output import Output
class NamingConvention(AbstractDetector):
@ -36,28 +38,29 @@ Solidity defines a [naming convention](https://solidity.readthedocs.io/en/v0.4.2
STANDARD_JSON = False
@staticmethod
def is_cap_words(name):
def is_cap_words(name: str) -> bool:
return re.search("^[A-Z]([A-Za-z0-9]+)?_?$", name) is not None
@staticmethod
def is_mixed_case(name):
def is_mixed_case(name: str) -> bool:
return re.search("^[a-z]([A-Za-z0-9]+)?_?$", name) is not None
@staticmethod
def is_mixed_case_with_underscore(name):
def is_mixed_case_with_underscore(name: str) -> bool:
# Allow _ at the beginning to represent private variable
# or unused parameters
return re.search("^[_]?[a-z]([A-Za-z0-9]+)?_?$", name) is not None
@staticmethod
def is_upper_case_with_underscores(name):
def is_upper_case_with_underscores(name: str) -> bool:
return re.search("^[A-Z0-9_]+_?$", name) is not None
@staticmethod
def should_avoid_name(name):
def should_avoid_name(name: str) -> bool:
return re.search("^[lOI]$", name) is not None
def _detect(self): # pylint: disable=too-many-branches,too-many-statements
# pylint: disable=too-many-branches,too-many-statements
def _detect(self) -> List[Output]:
results = []
for contract in self.contracts:

@ -13,6 +13,7 @@ from slither.core.declarations.solidity_variables import (
)
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import Binary, BinaryType
from slither.utils.output import Output
def _timestamp(func: Function) -> List[Node]:
@ -69,7 +70,7 @@ class Timestamp(AbstractDetector):
WIKI_EXPLOIT_SCENARIO = """"Bob's contract relies on `block.timestamp` for its randomness. Eve is a miner and manipulates `block.timestamp` to exploit Bob's contract."""
WIKI_RECOMMENDATION = "Avoid relying on `block.timestamp`."
def _detect(self):
def _detect(self) -> List[Output]:
""""""
results = []

@ -1,9 +1,13 @@
"""
Module detecting usage of low level calls
"""
from typing import List, Tuple
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import LowLevelCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.utils.output import Output
class LowLevelCalls(AbstractDetector):
@ -23,7 +27,7 @@ class LowLevelCalls(AbstractDetector):
WIKI_RECOMMENDATION = "Avoid low-level calls. Check the call success. If the call is meant for a contract, check for code existence."
@staticmethod
def _contains_low_level_calls(node):
def _contains_low_level_calls(node: Node) -> bool:
"""
Check if the node contains Low Level Calls
Returns:
@ -31,7 +35,9 @@ class LowLevelCalls(AbstractDetector):
"""
return any(isinstance(ir, LowLevelCall) for ir in node.irs)
def detect_low_level_calls(self, contract):
def detect_low_level_calls(
self, contract: Contract
) -> List[Tuple[FunctionContract, List[Node]]]:
ret = []
for f in [f for f in contract.functions if contract == f.contract_declarer]:
nodes = f.nodes
@ -40,7 +46,7 @@ class LowLevelCalls(AbstractDetector):
ret.append((f, assembly_nodes))
return ret
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect the functions that use low level calls"""
results = []
for c in self.contracts:

@ -2,11 +2,18 @@
Module detecting missing events for critical contract parameters set by owners and used in access control
"""
from typing import List, Tuple
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.slithir.operations.event_call import EventCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.modifier import Modifier
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations.event_call import EventCall
from slither.utils.output import Output
class MissingEventsAccessControl(AbstractDetector):
@ -45,7 +52,9 @@ contract C {
WIKI_RECOMMENDATION = "Emit an event for critical parameter changes."
@staticmethod
def _detect_missing_events(contract):
def _detect_missing_events(
contract: Contract,
) -> List[Tuple[FunctionContract, List[Tuple[Node, StateVariable, Modifier]]]]:
"""
Detects if critical contract parameters set by owners and used in access control are missing events
:param contract: The contract to check
@ -80,7 +89,7 @@ contract C {
results.append((function, nodes))
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect missing events for critical contract parameters set by owners and used in access control
Returns:
list: {'(function, node)'}

@ -2,11 +2,17 @@
Module detecting missing events for critical contract parameters set by owners and used in arithmetic
"""
from typing import List, Tuple
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.slithir.operations.event_call import EventCall
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.core.solidity_types.elementary_type import ElementaryType, Int, Uint
from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations.event_call import EventCall
from slither.utils.output import Output
class MissingEventsArithmetic(AbstractDetector):
@ -49,7 +55,9 @@ contract C {
WIKI_RECOMMENDATION = "Emit an event for critical parameter changes."
@staticmethod
def _detect_unprotected_use(contract, sv):
def _detect_unprotected_use(
contract: Contract, sv: StateVariable
) -> List[Tuple[Node, FunctionContract]]:
unprotected_functions = [
function for function in contract.functions_declared if not function.is_protected()
]
@ -60,7 +68,9 @@ contract C {
if sv in node.state_variables_read
]
def _detect_missing_events(self, contract):
def _detect_missing_events(
self, contract: Contract
) -> List[Tuple[FunctionContract, List[Tuple[Node, List[Tuple[Node, FunctionContract]]]]]]:
"""
Detects if critical contract parameters set by owners and used in arithmetic are missing events
:param contract: The contract to check
@ -101,7 +111,7 @@ contract C {
results.append((function, nodes))
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect missing events for critical contract parameters set by owners and used in arithmetic
Returns:
list: {'(function, node)'}

@ -3,12 +3,19 @@ Module detecting missing zero address validation
"""
from collections import defaultdict
from typing import DefaultDict, List, Tuple, Union
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.analyses.data_dependency.data_dependency import is_tainted
from slither.core.cfg.node import Node
from slither.core.declarations.contract import Contract
from slither.core.declarations.function import ModifierStatements
from slither.core.declarations.function_contract import FunctionContract
from slither.core.solidity_types.elementary_type import ElementaryType
from slither.slithir.operations import Send, Transfer, LowLevelCall
from slither.core.variables.local_variable import LocalVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import Call
from slither.slithir.operations import Send, Transfer, LowLevelCall
from slither.utils.output import Output
class MissingZeroAddressValidation(AbstractDetector):
@ -46,7 +53,9 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
WIKI_RECOMMENDATION = "Check that the address is not zero."
def _zero_address_validation_in_modifier(self, var, modifier_exprs):
def _zero_address_validation_in_modifier(
self, var: LocalVariable, modifier_exprs: List[ModifierStatements]
) -> bool:
for mod in modifier_exprs:
for node in mod.nodes:
# Skip validation if the modifier's parameters contains more than one variable
@ -62,7 +71,9 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
return True
return False
def _zero_address_validation(self, var, node, explored):
def _zero_address_validation(
self, var: LocalVariable, node: Node, explored: List[Node]
) -> bool:
"""
Detects (recursively) if var is (zero address) checked in the function node
"""
@ -83,7 +94,9 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
return True
return False
def _detect_missing_zero_address_validation(self, contract):
def _detect_missing_zero_address_validation(
self, contract: Contract
) -> List[Union[Tuple[FunctionContract, DefaultDict[LocalVariable, List[Node]]]]]:
"""
Detects if addresses are zero address validated before use.
:param contract: The contract to check
@ -130,7 +143,7 @@ Bob calls `updateOwner` without specifying the `newOwner`, so Bob loses ownershi
results.append((function, var_nodes))
return results
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect if addresses are zero address validated before use.
Returns:
list: {'(function, node)'}

@ -4,6 +4,7 @@ Module detecting unused return values from low level
from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.operations.unused_return_values import UnusedReturnValues
from slither.slithir.operations import LowLevelCall
from slither.slithir.operations.operation import Operation
class UncheckedLowLevel(UnusedReturnValues):
@ -37,5 +38,5 @@ If the low level is used to prevent blocking operations, consider logging failed
WIKI_RECOMMENDATION = "Ensure that the return value of a low-level call is checked or logged."
def _is_instance(self, ir): # pylint: disable=no-self-use
def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, LowLevelCall)

@ -5,6 +5,7 @@ Module detecting unused return values from send
from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.operations.unused_return_values import UnusedReturnValues
from slither.slithir.operations import Send
from slither.slithir.operations.operation import Operation
class UncheckedSend(UnusedReturnValues):
@ -38,5 +39,5 @@ If `send` is used to prevent blocking operations, consider logging the failed `s
WIKI_RECOMMENDATION = "Ensure that the return value of `send` is checked or logged."
def _is_instance(self, ir): # pylint: disable=no-self-use
def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, Send)

@ -6,6 +6,7 @@ from slither.core.declarations import Function
from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.operations.unused_return_values import UnusedReturnValues
from slither.slithir.operations import HighLevelCall
from slither.slithir.operations.operation import Operation
class UncheckedTransfer(UnusedReturnValues):
@ -45,7 +46,7 @@ Several tokens do not revert in case of failure and return false. If one of thes
"Use `SafeERC20`, or ensure that the transfer/transferFrom return value is checked."
)
def _is_instance(self, ir): # pylint: disable=no-self-use
def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return (
isinstance(ir, HighLevelCall)
and isinstance(ir.function, Function)

@ -1,11 +1,16 @@
"""
Module detecting unused return values from external calls
"""
from typing import List
from slither.core.cfg.node import Node
from slither.core.declarations import Function
from slither.core.declarations.function_contract import FunctionContract
from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import HighLevelCall
from slither.core.declarations import Function
from slither.slithir.operations.operation import Operation
from slither.utils.output import Output
class UnusedReturnValues(AbstractDetector):
@ -40,7 +45,7 @@ contract MyConc{
WIKI_RECOMMENDATION = "Ensure that all the return values of the function calls are used."
def _is_instance(self, ir): # pylint: disable=no-self-use
def _is_instance(self, ir: Operation) -> bool: # pylint: disable=no-self-use
return isinstance(ir, HighLevelCall) and (
(
isinstance(ir.function, Function)
@ -50,7 +55,9 @@ contract MyConc{
or not isinstance(ir.function, Function)
)
def detect_unused_return_values(self, f): # pylint: disable=no-self-use
def detect_unused_return_values(
self, f: FunctionContract
) -> List[Node]: # pylint: disable=no-self-use
"""
Return the nodes where the return value of a call is unused
Args:
@ -73,7 +80,7 @@ contract MyConc{
return [nodes_origin[value].node for value in values_returned]
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect high level calls which return a value that are never used"""
results = []
for c in self.compilation_unit.contracts:

@ -1,5 +1,8 @@
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import Nop
from slither.utils.output import Output
class VoidConstructor(AbstractDetector):
@ -26,7 +29,7 @@ contract B is A{
When reading `B`'s constructor definition, we might assume that `A()` initiates the contract, but no code is executed."""
# endregion wiki_exploit_scenario
def _detect(self):
def _detect(self) -> List[Output]:
""""""
results = []
for c in self.contracts:

@ -5,10 +5,11 @@
Iterate over all the nodes of the graph until reaching a fixpoint
"""
from collections import namedtuple, defaultdict
from typing import List
from typing import DefaultDict, Set, List
from slither.detectors.abstract_detector import DetectorClassification
from .reentrancy import Reentrancy, to_hashable
from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable
from slither.utils.output import Output
FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
@ -50,7 +51,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
STANDARD_JSON = False
def find_reentrancies(self):
def find_reentrancies(self) -> DefaultDict[FindingKey, Set[FindingValue]]:
result = defaultdict(set)
for contract in self.contracts:
for f in contract.functions_and_modifiers_declared:
@ -87,7 +88,7 @@ Only report reentrancy that acts as a double call (see `reentrancy-eth`, `reentr
result[finding_key] |= not_read_then_written
return result
def _detect(self): # pylint: disable=too-many-branches
def _detect(self) -> List[Output]: # pylint: disable=too-many-branches
""""""
super()._detect()

@ -5,9 +5,11 @@
Iterate over all the nodes of the graph until reaching a fixpoint
"""
from collections import namedtuple, defaultdict
from typing import DefaultDict, List, Set
from slither.detectors.abstract_detector import DetectorClassification
from .reentrancy import Reentrancy, to_hashable
from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable
from slither.utils.output import Output
FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
@ -48,7 +50,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
STANDARD_JSON = False
def find_reentrancies(self):
def find_reentrancies(self) -> DefaultDict[FindingKey, Set[FindingValue]]:
result = defaultdict(set)
for contract in self.contracts:
for f in contract.functions_and_modifiers_declared:
@ -80,7 +82,7 @@ If `d.()` re-enters, the `Counter` events will be shown in an incorrect order, w
result[finding_key] |= finding_vars
return result
def _detect(self): # pylint: disable=too-many-branches
def _detect(self) -> List[Output]: # pylint: disable=too-many-branches
""""""
super()._detect()

@ -5,11 +5,16 @@
Iterate over all the nodes of the graph until reaching a fixpoint
"""
from collections import namedtuple, defaultdict
from typing import DefaultDict, List, Union, Set
from slither.core.variables.variable import Variable
from slither.detectors.abstract_detector import DetectorClassification
from slither.detectors.reentrancy.reentrancy import Reentrancy, to_hashable
from slither.slithir.operations import Send, Transfer, EventCall
from .reentrancy import Reentrancy, to_hashable
from slither.slithir.operations.high_level_call import HighLevelCall
from slither.slithir.operations.member import Member
from slither.slithir.operations.return_operation import Return
from slither.utils.output import Output
FindingKey = namedtuple("FindingKey", ["function", "calls", "send_eth"])
FindingValue = namedtuple("FindingValue", ["variable", "node", "nodes"])
@ -50,7 +55,7 @@ Only report reentrancy that is based on `transfer` or `send`."""
WIKI_RECOMMENDATION = "Apply the [`check-effects-interactions` pattern](http://solidity.readthedocs.io/en/v0.4.21/security-considerations.html#re-entrancy)."
@staticmethod
def can_callback(ir):
def can_callback(ir: Union[Member, Return, HighLevelCall]) -> bool:
"""
Same as Reentrancy, but also consider Send and Transfer
@ -59,8 +64,8 @@ Only report reentrancy that is based on `transfer` or `send`."""
STANDARD_JSON = False
def find_reentrancies(self):
result = defaultdict(set)
def find_reentrancies(self) -> DefaultDict[FindingKey, Set[FindingValue]]:
result: DefaultDict[FindingKey, Set[FindingValue]] = defaultdict(set)
for contract in self.contracts:
for f in contract.functions_and_modifiers_declared:
for node in f.nodes:
@ -97,7 +102,7 @@ Only report reentrancy that is based on `transfer` or `send`."""
result[finding_key] |= finding_vars
return result
def _detect(self): # pylint: disable=too-many-branches,too-many-locals
def _detect(self) -> List[Output]: # pylint: disable=too-many-branches,too-many-locals
""""""
super()._detect()

@ -6,6 +6,7 @@ from slither.core.cfg.node import Node
from slither.core.declarations import Function, Contract, SolidityVariableComposed
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.slithir.operations import LowLevelCall, HighLevelCall
from slither.utils.output import Output
def _detect_token_reentrant(contract: Contract) -> Dict[Function, List[Node]]:
@ -82,7 +83,7 @@ contract MyDefi{
If you do, ensure your users are aware of the potential issues."""
# endregion wiki_recommendation
def _detect(self):
def _detect(self) -> List[Output]:
results = []
for contract in self.compilation_unit.contracts_derived:
vulns = _detect_token_reentrant(contract)

@ -1,8 +1,16 @@
"""
Module detecting reserved keyword shadowing
"""
from typing import List, Tuple, Union, Optional
from slither.core.declarations import Function, Event
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.modifier import Modifier
from slither.core.variables import Variable
from slither.core.variables.local_variable import LocalVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class BuiltinSymbolShadowing(AbstractDetector):
@ -114,7 +122,7 @@ contract Bug {
"unchecked",
]
def is_builtin_symbol(self, word):
def is_builtin_symbol(self, word: Optional[str]) -> bool:
"""Detects if a given word is a built-in symbol.
Returns:
@ -122,7 +130,9 @@ contract Bug {
return word in self.BUILTIN_SYMBOLS or word in self.RESERVED_KEYWORDS
def detect_builtin_shadowing_locals(self, function_or_modifier):
def detect_builtin_shadowing_locals(
self, function_or_modifier: Union[Modifier, FunctionContract]
) -> List[Tuple[str, LocalVariable]]:
"""Detects if local variables in a given function/modifier are named after built-in symbols.
Any such items are returned in a list.
@ -135,14 +145,16 @@ contract Bug {
results.append((self.SHADOWING_LOCAL_VARIABLE, local))
return results
def detect_builtin_shadowing_definitions(self, contract):
def detect_builtin_shadowing_definitions(
self, contract: Contract
) -> List[Tuple[str, Union[Function, Variable, Event]]]:
"""Detects if functions, access modifiers, events, state variables, or local variables are named after built-in
symbols. Any such definitions are returned in a list.
Returns:
list of tuple: (type, definition, [local variable parent])"""
result = []
result: List[Tuple[str, Union[Function, Variable, Event]]] = []
# Loop through all functions, modifiers, variables (state and local) to detect any built-in symbol keywords.
for function in contract.functions_declared:
@ -164,7 +176,7 @@ contract Bug {
return result
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect shadowing of built-in symbols
Recursively visit the calls

@ -1,8 +1,16 @@
"""
Module detecting local variable shadowing
"""
from typing import List, Tuple, Union
from slither.core.declarations.contract import Contract
from slither.core.declarations.event import Event
from slither.core.declarations.function_contract import FunctionContract
from slither.core.declarations.modifier import Modifier
from slither.core.variables.local_variable import LocalVariable
from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
class LocalShadowing(AbstractDetector):
@ -50,13 +58,30 @@ contract Bug {
OVERSHADOWED_STATE_VARIABLE = "state variable"
OVERSHADOWED_EVENT = "event"
def detect_shadowing_definitions(self, contract): # pylint: disable=too-many-branches
# pylint: disable=too-many-branches
def detect_shadowing_definitions(
self, contract: Contract
) -> List[
Union[
Tuple[LocalVariable, List[Tuple[str, StateVariable]]],
Tuple[LocalVariable, List[Tuple[str, FunctionContract]]],
Tuple[LocalVariable, List[Tuple[str, Modifier]]],
Tuple[LocalVariable, List[Tuple[str, Event]]],
]
]:
"""Detects if functions, access modifiers, events, state variables, and local variables are named after
reserved keywords. Any such definitions are returned in a list.
Returns:
list of tuple: (type, contract name, definition)"""
result = []
result: List[
Union[
Tuple[LocalVariable, List[Tuple[str, StateVariable]]],
Tuple[LocalVariable, List[Tuple[str, FunctionContract]]],
Tuple[LocalVariable, List[Tuple[str, Modifier]]],
Tuple[LocalVariable, List[Tuple[str, Event]]],
]
] = []
# Loop through all functions + modifiers in this contract.
for function in contract.functions + contract.modifiers:
@ -93,7 +118,7 @@ contract Bug {
return result
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect shadowing local variables
Recursively visit the calls

@ -2,12 +2,16 @@
Module detecting shadowing of state variables
"""
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from typing import List
from slither.core.declarations import Contract
from .common import is_upgradable_gap_variable
from slither.core.variables.state_variable import StateVariable
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.detectors.shadowing.common import is_upgradable_gap_variable
from slither.utils.output import Output
def detect_shadowing(contract: Contract):
def detect_shadowing(contract: Contract) -> List[List[StateVariable]]:
ret = []
variables_fathers = []
for father in contract.inheritance:
@ -70,7 +74,7 @@ contract DerivedContract is BaseContract{
WIKI_RECOMMENDATION = "Remove the state variable shadowing."
def _detect(self):
def _detect(self) -> List[Output]:
"""Detect shadowing
Recursively visit the calls

@ -1,10 +1,12 @@
from collections import defaultdict
from typing import Any, List
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
def _find_missing_inheritance(compilation_unit: SlitherCompilationUnit):
def _find_missing_inheritance(compilation_unit: SlitherCompilationUnit) -> List[Any]:
"""
Filter contracts with missing inheritance to return only the "most base" contracts
in the inheritance tree.
@ -50,7 +52,8 @@ As a result, the second contract cannot be analyzed.
WIKI_RECOMMENDATION = "Rename the contract."
def _detect(self): # pylint: disable=too-many-locals,too-many-branches
# pylint: disable=too-many-locals,too-many-branches
def _detect(self) -> List[Output]:
results = []
compilation_unit = self.compilation_unit

@ -1,5 +1,9 @@
import re
from typing import List
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.utils.output import Output
# pylint: disable=bidirectional-unicode
class RightToLeftOverride(AbstractDetector):
@ -52,7 +56,7 @@ contract Token
RTLO_CHARACTER_ENCODED = "\u202e".encode("utf-8")
STANDARD_JSON = False
def _detect(self):
def _detect(self) -> List[Output]:
results = []
pattern = re.compile(".*\u202e.*".encode("utf-8"))

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

Loading…
Cancel
Save