convert tuple on lhs and index access to struct and field access

pull/2099/head
alpharush 1 year ago
parent e561d33eb1
commit 3ca9d0f228
  1. 46
      slither/visitors/slithir/expression_to_slithir.py
  2. 28
      slither/vyper_parsing/type_parsing.py
  3. 4
      slither/vyper_parsing/variables/local_variable.py

@ -11,6 +11,7 @@ from slither.core.declarations import (
EnumContract,
EnumTopLevel,
Enum,
Structure,
)
from slither.core.expressions import (
AssignmentOperation,
@ -233,6 +234,35 @@ class ExpressionToSlithIR(ExpressionVisitor):
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, left)
elif (
isinstance(left.type, UserDefinedType)
and isinstance(left.type.type, Structure)
and isinstance(right, TupleVariable)
):
# This will result in a `NewStructure` operation where
# each field is assigned the value unpacked from the tuple
# (see `slither.vyper_parsing.type_parsing.parse_type`)
args = []
for idx, elem in enumerate(left.type.type.elems.values()):
temp = TemporaryVariable(self._node)
temp.type = elem.type
args.append(temp)
operation = Unpack(temp, right, idx)
operation.set_expression(expression)
self._result.append(operation)
for arg in args:
op = Argument(arg)
op.set_expression(expression)
self._result.append(op)
operation = TmpCall(
left.type.type, len(left.type.type.elems), left, left.type.type.name
)
operation.set_expression(expression)
self._result.append(operation)
else:
operation = convert_assignment(
left, right, expression.type, expression.expression_return_type
@ -417,6 +447,21 @@ class ExpressionToSlithIR(ExpressionVisitor):
set_val(expression, t)
return
val = ReferenceVariable(self._node)
if (
isinstance(left, LocalVariable)
and isinstance(left.type, UserDefinedType)
and isinstance(left.type.type, Structure)
):
# We rewrite the index access to a tuple variable as
# an access to its field i.e. the 0th element is the field "_0"
# (see `slither.vyper_parsing.type_parsing.parse_type`)
operation = Member(left, Constant("_" + str(right)), val)
operation.set_expression(expression)
self._result.append(operation)
set_val(expression, val)
return
# access to anonymous array
# such as [0,1][x]
if isinstance(left, list):
@ -426,6 +471,7 @@ class ExpressionToSlithIR(ExpressionVisitor):
operation = InitArray(init_array_right, init_array_val)
operation.set_expression(expression)
self._result.append(operation)
operation = Index(val, left, right)
operation.set_expression(expression)
self._result.append(operation)

@ -20,7 +20,7 @@ def parse_type(annotation: Union[Name, Subscript, Call], caller_context):
else:
contract = caller_context
assert isinstance(annotation, (Name, Subscript, Call))
assert isinstance(annotation, (Name, Subscript, Call, Tuple))
print(annotation)
if isinstance(annotation, Name):
name = annotation.id
@ -54,12 +54,36 @@ def parse_type(annotation: Union[Name, Subscript, Call], caller_context):
return ArrayType(type_, length)
elif isinstance(annotation, Call):
# TODO event variable represented as Call
return parse_type(annotation.args[0], caller_context)
elif isinstance(annotation, Tuple):
# Vyper has tuple types like python x = f() where f() -> (y,z)
# and tuple elements can be unpacked like x[0]: y and x[1]: z.
# We model these as a struct and unpack each index into a field
# e.g. accessing the 0th element is translated as x._0
from slither.core.declarations.structure import Structure
from slither.core.variables.structure_variable import StructureVariable
st = Structure(caller_context.compilation_unit)
st.set_offset("-1:-1:-1", caller_context.compilation_unit)
st.name = "FAKE_TUPLE"
for idx, elem_info in enumerate(annotation.elements):
elem = StructureVariable()
elem.type = parse_type(elem_info, caller_context)
elem.name = f"_{idx}"
elem.set_structure(st)
elem.set_offset("-1:-1:-1", caller_context.compilation_unit)
st.elems[elem.name] = elem
st.add_elem_in_order(elem.name)
st.name += elem.name
return UserDefinedType(st)
else:
assert False
lname = name.lower() # todo map String to string
lname = name.lower() # TODO map String to string
if lname in ElementaryTypeName:
return ElementaryType(lname)

@ -1,7 +1,7 @@
from typing import Union
from slither.core.variables.local_variable import LocalVariable
from slither.vyper_parsing.ast.types import Arg, Name, AnnAssign, Subscript, Call
from slither.vyper_parsing.ast.types import Arg, Name, AnnAssign, Subscript, Call, Tuple
from slither.vyper_parsing.type_parsing import parse_type
@ -23,7 +23,7 @@ class LocalVariableVyper:
self._variable.name = ""
self._elem_to_parse = variable_data
assert isinstance(self._elem_to_parse, (Name, Subscript, Call))
assert isinstance(self._elem_to_parse, (Name, Subscript, Call, Tuple))
self._variable.set_location("default")

Loading…
Cancel
Save