From 2d256ddd93ccdd83108a10cd4bba4c826dd45666 Mon Sep 17 00:00:00 2001 From: Josselin Date: Wed, 24 Jun 2020 19:30:38 +0200 Subject: [PATCH] Improve support of top-level structures and enums --- slither/core/slither_core.py | 22 +++++++++++++++++-- .../expressions/expression_parsing.py | 10 +++++++++ slither/solc_parsing/slitherSolc.py | 11 +++++----- .../solidity_types/type_parsing.py | 4 ++-- 4 files changed, 38 insertions(+), 9 deletions(-) diff --git a/slither/core/slither_core.py b/slither/core/slither_core.py index cb4a5fd04..c2c8d365f 100644 --- a/slither/core/slither_core.py +++ b/slither/core/slither_core.py @@ -11,7 +11,7 @@ from typing import Optional, Dict, List, Set, Union from crytic_compile import CryticCompile from slither.core.context.context import Context -from slither.core.declarations import Contract, Pragma, Import, Function, Modifier +from slither.core.declarations import Contract, Pragma, Import, Function, Modifier, Structure, Enum from slither.core.variables.state_variable import StateVariable from slither.slithir.operations import InternalCall from slither.slithir.variables import Constant @@ -136,7 +136,7 @@ class SlitherCore(Context): """list(Contract): List of contracts that are derived and not inherited.""" inheritance = (x.inheritance for x in self.contracts) inheritance = [item for sublist in inheritance for item in sublist] - return [c for c in self._contracts.values() if c not in inheritance] + return [c for c in self._contracts.values() if c not in inheritance and not c.is_top_level] @property def contracts_as_dict(self) -> Dict[str, Contract]: @@ -200,6 +200,24 @@ class SlitherCore(Context): self._all_state_variables = set(state_variables) return list(self._all_state_variables) + # endregion + ################################################################################### + ################################################################################### + # region Top level + ################################################################################### + ################################################################################### + + @property + def top_level_structures(self) -> List[Structure]: + top_level_structures = [c.structures for c in self.contracts if c.is_top_level] + return [st for sublist in top_level_structures for st in sublist] + + + @property + def top_level_enums(self) -> List[Enum]: + top_level_enums = [c.enums for c in self.contracts if c.is_top_level] + return [st for sublist in top_level_enums for st in sublist] + # endregion ################################################################################### ################################################################################### diff --git a/slither/solc_parsing/expressions/expression_parsing.py b/slither/solc_parsing/expressions/expression_parsing.py index d2ee972df..4b78a2a10 100644 --- a/slither/solc_parsing/expressions/expression_parsing.py +++ b/slither/solc_parsing/expressions/expression_parsing.py @@ -168,6 +168,11 @@ def find_variable( if var_name in structures: return structures[var_name] + structures_top_level = contract.slither.top_level_structures + for st in structures_top_level: + if st.name == var_name: + return st + events = contract.events_as_dict if var_name in events: return events[var_name] @@ -176,6 +181,11 @@ def find_variable( if var_name in enums: return enums[var_name] + enums_top_level = contract.slither.top_level_enums + for enum in enums_top_level: + if enum.name == var_name: + return enum + # If the enum is refered as its name rather than its canonicalName enums = {e.name: e for e in contract.enums} if var_name in enums: diff --git a/slither/solc_parsing/slitherSolc.py b/slither/solc_parsing/slitherSolc.py index d5de1b56a..695a11184 100644 --- a/slither/solc_parsing/slitherSolc.py +++ b/slither/solc_parsing/slitherSolc.py @@ -163,15 +163,16 @@ class SlitherSolc: assert self._is_compact_ast # Do not support top level definition for legacy AST fake_contract_data = { "name": f"SlitherInternalTopLevelContract{self._top_level_contracts_counter}", - "id": -1000, # TODO: determine if collission possible + "id": -1000 + self._top_level_contracts_counter, # TODO: determine if collission possible "linearizedBaseContracts": [], "fullyImplemented": True, "contractKind": "SLitherInternal", } self._top_level_contracts_counter += 1 - top_level_contract = ContractSolc(self, fake_contract_data) - top_level_contract.is_top_level = True - top_level_contract.set_offset(contract_data["src"], self) + contract = Contract() + top_level_contract = ContractSolc(self, contract, fake_contract_data) + contract.is_top_level = True + contract.set_offset(contract_data["src"], self._core) if contract_data[self.get_key()] == "StructDefinition": top_level_contract._structuresNotParsed.append( @@ -182,7 +183,7 @@ class SlitherSolc: contract_data ) # Todo add proper setters - self._contractsNotParsed.append(top_level_contract) + self._underlying_contract_to_parser[contract] = top_level_contract def _parse_source_unit(self, data: Dict, filename: str): if data[self.get_key()] != "SourceUnit": diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index 9d11936ad..4ec8f5112 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -167,8 +167,8 @@ def parse_type(t: Union[Dict, UnknownType], caller_context): else: key = "name" - structures = contract.structures - enums = contract.enums + structures = contract.structures + contract.slither.top_level_structures + enums = contract.enums + contract.slither.top_level_enums contracts = contract.slither.contracts if isinstance(t, UnknownType):