diff --git a/slither/printers/inheritance/inheritance_graph.py b/slither/printers/inheritance/inheritance_graph.py index ab19c56656..0de5edc909 100644 --- a/slither/printers/inheritance/inheritance_graph.py +++ b/slither/printers/inheritance/inheritance_graph.py @@ -108,8 +108,9 @@ def _summary(self, contract): ] # Add arrows (number them if there is more than one path so we know order of declaration for inheritance). + # Note: `inheritance` is already filtered to exclude mocks and (by default) interfaces. if len(inheritance) == 1: - immediate_inheritance = contract.immediate_inheritance[0] + immediate_inheritance = inheritance[0] ret += f"c{contract.id}_{contract.name} -> c{immediate_inheritance.id}_{immediate_inheritance};\n" else: for i, immediate_inheritance in enumerate(inheritance): diff --git a/tests/e2e/printers/test_data/test_contract_names/D.sol b/tests/e2e/printers/test_data/test_contract_names/D.sol new file mode 100644 index 0000000000..927151d438 --- /dev/null +++ b/tests/e2e/printers/test_data/test_contract_names/D.sol @@ -0,0 +1,11 @@ +import "./A.sol"; + +interface MyInterfaceY { + function ping() external; +} + +// Intentionally list the interface first to ensure the inheritance-graph printer +// respects the interface filtering logic (see issue #2150). +contract D is MyInterfaceY, A { + function ping() external override {} +} diff --git a/tests/e2e/printers/test_printers.py b/tests/e2e/printers/test_printers.py index 8d9d15f603..dc2861c834 100644 --- a/tests/e2e/printers/test_printers.py +++ b/tests/e2e/printers/test_printers.py @@ -29,6 +29,7 @@ def test_inheritance_graph_printer(solc_binary_path) -> None: standard_json.add_source_file(Path(TEST_DATA_DIR, "test_contract_names", "B.sol").as_posix()) standard_json.add_source_file(Path(TEST_DATA_DIR, "test_contract_names", "B2.sol").as_posix()) standard_json.add_source_file(Path(TEST_DATA_DIR, "test_contract_names", "C.sol").as_posix()) + standard_json.add_source_file(Path(TEST_DATA_DIR, "test_contract_names", "D.sol").as_posix()) compilation = CryticCompile(standard_json, solc=solc_path) slither = Slither(compilation) printer = PrinterInheritanceGraph(slither=slither, logger=None) @@ -44,6 +45,7 @@ def test_inheritance_graph_printer(solc_binary_path) -> None: assert counter["B -> A"] == 2 assert counter["C -> A"] == 1 + assert counter["D -> A"] == 1 # Let also test the include/exclude interface behavior # Check that the interface is not included assert "MyInterfaceX" not in content