Add scope information in slithIR CFG

The main usage in the short term is to allow unchecked block
In the long term it will allow better handling of variables usage
pull/836/head
Josselin 4 years ago
parent 9533947d84
commit 571a849757
  1. 5
      slither/core/cfg/node.py
  2. 14
      slither/core/cfg/scope.py
  3. 13
      slither/core/declarations/contract.py
  4. 22
      slither/core/declarations/function.py
  5. 3
      slither/slithir/operations/binary.py
  6. 129
      slither/solc_parsing/declarations/function.py
  7. 10
      slither/solc_parsing/declarations/modifier.py
  8. 76
      slither/solc_parsing/yul/parse_yul.py
  9. BIN
      tests/ast-parsing/compile/scope-0.4.0-legacy.zip
  10. BIN
      tests/ast-parsing/compile/scope-0.4.1-legacy.zip
  11. BIN
      tests/ast-parsing/compile/scope-0.4.10-legacy.zip
  12. BIN
      tests/ast-parsing/compile/scope-0.4.11-legacy.zip
  13. BIN
      tests/ast-parsing/compile/scope-0.4.12-compact.zip
  14. BIN
      tests/ast-parsing/compile/scope-0.4.12-legacy.zip
  15. BIN
      tests/ast-parsing/compile/scope-0.4.13-compact.zip
  16. BIN
      tests/ast-parsing/compile/scope-0.4.13-legacy.zip
  17. BIN
      tests/ast-parsing/compile/scope-0.4.14-compact.zip
  18. BIN
      tests/ast-parsing/compile/scope-0.4.14-legacy.zip
  19. BIN
      tests/ast-parsing/compile/scope-0.4.15-compact.zip
  20. BIN
      tests/ast-parsing/compile/scope-0.4.15-legacy.zip
  21. BIN
      tests/ast-parsing/compile/scope-0.4.16-compact.zip
  22. BIN
      tests/ast-parsing/compile/scope-0.4.16-legacy.zip
  23. BIN
      tests/ast-parsing/compile/scope-0.4.17-compact.zip
  24. BIN
      tests/ast-parsing/compile/scope-0.4.17-legacy.zip
  25. BIN
      tests/ast-parsing/compile/scope-0.4.18-compact.zip
  26. BIN
      tests/ast-parsing/compile/scope-0.4.18-legacy.zip
  27. BIN
      tests/ast-parsing/compile/scope-0.4.19-compact.zip
  28. BIN
      tests/ast-parsing/compile/scope-0.4.19-legacy.zip
  29. BIN
      tests/ast-parsing/compile/scope-0.4.2-legacy.zip
  30. BIN
      tests/ast-parsing/compile/scope-0.4.20-compact.zip
  31. BIN
      tests/ast-parsing/compile/scope-0.4.20-legacy.zip
  32. BIN
      tests/ast-parsing/compile/scope-0.4.21-compact.zip
  33. BIN
      tests/ast-parsing/compile/scope-0.4.21-legacy.zip
  34. BIN
      tests/ast-parsing/compile/scope-0.4.22-compact.zip
  35. BIN
      tests/ast-parsing/compile/scope-0.4.22-legacy.zip
  36. BIN
      tests/ast-parsing/compile/scope-0.4.23-compact.zip
  37. BIN
      tests/ast-parsing/compile/scope-0.4.23-legacy.zip
  38. BIN
      tests/ast-parsing/compile/scope-0.4.24-compact.zip
  39. BIN
      tests/ast-parsing/compile/scope-0.4.24-legacy.zip
  40. BIN
      tests/ast-parsing/compile/scope-0.4.25-compact.zip
  41. BIN
      tests/ast-parsing/compile/scope-0.4.25-legacy.zip
  42. BIN
      tests/ast-parsing/compile/scope-0.4.26-compact.zip
  43. BIN
      tests/ast-parsing/compile/scope-0.4.26-legacy.zip
  44. BIN
      tests/ast-parsing/compile/scope-0.4.3-legacy.zip
  45. BIN
      tests/ast-parsing/compile/scope-0.4.4-legacy.zip
  46. BIN
      tests/ast-parsing/compile/scope-0.4.5-legacy.zip
  47. BIN
      tests/ast-parsing/compile/scope-0.4.6-legacy.zip
  48. BIN
      tests/ast-parsing/compile/scope-0.4.7-legacy.zip
  49. BIN
      tests/ast-parsing/compile/scope-0.4.8-legacy.zip
  50. BIN
      tests/ast-parsing/compile/scope-0.4.9-legacy.zip
  51. BIN
      tests/ast-parsing/compile/scope-0.5.0-compact.zip
  52. BIN
      tests/ast-parsing/compile/scope-0.5.0-legacy.zip
  53. BIN
      tests/ast-parsing/compile/scope-0.5.1-compact.zip
  54. BIN
      tests/ast-parsing/compile/scope-0.5.1-legacy.zip
  55. BIN
      tests/ast-parsing/compile/scope-0.5.10-compact.zip
  56. BIN
      tests/ast-parsing/compile/scope-0.5.10-legacy.zip
  57. BIN
      tests/ast-parsing/compile/scope-0.5.11-compact.zip
  58. BIN
      tests/ast-parsing/compile/scope-0.5.11-legacy.zip
  59. BIN
      tests/ast-parsing/compile/scope-0.5.12-compact.zip
  60. BIN
      tests/ast-parsing/compile/scope-0.5.12-legacy.zip
  61. BIN
      tests/ast-parsing/compile/scope-0.5.13-compact.zip
  62. BIN
      tests/ast-parsing/compile/scope-0.5.13-legacy.zip
  63. BIN
      tests/ast-parsing/compile/scope-0.5.14-compact.zip
  64. BIN
      tests/ast-parsing/compile/scope-0.5.14-legacy.zip
  65. BIN
      tests/ast-parsing/compile/scope-0.5.15-compact.zip
  66. BIN
      tests/ast-parsing/compile/scope-0.5.15-legacy.zip
  67. BIN
      tests/ast-parsing/compile/scope-0.5.16-compact.zip
  68. BIN
      tests/ast-parsing/compile/scope-0.5.16-legacy.zip
  69. BIN
      tests/ast-parsing/compile/scope-0.5.17-compact.zip
  70. BIN
      tests/ast-parsing/compile/scope-0.5.17-legacy.zip
  71. BIN
      tests/ast-parsing/compile/scope-0.5.2-compact.zip
  72. BIN
      tests/ast-parsing/compile/scope-0.5.2-legacy.zip
  73. BIN
      tests/ast-parsing/compile/scope-0.5.3-compact.zip
  74. BIN
      tests/ast-parsing/compile/scope-0.5.3-legacy.zip
  75. BIN
      tests/ast-parsing/compile/scope-0.5.4-compact.zip
  76. BIN
      tests/ast-parsing/compile/scope-0.5.4-legacy.zip
  77. BIN
      tests/ast-parsing/compile/scope-0.5.5-compact.zip
  78. BIN
      tests/ast-parsing/compile/scope-0.5.5-legacy.zip
  79. BIN
      tests/ast-parsing/compile/scope-0.5.6-compact.zip
  80. BIN
      tests/ast-parsing/compile/scope-0.5.6-legacy.zip
  81. BIN
      tests/ast-parsing/compile/scope-0.5.7-compact.zip
  82. BIN
      tests/ast-parsing/compile/scope-0.5.7-legacy.zip
  83. BIN
      tests/ast-parsing/compile/scope-0.5.8-compact.zip
  84. BIN
      tests/ast-parsing/compile/scope-0.5.8-legacy.zip
  85. BIN
      tests/ast-parsing/compile/scope-0.5.9-compact.zip
  86. BIN
      tests/ast-parsing/compile/scope-0.5.9-legacy.zip
  87. BIN
      tests/ast-parsing/compile/scope-0.6.0-compact.zip
  88. BIN
      tests/ast-parsing/compile/scope-0.6.0-legacy.zip
  89. BIN
      tests/ast-parsing/compile/scope-0.6.1-compact.zip
  90. BIN
      tests/ast-parsing/compile/scope-0.6.1-legacy.zip
  91. BIN
      tests/ast-parsing/compile/scope-0.6.10-compact.zip
  92. BIN
      tests/ast-parsing/compile/scope-0.6.10-legacy.zip
  93. BIN
      tests/ast-parsing/compile/scope-0.6.11-compact.zip
  94. BIN
      tests/ast-parsing/compile/scope-0.6.11-legacy.zip
  95. BIN
      tests/ast-parsing/compile/scope-0.6.12-compact.zip
  96. BIN
      tests/ast-parsing/compile/scope-0.6.12-legacy.zip
  97. BIN
      tests/ast-parsing/compile/scope-0.6.2-compact.zip
  98. BIN
      tests/ast-parsing/compile/scope-0.6.2-legacy.zip
  99. BIN
      tests/ast-parsing/compile/scope-0.6.3-compact.zip
  100. BIN
      tests/ast-parsing/compile/scope-0.6.3-legacy.zip
  101. Some files were not shown because too many files have changed in this diff Show More

@ -54,6 +54,7 @@ if TYPE_CHECKING:
LibraryCallType, LibraryCallType,
LowLevelCallType, LowLevelCallType,
) )
from slither.core.cfg.scope import Scope
# pylint: disable=too-many-lines,too-many-branches,too-many-instance-attributes # pylint: disable=too-many-lines,too-many-branches,too-many-instance-attributes
@ -152,7 +153,7 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
""" """
def __init__(self, node_type: NodeType, node_id: int): def __init__(self, node_type: NodeType, node_id: int, scope: Union["Scope", "Function"]):
super().__init__() super().__init__()
self._node_type = node_type self._node_type = node_type
@ -220,6 +221,8 @@ class Node(SourceMapping, ChildFunction): # pylint: disable=too-many-public-met
self._asm_source_code: Optional[Union[str, Dict]] = None self._asm_source_code: Optional[Union[str, Dict]] = None
self.scope = scope
################################################################################### ###################################################################################
################################################################################### ###################################################################################
# region General's properties # region General's properties

@ -0,0 +1,14 @@
from typing import List, TYPE_CHECKING, Union
if TYPE_CHECKING:
from slither.core.cfg.node import Node
from slither.core.declarations.function import Function
class Scope:
def __init__(self, is_checked:bool, is_yul: bool, scope: Union["Scope", "Function"]):
self.nodes: List[Node] = []
self.is_checked = is_checked
self.is_yul = is_yul
self.father = scope

@ -7,6 +7,7 @@ from typing import Optional, List, Dict, Callable, Tuple, TYPE_CHECKING, Union
from crytic_compile.platform import Type as PlatformType from crytic_compile.platform import Type as PlatformType
from slither.core.cfg.scope import Scope
from slither.core.solidity_types.type import Type from slither.core.solidity_types.type import Type
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
@ -1114,12 +1115,12 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
constructor_variable.set_offset(self.source_mapping, self.compilation_unit) constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
self._functions[constructor_variable.canonical_name] = constructor_variable self._functions[constructor_variable.canonical_name] = constructor_variable
prev_node = self._create_node(constructor_variable, 0, variable_candidate) prev_node = self._create_node(constructor_variable, 0, variable_candidate, constructor_variable)
variable_candidate.node_initialization = prev_node variable_candidate.node_initialization = prev_node
counter = 1 counter = 1
for v in self.state_variables[idx + 1 :]: for v in self.state_variables[idx + 1 :]:
if v.expression and not v.is_constant: if v.expression and not v.is_constant:
next_node = self._create_node(constructor_variable, counter, v) next_node = self._create_node(constructor_variable, counter, v, prev_node.scope)
v.node_initialization = next_node v.node_initialization = next_node
prev_node.add_son(next_node) prev_node.add_son(next_node)
next_node.add_father(prev_node) next_node.add_father(prev_node)
@ -1142,12 +1143,12 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
constructor_variable.set_offset(self.source_mapping, self.compilation_unit) constructor_variable.set_offset(self.source_mapping, self.compilation_unit)
self._functions[constructor_variable.canonical_name] = constructor_variable self._functions[constructor_variable.canonical_name] = constructor_variable
prev_node = self._create_node(constructor_variable, 0, variable_candidate) prev_node = self._create_node(constructor_variable, 0, variable_candidate, constructor_variable)
variable_candidate.node_initialization = prev_node variable_candidate.node_initialization = prev_node
counter = 1 counter = 1
for v in self.state_variables[idx + 1 :]: for v in self.state_variables[idx + 1 :]:
if v.expression and v.is_constant: if v.expression and v.is_constant:
next_node = self._create_node(constructor_variable, counter, v) next_node = self._create_node(constructor_variable, counter, v, prev_node.scope)
v.node_initialization = next_node v.node_initialization = next_node
prev_node.add_son(next_node) prev_node.add_son(next_node)
next_node.add_father(prev_node) next_node.add_father(prev_node)
@ -1156,7 +1157,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
break break
def _create_node(self, func: Function, counter: int, variable: "Variable"): def _create_node(self, func: Function, counter: int, variable: "Variable", scope: Union[Scope, Function]):
from slither.core.cfg.node import Node, NodeType from slither.core.cfg.node import Node, NodeType
from slither.core.expressions import ( from slither.core.expressions import (
AssignmentOperationType, AssignmentOperationType,
@ -1165,7 +1166,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
) )
# Function uses to create node for state variable declaration statements # Function uses to create node for state variable declaration statements
node = Node(NodeType.OTHER_ENTRYPOINT, counter) node = Node(NodeType.OTHER_ENTRYPOINT, counter, scope)
node.set_offset(variable.source_mapping, self.compilation_unit) node.set_offset(variable.source_mapping, self.compilation_unit)
node.set_function(func) node.set_function(func)
func.add_node(node) func.add_node(node)

@ -8,6 +8,7 @@ from enum import Enum
from itertools import groupby from itertools import groupby
from typing import Dict, TYPE_CHECKING, List, Optional, Set, Union, Callable, Tuple from typing import Dict, TYPE_CHECKING, List, Optional, Set, Union, Callable, Tuple
from slither.core.cfg.scope import Scope
from slither.core.declarations.solidity_variables import ( from slither.core.declarations.solidity_variables import (
SolidityFunction, SolidityFunction,
SolidityVariable, SolidityVariable,
@ -313,13 +314,16 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods
return True return True
return self._can_send_eth return self._can_send_eth
# @property @property
# def slither(self) -> "SlitherCore": def is_checked(self) -> bool:
# return self._slither """
# Return true if the overflow are enabled by default
# @slither.setter
# def slither(self, sl: "SlitherCore"):
# self._slither = sl :return:
"""
return self.compilation_unit.solc_version >= "0.8.0"
# endregion # endregion
################################################################################### ###################################################################################
@ -1527,10 +1531,10 @@ class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def new_node(self, node_type: "NodeType", src: Union[str, Dict]) -> "Node": def new_node(self, node_type: "NodeType", src: Union[str, Dict], scope: Union[Scope, "Function"]) -> "Node":
from slither.core.cfg.node import Node from slither.core.cfg.node import Node
node = Node(node_type, self._counter_nodes) node = Node(node_type, self._counter_nodes, scope)
node.set_offset(src, self.compilation_unit) node.set_offset(src, self.compilation_unit)
self._counter_nodes += 1 self._counter_nodes += 1
node.set_function(self) node.set_function(self)

@ -131,7 +131,7 @@ class BinaryType(Enum):
class Binary(OperationWithLValue): class Binary(OperationWithLValue):
def __init__(self, result, left_variable, right_variable, operation_type): def __init__(self, result, left_variable, right_variable, operation_type: BinaryType, is_checked: bool=False):
assert is_valid_rvalue(left_variable) or isinstance(left_variable, Function) assert is_valid_rvalue(left_variable) or isinstance(left_variable, Function)
assert is_valid_rvalue(right_variable) or isinstance(right_variable, Function) assert is_valid_rvalue(right_variable) or isinstance(right_variable, Function)
assert is_valid_lvalue(result) assert is_valid_lvalue(result)
@ -144,6 +144,7 @@ class Binary(OperationWithLValue):
result.set_type(ElementaryType("bool")) result.set_type(ElementaryType("bool"))
else: else:
result.set_type(left_variable.type) result.set_type(left_variable.type)
self.is_checked = is_checked
@property @property
def read(self): def read(self):

@ -2,6 +2,7 @@ import logging
from typing import Dict, Optional, Union, List, TYPE_CHECKING from typing import Dict, Optional, Union, List, TYPE_CHECKING
from slither.core.cfg.node import NodeType, link_nodes, insert_node, Node from slither.core.cfg.node import NodeType, link_nodes, insert_node, Node
from slither.core.cfg.scope import Scope
from slither.core.declarations.contract import Contract from slither.core.declarations.contract import Contract
from slither.core.declarations.function import ( from slither.core.declarations.function import (
Function, Function,
@ -328,14 +329,15 @@ class FunctionSolc:
################################################################################### ###################################################################################
################################################################################### ###################################################################################
def _new_node(self, node_type: NodeType, src: Union[str, Dict]) -> NodeSolc: def _new_node(self, node_type: NodeType, src: Union[str, Dict], scope: Union[Scope, "Function"]) -> NodeSolc:
node = self._function.new_node(node_type, src) node = self._function.new_node(node_type, src, scope)
node_parser = NodeSolc(node) node_parser = NodeSolc(node)
self._node_to_nodesolc[node] = node_parser self._node_to_nodesolc[node] = node_parser
return node_parser return node_parser
def _new_yul_block(self, src: Union[str, Dict]) -> YulBlock: def _new_yul_block(self, src: Union[str, Dict], father_scope: Union[Scope, Function]) -> YulBlock:
node = self._function.new_node(NodeType.ASSEMBLY, src) scope = Scope(False, True, father_scope)
node = self._function.new_node(NodeType.ASSEMBLY, src, scope)
contract = None contract = None
if isinstance(self._function, FunctionContract): if isinstance(self._function, FunctionContract):
contract = self._function.contract contract = self._function.contract
@ -343,6 +345,7 @@ class FunctionSolc:
contract, contract,
node, node,
[self._function.name, f"asm_{len(self._node_to_yulobject)}"], [self._function.name, f"asm_{len(self._node_to_yulobject)}"],
scope,
parent_func=self._function, parent_func=self._function,
) )
self._node_to_yulobject[node] = yul_object self._node_to_yulobject[node] = yul_object
@ -363,25 +366,29 @@ class FunctionSolc:
condition = if_statement["condition"] condition = if_statement["condition"]
# Note: check if the expression could be directly # Note: check if the expression could be directly
# parsed here # parsed here
condition_node = self._new_node(NodeType.IF, condition["src"]) condition_node = self._new_node(NodeType.IF, condition["src"], node.underlying_node.scope)
condition_node.add_unparsed_expression(condition) condition_node.add_unparsed_expression(condition)
link_underlying_nodes(node, condition_node) link_underlying_nodes(node, condition_node)
trueStatement = self._parse_statement(if_statement["trueBody"], condition_node) true_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
trueStatement = self._parse_statement(if_statement["trueBody"], condition_node, true_scope)
if "falseBody" in if_statement and if_statement["falseBody"]: if "falseBody" in if_statement and if_statement["falseBody"]:
falseStatement = self._parse_statement(if_statement["falseBody"], condition_node) false_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
falseStatement = self._parse_statement(if_statement["falseBody"], condition_node, false_scope)
else: else:
children = if_statement[self.get_children("children")] children = if_statement[self.get_children("children")]
condition = children[0] condition = children[0]
# Note: check if the expression could be directly # Note: check if the expression could be directly
# parsed here # parsed here
condition_node = self._new_node(NodeType.IF, condition["src"]) condition_node = self._new_node(NodeType.IF, condition["src"], node.underlying_node.scope)
condition_node.add_unparsed_expression(condition) condition_node.add_unparsed_expression(condition)
link_underlying_nodes(node, condition_node) link_underlying_nodes(node, condition_node)
trueStatement = self._parse_statement(children[1], condition_node) true_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
trueStatement = self._parse_statement(children[1], condition_node, true_scope)
if len(children) == 3: if len(children) == 3:
falseStatement = self._parse_statement(children[2], condition_node) false_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
falseStatement = self._parse_statement(children[2], condition_node, false_scope)
endIf_node = self._new_node(NodeType.ENDIF, if_statement["src"]) endIf_node = self._new_node(NodeType.ENDIF, if_statement["src"], node.underlying_node.scope)
link_underlying_nodes(trueStatement, endIf_node) link_underlying_nodes(trueStatement, endIf_node)
if falseStatement: if falseStatement:
@ -393,20 +400,21 @@ class FunctionSolc:
def _parse_while(self, whilte_statement: Dict, node: NodeSolc) -> NodeSolc: def _parse_while(self, whilte_statement: Dict, node: NodeSolc) -> NodeSolc:
# WhileStatement = 'while' '(' Expression ')' Statement # WhileStatement = 'while' '(' Expression ')' Statement
node_startWhile = self._new_node(NodeType.STARTLOOP, whilte_statement["src"]) node_startWhile = self._new_node(NodeType.STARTLOOP, whilte_statement["src"], node.underlying_node.scope)
body_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
if self.is_compact_ast: if self.is_compact_ast:
node_condition = self._new_node(NodeType.IFLOOP, whilte_statement["condition"]["src"]) node_condition = self._new_node(NodeType.IFLOOP, whilte_statement["condition"]["src"], node.underlying_node.scope)
node_condition.add_unparsed_expression(whilte_statement["condition"]) node_condition.add_unparsed_expression(whilte_statement["condition"])
statement = self._parse_statement(whilte_statement["body"], node_condition) statement = self._parse_statement(whilte_statement["body"], node_condition, body_scope)
else: else:
children = whilte_statement[self.get_children("children")] children = whilte_statement[self.get_children("children")]
expression = children[0] expression = children[0]
node_condition = self._new_node(NodeType.IFLOOP, expression["src"]) node_condition = self._new_node(NodeType.IFLOOP, expression["src"], node.underlying_node.scope)
node_condition.add_unparsed_expression(expression) node_condition.add_unparsed_expression(expression)
statement = self._parse_statement(children[1], node_condition) statement = self._parse_statement(children[1], node_condition, body_scope)
node_endWhile = self._new_node(NodeType.ENDLOOP, whilte_statement["src"]) node_endWhile = self._new_node(NodeType.ENDLOOP, whilte_statement["src"], node.underlying_node.scope)
link_underlying_nodes(node, node_startWhile) link_underlying_nodes(node, node_startWhile)
link_underlying_nodes(node_startWhile, node_condition) link_underlying_nodes(node_startWhile, node_condition)
@ -542,17 +550,23 @@ class FunctionSolc:
else: else:
pre, cond, post, body = self._parse_for_legacy_ast(statement) pre, cond, post, body = self._parse_for_legacy_ast(statement)
node_startLoop = self._new_node(NodeType.STARTLOOP, statement["src"]) node_startLoop = self._new_node(NodeType.STARTLOOP, statement["src"], node.underlying_node.scope)
node_endLoop = self._new_node(NodeType.ENDLOOP, statement["src"]) node_endLoop = self._new_node(NodeType.ENDLOOP, statement["src"], node.underlying_node.scope)
last_scope = node.underlying_node.scope
if pre: if pre:
node_init_expression = self._parse_statement(pre, node) pre_scope = Scope(node.underlying_node.scope.is_checked, False, last_scope)
last_scope = pre_scope
node_init_expression = self._parse_statement(pre, node, pre_scope)
link_underlying_nodes(node_init_expression, node_startLoop) link_underlying_nodes(node_init_expression, node_startLoop)
else: else:
link_underlying_nodes(node, node_startLoop) link_underlying_nodes(node, node_startLoop)
if cond: if cond:
node_condition = self._new_node(NodeType.IFLOOP, cond["src"]) cond_scope = Scope(node.underlying_node.scope.is_checked, False, last_scope)
cond_scope = last_scope
node_condition = self._new_node(NodeType.IFLOOP, cond["src"], cond_scope)
node_condition.add_unparsed_expression(cond) node_condition.add_unparsed_expression(cond)
link_underlying_nodes(node_startLoop, node_condition) link_underlying_nodes(node_startLoop, node_condition)
@ -561,10 +575,12 @@ class FunctionSolc:
node_condition = None node_condition = None
node_beforeBody = node_startLoop node_beforeBody = node_startLoop
node_body = self._parse_statement(body, node_beforeBody) body_scope = Scope(node.underlying_node.scope.is_checked, False, last_scope)
last_scope = body_scope
node_body = self._parse_statement(body, node_beforeBody, body_scope)
if post: if post:
node_loopexpression = self._parse_statement(post, node_body) node_loopexpression = self._parse_statement(post, node_body, last_scope)
link_underlying_nodes(node_loopexpression, node_beforeBody) link_underlying_nodes(node_loopexpression, node_beforeBody)
else: else:
# node_loopexpression = None # node_loopexpression = None
@ -581,21 +597,23 @@ class FunctionSolc:
def _parse_dowhile(self, do_while_statement: Dict, node: NodeSolc) -> NodeSolc: def _parse_dowhile(self, do_while_statement: Dict, node: NodeSolc) -> NodeSolc:
node_startDoWhile = self._new_node(NodeType.STARTLOOP, do_while_statement["src"]) node_startDoWhile = self._new_node(NodeType.STARTLOOP, do_while_statement["src"], node.underlying_node.scope)
condition_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
if self.is_compact_ast: if self.is_compact_ast:
node_condition = self._new_node(NodeType.IFLOOP, do_while_statement["condition"]["src"]) node_condition = self._new_node(NodeType.IFLOOP, do_while_statement["condition"]["src"], condition_scope)
node_condition.add_unparsed_expression(do_while_statement["condition"]) node_condition.add_unparsed_expression(do_while_statement["condition"])
statement = self._parse_statement(do_while_statement["body"], node_condition) statement = self._parse_statement(do_while_statement["body"], node_condition, condition_scope)
else: else:
children = do_while_statement[self.get_children("children")] children = do_while_statement[self.get_children("children")]
# same order in the AST as while # same order in the AST as while
expression = children[0] expression = children[0]
node_condition = self._new_node(NodeType.IFLOOP, expression["src"]) node_condition = self._new_node(NodeType.IFLOOP, expression["src"], condition_scope)
node_condition.add_unparsed_expression(expression) node_condition.add_unparsed_expression(expression)
statement = self._parse_statement(children[1], node_condition) statement = self._parse_statement(children[1], node_condition, condition_scope)
node_endDoWhile = self._new_node(NodeType.ENDLOOP, do_while_statement["src"]) body_scope = Scope(node.underlying_node.scope.is_checked, False, condition_scope)
node_endDoWhile = self._new_node(NodeType.ENDLOOP, do_while_statement["src"], body_scope)
link_underlying_nodes(node, node_startDoWhile) link_underlying_nodes(node, node_startDoWhile)
# empty block, loop from the start to the condition # empty block, loop from the start to the condition
@ -615,8 +633,8 @@ class FunctionSolc:
if externalCall is None: if externalCall is None:
raise ParsingError("Try/Catch not correctly parsed by Slither %s" % statement) raise ParsingError("Try/Catch not correctly parsed by Slither %s" % statement)
catch_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
new_node = self._new_node(NodeType.TRY, statement["src"]) new_node = self._new_node(NodeType.TRY, statement["src"], catch_scope)
new_node.add_unparsed_expression(externalCall) new_node.add_unparsed_expression(externalCall)
link_underlying_nodes(node, new_node) link_underlying_nodes(node, new_node)
node = new_node node = new_node
@ -630,7 +648,9 @@ class FunctionSolc:
if block is None: if block is None:
raise ParsingError("Catch not correctly parsed by Slither %s" % statement) raise ParsingError("Catch not correctly parsed by Slither %s" % statement)
try_node = self._new_node(NodeType.CATCH, statement["src"]) try_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
try_node = self._new_node(NodeType.CATCH, statement["src"], try_scope)
link_underlying_nodes(node, try_node) link_underlying_nodes(node, try_node)
if self.is_compact_ast: if self.is_compact_ast:
@ -643,7 +663,7 @@ class FunctionSolc:
assert param[self.get_key()] == "VariableDeclaration" assert param[self.get_key()] == "VariableDeclaration"
self._add_param(param) self._add_param(param)
return self._parse_statement(block, try_node) return self._parse_statement(block, try_node, try_scope)
def _parse_variable_definition(self, statement: Dict, node: NodeSolc) -> NodeSolc: def _parse_variable_definition(self, statement: Dict, node: NodeSolc) -> NodeSolc:
try: try:
@ -655,7 +675,7 @@ class FunctionSolc:
self._add_local_variable(local_var_parser) self._add_local_variable(local_var_parser)
# local_var.analyze(self) # local_var.analyze(self)
new_node = self._new_node(NodeType.VARIABLE, statement["src"]) new_node = self._new_node(NodeType.VARIABLE, statement["src"], node.underlying_node.scope)
new_node.underlying_node.add_variable_declaration(local_var) new_node.underlying_node.add_variable_declaration(local_var)
link_underlying_nodes(node, new_node) link_underlying_nodes(node, new_node)
return new_node return new_node
@ -738,7 +758,7 @@ class FunctionSolc:
"typeDescriptions": {"typeString": "tuple()"}, "typeDescriptions": {"typeString": "tuple()"},
} }
node = new_node node = new_node
new_node = self._new_node(NodeType.EXPRESSION, statement["src"]) new_node = self._new_node(NodeType.EXPRESSION, statement["src"], node.underlying_node.scope)
new_node.add_unparsed_expression(expression) new_node.add_unparsed_expression(expression)
link_underlying_nodes(node, new_node) link_underlying_nodes(node, new_node)
@ -818,7 +838,7 @@ class FunctionSolc:
], ],
} }
node = new_node node = new_node
new_node = self._new_node(NodeType.EXPRESSION, statement["src"]) new_node = self._new_node(NodeType.EXPRESSION, statement["src"], node.underlying_node.scope)
new_node.add_unparsed_expression(expression) new_node.add_unparsed_expression(expression)
link_underlying_nodes(node, new_node) link_underlying_nodes(node, new_node)
@ -835,12 +855,12 @@ class FunctionSolc:
self._add_local_variable(local_var_parser) self._add_local_variable(local_var_parser)
new_node = self._new_node(NodeType.VARIABLE, statement["src"]) new_node = self._new_node(NodeType.VARIABLE, statement["src"], node.underlying_node.scope)
new_node.underlying_node.add_variable_declaration(local_var) new_node.underlying_node.add_variable_declaration(local_var)
link_underlying_nodes(node, new_node) link_underlying_nodes(node, new_node)
return new_node return new_node
def _parse_statement(self, statement: Dict, node: NodeSolc) -> NodeSolc: def _parse_statement(self, statement: Dict, node: NodeSolc, scope: Union[Scope, Function]) -> NodeSolc:
""" """
Return: Return:
@ -865,7 +885,7 @@ class FunctionSolc:
# Added with solc 0.6 - the yul code is an AST # Added with solc 0.6 - the yul code is an AST
if "AST" in statement and not self.compilation_unit.core.skip_assembly: if "AST" in statement and not self.compilation_unit.core.skip_assembly:
self._function.contains_assembly = True self._function.contains_assembly = True
yul_object = self._new_yul_block(statement["src"]) yul_object = self._new_yul_block(statement["src"], scope)
entrypoint = yul_object.entrypoint entrypoint = yul_object.entrypoint
exitpoint = yul_object.convert(statement["AST"]) exitpoint = yul_object.convert(statement["AST"])
@ -874,7 +894,7 @@ class FunctionSolc:
link_underlying_nodes(node, entrypoint) link_underlying_nodes(node, entrypoint)
node = exitpoint node = exitpoint
else: else:
asm_node = self._new_node(NodeType.ASSEMBLY, statement["src"]) asm_node = self._new_node(NodeType.ASSEMBLY, statement["src"], scope)
self._function.contains_assembly = True self._function.contains_assembly = True
# Added with solc 0.4.12 # Added with solc 0.4.12
if "operations" in statement: if "operations" in statement:
@ -886,15 +906,15 @@ class FunctionSolc:
# For Continue / Break / Return / Throw # For Continue / Break / Return / Throw
# The is fixed later # The is fixed later
elif name == "Continue": elif name == "Continue":
continue_node = self._new_node(NodeType.CONTINUE, statement["src"]) continue_node = self._new_node(NodeType.CONTINUE, statement["src"], scope)
link_underlying_nodes(node, continue_node) link_underlying_nodes(node, continue_node)
node = continue_node node = continue_node
elif name == "Break": elif name == "Break":
break_node = self._new_node(NodeType.BREAK, statement["src"]) break_node = self._new_node(NodeType.BREAK, statement["src"], scope)
link_underlying_nodes(node, break_node) link_underlying_nodes(node, break_node)
node = break_node node = break_node
elif name == "Return": elif name == "Return":
return_node = self._new_node(NodeType.RETURN, statement["src"]) return_node = self._new_node(NodeType.RETURN, statement["src"], scope)
link_underlying_nodes(node, return_node) link_underlying_nodes(node, return_node)
if self.is_compact_ast: if self.is_compact_ast:
if statement.get("expression", None): if statement.get("expression", None):
@ -909,7 +929,7 @@ class FunctionSolc:
return_node.add_unparsed_expression(expression) return_node.add_unparsed_expression(expression)
node = return_node node = return_node
elif name == "Throw": elif name == "Throw":
throw_node = self._new_node(NodeType.THROW, statement["src"]) throw_node = self._new_node(NodeType.THROW, statement["src"], scope)
link_underlying_nodes(node, throw_node) link_underlying_nodes(node, throw_node)
node = throw_node node = throw_node
elif name == "EmitStatement": elif name == "EmitStatement":
@ -918,7 +938,7 @@ class FunctionSolc:
expression = statement["eventCall"] expression = statement["eventCall"]
else: else:
expression = statement[self.get_children("children")][0] expression = statement[self.get_children("children")][0]
new_node = self._new_node(NodeType.EXPRESSION, statement["src"]) new_node = self._new_node(NodeType.EXPRESSION, statement["src"], scope)
new_node.add_unparsed_expression(expression) new_node.add_unparsed_expression(expression)
link_underlying_nodes(node, new_node) link_underlying_nodes(node, new_node)
node = new_node node = new_node
@ -932,7 +952,7 @@ class FunctionSolc:
expression = statement[self.get_children("expression")] expression = statement[self.get_children("expression")]
else: else:
expression = statement[self.get_children("expression")][0] expression = statement[self.get_children("expression")][0]
new_node = self._new_node(NodeType.EXPRESSION, statement["src"]) new_node = self._new_node(NodeType.EXPRESSION, statement["src"], scope)
new_node.add_unparsed_expression(expression) new_node.add_unparsed_expression(expression)
link_underlying_nodes(node, new_node) link_underlying_nodes(node, new_node)
node = new_node node = new_node
@ -957,15 +977,16 @@ class FunctionSolc:
else: else:
statements = block[self.get_children("children")] statements = block[self.get_children("children")]
new_scope = Scope(node.underlying_node.scope.is_checked, False, node.underlying_node.scope)
for statement in statements: for statement in statements:
node = self._parse_statement(statement, node) node = self._parse_statement(statement, node, new_scope)
return node return node
def _parse_cfg(self, cfg: Dict): def _parse_cfg(self, cfg: Dict):
assert cfg[self.get_key()] == "Block" assert cfg[self.get_key()] == "Block"
node = self._new_node(NodeType.ENTRYPOINT, cfg["src"]) node = self._new_node(NodeType.ENTRYPOINT, cfg["src"], self.underlying_function)
self._function.entry_point = node.underlying_node self._function.entry_point = node.underlying_node
if self.is_compact_ast: if self.is_compact_ast:
@ -1125,7 +1146,7 @@ class FunctionSolc:
for m in ExportValues(m).result(): for m in ExportValues(m).result():
if isinstance(m, Function): if isinstance(m, Function):
node_parser = self._new_node(NodeType.EXPRESSION, modifier["src"]) node_parser = self._new_node(NodeType.EXPRESSION, modifier["src"], self.underlying_function)
node_parser.add_unparsed_expression(modifier) node_parser.add_unparsed_expression(modifier)
# The latest entry point is the entry point, or the latest modifier call # The latest entry point is the entry point, or the latest modifier call
if self._function.modifiers: if self._function.modifiers:
@ -1142,7 +1163,7 @@ class FunctionSolc:
) )
elif isinstance(m, Contract): elif isinstance(m, Contract):
node_parser = self._new_node(NodeType.EXPRESSION, modifier["src"]) node_parser = self._new_node(NodeType.EXPRESSION, modifier["src"], self.underlying_function)
node_parser.add_unparsed_expression(modifier) node_parser.add_unparsed_expression(modifier)
# The latest entry point is the entry point, or the latest constructor call # The latest entry point is the entry point, or the latest constructor call
if self._function.explicit_base_constructor_calls_statements: if self._function.explicit_base_constructor_calls_statements:
@ -1270,14 +1291,14 @@ class FunctionSolc:
true_expr: "Expression", true_expr: "Expression",
false_expr: "Expression", false_expr: "Expression",
): ):
condition_node = self._new_node(NodeType.IF, node.source_mapping) condition_node = self._new_node(NodeType.IF, node.source_mapping, node.scope)
condition_node.underlying_node.add_expression(condition) condition_node.underlying_node.add_expression(condition)
condition_node.analyze_expressions(self) condition_node.analyze_expressions(self)
if node.type == NodeType.VARIABLE: if node.type == NodeType.VARIABLE:
condition_node.underlying_node.add_variable_declaration(node.variable_declaration) condition_node.underlying_node.add_variable_declaration(node.variable_declaration)
true_node_parser = self._new_node(NodeType.EXPRESSION, node.source_mapping) true_node_parser = self._new_node(NodeType.EXPRESSION, node.source_mapping, node.scope)
if node.type == NodeType.VARIABLE: if node.type == NodeType.VARIABLE:
assert isinstance(true_expr, AssignmentOperation) assert isinstance(true_expr, AssignmentOperation)
# true_expr = true_expr.expression_right # true_expr = true_expr.expression_right
@ -1286,7 +1307,7 @@ class FunctionSolc:
true_node_parser.underlying_node.add_expression(true_expr) true_node_parser.underlying_node.add_expression(true_expr)
true_node_parser.analyze_expressions(self) true_node_parser.analyze_expressions(self)
false_node_parser = self._new_node(NodeType.EXPRESSION, node.source_mapping) false_node_parser = self._new_node(NodeType.EXPRESSION, node.source_mapping, node.scope)
if node.type == NodeType.VARIABLE: if node.type == NodeType.VARIABLE:
assert isinstance(false_expr, AssignmentOperation) assert isinstance(false_expr, AssignmentOperation)
elif node.type == NodeType.RETURN: elif node.type == NodeType.RETURN:
@ -1295,7 +1316,7 @@ class FunctionSolc:
false_node_parser.underlying_node.add_expression(false_expr) false_node_parser.underlying_node.add_expression(false_expr)
false_node_parser.analyze_expressions(self) false_node_parser.analyze_expressions(self)
endif_node = self._new_node(NodeType.ENDIF, node.source_mapping) endif_node = self._new_node(NodeType.ENDIF, node.source_mapping, node.scope)
for father in node.fathers: for father in node.fathers:
father.remove_son(node) father.remove_son(node)

@ -1,10 +1,11 @@
""" """
Event module Event module
""" """
from typing import Dict, TYPE_CHECKING from typing import Dict, TYPE_CHECKING, Union
from slither.core.cfg.node import NodeType from slither.core.cfg.node import NodeType
from slither.core.cfg.node import link_nodes from slither.core.cfg.node import link_nodes
from slither.core.cfg.scope import Scope
from slither.core.declarations.modifier import Modifier from slither.core.declarations.modifier import Modifier
from slither.solc_parsing.cfg.node import NodeSolc from slither.solc_parsing.cfg.node import NodeSolc
from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.function import FunctionSolc
@ -12,6 +13,7 @@ from slither.solc_parsing.declarations.function import FunctionSolc
if TYPE_CHECKING: if TYPE_CHECKING:
from slither.solc_parsing.declarations.contract import ContractSolc from slither.solc_parsing.declarations.contract import ContractSolc
from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc
from slither.core.declarations import Function
class ModifierSolc(FunctionSolc): class ModifierSolc(FunctionSolc):
@ -91,10 +93,10 @@ class ModifierSolc(FunctionSolc):
# self._analyze_read_write() # self._analyze_read_write()
# self._analyze_calls() # self._analyze_calls()
def _parse_statement(self, statement: Dict, node: NodeSolc) -> NodeSolc: def _parse_statement(self, statement: Dict, node: NodeSolc, scope: Union[Scope, "Function"]) -> NodeSolc:
name = statement[self.get_key()] name = statement[self.get_key()]
if name == "PlaceholderStatement": if name == "PlaceholderStatement":
placeholder_node = self._new_node(NodeType.PLACEHOLDER, statement["src"]) placeholder_node = self._new_node(NodeType.PLACEHOLDER, statement["src"], scope)
link_nodes(node.underlying_node, placeholder_node.underlying_node) link_nodes(node.underlying_node, placeholder_node.underlying_node)
return placeholder_node return placeholder_node
return super()._parse_statement(statement, node) return super()._parse_statement(statement, node, scope)

@ -3,6 +3,7 @@ import json
from typing import Optional, Dict, List, Union from typing import Optional, Dict, List, Union
from slither.core.cfg.node import NodeType, Node, link_nodes from slither.core.cfg.node import NodeType, Node, link_nodes
from slither.core.cfg.scope import Scope
from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.declarations import ( from slither.core.declarations import (
Function, Function,
@ -22,6 +23,7 @@ from slither.core.expressions import (
) )
from slither.core.expressions.expression import Expression from slither.core.expressions.expression import Expression
from slither.core.solidity_types import ElementaryType 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.local_variable import LocalVariable
from slither.exceptions import SlitherException from slither.exceptions import SlitherException
from slither.solc_parsing.yul.evm_functions import ( from slither.solc_parsing.yul.evm_functions import (
@ -196,9 +198,9 @@ class YulLocalVariable: # pylint: disable=too-few-public-methods
class YulFunction(YulScope): class YulFunction(YulScope):
__slots__ = ["_function", "_root", "_ast", "_nodes", "_entrypoint"] __slots__ = ["_function", "_root", "_ast", "_nodes", "_entrypoint", "node_scope"]
def __init__(self, func: Function, root: YulScope, ast: Dict): def __init__(self, func: Function, root: YulScope, ast: Dict, node_scope: Union[Function, Scope]):
super().__init__(root.contract, root.id + [ast["name"]], parent_func=root.parent_func) super().__init__(root.contract, root.id + [ast["name"]], parent_func=root.parent_func)
assert ast["nodeType"] == "YulFunctionDefinition" assert ast["nodeType"] == "YulFunctionDefinition"
@ -211,12 +213,15 @@ class YulFunction(YulScope):
func.name = ast["name"] func.name = ast["name"]
func.set_visibility("private") func.set_visibility("private")
func.set_offset(ast["src"], root.compilation_unit) if isinstance(func, SourceMapping):
func.set_contract(root.contract) func.set_offset(ast["src"], root.compilation_unit)
if isinstance(func, FunctionContract):
func.set_contract(root.contract)
func.set_contract_declarer(root.contract)
func.compilation_unit = root.compilation_unit func.compilation_unit = root.compilation_unit
func.set_contract_declarer(root.contract)
func.scope = root.id func.scope = root.id
func.is_implemented = True func.is_implemented = True
self.node_scope = node_scope
self._nodes: List[YulNode] = [] self._nodes: List[YulNode] = []
self._entrypoint = self.new_node(NodeType.ASSEMBLY, ast["src"]) self._entrypoint = self.new_node(NodeType.ASSEMBLY, ast["src"])
@ -237,16 +242,16 @@ class YulFunction(YulScope):
link_underlying_nodes(self._entrypoint, node) link_underlying_nodes(self._entrypoint, node)
for param in self._ast.get("parameters", []): for param in self._ast.get("parameters", []):
node = convert_yul(self, node, param) node = convert_yul(self, node, param, self.node_scope)
self._function.add_parameters( self._function.add_parameters(
self.get_yul_local_variable_from_name(param["name"]).underlying self.get_yul_local_variable_from_name(param["name"]).underlying
) )
for ret in self._ast.get("returnVariables", []): for ret in self._ast.get("returnVariables", []):
node = convert_yul(self, node, ret) node = convert_yul(self, node, ret, self.node_scope)
self._function.add_return(self.get_yul_local_variable_from_name(ret["name"]).underlying) self._function.add_return(self.get_yul_local_variable_from_name(ret["name"]).underlying)
convert_yul(self, node, self._ast["body"]) convert_yul(self, node, self._ast["body"], self.node_scope)
def parse_body(self): def parse_body(self):
for node in self._nodes: for node in self._nodes:
@ -254,7 +259,7 @@ class YulFunction(YulScope):
def new_node(self, node_type, src) -> YulNode: def new_node(self, node_type, src) -> YulNode:
if self._function: if self._function:
node = self._function.new_node(node_type, src) node = self._function.new_node(node_type, src, self.node_scope)
else: else:
raise SlitherException("standalone yul objects are not supported yet") raise SlitherException("standalone yul objects are not supported yet")
@ -270,13 +275,14 @@ class YulBlock(YulScope):
""" """
__slots__ = ["_entrypoint", "_parent_func", "_nodes"] __slots__ = ["_entrypoint", "_parent_func", "_nodes", "node_scope"]
def __init__(self, contract: Optional[Contract], entrypoint: Node, yul_id: List[str], **kwargs): def __init__(self, contract: Optional[Contract], entrypoint: Node, yul_id: List[str], node_scope: Union[Scope, Function], **kwargs):
super().__init__(contract, yul_id, **kwargs) super().__init__(contract, yul_id, **kwargs)
self._entrypoint: YulNode = YulNode(entrypoint, self) self._entrypoint: YulNode = YulNode(entrypoint, self)
self._nodes: List[YulNode] = [] self._nodes: List[YulNode] = []
self.node_scope = node_scope
@property @property
def entrypoint(self) -> YulNode: def entrypoint(self) -> YulNode:
@ -288,7 +294,7 @@ class YulBlock(YulScope):
def new_node(self, node_type: NodeType, src: Union[str, Dict]) -> YulNode: def new_node(self, node_type: NodeType, src: Union[str, Dict]) -> YulNode:
if self._parent_func: if self._parent_func:
node = self._parent_func.new_node(node_type, src) node = self._parent_func.new_node(node_type, src, self.node_scope)
else: else:
raise SlitherException("standalone yul objects are not supported yet") raise SlitherException("standalone yul objects are not supported yet")
@ -297,7 +303,7 @@ class YulBlock(YulScope):
return yul_node return yul_node
def convert(self, ast: Dict) -> YulNode: def convert(self, ast: Dict) -> YulNode:
return convert_yul(self, self._entrypoint, ast) return convert_yul(self, self._entrypoint, ast, self.node_scope)
def analyze_expressions(self): def analyze_expressions(self):
for node in self._nodes: for node in self._nodes:
@ -327,9 +333,9 @@ class YulBlock(YulScope):
# dispatches to a specialized function based on a lookup dictionary. # dispatches to a specialized function based on a lookup dictionary.
def convert_yul_block(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_block(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode:
for statement in ast["statements"]: for statement in ast["statements"]:
parent = convert_yul(root, parent, statement) parent = convert_yul(root, parent, statement, node_scope)
return parent return parent
@ -347,9 +353,9 @@ def convert_yul_function_definition(root: YulScope, parent: YulNode, ast: Dict)
return parent return parent
def convert_yul_variable_declaration(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_variable_declaration(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode:
for variable_ast in ast["variables"]: for variable_ast in ast["variables"]:
parent = convert_yul(root, parent, variable_ast) parent = convert_yul(root, parent, variable_ast, node_scope)
node = root.new_node(NodeType.EXPRESSION, ast["src"]) node = root.new_node(NodeType.EXPRESSION, ast["src"])
node.add_unparsed_expression(ast) node.add_unparsed_expression(ast)
@ -358,14 +364,14 @@ def convert_yul_variable_declaration(root: YulScope, parent: YulNode, ast: Dict)
return node return node
def convert_yul_assignment(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_assignment(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode:
node = root.new_node(NodeType.EXPRESSION, ast["src"]) node = root.new_node(NodeType.EXPRESSION, ast["src"])
node.add_unparsed_expression(ast) node.add_unparsed_expression(ast)
link_underlying_nodes(parent, node) link_underlying_nodes(parent, node)
return node return node
def convert_yul_expression_statement(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_expression_statement(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode:
src = ast["src"] src = ast["src"]
expression_ast = ast["expression"] expression_ast = ast["expression"]
@ -376,7 +382,7 @@ def convert_yul_expression_statement(root: YulScope, parent: YulNode, ast: Dict)
return expression return expression
def convert_yul_if(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_if(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode:
# we're cheating and pretending that yul supports if/else so we can convert switch cleaner # we're cheating and pretending that yul supports if/else so we can convert switch cleaner
src = ast["src"] src = ast["src"]
@ -389,10 +395,10 @@ def convert_yul_if(root: YulScope, parent: YulNode, ast: Dict) -> YulNode:
condition.add_unparsed_expression(condition_ast) condition.add_unparsed_expression(condition_ast)
true_body = convert_yul(root, condition, true_body_ast) true_body = convert_yul(root, condition, true_body_ast, node_scope)
if false_body_ast: if false_body_ast:
false_body = convert_yul(root, condition, false_body_ast) false_body = convert_yul(root, condition, false_body_ast, node_scope)
link_underlying_nodes(false_body, end) link_underlying_nodes(false_body, end)
else: else:
link_underlying_nodes(condition, end) link_underlying_nodes(condition, end)
@ -403,7 +409,7 @@ def convert_yul_if(root: YulScope, parent: YulNode, ast: Dict) -> YulNode:
return end return end
def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode:
""" """
This is unfortunate. We don't really want a switch in our IR so we're going to This is unfortunate. We don't really want a switch in our IR so we're going to
translate it into a series of if/else statements. translate it into a series of if/else statements.
@ -484,10 +490,10 @@ def convert_yul_switch(root: YulScope, parent: YulNode, ast: Dict) -> YulNode:
else: else:
rewritten_switch["statements"].append(body_ast) rewritten_switch["statements"].append(body_ast)
return convert_yul(root, parent, rewritten_switch) return convert_yul(root, parent, rewritten_switch, node_scope)
def convert_yul_for_loop(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_for_loop(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode:
pre_ast = ast["pre"] pre_ast = ast["pre"]
condition_ast = ast["condition"] condition_ast = ast["condition"]
post_ast = ast["post"] post_ast = ast["post"]
@ -498,7 +504,7 @@ def convert_yul_for_loop(root: YulScope, parent: YulNode, ast: Dict) -> YulNode:
link_underlying_nodes(parent, start_loop) link_underlying_nodes(parent, start_loop)
pre = convert_yul(root, start_loop, pre_ast) pre = convert_yul(root, start_loop, pre_ast, node_scope)
condition = root.new_node(NodeType.IFLOOP, condition_ast["src"]) condition = root.new_node(NodeType.IFLOOP, condition_ast["src"])
condition.add_unparsed_expression(condition_ast) condition.add_unparsed_expression(condition_ast)
@ -506,34 +512,34 @@ def convert_yul_for_loop(root: YulScope, parent: YulNode, ast: Dict) -> YulNode:
link_underlying_nodes(condition, end_loop) link_underlying_nodes(condition, end_loop)
body = convert_yul(root, condition, body_ast) body = convert_yul(root, condition, body_ast, node_scope)
post = convert_yul(root, body, post_ast) post = convert_yul(root, body, post_ast, node_scope)
link_underlying_nodes(post, condition) link_underlying_nodes(post, condition)
return end_loop return end_loop
def convert_yul_break(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_break(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode:
break_ = root.new_node(NodeType.BREAK, ast["src"]) break_ = root.new_node(NodeType.BREAK, ast["src"])
link_underlying_nodes(parent, break_) link_underlying_nodes(parent, break_)
return break_ return break_
def convert_yul_continue(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_continue(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode:
continue_ = root.new_node(NodeType.CONTINUE, ast["src"]) continue_ = root.new_node(NodeType.CONTINUE, ast["src"])
link_underlying_nodes(parent, continue_) link_underlying_nodes(parent, continue_)
return continue_ return continue_
def convert_yul_leave(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_leave(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode:
leave = root.new_node(NodeType.RETURN, ast["src"]) leave = root.new_node(NodeType.RETURN, ast["src"])
link_underlying_nodes(parent, leave) link_underlying_nodes(parent, leave)
return leave return leave
def convert_yul_typed_name(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_typed_name(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode:
local_var = LocalVariable() local_var = LocalVariable()
var = YulLocalVariable(local_var, root, ast) var = YulLocalVariable(local_var, root, ast)
@ -546,14 +552,14 @@ def convert_yul_typed_name(root: YulScope, parent: YulNode, ast: Dict) -> YulNod
return node return node
def convert_yul_unsupported(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul_unsupported(root: YulScope, parent: YulNode, ast: Dict, _node_scope: Union[Function, Scope]) -> YulNode:
raise SlitherException( raise SlitherException(
f"no converter available for {ast['nodeType']} {json.dumps(ast, indent=2)}" f"no converter available for {ast['nodeType']} {json.dumps(ast, indent=2)}"
) )
def convert_yul(root: YulScope, parent: YulNode, ast: Dict) -> YulNode: def convert_yul(root: YulScope, parent: YulNode, ast: Dict, node_scope: Union[Function, Scope]) -> YulNode:
return converters.get(ast["nodeType"], convert_yul_unsupported)(root, parent, ast) return converters.get(ast["nodeType"], convert_yul_unsupported)(root, parent, ast, node_scope)
converters = { converters = {

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

Loading…
Cancel
Save