|
|
|
from pathlib import Path
|
|
|
|
from slither import Slither
|
|
|
|
from slither.core.cfg.node import NodeType
|
|
|
|
from slither.slithir.operations import Assignment, Unpack
|
|
|
|
from slither.core.expressions import (
|
|
|
|
AssignmentOperation,
|
|
|
|
TupleExpression,
|
|
|
|
NewElementaryType,
|
|
|
|
CallExpression,
|
|
|
|
)
|
|
|
|
|
|
|
|
|
|
|
|
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data"
|
|
|
|
# pylint: disable=too-many-nested-blocks
|
|
|
|
def test_ternary_conversions(solc_binary_path) -> None:
|
|
|
|
"""This tests that true and false sons define the same number of variables that the father node declares"""
|
|
|
|
solc_path = solc_binary_path("0.8.0")
|
|
|
|
slither = Slither(Path(TEST_DATA_DIR, "ternary_expressions.sol").as_posix(), solc=solc_path)
|
|
|
|
contract = next(c for c in slither.contracts if c.name == "C")
|
|
|
|
for function in contract.functions:
|
|
|
|
vars_declared = 0
|
|
|
|
vars_assigned = 0
|
|
|
|
for node in function.nodes:
|
|
|
|
if node.type in [NodeType.IF, NodeType.IFLOOP]:
|
|
|
|
|
|
|
|
# Iterate over true and false son
|
|
|
|
for inner_node in node.sons:
|
|
|
|
# Count all variables declared
|
|
|
|
expression = inner_node.expression
|
|
|
|
if isinstance(
|
|
|
|
expression, (AssignmentOperation, NewElementaryType, CallExpression)
|
|
|
|
):
|
|
|
|
var_expr = expression.expression_left
|
|
|
|
# Only tuples declare more than one var
|
|
|
|
if isinstance(var_expr, TupleExpression):
|
|
|
|
vars_declared += len(var_expr.expressions)
|
|
|
|
else:
|
|
|
|
vars_declared += 1
|
|
|
|
|
|
|
|
for ir in inner_node.irs:
|
|
|
|
# Count all variables defined
|
|
|
|
if isinstance(ir, (Assignment, Unpack)):
|
|
|
|
vars_assigned += 1
|
|
|
|
assert vars_declared == vars_assigned and vars_assigned != 0
|
|
|
|
|
|
|
|
|
|
|
|
def test_ternary_tuple(solc_binary_path) -> None:
|
|
|
|
"""
|
|
|
|
Test that in the ternary liftings of an assignment of the form `(z, ) = ...`,
|
|
|
|
we obtain `z` from an unpack operation in both lifitings
|
|
|
|
"""
|
|
|
|
solc_path = solc_binary_path("0.8.0")
|
|
|
|
slither = Slither(Path(TEST_DATA_DIR, "ternary_expressions.sol").as_posix(), solc=solc_path)
|
|
|
|
contract = next(c for c in slither.contracts if c.name == "D")
|
|
|
|
fn = next(f for f in contract.functions if f.name == "a")
|
|
|
|
|
|
|
|
if_nodes = [n for n in fn.nodes if n.type == NodeType.IF]
|
|
|
|
assert len(if_nodes) == 1
|
|
|
|
|
|
|
|
if_node = if_nodes[0]
|
|
|
|
assert isinstance(if_node.son_true.expression, AssignmentOperation)
|
|
|
|
assert (
|
|
|
|
len([ir for ir in if_node.son_true.all_slithir_operations() if isinstance(ir, Unpack)]) == 1
|
|
|
|
)
|
|
|
|
assert (
|
|
|
|
len([ir for ir in if_node.son_false.all_slithir_operations() if isinstance(ir, Unpack)])
|
|
|
|
== 1
|
|
|
|
)
|