|
|
@ -1,23 +1,26 @@ |
|
|
|
import logging |
|
|
|
import logging |
|
|
|
import re |
|
|
|
import re |
|
|
|
|
|
|
|
from typing import Dict, TYPE_CHECKING, Optional, Union |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
from slither.core.declarations import Event, Enum, Structure |
|
|
|
from slither.core.declarations.contract import Contract |
|
|
|
from slither.core.declarations.contract import Contract |
|
|
|
from slither.core.declarations.function import Function |
|
|
|
from slither.core.declarations.function import Function |
|
|
|
from slither.core.declarations.solidity_variables import (SOLIDITY_FUNCTIONS, |
|
|
|
from slither.core.declarations.solidity_variables import ( |
|
|
|
|
|
|
|
SOLIDITY_FUNCTIONS, |
|
|
|
SOLIDITY_VARIABLES, |
|
|
|
SOLIDITY_VARIABLES, |
|
|
|
SOLIDITY_VARIABLES_COMPOSED, |
|
|
|
SOLIDITY_VARIABLES_COMPOSED, |
|
|
|
SolidityFunction, |
|
|
|
SolidityFunction, |
|
|
|
SolidityVariable, |
|
|
|
SolidityVariable, |
|
|
|
SolidityVariableComposed) |
|
|
|
SolidityVariableComposed, |
|
|
|
from slither.core.expressions.assignment_operation import (AssignmentOperation, |
|
|
|
) |
|
|
|
AssignmentOperationType) |
|
|
|
from slither.core.expressions.assignment_operation import ( |
|
|
|
from slither.core.expressions.binary_operation import (BinaryOperation, |
|
|
|
AssignmentOperation, |
|
|
|
BinaryOperationType) |
|
|
|
AssignmentOperationType, |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
from slither.core.expressions.binary_operation import BinaryOperation, BinaryOperationType |
|
|
|
from slither.core.expressions.call_expression import CallExpression |
|
|
|
from slither.core.expressions.call_expression import CallExpression |
|
|
|
from slither.core.expressions.conditional_expression import \ |
|
|
|
from slither.core.expressions.conditional_expression import ConditionalExpression |
|
|
|
ConditionalExpression |
|
|
|
from slither.core.expressions.elementary_type_name_expression import ElementaryTypeNameExpression |
|
|
|
from slither.core.expressions.elementary_type_name_expression import \ |
|
|
|
|
|
|
|
ElementaryTypeNameExpression |
|
|
|
|
|
|
|
from slither.core.expressions.identifier import Identifier |
|
|
|
from slither.core.expressions.identifier import Identifier |
|
|
|
from slither.core.expressions.index_access import IndexAccess |
|
|
|
from slither.core.expressions.index_access import IndexAccess |
|
|
|
from slither.core.expressions.literal import Literal |
|
|
|
from slither.core.expressions.literal import Literal |
|
|
@ -29,16 +32,18 @@ from slither.core.expressions.super_call_expression import SuperCallExpression |
|
|
|
from slither.core.expressions.super_identifier import SuperIdentifier |
|
|
|
from slither.core.expressions.super_identifier import SuperIdentifier |
|
|
|
from slither.core.expressions.tuple_expression import TupleExpression |
|
|
|
from slither.core.expressions.tuple_expression import TupleExpression |
|
|
|
from slither.core.expressions.type_conversion import TypeConversion |
|
|
|
from slither.core.expressions.type_conversion import TypeConversion |
|
|
|
from slither.core.expressions.unary_operation import (UnaryOperation, |
|
|
|
from slither.core.expressions.unary_operation import UnaryOperation, UnaryOperationType |
|
|
|
UnaryOperationType) |
|
|
|
from slither.core.solidity_types import ArrayType, ElementaryType, FunctionType, MappingType |
|
|
|
from slither.core.solidity_types import (ArrayType, ElementaryType, |
|
|
|
from slither.core.variables.variable import Variable |
|
|
|
FunctionType, MappingType) |
|
|
|
|
|
|
|
from slither.solc_parsing.solidity_types.type_parsing import (UnknownType, |
|
|
|
|
|
|
|
parse_type) |
|
|
|
|
|
|
|
from slither.solc_parsing.exceptions import ParsingError, VariableNotFound |
|
|
|
from slither.solc_parsing.exceptions import ParsingError, VariableNotFound |
|
|
|
|
|
|
|
from slither.solc_parsing.solidity_types.type_parsing import UnknownType, parse_type |
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger("ExpressionParsing") |
|
|
|
if TYPE_CHECKING: |
|
|
|
|
|
|
|
from slither.core.expressions.expression import Expression |
|
|
|
|
|
|
|
from slither.solc_parsing.declarations.function import FunctionSolc |
|
|
|
|
|
|
|
from slither.solc_parsing.declarations.contract import ContractSolc |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
logger = logging.getLogger("ExpressionParsing") |
|
|
|
|
|
|
|
|
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
@ -46,21 +51,34 @@ logger = logging.getLogger("ExpressionParsing") |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
def get_pointer_name(variable): |
|
|
|
CallerContext = Union["ContractSolc", "FunctionSolc"] |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def get_pointer_name(variable: Variable): |
|
|
|
curr_type = variable.type |
|
|
|
curr_type = variable.type |
|
|
|
while (isinstance(curr_type, (ArrayType, MappingType))): |
|
|
|
while isinstance(curr_type, (ArrayType, MappingType)): |
|
|
|
if isinstance(curr_type, ArrayType): |
|
|
|
if isinstance(curr_type, ArrayType): |
|
|
|
curr_type = curr_type.type |
|
|
|
curr_type = curr_type.type |
|
|
|
else: |
|
|
|
else: |
|
|
|
assert isinstance(curr_type, MappingType) |
|
|
|
assert isinstance(curr_type, MappingType) |
|
|
|
curr_type = curr_type.type_to |
|
|
|
curr_type = curr_type.type_to |
|
|
|
|
|
|
|
|
|
|
|
if isinstance(curr_type, (FunctionType)): |
|
|
|
if isinstance(curr_type, FunctionType): |
|
|
|
return variable.name + curr_type.parameters_signature |
|
|
|
return variable.name + curr_type.parameters_signature |
|
|
|
return None |
|
|
|
return None |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def find_variable(var_name, caller_context, referenced_declaration=None, is_super=False): |
|
|
|
def find_variable( |
|
|
|
|
|
|
|
var_name: str, |
|
|
|
|
|
|
|
caller_context: CallerContext, |
|
|
|
|
|
|
|
referenced_declaration: Optional[int] = None, |
|
|
|
|
|
|
|
is_super=False, |
|
|
|
|
|
|
|
) -> Union[ |
|
|
|
|
|
|
|
Variable, Function, Contract, SolidityVariable, SolidityFunction, Event, Enum, Structure |
|
|
|
|
|
|
|
]: |
|
|
|
|
|
|
|
from slither.solc_parsing.declarations.contract import ContractSolc |
|
|
|
|
|
|
|
from slither.solc_parsing.declarations.function import FunctionSolc |
|
|
|
|
|
|
|
|
|
|
|
# variable are looked from the contract declarer |
|
|
|
# variable are looked from the contract declarer |
|
|
|
# functions can be shadowed, but are looked from the contract instance, rather than the contract declarer |
|
|
|
# functions can be shadowed, but are looked from the contract instance, rather than the contract declarer |
|
|
|
# the difference between function and variable come from the fact that an internal call, or an variable access |
|
|
|
# the difference between function and variable come from the fact that an internal call, or an variable access |
|
|
@ -76,24 +94,24 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe |
|
|
|
# for events it's unclear what should be the behavior, as they can be shadowed, but there is not impact |
|
|
|
# for events it's unclear what should be the behavior, as they can be shadowed, but there is not impact |
|
|
|
# structure/enums cannot be shadowed |
|
|
|
# structure/enums cannot be shadowed |
|
|
|
|
|
|
|
|
|
|
|
if isinstance(caller_context, Contract): |
|
|
|
if isinstance(caller_context, ContractSolc): |
|
|
|
function = None |
|
|
|
function: Optional[FunctionSolc] = None |
|
|
|
contract = caller_context |
|
|
|
contract = caller_context.underlying_contract |
|
|
|
contract_declarer = caller_context |
|
|
|
contract_declarer = caller_context.underlying_contract |
|
|
|
elif isinstance(caller_context, Function): |
|
|
|
elif isinstance(caller_context, FunctionSolc): |
|
|
|
function = caller_context |
|
|
|
function = caller_context |
|
|
|
contract = function.contract |
|
|
|
contract = function.underlying_function.contract |
|
|
|
contract_declarer = function.contract_declarer |
|
|
|
contract_declarer = function.underlying_function.contract_declarer |
|
|
|
else: |
|
|
|
else: |
|
|
|
raise ParsingError('Incorrect caller context') |
|
|
|
raise ParsingError("Incorrect caller context") |
|
|
|
|
|
|
|
|
|
|
|
if function: |
|
|
|
if function: |
|
|
|
# We look for variable declared with the referencedDeclaration attr |
|
|
|
# We look for variable declared with the referencedDeclaration attr |
|
|
|
func_variables = function.variables_renamed |
|
|
|
func_variables = function.variables_renamed |
|
|
|
if referenced_declaration and referenced_declaration in func_variables: |
|
|
|
if referenced_declaration and referenced_declaration in func_variables: |
|
|
|
return func_variables[referenced_declaration] |
|
|
|
return func_variables[referenced_declaration].underlying_variable |
|
|
|
# If not found, check for name |
|
|
|
# If not found, check for name |
|
|
|
func_variables = function.variables_as_dict() |
|
|
|
func_variables = function.underlying_function.variables_as_dict |
|
|
|
if var_name in func_variables: |
|
|
|
if var_name in func_variables: |
|
|
|
return func_variables[var_name] |
|
|
|
return func_variables[var_name] |
|
|
|
# A local variable can be a pointer |
|
|
|
# A local variable can be a pointer |
|
|
@ -101,12 +119,14 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe |
|
|
|
# function test(function(uint) internal returns(bool) t) interna{ |
|
|
|
# function test(function(uint) internal returns(bool) t) interna{ |
|
|
|
# Will have a local variable t which will match the signature |
|
|
|
# Will have a local variable t which will match the signature |
|
|
|
# t(uint256) |
|
|
|
# t(uint256) |
|
|
|
func_variables_ptr = {get_pointer_name(f): f for f in function.variables} |
|
|
|
func_variables_ptr = { |
|
|
|
|
|
|
|
get_pointer_name(f): f for f in function.underlying_function.variables |
|
|
|
|
|
|
|
} |
|
|
|
if var_name and var_name in func_variables_ptr: |
|
|
|
if var_name and var_name in func_variables_ptr: |
|
|
|
return func_variables_ptr[var_name] |
|
|
|
return func_variables_ptr[var_name] |
|
|
|
|
|
|
|
|
|
|
|
# variable are looked from the contract declarer |
|
|
|
# variable are looked from the contract declarer |
|
|
|
contract_variables = contract_declarer.variables_as_dict() |
|
|
|
contract_variables = contract_declarer.variables_as_dict |
|
|
|
if var_name in contract_variables: |
|
|
|
if var_name in contract_variables: |
|
|
|
return contract_variables[var_name] |
|
|
|
return contract_variables[var_name] |
|
|
|
|
|
|
|
|
|
|
@ -118,8 +138,12 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe |
|
|
|
if is_super: |
|
|
|
if is_super: |
|
|
|
getter_available = lambda f: f.functions_declared |
|
|
|
getter_available = lambda f: f.functions_declared |
|
|
|
d = {f.canonical_name: f for f in contract.functions} |
|
|
|
d = {f.canonical_name: f for f in contract.functions} |
|
|
|
functions = {f.full_name: f for f in |
|
|
|
functions = { |
|
|
|
contract_declarer.available_elements_from_inheritances(d, getter_available).values()} |
|
|
|
f.full_name: f |
|
|
|
|
|
|
|
for f in contract_declarer.available_elements_from_inheritances( |
|
|
|
|
|
|
|
d, getter_available |
|
|
|
|
|
|
|
).values() |
|
|
|
|
|
|
|
} |
|
|
|
else: |
|
|
|
else: |
|
|
|
functions = contract.available_functions_as_dict() |
|
|
|
functions = contract.available_functions_as_dict() |
|
|
|
if var_name in functions: |
|
|
|
if var_name in functions: |
|
|
@ -128,23 +152,27 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe |
|
|
|
if is_super: |
|
|
|
if is_super: |
|
|
|
getter_available = lambda m: m.modifiers_declared |
|
|
|
getter_available = lambda m: m.modifiers_declared |
|
|
|
d = {m.canonical_name: m for m in contract.modifiers} |
|
|
|
d = {m.canonical_name: m for m in contract.modifiers} |
|
|
|
modifiers = {m.full_name: m for m in |
|
|
|
modifiers = { |
|
|
|
contract_declarer.available_elements_from_inheritances(d, getter_available).values()} |
|
|
|
m.full_name: m |
|
|
|
|
|
|
|
for m in contract_declarer.available_elements_from_inheritances( |
|
|
|
|
|
|
|
d, getter_available |
|
|
|
|
|
|
|
).values() |
|
|
|
|
|
|
|
} |
|
|
|
else: |
|
|
|
else: |
|
|
|
modifiers = contract.available_modifiers_as_dict() |
|
|
|
modifiers = contract.available_modifiers_as_dict() |
|
|
|
if var_name in modifiers: |
|
|
|
if var_name in modifiers: |
|
|
|
return modifiers[var_name] |
|
|
|
return modifiers[var_name] |
|
|
|
|
|
|
|
|
|
|
|
# structures are looked on the contract declarer |
|
|
|
# structures are looked on the contract declarer |
|
|
|
structures = contract.structures_as_dict() |
|
|
|
structures = contract.structures_as_dict |
|
|
|
if var_name in structures: |
|
|
|
if var_name in structures: |
|
|
|
return structures[var_name] |
|
|
|
return structures[var_name] |
|
|
|
|
|
|
|
|
|
|
|
events = contract.events_as_dict() |
|
|
|
events = contract.events_as_dict |
|
|
|
if var_name in events: |
|
|
|
if var_name in events: |
|
|
|
return events[var_name] |
|
|
|
return events[var_name] |
|
|
|
|
|
|
|
|
|
|
|
enums = contract.enums_as_dict() |
|
|
|
enums = contract.enums_as_dict |
|
|
|
if var_name in enums: |
|
|
|
if var_name in enums: |
|
|
|
return enums[var_name] |
|
|
|
return enums[var_name] |
|
|
|
|
|
|
|
|
|
|
@ -154,7 +182,7 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe |
|
|
|
return enums[var_name] |
|
|
|
return enums[var_name] |
|
|
|
|
|
|
|
|
|
|
|
# Could refer to any enum |
|
|
|
# Could refer to any enum |
|
|
|
all_enums = [c.enums_as_dict() for c in contract.slither.contracts] |
|
|
|
all_enums = [c.enums_as_dict for c in contract.slither.contracts] |
|
|
|
all_enums = {k: v for d in all_enums for k, v in d.items()} |
|
|
|
all_enums = {k: v for d in all_enums for k, v in d.items()} |
|
|
|
if var_name in all_enums: |
|
|
|
if var_name in all_enums: |
|
|
|
return all_enums[var_name] |
|
|
|
return all_enums[var_name] |
|
|
@ -165,19 +193,22 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe |
|
|
|
if var_name in SOLIDITY_FUNCTIONS: |
|
|
|
if var_name in SOLIDITY_FUNCTIONS: |
|
|
|
return SolidityFunction(var_name) |
|
|
|
return SolidityFunction(var_name) |
|
|
|
|
|
|
|
|
|
|
|
contracts = contract.slither.contracts_as_dict() |
|
|
|
contracts = contract.slither.contracts_as_dict |
|
|
|
if var_name in contracts: |
|
|
|
if var_name in contracts: |
|
|
|
return contracts[var_name] |
|
|
|
return contracts[var_name] |
|
|
|
|
|
|
|
|
|
|
|
if referenced_declaration: |
|
|
|
if referenced_declaration: |
|
|
|
for contract in contract.slither.contracts: |
|
|
|
# id of the contracts is the referenced declaration |
|
|
|
if contract.id == referenced_declaration: |
|
|
|
# This is not true for the functions, as we dont always have the referenced_declaration |
|
|
|
return contract |
|
|
|
# But maybe we could? (TODO) |
|
|
|
for function in contract.slither.functions: |
|
|
|
for contract_candidate in contract.slither.contracts: |
|
|
|
if function.referenced_declaration == referenced_declaration: |
|
|
|
if contract_candidate.id == referenced_declaration: |
|
|
|
return function |
|
|
|
return contract_candidate |
|
|
|
|
|
|
|
for function_candidate in caller_context.slither_parser.all_functions_parser: |
|
|
|
|
|
|
|
if function_candidate.referenced_declaration == referenced_declaration: |
|
|
|
|
|
|
|
return function_candidate.underlying_function |
|
|
|
|
|
|
|
|
|
|
|
raise VariableNotFound('Variable not found: {} (context {})'.format(var_name, caller_context)) |
|
|
|
raise VariableNotFound("Variable not found: {} (context {})".format(var_name, caller_context)) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# endregion |
|
|
|
# endregion |
|
|
@ -187,38 +218,39 @@ def find_variable(var_name, caller_context, referenced_declaration=None, is_supe |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
def filter_name(value): |
|
|
|
|
|
|
|
value = value.replace(' memory', '') |
|
|
|
def filter_name(value: str) -> str: |
|
|
|
value = value.replace(' storage', '') |
|
|
|
value = value.replace(" memory", "") |
|
|
|
value = value.replace(' external', '') |
|
|
|
value = value.replace(" storage", "") |
|
|
|
value = value.replace(' internal', '') |
|
|
|
value = value.replace(" external", "") |
|
|
|
value = value.replace('struct ', '') |
|
|
|
value = value.replace(" internal", "") |
|
|
|
value = value.replace('contract ', '') |
|
|
|
value = value.replace("struct ", "") |
|
|
|
value = value.replace('enum ', '') |
|
|
|
value = value.replace("contract ", "") |
|
|
|
value = value.replace(' ref', '') |
|
|
|
value = value.replace("enum ", "") |
|
|
|
value = value.replace(' pointer', '') |
|
|
|
value = value.replace(" ref", "") |
|
|
|
value = value.replace(' pure', '') |
|
|
|
value = value.replace(" pointer", "") |
|
|
|
value = value.replace(' view', '') |
|
|
|
value = value.replace(" pure", "") |
|
|
|
value = value.replace(' constant', '') |
|
|
|
value = value.replace(" view", "") |
|
|
|
value = value.replace(' payable', '') |
|
|
|
value = value.replace(" constant", "") |
|
|
|
value = value.replace('function (', 'function(') |
|
|
|
value = value.replace(" payable", "") |
|
|
|
value = value.replace('returns (', 'returns(') |
|
|
|
value = value.replace("function (", "function(") |
|
|
|
|
|
|
|
value = value.replace("returns (", "returns(") |
|
|
|
|
|
|
|
|
|
|
|
# remove the text remaining after functio(...) |
|
|
|
# remove the text remaining after functio(...) |
|
|
|
# which should only be ..returns(...) |
|
|
|
# which should only be ..returns(...) |
|
|
|
# nested parenthesis so we use a system of counter on parenthesis |
|
|
|
# nested parenthesis so we use a system of counter on parenthesis |
|
|
|
idx = value.find('(') |
|
|
|
idx = value.find("(") |
|
|
|
if idx: |
|
|
|
if idx: |
|
|
|
counter = 1 |
|
|
|
counter = 1 |
|
|
|
max_idx = len(value) |
|
|
|
max_idx = len(value) |
|
|
|
while counter: |
|
|
|
while counter: |
|
|
|
assert idx < max_idx |
|
|
|
assert idx < max_idx |
|
|
|
idx = idx + 1 |
|
|
|
idx = idx + 1 |
|
|
|
if value[idx] == '(': |
|
|
|
if value[idx] == "(": |
|
|
|
counter += 1 |
|
|
|
counter += 1 |
|
|
|
elif value[idx] == ')': |
|
|
|
elif value[idx] == ")": |
|
|
|
counter -= 1 |
|
|
|
counter -= 1 |
|
|
|
value = value[:idx + 1] |
|
|
|
value = value[: idx + 1] |
|
|
|
return value |
|
|
|
return value |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
@ -230,35 +262,38 @@ def filter_name(value): |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
################################################################################### |
|
|
|
|
|
|
|
|
|
|
|
def parse_call(expression, caller_context): |
|
|
|
|
|
|
|
src = expression['src'] |
|
|
|
def parse_call(expression: Dict, caller_context): |
|
|
|
|
|
|
|
src = expression["src"] |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
attributes = expression |
|
|
|
attributes = expression |
|
|
|
type_conversion = expression['kind'] == 'typeConversion' |
|
|
|
type_conversion = expression["kind"] == "typeConversion" |
|
|
|
type_return = attributes['typeDescriptions']['typeString'] |
|
|
|
type_return = attributes["typeDescriptions"]["typeString"] |
|
|
|
|
|
|
|
|
|
|
|
else: |
|
|
|
else: |
|
|
|
attributes = expression['attributes'] |
|
|
|
attributes = expression["attributes"] |
|
|
|
type_conversion = attributes['type_conversion'] |
|
|
|
type_conversion = attributes["type_conversion"] |
|
|
|
type_return = attributes['type'] |
|
|
|
type_return = attributes["type"] |
|
|
|
|
|
|
|
|
|
|
|
if type_conversion: |
|
|
|
if type_conversion: |
|
|
|
type_call = parse_type(UnknownType(type_return), caller_context) |
|
|
|
type_call = parse_type(UnknownType(type_return), caller_context) |
|
|
|
|
|
|
|
|
|
|
|
if caller_context.is_compact_ast: |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
assert len(expression['arguments']) == 1 |
|
|
|
assert len(expression["arguments"]) == 1 |
|
|
|
expression_to_parse = expression['arguments'][0] |
|
|
|
expression_to_parse = expression["arguments"][0] |
|
|
|
else: |
|
|
|
else: |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
assert len(children) == 2 |
|
|
|
assert len(children) == 2 |
|
|
|
type_info = children[0] |
|
|
|
type_info = children[0] |
|
|
|
expression_to_parse = children[1] |
|
|
|
expression_to_parse = children[1] |
|
|
|
assert type_info['name'] in ['ElementaryTypenameExpression', |
|
|
|
assert type_info["name"] in [ |
|
|
|
'ElementaryTypeNameExpression', |
|
|
|
"ElementaryTypenameExpression", |
|
|
|
'Identifier', |
|
|
|
"ElementaryTypeNameExpression", |
|
|
|
'TupleExpression', |
|
|
|
"Identifier", |
|
|
|
'IndexAccess', |
|
|
|
"TupleExpression", |
|
|
|
'MemberAccess'] |
|
|
|
"IndexAccess", |
|
|
|
|
|
|
|
"MemberAccess", |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
|
|
|
|
expression = parse_expression(expression_to_parse, caller_context) |
|
|
|
expression = parse_expression(expression_to_parse, caller_context) |
|
|
|
t = TypeConversion(expression, type_call) |
|
|
|
t = TypeConversion(expression, type_call) |
|
|
@ -269,33 +304,33 @@ def parse_call(expression, caller_context): |
|
|
|
call_value = None |
|
|
|
call_value = None |
|
|
|
call_salt = None |
|
|
|
call_salt = None |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
called = parse_expression(expression['expression'], caller_context) |
|
|
|
called = parse_expression(expression["expression"], caller_context) |
|
|
|
# If the next expression is a FunctionCallOptions |
|
|
|
# If the next expression is a FunctionCallOptions |
|
|
|
# We can here the gas/value information |
|
|
|
# We can here the gas/value information |
|
|
|
# This is only available if the syntax is {gas: , value: } |
|
|
|
# This is only available if the syntax is {gas: , value: } |
|
|
|
# For the .gas().value(), the member are considered as function call |
|
|
|
# For the .gas().value(), the member are considered as function call |
|
|
|
# And converted later to the correct info (convert.py) |
|
|
|
# And converted later to the correct info (convert.py) |
|
|
|
if expression['expression'][caller_context.get_key()] == 'FunctionCallOptions': |
|
|
|
if expression["expression"][caller_context.get_key()] == "FunctionCallOptions": |
|
|
|
call_with_options = expression['expression'] |
|
|
|
call_with_options = expression["expression"] |
|
|
|
for idx, name in enumerate(call_with_options.get('names', [])): |
|
|
|
for idx, name in enumerate(call_with_options.get("names", [])): |
|
|
|
option = parse_expression(call_with_options['options'][idx], caller_context) |
|
|
|
option = parse_expression(call_with_options["options"][idx], caller_context) |
|
|
|
if name == 'value': |
|
|
|
if name == "value": |
|
|
|
call_value = option |
|
|
|
call_value = option |
|
|
|
if name == 'gas': |
|
|
|
if name == "gas": |
|
|
|
call_gas = option |
|
|
|
call_gas = option |
|
|
|
if name == 'salt': |
|
|
|
if name == "salt": |
|
|
|
call_salt = option |
|
|
|
call_salt = option |
|
|
|
arguments = [] |
|
|
|
arguments = [] |
|
|
|
if expression['arguments']: |
|
|
|
if expression["arguments"]: |
|
|
|
arguments = [parse_expression(a, caller_context) for a in expression['arguments']] |
|
|
|
arguments = [parse_expression(a, caller_context) for a in expression["arguments"]] |
|
|
|
else: |
|
|
|
else: |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
called = parse_expression(children[0], caller_context) |
|
|
|
called = parse_expression(children[0], caller_context) |
|
|
|
arguments = [parse_expression(a, caller_context) for a in children[1::]] |
|
|
|
arguments = [parse_expression(a, caller_context) for a in children[1::]] |
|
|
|
|
|
|
|
|
|
|
|
if isinstance(called, SuperCallExpression): |
|
|
|
if isinstance(called, SuperCallExpression): |
|
|
|
sp = SuperCallExpression(called, arguments, type_return) |
|
|
|
sp = SuperCallExpression(called, arguments, type_return) |
|
|
|
sp.set_offset(expression['src'], caller_context.slither) |
|
|
|
sp.set_offset(expression["src"], caller_context.slither) |
|
|
|
return sp |
|
|
|
return sp |
|
|
|
call_expression = CallExpression(called, arguments, type_return) |
|
|
|
call_expression = CallExpression(called, arguments, type_return) |
|
|
|
call_expression.set_offset(src, caller_context.slither) |
|
|
|
call_expression.set_offset(src, caller_context.slither) |
|
|
@ -307,46 +342,48 @@ def parse_call(expression, caller_context): |
|
|
|
return call_expression |
|
|
|
return call_expression |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_super_name(expression, is_compact_ast): |
|
|
|
def parse_super_name(expression: Dict, is_compact_ast: bool) -> str: |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
assert expression['nodeType'] == 'MemberAccess' |
|
|
|
assert expression["nodeType"] == "MemberAccess" |
|
|
|
base_name = expression['memberName'] |
|
|
|
base_name = expression["memberName"] |
|
|
|
arguments = expression['typeDescriptions']['typeString'] |
|
|
|
arguments = expression["typeDescriptions"]["typeString"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
assert expression['name'] == 'MemberAccess' |
|
|
|
assert expression["name"] == "MemberAccess" |
|
|
|
attributes = expression['attributes'] |
|
|
|
attributes = expression["attributes"] |
|
|
|
base_name = attributes['member_name'] |
|
|
|
base_name = attributes["member_name"] |
|
|
|
arguments = attributes['type'] |
|
|
|
arguments = attributes["type"] |
|
|
|
|
|
|
|
|
|
|
|
assert arguments.startswith('function ') |
|
|
|
assert arguments.startswith("function ") |
|
|
|
# remove function (...() |
|
|
|
# remove function (...() |
|
|
|
arguments = arguments[len('function '):] |
|
|
|
arguments = arguments[len("function ") :] |
|
|
|
|
|
|
|
|
|
|
|
arguments = filter_name(arguments) |
|
|
|
arguments = filter_name(arguments) |
|
|
|
if ' ' in arguments: |
|
|
|
if " " in arguments: |
|
|
|
arguments = arguments[:arguments.find(' ')] |
|
|
|
arguments = arguments[: arguments.find(" ")] |
|
|
|
|
|
|
|
|
|
|
|
return base_name + arguments |
|
|
|
return base_name + arguments |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def _parse_elementary_type_name_expression(expression, is_compact_ast, caller_context): |
|
|
|
def _parse_elementary_type_name_expression( |
|
|
|
|
|
|
|
expression: Dict, is_compact_ast: bool, caller_context |
|
|
|
|
|
|
|
) -> ElementaryTypeNameExpression: |
|
|
|
# nop exression |
|
|
|
# nop exression |
|
|
|
# uint; |
|
|
|
# uint; |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
value = expression['typeName'] |
|
|
|
value = expression["typeName"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
assert 'children' not in expression |
|
|
|
assert "children" not in expression |
|
|
|
value = expression['attributes']['value'] |
|
|
|
value = expression["attributes"]["value"] |
|
|
|
if isinstance(value, dict): |
|
|
|
if isinstance(value, dict): |
|
|
|
t = parse_type(value, caller_context) |
|
|
|
t = parse_type(value, caller_context) |
|
|
|
else: |
|
|
|
else: |
|
|
|
t = parse_type(UnknownType(value), caller_context) |
|
|
|
t = parse_type(UnknownType(value), caller_context) |
|
|
|
e = ElementaryTypeNameExpression(t) |
|
|
|
e = ElementaryTypeNameExpression(t) |
|
|
|
e.set_offset(expression['src'], caller_context.slither) |
|
|
|
e.set_offset(expression["src"], caller_context.slither) |
|
|
|
return e |
|
|
|
return e |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
def parse_expression(expression, caller_context): |
|
|
|
def parse_expression(expression: Dict, caller_context: CallerContext) -> "Expression": |
|
|
|
""" |
|
|
|
""" |
|
|
|
|
|
|
|
|
|
|
|
Returns: |
|
|
|
Returns: |
|
|
@ -378,53 +415,53 @@ def parse_expression(expression, caller_context): |
|
|
|
# The AST naming does not follow the spec |
|
|
|
# The AST naming does not follow the spec |
|
|
|
name = expression[caller_context.get_key()] |
|
|
|
name = expression[caller_context.get_key()] |
|
|
|
is_compact_ast = caller_context.is_compact_ast |
|
|
|
is_compact_ast = caller_context.is_compact_ast |
|
|
|
src = expression['src'] |
|
|
|
src = expression["src"] |
|
|
|
|
|
|
|
|
|
|
|
if name == 'UnaryOperation': |
|
|
|
if name == "UnaryOperation": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
attributes = expression |
|
|
|
attributes = expression |
|
|
|
else: |
|
|
|
else: |
|
|
|
attributes = expression['attributes'] |
|
|
|
attributes = expression["attributes"] |
|
|
|
assert 'prefix' in attributes |
|
|
|
assert "prefix" in attributes |
|
|
|
operation_type = UnaryOperationType.get_type(attributes['operator'], attributes['prefix']) |
|
|
|
operation_type = UnaryOperationType.get_type(attributes["operator"], attributes["prefix"]) |
|
|
|
|
|
|
|
|
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
expression = parse_expression(expression['subExpression'], caller_context) |
|
|
|
expression = parse_expression(expression["subExpression"], caller_context) |
|
|
|
else: |
|
|
|
else: |
|
|
|
assert len(expression['children']) == 1 |
|
|
|
assert len(expression["children"]) == 1 |
|
|
|
expression = parse_expression(expression['children'][0], caller_context) |
|
|
|
expression = parse_expression(expression["children"][0], caller_context) |
|
|
|
unary_op = UnaryOperation(expression, operation_type) |
|
|
|
unary_op = UnaryOperation(expression, operation_type) |
|
|
|
unary_op.set_offset(src, caller_context.slither) |
|
|
|
unary_op.set_offset(src, caller_context.slither) |
|
|
|
return unary_op |
|
|
|
return unary_op |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'BinaryOperation': |
|
|
|
elif name == "BinaryOperation": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
attributes = expression |
|
|
|
attributes = expression |
|
|
|
else: |
|
|
|
else: |
|
|
|
attributes = expression['attributes'] |
|
|
|
attributes = expression["attributes"] |
|
|
|
operation_type = BinaryOperationType.get_type(attributes['operator']) |
|
|
|
operation_type = BinaryOperationType.get_type(attributes["operator"]) |
|
|
|
|
|
|
|
|
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
left_expression = parse_expression(expression['leftExpression'], caller_context) |
|
|
|
left_expression = parse_expression(expression["leftExpression"], caller_context) |
|
|
|
right_expression = parse_expression(expression['rightExpression'], caller_context) |
|
|
|
right_expression = parse_expression(expression["rightExpression"], caller_context) |
|
|
|
else: |
|
|
|
else: |
|
|
|
assert len(expression['children']) == 2 |
|
|
|
assert len(expression["children"]) == 2 |
|
|
|
left_expression = parse_expression(expression['children'][0], caller_context) |
|
|
|
left_expression = parse_expression(expression["children"][0], caller_context) |
|
|
|
right_expression = parse_expression(expression['children'][1], caller_context) |
|
|
|
right_expression = parse_expression(expression["children"][1], caller_context) |
|
|
|
binary_op = BinaryOperation(left_expression, right_expression, operation_type) |
|
|
|
binary_op = BinaryOperation(left_expression, right_expression, operation_type) |
|
|
|
binary_op.set_offset(src, caller_context.slither) |
|
|
|
binary_op.set_offset(src, caller_context.slither) |
|
|
|
return binary_op |
|
|
|
return binary_op |
|
|
|
|
|
|
|
|
|
|
|
elif name in 'FunctionCall': |
|
|
|
elif name in "FunctionCall": |
|
|
|
return parse_call(expression, caller_context) |
|
|
|
return parse_call(expression, caller_context) |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'FunctionCallOptions': |
|
|
|
elif name == "FunctionCallOptions": |
|
|
|
# call/gas info are handled in parse_call |
|
|
|
# call/gas info are handled in parse_call |
|
|
|
called = parse_expression(expression['expression'], caller_context) |
|
|
|
called = parse_expression(expression["expression"], caller_context) |
|
|
|
assert isinstance(called, (MemberAccess, NewContract)) |
|
|
|
assert isinstance(called, (MemberAccess, NewContract)) |
|
|
|
return called |
|
|
|
return called |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'TupleExpression': |
|
|
|
elif name == "TupleExpression": |
|
|
|
""" |
|
|
|
""" |
|
|
|
For expression like |
|
|
|
For expression like |
|
|
|
(a,,c) = (1,2,3) |
|
|
|
(a,,c) = (1,2,3) |
|
|
@ -437,35 +474,39 @@ def parse_expression(expression, caller_context): |
|
|
|
Note: this is only possible with Solidity >= 0.4.12 |
|
|
|
Note: this is only possible with Solidity >= 0.4.12 |
|
|
|
""" |
|
|
|
""" |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
expressions = [parse_expression(e, caller_context) if e else None for e in expression['components']] |
|
|
|
expressions = [ |
|
|
|
else: |
|
|
|
parse_expression(e, caller_context) if e else None for e in expression["components"] |
|
|
|
if 'children' not in expression: |
|
|
|
] |
|
|
|
attributes = expression['attributes'] |
|
|
|
else: |
|
|
|
components = attributes['components'] |
|
|
|
if "children" not in expression: |
|
|
|
expressions = [parse_expression(c, caller_context) if c else None for c in components] |
|
|
|
attributes = expression["attributes"] |
|
|
|
else: |
|
|
|
components = attributes["components"] |
|
|
|
expressions = [parse_expression(e, caller_context) for e in expression['children']] |
|
|
|
expressions = [ |
|
|
|
|
|
|
|
parse_expression(c, caller_context) if c else None for c in components |
|
|
|
|
|
|
|
] |
|
|
|
|
|
|
|
else: |
|
|
|
|
|
|
|
expressions = [parse_expression(e, caller_context) for e in expression["children"]] |
|
|
|
# Add none for empty tuple items |
|
|
|
# Add none for empty tuple items |
|
|
|
if "attributes" in expression: |
|
|
|
if "attributes" in expression: |
|
|
|
if "type" in expression['attributes']: |
|
|
|
if "type" in expression["attributes"]: |
|
|
|
t = expression['attributes']['type'] |
|
|
|
t = expression["attributes"]["type"] |
|
|
|
if ',,' in t or '(,' in t or ',)' in t: |
|
|
|
if ",," in t or "(," in t or ",)" in t: |
|
|
|
t = t[len('tuple('):-1] |
|
|
|
t = t[len("tuple(") : -1] |
|
|
|
elems = t.split(',') |
|
|
|
elems = t.split(",") |
|
|
|
for idx in range(len(elems)): |
|
|
|
for idx in range(len(elems)): |
|
|
|
if elems[idx] == '': |
|
|
|
if elems[idx] == "": |
|
|
|
expressions.insert(idx, None) |
|
|
|
expressions.insert(idx, None) |
|
|
|
t = TupleExpression(expressions) |
|
|
|
t = TupleExpression(expressions) |
|
|
|
t.set_offset(src, caller_context.slither) |
|
|
|
t.set_offset(src, caller_context.slither) |
|
|
|
return t |
|
|
|
return t |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'Conditional': |
|
|
|
elif name == "Conditional": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
if_expression = parse_expression(expression['condition'], caller_context) |
|
|
|
if_expression = parse_expression(expression["condition"], caller_context) |
|
|
|
then_expression = parse_expression(expression['trueExpression'], caller_context) |
|
|
|
then_expression = parse_expression(expression["trueExpression"], caller_context) |
|
|
|
else_expression = parse_expression(expression['falseExpression'], caller_context) |
|
|
|
else_expression = parse_expression(expression["falseExpression"], caller_context) |
|
|
|
else: |
|
|
|
else: |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
assert len(children) == 3 |
|
|
|
assert len(children) == 3 |
|
|
|
if_expression = parse_expression(children[0], caller_context) |
|
|
|
if_expression = parse_expression(children[0], caller_context) |
|
|
|
then_expression = parse_expression(children[1], caller_context) |
|
|
|
then_expression = parse_expression(children[1], caller_context) |
|
|
@ -474,100 +515,103 @@ def parse_expression(expression, caller_context): |
|
|
|
conditional.set_offset(src, caller_context.slither) |
|
|
|
conditional.set_offset(src, caller_context.slither) |
|
|
|
return conditional |
|
|
|
return conditional |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'Assignment': |
|
|
|
elif name == "Assignment": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
left_expression = parse_expression(expression['leftHandSide'], caller_context) |
|
|
|
left_expression = parse_expression(expression["leftHandSide"], caller_context) |
|
|
|
right_expression = parse_expression(expression['rightHandSide'], caller_context) |
|
|
|
right_expression = parse_expression(expression["rightHandSide"], caller_context) |
|
|
|
|
|
|
|
|
|
|
|
operation_type = AssignmentOperationType.get_type(expression['operator']) |
|
|
|
operation_type = AssignmentOperationType.get_type(expression["operator"]) |
|
|
|
|
|
|
|
|
|
|
|
operation_return_type = expression['typeDescriptions']['typeString'] |
|
|
|
operation_return_type = expression["typeDescriptions"]["typeString"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
attributes = expression['attributes'] |
|
|
|
attributes = expression["attributes"] |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
assert len(expression['children']) == 2 |
|
|
|
assert len(expression["children"]) == 2 |
|
|
|
left_expression = parse_expression(children[0], caller_context) |
|
|
|
left_expression = parse_expression(children[0], caller_context) |
|
|
|
right_expression = parse_expression(children[1], caller_context) |
|
|
|
right_expression = parse_expression(children[1], caller_context) |
|
|
|
|
|
|
|
|
|
|
|
operation_type = AssignmentOperationType.get_type(attributes['operator']) |
|
|
|
operation_type = AssignmentOperationType.get_type(attributes["operator"]) |
|
|
|
operation_return_type = attributes['type'] |
|
|
|
operation_return_type = attributes["type"] |
|
|
|
|
|
|
|
|
|
|
|
assignement = AssignmentOperation(left_expression, right_expression, operation_type, operation_return_type) |
|
|
|
assignement = AssignmentOperation( |
|
|
|
|
|
|
|
left_expression, right_expression, operation_type, operation_return_type |
|
|
|
|
|
|
|
) |
|
|
|
assignement.set_offset(src, caller_context.slither) |
|
|
|
assignement.set_offset(src, caller_context.slither) |
|
|
|
return assignement |
|
|
|
return assignement |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
elif name == "Literal": |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'Literal': |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
subdenomination = None |
|
|
|
subdenomination = None |
|
|
|
|
|
|
|
|
|
|
|
assert 'children' not in expression |
|
|
|
assert "children" not in expression |
|
|
|
|
|
|
|
|
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
value = expression['value'] |
|
|
|
value = expression["value"] |
|
|
|
if value: |
|
|
|
if value: |
|
|
|
if 'subdenomination' in expression and expression['subdenomination']: |
|
|
|
if "subdenomination" in expression and expression["subdenomination"]: |
|
|
|
subdenomination = expression['subdenomination'] |
|
|
|
subdenomination = expression["subdenomination"] |
|
|
|
elif not value and value != "": |
|
|
|
elif not value and value != "": |
|
|
|
value = '0x' + expression['hexValue'] |
|
|
|
value = "0x" + expression["hexValue"] |
|
|
|
type = expression['typeDescriptions']['typeString'] |
|
|
|
type_candidate = expression["typeDescriptions"]["typeString"] |
|
|
|
|
|
|
|
|
|
|
|
# Length declaration for array was None until solc 0.5.5 |
|
|
|
# Length declaration for array was None until solc 0.5.5 |
|
|
|
if type is None: |
|
|
|
if type_candidate is None: |
|
|
|
if expression['kind'] == 'number': |
|
|
|
if expression["kind"] == "number": |
|
|
|
type = 'int_const' |
|
|
|
type_candidate = "int_const" |
|
|
|
else: |
|
|
|
else: |
|
|
|
value = expression['attributes']['value'] |
|
|
|
value = expression["attributes"]["value"] |
|
|
|
if value: |
|
|
|
if value: |
|
|
|
if 'subdenomination' in expression['attributes'] and expression['attributes']['subdenomination']: |
|
|
|
if ( |
|
|
|
subdenomination = expression['attributes']['subdenomination'] |
|
|
|
"subdenomination" in expression["attributes"] |
|
|
|
|
|
|
|
and expression["attributes"]["subdenomination"] |
|
|
|
|
|
|
|
): |
|
|
|
|
|
|
|
subdenomination = expression["attributes"]["subdenomination"] |
|
|
|
elif value is None: |
|
|
|
elif value is None: |
|
|
|
# for literal declared as hex |
|
|
|
# for literal declared as hex |
|
|
|
# see https://solidity.readthedocs.io/en/v0.4.25/types.html?highlight=hex#hexadecimal-literals |
|
|
|
# see https://solidity.readthedocs.io/en/v0.4.25/types.html?highlight=hex#hexadecimal-literals |
|
|
|
assert 'hexvalue' in expression['attributes'] |
|
|
|
assert "hexvalue" in expression["attributes"] |
|
|
|
value = '0x' + expression['attributes']['hexvalue'] |
|
|
|
value = "0x" + expression["attributes"]["hexvalue"] |
|
|
|
type = expression['attributes']['type'] |
|
|
|
type_candidate = expression["attributes"]["type"] |
|
|
|
|
|
|
|
|
|
|
|
if type is None: |
|
|
|
if type_candidate is None: |
|
|
|
if value.isdecimal(): |
|
|
|
if value.isdecimal(): |
|
|
|
type = ElementaryType('uint256') |
|
|
|
type_candidate = ElementaryType("uint256") |
|
|
|
else: |
|
|
|
else: |
|
|
|
type = ElementaryType('string') |
|
|
|
type_candidate = ElementaryType("string") |
|
|
|
elif type.startswith('int_const '): |
|
|
|
elif type_candidate.startswith("int_const "): |
|
|
|
type = ElementaryType('uint256') |
|
|
|
type_candidate = ElementaryType("uint256") |
|
|
|
elif type.startswith('bool'): |
|
|
|
elif type_candidate.startswith("bool"): |
|
|
|
type = ElementaryType('bool') |
|
|
|
type_candidate = ElementaryType("bool") |
|
|
|
elif type.startswith('address'): |
|
|
|
elif type_candidate.startswith("address"): |
|
|
|
type = ElementaryType('address') |
|
|
|
type_candidate = ElementaryType("address") |
|
|
|
else: |
|
|
|
else: |
|
|
|
type = ElementaryType('string') |
|
|
|
type_candidate = ElementaryType("string") |
|
|
|
literal = Literal(value, type, subdenomination) |
|
|
|
literal = Literal(value, type_candidate, subdenomination) |
|
|
|
literal.set_offset(src, caller_context.slither) |
|
|
|
literal.set_offset(src, caller_context.slither) |
|
|
|
return literal |
|
|
|
return literal |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'Identifier': |
|
|
|
elif name == "Identifier": |
|
|
|
assert 'children' not in expression |
|
|
|
assert "children" not in expression |
|
|
|
|
|
|
|
|
|
|
|
t = None |
|
|
|
t = None |
|
|
|
|
|
|
|
|
|
|
|
if caller_context.is_compact_ast: |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
value = expression['name'] |
|
|
|
value = expression["name"] |
|
|
|
t = expression['typeDescriptions']['typeString'] |
|
|
|
t = expression["typeDescriptions"]["typeString"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
value = expression['attributes']['value'] |
|
|
|
value = expression["attributes"]["value"] |
|
|
|
if 'type' in expression['attributes']: |
|
|
|
if "type" in expression["attributes"]: |
|
|
|
t = expression['attributes']['type'] |
|
|
|
t = expression["attributes"]["type"] |
|
|
|
|
|
|
|
|
|
|
|
if t: |
|
|
|
if t: |
|
|
|
found = re.findall('[struct|enum|function|modifier] \(([\[\] ()a-zA-Z0-9\.,_]*)\)', t) |
|
|
|
found = re.findall("[struct|enum|function|modifier] \(([\[\] ()a-zA-Z0-9\.,_]*)\)", t) |
|
|
|
assert len(found) <= 1 |
|
|
|
assert len(found) <= 1 |
|
|
|
if found: |
|
|
|
if found: |
|
|
|
value = value + '(' + found[0] + ')' |
|
|
|
value = value + "(" + found[0] + ")" |
|
|
|
value = filter_name(value) |
|
|
|
value = filter_name(value) |
|
|
|
|
|
|
|
|
|
|
|
if 'referencedDeclaration' in expression: |
|
|
|
if "referencedDeclaration" in expression: |
|
|
|
referenced_declaration = expression['referencedDeclaration'] |
|
|
|
referenced_declaration = expression["referencedDeclaration"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
referenced_declaration = None |
|
|
|
referenced_declaration = None |
|
|
|
|
|
|
|
|
|
|
@ -577,14 +621,14 @@ def parse_expression(expression, caller_context): |
|
|
|
identifier.set_offset(src, caller_context.slither) |
|
|
|
identifier.set_offset(src, caller_context.slither) |
|
|
|
return identifier |
|
|
|
return identifier |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'IndexAccess': |
|
|
|
elif name == "IndexAccess": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
index_type = expression['typeDescriptions']['typeString'] |
|
|
|
index_type = expression["typeDescriptions"]["typeString"] |
|
|
|
left = expression['baseExpression'] |
|
|
|
left = expression["baseExpression"] |
|
|
|
right = expression['indexExpression'] |
|
|
|
right = expression["indexExpression"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
index_type = expression['attributes']['type'] |
|
|
|
index_type = expression["attributes"]["type"] |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
assert len(children) == 2 |
|
|
|
assert len(children) == 2 |
|
|
|
left = children[0] |
|
|
|
left = children[0] |
|
|
|
right = children[1] |
|
|
|
right = children[1] |
|
|
@ -600,22 +644,22 @@ def parse_expression(expression, caller_context): |
|
|
|
index.set_offset(src, caller_context.slither) |
|
|
|
index.set_offset(src, caller_context.slither) |
|
|
|
return index |
|
|
|
return index |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'MemberAccess': |
|
|
|
elif name == "MemberAccess": |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
if caller_context.is_compact_ast: |
|
|
|
member_name = expression['memberName'] |
|
|
|
member_name = expression["memberName"] |
|
|
|
member_type = expression['typeDescriptions']['typeString'] |
|
|
|
member_type = expression["typeDescriptions"]["typeString"] |
|
|
|
member_expression = parse_expression(expression['expression'], caller_context) |
|
|
|
member_expression = parse_expression(expression["expression"], caller_context) |
|
|
|
else: |
|
|
|
else: |
|
|
|
member_name = expression['attributes']['member_name'] |
|
|
|
member_name = expression["attributes"]["member_name"] |
|
|
|
member_type = expression['attributes']['type'] |
|
|
|
member_type = expression["attributes"]["type"] |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
assert len(children) == 1 |
|
|
|
assert len(children) == 1 |
|
|
|
member_expression = parse_expression(children[0], caller_context) |
|
|
|
member_expression = parse_expression(children[0], caller_context) |
|
|
|
if str(member_expression) == 'super': |
|
|
|
if str(member_expression) == "super": |
|
|
|
super_name = parse_super_name(expression, is_compact_ast) |
|
|
|
super_name = parse_super_name(expression, is_compact_ast) |
|
|
|
var = find_variable(super_name, caller_context, is_super=True) |
|
|
|
var = find_variable(super_name, caller_context, is_super=True) |
|
|
|
if var is None: |
|
|
|
if var is None: |
|
|
|
raise VariableNotFound('Variable not found: {}'.format(super_name)) |
|
|
|
raise VariableNotFound("Variable not found: {}".format(super_name)) |
|
|
|
sup = SuperIdentifier(var) |
|
|
|
sup = SuperIdentifier(var) |
|
|
|
sup.set_offset(src, caller_context.slither) |
|
|
|
sup.set_offset(src, caller_context.slither) |
|
|
|
return sup |
|
|
|
return sup |
|
|
@ -627,81 +671,82 @@ def parse_expression(expression, caller_context): |
|
|
|
return idx |
|
|
|
return idx |
|
|
|
return member_access |
|
|
|
return member_access |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'ElementaryTypeNameExpression': |
|
|
|
elif name == "ElementaryTypeNameExpression": |
|
|
|
return _parse_elementary_type_name_expression(expression, is_compact_ast, caller_context) |
|
|
|
return _parse_elementary_type_name_expression(expression, is_compact_ast, caller_context) |
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
# NewExpression is not a root expression, it's always the child of another expression |
|
|
|
# NewExpression is not a root expression, it's always the child of another expression |
|
|
|
elif name == 'NewExpression': |
|
|
|
elif name == "NewExpression": |
|
|
|
|
|
|
|
|
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
type_name = expression['typeName'] |
|
|
|
type_name = expression["typeName"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
assert len(children) == 1 |
|
|
|
assert len(children) == 1 |
|
|
|
type_name = children[0] |
|
|
|
type_name = children[0] |
|
|
|
|
|
|
|
|
|
|
|
if type_name[caller_context.get_key()] == 'ArrayTypeName': |
|
|
|
if type_name[caller_context.get_key()] == "ArrayTypeName": |
|
|
|
depth = 0 |
|
|
|
depth = 0 |
|
|
|
while type_name[caller_context.get_key()] == 'ArrayTypeName': |
|
|
|
while type_name[caller_context.get_key()] == "ArrayTypeName": |
|
|
|
# Note: dont conserve the size of the array if provided |
|
|
|
# Note: dont conserve the size of the array if provided |
|
|
|
# We compute it directly |
|
|
|
# We compute it directly |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
type_name = type_name['baseType'] |
|
|
|
type_name = type_name["baseType"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
type_name = type_name['children'][0] |
|
|
|
type_name = type_name["children"][0] |
|
|
|
depth += 1 |
|
|
|
depth += 1 |
|
|
|
if type_name[caller_context.get_key()] == 'ElementaryTypeName': |
|
|
|
if type_name[caller_context.get_key()] == "ElementaryTypeName": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
array_type = ElementaryType(type_name['name']) |
|
|
|
array_type = ElementaryType(type_name["name"]) |
|
|
|
else: |
|
|
|
else: |
|
|
|
array_type = ElementaryType(type_name['attributes']['name']) |
|
|
|
array_type = ElementaryType(type_name["attributes"]["name"]) |
|
|
|
elif type_name[caller_context.get_key()] == 'UserDefinedTypeName': |
|
|
|
elif type_name[caller_context.get_key()] == "UserDefinedTypeName": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
array_type = parse_type(UnknownType(type_name['name']), caller_context) |
|
|
|
array_type = parse_type(UnknownType(type_name["name"]), caller_context) |
|
|
|
else: |
|
|
|
else: |
|
|
|
array_type = parse_type(UnknownType(type_name['attributes']['name']), caller_context) |
|
|
|
array_type = parse_type( |
|
|
|
elif type_name[caller_context.get_key()] == 'FunctionTypeName': |
|
|
|
UnknownType(type_name["attributes"]["name"]), caller_context |
|
|
|
|
|
|
|
) |
|
|
|
|
|
|
|
elif type_name[caller_context.get_key()] == "FunctionTypeName": |
|
|
|
array_type = parse_type(type_name, caller_context) |
|
|
|
array_type = parse_type(type_name, caller_context) |
|
|
|
else: |
|
|
|
else: |
|
|
|
raise ParsingError('Incorrect type array {}'.format(type_name)) |
|
|
|
raise ParsingError("Incorrect type array {}".format(type_name)) |
|
|
|
array = NewArray(depth, array_type) |
|
|
|
array = NewArray(depth, array_type) |
|
|
|
array.set_offset(src, caller_context.slither) |
|
|
|
array.set_offset(src, caller_context.slither) |
|
|
|
return array |
|
|
|
return array |
|
|
|
|
|
|
|
|
|
|
|
if type_name[caller_context.get_key()] == 'ElementaryTypeName': |
|
|
|
if type_name[caller_context.get_key()] == "ElementaryTypeName": |
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
elem_type = ElementaryType(type_name['name']) |
|
|
|
elem_type = ElementaryType(type_name["name"]) |
|
|
|
else: |
|
|
|
else: |
|
|
|
elem_type = ElementaryType(type_name['attributes']['name']) |
|
|
|
elem_type = ElementaryType(type_name["attributes"]["name"]) |
|
|
|
new_elem = NewElementaryType(elem_type) |
|
|
|
new_elem = NewElementaryType(elem_type) |
|
|
|
new_elem.set_offset(src, caller_context.slither) |
|
|
|
new_elem.set_offset(src, caller_context.slither) |
|
|
|
return new_elem |
|
|
|
return new_elem |
|
|
|
|
|
|
|
|
|
|
|
assert type_name[caller_context.get_key()] == 'UserDefinedTypeName' |
|
|
|
assert type_name[caller_context.get_key()] == "UserDefinedTypeName" |
|
|
|
|
|
|
|
|
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
contract_name = type_name['name'] |
|
|
|
contract_name = type_name["name"] |
|
|
|
else: |
|
|
|
else: |
|
|
|
contract_name = type_name['attributes']['name'] |
|
|
|
contract_name = type_name["attributes"]["name"] |
|
|
|
new = NewContract(contract_name) |
|
|
|
new = NewContract(contract_name) |
|
|
|
new.set_offset(src, caller_context.slither) |
|
|
|
new.set_offset(src, caller_context.slither) |
|
|
|
return new |
|
|
|
return new |
|
|
|
|
|
|
|
|
|
|
|
elif name == 'ModifierInvocation': |
|
|
|
elif name == "ModifierInvocation": |
|
|
|
|
|
|
|
|
|
|
|
if is_compact_ast: |
|
|
|
if is_compact_ast: |
|
|
|
called = parse_expression(expression['modifierName'], caller_context) |
|
|
|
called = parse_expression(expression["modifierName"], caller_context) |
|
|
|
arguments = [] |
|
|
|
arguments = [] |
|
|
|
if expression['arguments']: |
|
|
|
if expression["arguments"]: |
|
|
|
arguments = [parse_expression(a, caller_context) for a in expression['arguments']] |
|
|
|
arguments = [parse_expression(a, caller_context) for a in expression["arguments"]] |
|
|
|
else: |
|
|
|
else: |
|
|
|
children = expression['children'] |
|
|
|
children = expression["children"] |
|
|
|
called = parse_expression(children[0], caller_context) |
|
|
|
called = parse_expression(children[0], caller_context) |
|
|
|
arguments = [parse_expression(a, caller_context) for a in children[1::]] |
|
|
|
arguments = [parse_expression(a, caller_context) for a in children[1::]] |
|
|
|
|
|
|
|
|
|
|
|
call = CallExpression(called, arguments, 'Modifier') |
|
|
|
call = CallExpression(called, arguments, "Modifier") |
|
|
|
call.set_offset(src, caller_context.slither) |
|
|
|
call.set_offset(src, caller_context.slither) |
|
|
|
return call |
|
|
|
return call |
|
|
|
|
|
|
|
|
|
|
|
raise ParsingError('Expression not parsed %s' % name) |
|
|
|
raise ParsingError("Expression not parsed %s" % name) |
|
|
|