From 41f599b5463c2518cf71d41556e0597cda298f4b Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 22 Aug 2022 17:50:35 +0200 Subject: [PATCH 1/4] Remove libraries, mock contract, option interfaces --- slither/__main__.py | 8 ++++++++ slither/printers/inheritance/inheritance_graph.py | 8 ++++++-- slither/slither.py | 4 +++- 3 files changed, 17 insertions(+), 3 deletions(-) diff --git a/slither/__main__.py b/slither/__main__.py index caaef5730b..d303aebe68 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -335,6 +335,14 @@ def parse_args( default=defaults_flag_in_config["printers_to_run"], ) + group_printer.add_argument( + "--exclude-interfaces", + help= "Exclude interfaces from inheritance-graph printer", + action="store_true", + dest="exclude_interfaces", + default=False, + ) + group_detector.add_argument( "--list-detectors", help="List available detectors", diff --git a/slither/printers/inheritance/inheritance_graph.py b/slither/printers/inheritance/inheritance_graph.py index a16ce273af..3a91f1523f 100644 --- a/slither/printers/inheritance/inheritance_graph.py +++ b/slither/printers/inheritance/inheritance_graph.py @@ -98,12 +98,14 @@ def _summary(self, contract): """ ret = "" + inheritance = [i for i in contract.immediate_inheritance if "mock" not in i.name.lower()] + # Add arrows (number them if there is more than one path so we know order of declaration for inheritance). - if len(contract.immediate_inheritance) == 1: + if len(inheritance) == 1: immediate_inheritance = contract.immediate_inheritance[0] ret += f"c{contract.id}_{contract.name} -> c{immediate_inheritance.id}_{immediate_inheritance};\n" else: - for i, immediate_inheritance in enumerate(contract.immediate_inheritance): + for i, immediate_inheritance in enumerate(inheritance): ret += f'c{contract.id}_{contract.name} -> c{immediate_inheritance.id}_{immediate_inheritance} [ label="{i + 1}" ];\n' # Functions @@ -195,6 +197,8 @@ def output(self, filename): content = 'digraph "" {\n' for c in self.contracts: + if c.is_top_level or "mock" in c.name.lower() or c.is_library or (self.slither.exclude_interfaces and c.is_interface): + continue content += self._summary(c) + "\n" content += "}" diff --git a/slither/slither.py b/slither/slither.py index 0f22185353..72cf365362 100644 --- a/slither/slither.py +++ b/slither/slither.py @@ -196,10 +196,12 @@ def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None: if printers_to_run == "echidna": self.skip_data_dependency = True + # Used in inheritance-graph printer + self.exclude_interfaces = kwargs.get("exclude_interfaces", False) + self._init_parsing_and_analyses(kwargs.get("skip_analyze", False)) def _init_parsing_and_analyses(self, skip_analyze: bool) -> None: - for parser in self._parsers: try: parser.parse_contracts() From ea01702294bf8b2e4c512063402020a795e68cf1 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 22 Aug 2022 18:04:23 +0200 Subject: [PATCH 2/4] Fix remove interfaces inherited --- slither/printers/inheritance/inheritance_graph.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/slither/printers/inheritance/inheritance_graph.py b/slither/printers/inheritance/inheritance_graph.py index 3a91f1523f..36fb6c4328 100644 --- a/slither/printers/inheritance/inheritance_graph.py +++ b/slither/printers/inheritance/inheritance_graph.py @@ -98,7 +98,7 @@ def _summary(self, contract): """ ret = "" - inheritance = [i for i in contract.immediate_inheritance if "mock" not in i.name.lower()] + inheritance = [i for i in contract.immediate_inheritance if "mock" not in i.name.lower() and (self.slither.exclude_interfaces and not i.is_interface)] # Add arrows (number them if there is more than one path so we know order of declaration for inheritance). if len(inheritance) == 1: From 4164039011de66c076981d5f652c076a2ab53a96 Mon Sep 17 00:00:00 2001 From: Simone Date: Mon, 22 Aug 2022 18:14:14 +0200 Subject: [PATCH 3/4] Fix --- slither/printers/inheritance/inheritance_graph.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/slither/printers/inheritance/inheritance_graph.py b/slither/printers/inheritance/inheritance_graph.py index 36fb6c4328..a593d20eed 100644 --- a/slither/printers/inheritance/inheritance_graph.py +++ b/slither/printers/inheritance/inheritance_graph.py @@ -98,7 +98,8 @@ def _summary(self, contract): """ ret = "" - inheritance = [i for i in contract.immediate_inheritance if "mock" not in i.name.lower() and (self.slither.exclude_interfaces and not i.is_interface)] + # Remove contracts that have "mock" in the name and if --exclude-interface removes inherited interfaces + inheritance = [i for i in contract.immediate_inheritance if "mock" not in i.name.lower() and (not self.slither.exclude_interfaces or self.slither.exclude_interfaces and not i.is_interface)] # Add arrows (number them if there is more than one path so we know order of declaration for inheritance). if len(inheritance) == 1: From 20fa97cbacb33330da75f2678313f2727fc6d0a5 Mon Sep 17 00:00:00 2001 From: Alexis Date: Tue, 9 Apr 2024 17:18:02 +0200 Subject: [PATCH 4/4] Remove interface from inheritance graph. --- slither/__main__.py | 6 +++--- .../printers/inheritance/inheritance_graph.py | 17 ++++++++++++++--- slither/slither.py | 2 +- .../test_data/test_contract_names/C.sol | 16 +++++++++++++++- tests/e2e/printers/test_printers.py | 12 ++++++++++++ 5 files changed, 45 insertions(+), 8 deletions(-) diff --git a/slither/__main__.py b/slither/__main__.py index d303aebe68..de818c2882 100644 --- a/slither/__main__.py +++ b/slither/__main__.py @@ -336,10 +336,10 @@ def parse_args( ) group_printer.add_argument( - "--exclude-interfaces", - help= "Exclude interfaces from inheritance-graph printer", + "--include-interfaces", + help="Include interfaces from inheritance-graph printer", action="store_true", - dest="exclude_interfaces", + dest="include_interfaces", default=False, ) diff --git a/slither/printers/inheritance/inheritance_graph.py b/slither/printers/inheritance/inheritance_graph.py index a593d20eed..54b525c774 100644 --- a/slither/printers/inheritance/inheritance_graph.py +++ b/slither/printers/inheritance/inheritance_graph.py @@ -98,8 +98,14 @@ def _summary(self, contract): """ ret = "" - # Remove contracts that have "mock" in the name and if --exclude-interface removes inherited interfaces - inheritance = [i for i in contract.immediate_inheritance if "mock" not in i.name.lower() and (not self.slither.exclude_interfaces or self.slither.exclude_interfaces and not i.is_interface)] + # Remove contracts that have "mock" in the name and if --include-interfaces in False (default) + # removes inherited interfaces + inheritance = [ + i + for i in contract.immediate_inheritance + if "mock" not in i.name.lower() + and (not i.is_interface or self.slither.include_interfaces) + ] # Add arrows (number them if there is more than one path so we know order of declaration for inheritance). if len(inheritance) == 1: @@ -116,6 +122,7 @@ def _summary(self, contract): for f in contract.functions if not f.is_constructor and not f.is_constructor_variables + and not f.is_virtual and f.contract_declarer == contract and f.visibility in visibilities ] @@ -198,7 +205,11 @@ def output(self, filename): content = 'digraph "" {\n' for c in self.contracts: - if c.is_top_level or "mock" in c.name.lower() or c.is_library or (self.slither.exclude_interfaces and c.is_interface): + if ( + "mock" in c.name.lower() + or c.is_library + or (c.is_interface and not self.slither.include_interfaces) + ): continue content += self._summary(c) + "\n" content += "}" diff --git a/slither/slither.py b/slither/slither.py index 72cf365362..7adc0694ca 100644 --- a/slither/slither.py +++ b/slither/slither.py @@ -197,7 +197,7 @@ def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None: self.skip_data_dependency = True # Used in inheritance-graph printer - self.exclude_interfaces = kwargs.get("exclude_interfaces", False) + self.include_interfaces = kwargs.get("include_interfaces", False) self._init_parsing_and_analyses(kwargs.get("skip_analyze", False)) diff --git a/tests/e2e/printers/test_data/test_contract_names/C.sol b/tests/e2e/printers/test_data/test_contract_names/C.sol index 90bc35df39..d6ba9b5c15 100644 --- a/tests/e2e/printers/test_data/test_contract_names/C.sol +++ b/tests/e2e/printers/test_data/test_contract_names/C.sol @@ -1,7 +1,21 @@ import "./A.sol"; -contract C is A { +interface MyInterfaceX { + function count() external view returns (uint256); + + function increment() external; +} + +contract C is A, MyInterfaceX { function c_main() public pure { a_main(); } + + function count() external view override returns (uint256){ + return 1; + } + + function increment() external override { + + } } diff --git a/tests/e2e/printers/test_printers.py b/tests/e2e/printers/test_printers.py index 26429d3381..3dea8b74a4 100644 --- a/tests/e2e/printers/test_printers.py +++ b/tests/e2e/printers/test_printers.py @@ -34,3 +34,15 @@ def test_inheritance_printer(solc_binary_path) -> None: assert counter["B -> A"] == 2 assert counter["C -> A"] == 1 + + # Lets also test the include/exclude interface behavior + # Check that the interface is not included + assert "MyInterfaceX" not in content + + slither.include_interfaces = True + output = printer.output("test_printer.dot") + content = output.elements[0]["name"]["content"] + assert "MyInterfaceX" in content + + # Remove test generated files + Path("test_printer.dot").unlink(missing_ok=True)