Static Analyzer for Solidity
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
slither/tests/unit/core/test_virtual_overrides.py

152 lines
6.2 KiB

from pathlib import Path
from slither import Slither
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data"
def test_overrides(solc_binary_path) -> None:
8 months ago
# pylint: disable=too-many-statements,too-many-locals
solc_path = solc_binary_path("0.8.15")
slither = Slither(Path(TEST_DATA_DIR, "virtual_overrides.sol").as_posix(), solc=solc_path)
test = slither.get_contract_from_name("Test")[0]
test_virtual_func = test.get_function_from_full_name("myVirtualFunction()")
assert test_virtual_func.is_virtual
assert not test_virtual_func.is_override
x = test.get_functions_overridden_by(test_virtual_func)
assert len(x) == 0
x = test_virtual_func.overridden_by
assert len(x) == 5
assert set(i.canonical_name for i in x) == set(
["A.myVirtualFunction()", "C.myVirtualFunction()", "X.myVirtualFunction()"]
)
a = slither.get_contract_from_name("A")[0]
a_virtual_func = a.get_function_from_full_name("myVirtualFunction()")
assert a_virtual_func.is_virtual
assert a_virtual_func.is_override
x = a.get_functions_overridden_by(a_virtual_func)
assert len(x) == 2
assert set(i.canonical_name for i in x) == set(["Test.myVirtualFunction()"])
b = slither.get_contract_from_name("B")[0]
b_virtual_func = b.get_function_from_full_name("myVirtualFunction()")
assert not b_virtual_func.is_virtual
assert b_virtual_func.is_override
x = b.get_functions_overridden_by(b_virtual_func)
assert len(x) == 2
assert set(i.canonical_name for i in x) == set(["A.myVirtualFunction()"])
assert len(b_virtual_func.overridden_by) == 0
c = slither.get_contract_from_name("C")[0]
c_virtual_func = c.get_function_from_full_name("myVirtualFunction()")
assert not c_virtual_func.is_virtual
assert c_virtual_func.is_override
x = c.get_functions_overridden_by(c_virtual_func)
assert len(x) == 2
# C should not override B as they are distinct leaves in the inheritance tree
assert set(i.canonical_name for i in x) == set(["Test.myVirtualFunction()"])
y = slither.get_contract_from_name("Y")[0]
y_virtual_func = y.get_function_from_full_name("myVirtualFunction()")
assert y_virtual_func.is_virtual
assert not y_virtual_func.is_override
x = y_virtual_func.overridden_by
assert len(x) == 1
assert x[0].canonical_name == "Z.myVirtualFunction()"
z = slither.get_contract_from_name("Z")[0]
z_virtual_func = z.get_function_from_full_name("myVirtualFunction()")
assert z_virtual_func.is_virtual
assert z_virtual_func.is_override
x = z.get_functions_overridden_by(z_virtual_func)
assert len(x) == 4
assert set(i.canonical_name for i in x) == set(
["Y.myVirtualFunction()", "X.myVirtualFunction()"]
)
8 months ago
k = slither.get_contract_from_name("K")[0]
k_virtual_func = k.get_function_from_full_name("a()")
assert not k_virtual_func.is_virtual
assert k_virtual_func.is_override
assert len(k_virtual_func.overrides) == 3
x = k_virtual_func.overrides
assert set(i.canonical_name for i in x) == set(["I.a()"])
8 months ago
i = slither.get_contract_from_name("I")[0]
i_virtual_func = i.get_function_from_full_name("a()")
assert i_virtual_func.is_virtual
assert not i_virtual_func.is_override
assert len(i_virtual_func.overrides) == 0
x = i_virtual_func.overridden_by
assert len(x) == 1
assert x[0].canonical_name == "K.a()"
def test_virtual_override_references_and_implementations(solc_binary_path) -> None:
solc_path = solc_binary_path("0.8.15")
file = Path(TEST_DATA_DIR, "virtual_overrides.sol").as_posix()
slither = Slither(file, solc=solc_path)
funcs = slither.offset_to_objects(file, 29)
assert len(funcs) == 1
func = funcs.pop()
assert func.canonical_name == "Test.myVirtualFunction()"
assert {(x.start, x.end) for x in slither.offset_to_implementations(file, 29)} == {
(20, 73),
(102, 164),
(274, 328),
(357, 419),
}
funcs = slither.offset_to_objects(file, 111)
assert len(funcs) == 1
func = funcs.pop()
assert func.canonical_name == "A.myVirtualFunction()"
# A.myVirtualFunction() is implemented in A and also overridden in B
assert {(x.start, x.end) for x in slither.offset_to_implementations(file, 111)} == {
(102, 164),
(190, 244),
}
# X is inherited by Z and Z.myVirtualFunction() overrides X.myVirtualFunction()
assert {(x.start, x.end) for x in slither.offset_to_references(file, 341)} == {
(514, 515),
(570, 571),
}
# The reference to X in inheritance specifier is the definition of Z
assert {(x.start, x.end) for x in slither.offset_to_definitions(file, 514)} == {(341, 343)}
# The reference to X in the function override specifier is the definition of Z
assert {(x.start, x.end) for x in slither.offset_to_definitions(file, 570)} == {(341, 343)}
# Y is inherited by Z and Z.myVirtualFunction() overrides Y.myVirtualFunction()
assert {(x.start, x.end) for x in slither.offset_to_references(file, 432)} == {
(511, 512),
(567, 568),
}
# The reference to Y in inheritance specifier is the definition of Z
assert {(x.start, x.end) for x in slither.offset_to_definitions(file, 511)} == {(432, 434)}
# The reference to Y in the function override specifier is the definition of Z
assert {(x.start, x.end) for x in slither.offset_to_definitions(file, 567)} == {(432, 434)}
# Name is abstract and has no implementation. It is inherited and implemented by Name2
assert {(x.start, x.end) for x in slither.offset_to_implementations(file, 612)} == {(657, 718)}
def test_virtual_is_implemented(solc_binary_path):
solc_path = solc_binary_path("0.8.15")
file = Path(TEST_DATA_DIR, "virtual_overrides.sol").as_posix()
slither = Slither(file, solc=solc_path)
test2 = slither.get_contract_from_name("Test2")[0]
f = test2.get_function_from_full_name("f()")
assert f.is_virtual
assert not f.is_implemented
a2 = slither.get_contract_from_name("A2")[0]
f = a2.get_function_from_full_name("f()")
assert f.is_virtual
assert f.is_implemented
# Test.2f() is not implemented, but A2 inherits from Test2 and overrides f()
assert {(x.start, x.end) for x in slither.offset_to_implementations(file, 759)} == {(809, 853)}