mirror of https://github.com/crytic/slither
parent
20ed490e2d
commit
0933dfa67c
@ -0,0 +1,58 @@ |
||||
contract Test { |
||||
function myVirtualFunction() virtual external { |
||||
} |
||||
} |
||||
|
||||
contract A is Test { |
||||
function myVirtualFunction() virtual override external { |
||||
} |
||||
} |
||||
|
||||
contract B is A { |
||||
function myVirtualFunction() override external { |
||||
} |
||||
|
||||
} |
||||
|
||||
contract C is Test { |
||||
function myVirtualFunction() override external { |
||||
} |
||||
} |
||||
|
||||
contract X is Test { |
||||
function myVirtualFunction() virtual override external { |
||||
} |
||||
} |
||||
|
||||
contract Y { |
||||
function myVirtualFunction() virtual external { |
||||
} |
||||
} |
||||
|
||||
contract Z is Y, X{ |
||||
function myVirtualFunction() virtual override(Y, X) external { |
||||
} |
||||
} |
||||
|
||||
|
||||
abstract contract Name { |
||||
constructor() { |
||||
|
||||
} |
||||
} |
||||
|
||||
contract Name2 is Name { |
||||
constructor() { |
||||
|
||||
} |
||||
} |
||||
|
||||
abstract contract Test2 { |
||||
function f() virtual public; |
||||
} |
||||
|
||||
contract A2 is Test2 { |
||||
function f() virtual override public { |
||||
} |
||||
} |
||||
|
@ -0,0 +1,124 @@ |
||||
from pathlib import Path |
||||
from slither import Slither |
||||
|
||||
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" |
||||
|
||||
|
||||
def test_overrides(solc_binary_path) -> None: |
||||
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) == 3, [i.canonical_name for i in x] |
||||
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) == 1 |
||||
assert x[0].canonical_name == "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) == 1 |
||||
assert x[0].canonical_name == "A.myVirtualFunction()" |
||||
assert len(b_virtual_func.overridden_by) == 0 |
||||
|
||||
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) == 2 |
||||
assert set([i.canonical_name for i in x]) == set( |
||||
["Y.myVirtualFunction()", "X.myVirtualFunction()"] |
||||
) |
||||
|
||||
|
||||
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)} |
Loading…
Reference in new issue