move nested logic into functions

pull/1501/head
alpharush 2 years ago
parent ca252f1472
commit baf4143345
  1. 178
      slither/utils/expression_manipulations.py

@ -23,7 +23,8 @@ from slither.all_exceptions import SlitherException
# pylint: disable=protected-access
def f_expressions(
e: AssignmentOperation, x: Union[Identifier, Literal, MemberAccess, IndexAccess]
e: Union[AssignmentOperation, BinaryOperation, TupleExpression],
x: Union[Identifier, Literal, MemberAccess, IndexAccess],
) -> None:
e._expressions.append(x)
@ -40,7 +41,7 @@ def f_call_gas(e: CallExpression, x):
e._gas = x
def f_expression(e, x):
def f_expression(e: Union[TypeConversion, UnaryOperation, MemberAccess], x):
e._expression = x
@ -86,7 +87,6 @@ class SplitTernaryExpression:
f(false_expression, copy.copy(next_expr))
return True
# pylint: disable=too-many-branches
def copy_expression(
self, expression: Expression, true_expression: Expression, false_expression: Expression
) -> None:
@ -102,108 +102,114 @@ class SplitTernaryExpression:
):
return
# case of lib
# (.. ? .. : ..).add
if isinstance(expression, MemberAccess):
next_expr = expression.expression
if self.conditional_not_ahead(
next_expr, true_expression, false_expression, f_expression
):
self.copy_expression(
next_expr, true_expression.expression, false_expression.expression
)
# pylint: disable=too-many-nested-blocks
elif isinstance(expression, (AssignmentOperation, BinaryOperation, TupleExpression)):
true_expression._expressions = []
false_expression._expressions = []
for next_expr in expression.expressions:
# TODO: can we get rid of `NoneType` expressions in `TupleExpression`?
if next_expr:
if isinstance(next_expr, IndexAccess):
# create an index access for each branch
# x[if cond ? 1 : 2] -> if cond { x[1] } else { x[2] }
for expr in next_expr.expressions:
if self.conditional_not_ahead(
expr, true_expression, false_expression, f_expressions
):
self.copy_expression(
expr,
true_expression.expressions[-1],
false_expression.expressions[-1],
)
if self.conditional_not_ahead(
next_expr, true_expression, false_expression, f_expressions
):
# always on last arguments added
self.copy_expression(
next_expr,
true_expression.expressions[-1],
false_expression.expressions[-1],
)
self.convert_expressions(expression, true_expression, false_expression)
elif isinstance(expression, CallExpression):
next_expr = expression.called
self.convert_call_expression(expression, next_expr, true_expression, false_expression)
elif isinstance(expression, (TypeConversion, UnaryOperation, MemberAccess)):
next_expr = expression.expression
if self.conditional_not_ahead(
next_expr, true_expression, false_expression, f_expression
):
self.copy_expression(
expression.expression,
true_expression.expression,
false_expression.expression,
)
# case of lib
# (.. ? .. : ..).add
if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_called):
self.copy_expression(next_expr, true_expression.called, false_expression.called)
else:
raise SlitherException(
f"Ternary operation not handled {expression}({type(expression)})"
)
# In order to handle ternaries in both call options, gas and value, we return early if the
# conditional is not ahead to rewrite both ternaries (see `_rewrite_ternary_as_if_else`).
if expression.call_gas:
# case of (..).func{gas: .. ? .. : ..}()
next_expr = expression.call_gas
if self.conditional_not_ahead(
next_expr, true_expression, false_expression, f_call_gas
):
self.copy_expression(
next_expr,
true_expression.call_gas,
false_expression.call_gas,
)
else:
return
def convert_expressions(
self,
expression: Union[AssignmentOperation, BinaryOperation, TupleExpression],
true_expression: Expression,
false_expression: Expression,
) -> None:
for next_expr in expression.expressions:
# TODO: can we get rid of `NoneType` expressions in `TupleExpression`?
if next_expr:
if isinstance(next_expr, IndexAccess):
self.convert_index_access(next_expr, true_expression, false_expression)
if expression.call_value:
# case of (..).func{value: .. ? .. : ..}()
next_expr = expression.call_value
if self.conditional_not_ahead(
next_expr, true_expression, false_expression, f_call_value
next_expr, true_expression, false_expression, f_expressions
):
# always on last arguments added
self.copy_expression(
next_expr,
true_expression.call_value,
false_expression.call_value,
true_expression.expressions[-1],
false_expression.expressions[-1],
)
else:
return
true_expression._arguments = []
false_expression._arguments = []
def convert_index_access(
self, next_expr: IndexAccess, true_expression: Expression, false_expression: Expression
) -> None:
# create an index access for each branch
# x[if cond ? 1 : 2] -> if cond { x[1] } else { x[2] }
for expr in next_expr.expressions:
if self.conditional_not_ahead(expr, true_expression, false_expression, f_expressions):
self.copy_expression(
expr,
true_expression.expressions[-1],
false_expression.expressions[-1],
)
for next_expr in expression.arguments:
if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_call):
# always on last arguments added
self.copy_expression(
next_expr,
true_expression.arguments[-1],
false_expression.arguments[-1],
)
def convert_call_expression(
self,
expression: CallExpression,
next_expr: Expression,
true_expression: Expression,
false_expression: Expression,
) -> None:
# case of lib
# (.. ? .. : ..).add
if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_called):
self.copy_expression(next_expr, true_expression.called, false_expression.called)
# In order to handle ternaries in both call options, gas and value, we return early if the
# conditional is not ahead to rewrite both ternaries (see `_rewrite_ternary_as_if_else`).
if expression.call_gas:
# case of (..).func{gas: .. ? .. : ..}()
next_expr = expression.call_gas
if self.conditional_not_ahead(next_expr, true_expression, false_expression, f_call_gas):
self.copy_expression(
next_expr,
true_expression.call_gas,
false_expression.call_gas,
)
else:
return
elif isinstance(expression, (TypeConversion, UnaryOperation)):
next_expr = expression.expression
if expression.call_value:
# case of (..).func{value: .. ? .. : ..}()
next_expr = expression.call_value
if self.conditional_not_ahead(
next_expr, true_expression, false_expression, f_expression
next_expr, true_expression, false_expression, f_call_value
):
self.copy_expression(
expression.expression,
true_expression.expression,
false_expression.expression,
next_expr,
true_expression.call_value,
false_expression.call_value,
)
else:
return
else:
raise SlitherException(
f"Ternary operation not handled {expression}({type(expression)})"
)
true_expression._arguments = []
false_expression._arguments = []
for expr in expression.arguments:
if self.conditional_not_ahead(expr, true_expression, false_expression, f_call):
# always on last arguments added
self.copy_expression(
expr,
true_expression.arguments[-1],
false_expression.arguments[-1],
)

Loading…
Cancel
Save