Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add IR conversion for constant state variable conversion #333

Merged
merged 2 commits into from
Sep 12, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
7 changes: 5 additions & 2 deletions slither/core/declarations/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,7 @@ class FunctionType(Enum):
CONSTRUCTOR = 1
FALLBACK = 2
CONSTRUCTOR_VARIABLES = 3 # Fake function to hold variable declaration statements
CONSTRUCTOR_CONSTANT_VARIABLES = 4 # Fake function to hold variable declaration statements

class Function(ChildContract, ChildInheritance, SourceMapping):
"""
Expand Down Expand Up @@ -153,6 +154,8 @@ def name(self):
return 'fallback'
elif self._function_type == FunctionType.CONSTRUCTOR_VARIABLES:
return 'slitherConstructorVariables'
elif self._function_type == FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES:
return 'slitherConstructorConstantVariables'
return self._name

@property
Expand Down Expand Up @@ -245,9 +248,9 @@ def is_constructor(self):
def is_constructor_variables(self):
"""
bool: True if the function is the constructor of the variables
Slither has a inbuilt function to hold the state variables initialization
Slither has inbuilt functions to hold the state variables initialization
"""
return self._function_type == FunctionType.CONSTRUCTOR_VARIABLES
return self._function_type in [FunctionType.CONSTRUCTOR_VARIABLES, FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES]

@property
def is_fallback(self):
Expand Down
10 changes: 6 additions & 4 deletions slither/solc_parsing/cfg/node.py
Original file line number Diff line number Diff line change
Expand Up @@ -37,10 +37,12 @@ def analyze_expressions(self, caller_context):
if self.type == NodeType.VARIABLE:
# Update the expression to be an assignement to the variable
#print(self.variable_declaration)
self._expression = AssignmentOperation(Identifier(self.variable_declaration),
self.expression,
AssignmentOperationType.ASSIGN,
self.variable_declaration.type)
_expression = AssignmentOperation(Identifier(self.variable_declaration),
self.expression,
AssignmentOperationType.ASSIGN,
self.variable_declaration.type)
_expression.set_offset(self.expression.source_mapping, self.slither)
self._expression = _expression

expression = self.expression
pp = ReadVar(expression)
Expand Down
25 changes: 25 additions & 0 deletions slither/solc_parsing/declarations/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -382,6 +382,7 @@ def _create_node(self, func, counter, variable):
AssignmentOperationType.ASSIGN,
variable.type)

expression.set_offset(variable.source_mapping, self.slither)
node.add_expression(expression)
return node

Expand All @@ -408,12 +409,36 @@ def add_constructor_variables(self):
prev_node.add_son(next_node)
next_node.add_father(prev_node)
counter += 1
break

for (idx, variable_candidate) in enumerate(self.state_variables):
if variable_candidate.expression and variable_candidate.is_constant:

constructor_variable = Function()
constructor_variable.set_function_type(FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES)
constructor_variable.set_contract(self)
constructor_variable.set_contract_declarer(self)
constructor_variable.set_visibility('internal')
# For now, source mapping of the constructor variable is the whole contract
# Could be improved with a targeted source mapping
constructor_variable.set_offset(self.source_mapping, self.slither)
self._functions[constructor_variable.canonical_name] = constructor_variable

prev_node = self._create_node(constructor_variable, 0, variable_candidate)
counter = 1
for v in self.state_variables[idx+1:]:
if v.expression and v.is_constant:
next_node = self._create_node(constructor_variable, counter, v)
prev_node.add_son(next_node)
next_node.add_father(prev_node)
counter += 1

break





def analyze_state_variables(self):
for var in self.variables:
var.analyze(self)
Expand Down
33 changes: 26 additions & 7 deletions slither/solc_parsing/expressions/expression_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -228,7 +228,7 @@ def filter_name(value):
###################################################################################

def parse_call(expression, caller_context):

src = expression['src']
if caller_context.is_compact_ast:
attributes = expression
type_conversion = expression['kind'] == 'typeConversion'
Expand Down Expand Up @@ -261,6 +261,7 @@ def parse_call(expression, caller_context):

expression = parse_expression(expression_to_parse, caller_context)
t = TypeConversion(expression, type_call)
t.set_offset(src, caller_context.slither)
return t

if caller_context.is_compact_ast:
Expand All @@ -276,7 +277,7 @@ def parse_call(expression, caller_context):
if isinstance(called, SuperCallExpression):
return SuperCallExpression(called, arguments, type_return)
call_expression = CallExpression(called, arguments, type_return)
call_expression.set_offset(expression['src'], caller_context.slither)
call_expression.set_offset(src, caller_context.slither)
return call_expression

def parse_super_name(expression, is_compact_ast):
Expand Down Expand Up @@ -311,7 +312,9 @@ def _parse_elementary_type_name_expression(expression, is_compact_ast, caller_co
value = expression['attributes']['value']
t = parse_type(UnknownType(value), caller_context)

return ElementaryTypeNameExpression(t)
e = ElementaryTypeNameExpression(t)
e.set_offset(expression['src'], caller_context.slither)
return e

def parse_expression(expression, caller_context):
"""
Expand Down Expand Up @@ -345,6 +348,7 @@ def parse_expression(expression, caller_context):
# The AST naming does not follow the spec
name = expression[caller_context.get_key()]
is_compact_ast = caller_context.is_compact_ast
src = expression['src']

if name == 'UnaryOperation':
if is_compact_ast:
Expand All @@ -360,6 +364,7 @@ def parse_expression(expression, caller_context):
assert len(expression['children']) == 1
expression = parse_expression(expression['children'][0], caller_context)
unary_op = UnaryOperation(expression, operation_type)
unary_op.set_offset(src, caller_context.slither)
return unary_op

elif name == 'BinaryOperation':
Expand All @@ -377,6 +382,7 @@ def parse_expression(expression, caller_context):
left_expression = parse_expression(expression['children'][0], caller_context)
right_expression = parse_expression(expression['children'][1], caller_context)
binary_op = BinaryOperation(left_expression, right_expression, operation_type)
binary_op.set_offset(src, caller_context.slither)
return binary_op

elif name == 'FunctionCall':
Expand Down Expand Up @@ -414,6 +420,7 @@ def parse_expression(expression, caller_context):
if elems[idx] == '':
expressions.insert(idx, None)
t = TupleExpression(expressions)
t.set_offset(src, caller_context.slither)
return t

elif name == 'Conditional':
Expand All @@ -428,6 +435,7 @@ def parse_expression(expression, caller_context):
then_expression = parse_expression(children[1], caller_context)
else_expression = parse_expression(children[2], caller_context)
conditional = ConditionalExpression(if_expression, then_expression, else_expression)
conditional.set_offset(src, caller_context.slither)
return conditional

elif name == 'Assignment':
Expand All @@ -449,6 +457,7 @@ def parse_expression(expression, caller_context):
operation_return_type = attributes['type']

assignement = AssignmentOperation(left_expression, right_expression, operation_type, operation_return_type)
assignement.set_offset(src, caller_context.slither)
return assignement


Expand Down Expand Up @@ -498,6 +507,7 @@ def parse_expression(expression, caller_context):
else:
type = ElementaryType('string')
literal = Literal(value, type, subdenomination)
literal.set_offset(src, caller_context.slither)
return literal

elif name == 'Identifier':
Expand Down Expand Up @@ -528,7 +538,7 @@ def parse_expression(expression, caller_context):
var = find_variable(value, caller_context, referenced_declaration)

identifier = Identifier(var)
identifier.set_offset(expression['src'], caller_context.slither)
identifier.set_offset(src, caller_context.slither)
return identifier

elif name == 'IndexAccess':
Expand All @@ -551,6 +561,7 @@ def parse_expression(expression, caller_context):
left_expression = parse_expression(left, caller_context)
right_expression = parse_expression(right, caller_context)
index = IndexAccess(left_expression, right_expression, index_type)
index.set_offset(src, caller_context.slither)
return index

elif name == 'MemberAccess':
Expand All @@ -569,10 +580,15 @@ def parse_expression(expression, caller_context):
var = find_variable(super_name, caller_context, is_super=True)
if var is None:
raise VariableNotFound('Variable not found: {}'.format(super_name))
return SuperIdentifier(var)
sup = SuperIdentifier(var)
sup.set_offset(src, caller_context.slither)
return sup
member_access = MemberAccess(member_name, member_type, member_expression)
member_access.set_offset(src, caller_context.slither)
if str(member_access) in SOLIDITY_VARIABLES_COMPOSED:
return Identifier(SolidityVariableComposed(str(member_access)))
idx = Identifier(SolidityVariableComposed(str(member_access)))
idx.set_offset(src, caller_context.slither)
return idx
return member_access

elif name == 'ElementaryTypeNameExpression':
Expand Down Expand Up @@ -614,6 +630,7 @@ def parse_expression(expression, caller_context):
else:
raise ParsingError('Incorrect type array {}'.format(type_name))
array = NewArray(depth, array_type)
array.set_offset(src, caller_context.slither)
return array

if type_name[caller_context.get_key()] == 'ElementaryTypeName':
Expand All @@ -622,6 +639,7 @@ def parse_expression(expression, caller_context):
else:
elem_type = ElementaryType(type_name['attributes']['name'])
new_elem = NewElementaryType(elem_type)
new_elem.set_offset(src, caller_context.slither)
return new_elem

assert type_name[caller_context.get_key()] == 'UserDefinedTypeName'
Expand All @@ -631,6 +649,7 @@ def parse_expression(expression, caller_context):
else:
contract_name = type_name['attributes']['name']
new = NewContract(contract_name)
new.set_offset(src, caller_context.slither)
return new

elif name == 'ModifierInvocation':
Expand All @@ -646,7 +665,7 @@ def parse_expression(expression, caller_context):
arguments = [parse_expression(a, caller_context) for a in children[1::]]

call = CallExpression(called, arguments, 'Modifier')
call.set_offset(expression['src'], caller_context.slither)
call.set_offset(src, caller_context.slither)
return call

raise ParsingError('Expression not parsed %s'%name)
Expand Down