Skip to content

Commit

Permalink
Change the way slither handles top level enum/struct
Browse files Browse the repository at this point in the history
- Split declaration.Enum/Structure to EnumContract/EnumToplevel (same
for structure)
- Update the parsing accordingly
  • Loading branch information
montyly committed Dec 14, 2020
1 parent e52a2ae commit 0a7738d
Show file tree
Hide file tree
Showing 34 changed files with 246 additions and 171 deletions.
2 changes: 2 additions & 0 deletions slither/core/declarations/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,3 +11,5 @@
SolidityFunction,
)
from .structure import Structure
from .enum_contract import EnumContract
from .structure_contract import StructureContract
23 changes: 11 additions & 12 deletions slither/core/declarations/contract.py
Original file line number Diff line number Diff line change
Expand Up @@ -25,8 +25,7 @@
# pylint: disable=too-many-lines,too-many-instance-attributes,import-outside-toplevel,too-many-nested-blocks
if TYPE_CHECKING:
from slither.utils.type_helpers import LibraryCallType, HighLevelCallType, InternalCallType
from slither.core.declarations import Enum, Event, Modifier
from slither.core.declarations import Structure
from slither.core.declarations import Enum, Event, Modifier, EnumContract, StructureContract
from slither.slithir.variables.variable import SlithIRVariable
from slither.core.variables.variable import Variable
from slither.core.variables.state_variable import StateVariable
Expand All @@ -51,8 +50,8 @@ def __init__(self):
# contract B is A(1) { ..
self._explicit_base_constructor_calls: List["Contract"] = []

self._enums: Dict[str, "Enum"] = {}
self._structures: Dict[str, "Structure"] = {}
self._enums: Dict[str, "EnumContract"] = {}
self._structures: Dict[str, "StructureContract"] = {}
self._events: Dict[str, "Event"] = {}
self._variables: Dict[str, "StateVariable"] = {}
self._variables_ordered: List["StateVariable"] = []
Expand Down Expand Up @@ -135,28 +134,28 @@ def is_interface(self, is_interface: bool):
###################################################################################

@property
def structures(self) -> List["Structure"]:
def structures(self) -> List["StructureContract"]:
"""
list(Structure): List of the structures
"""
return list(self._structures.values())

@property
def structures_inherited(self) -> List["Structure"]:
def structures_inherited(self) -> List["StructureContract"]:
"""
list(Structure): List of the inherited structures
"""
return [s for s in self.structures if s.contract != self]

@property
def structures_declared(self) -> List["Structure"]:
def structures_declared(self) -> List["StructureContract"]:
"""
list(Structues): List of the structures declared within the contract (not inherited)
"""
return [s for s in self.structures if s.contract == self]

@property
def structures_as_dict(self) -> Dict[str, "Structure"]:
def structures_as_dict(self) -> Dict[str, "StructureContract"]:
return self._structures

# endregion
Expand All @@ -167,25 +166,25 @@ def structures_as_dict(self) -> Dict[str, "Structure"]:
###################################################################################

@property
def enums(self) -> List["Enum"]:
def enums(self) -> List["EnumContract"]:
return list(self._enums.values())

@property
def enums_inherited(self) -> List["Enum"]:
def enums_inherited(self) -> List["EnumContract"]:
"""
list(Enum): List of the inherited enums
"""
return [e for e in self.enums if e.contract != self]

@property
def enums_declared(self) -> List["Enum"]:
def enums_declared(self) -> List["EnumContract"]:
"""
list(Enum): List of the enums declared within the contract (not inherited)
"""
return [e for e in self.enums if e.contract == self]

@property
def enums_as_dict(self) -> Dict[str, "Enum"]:
def enums_as_dict(self) -> Dict[str, "EnumContract"]:
return self._enums

# endregion
Expand Down
16 changes: 2 additions & 14 deletions slither/core/declarations/enum.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,9 @@
from typing import List, TYPE_CHECKING
from typing import List

from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.children.child_contract import ChildContract

if TYPE_CHECKING:
from slither.core.declarations import Contract


class Enum(ChildContract, SourceMapping):
class Enum(SourceMapping):
def __init__(self, name: str, canonical_name: str, values: List[str]):
super().__init__()
self._name = name
Expand All @@ -26,13 +22,5 @@ def name(self) -> str:
def values(self) -> List[str]:
return self._values

def is_declared_by(self, contract: "Contract") -> bool:
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract

def __str__(self):
return self.name
17 changes: 17 additions & 0 deletions slither/core/declarations/enum_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
from typing import TYPE_CHECKING

from slither.core.children.child_contract import ChildContract
from slither.core.declarations import Enum

if TYPE_CHECKING:
from slither.core.declarations import Contract


class EnumContract(Enum, ChildContract):
def is_declared_by(self, contract: "Contract") -> bool:
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract
6 changes: 6 additions & 0 deletions slither/core/declarations/enum_top_level.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from slither.core.declarations import Enum
from slither.core.declarations.top_level import TopLevel


class EnumTopLevel(Enum, TopLevel):
pass
11 changes: 1 addition & 10 deletions slither/core/declarations/structure.py
Original file line number Diff line number Diff line change
@@ -1,13 +1,12 @@
from typing import List, TYPE_CHECKING, Dict

from slither.core.children.child_contract import ChildContract
from slither.core.source_mapping.source_mapping import SourceMapping

if TYPE_CHECKING:
from slither.core.variables.structure_variable import StructureVariable


class Structure(ChildContract, SourceMapping):
class Structure(SourceMapping):
def __init__(self):
super().__init__()
self._name = None
Expand Down Expand Up @@ -39,14 +38,6 @@ def elems(self) -> Dict[str, "StructureVariable"]:
def add_elem_in_order(self, s: str):
self._elems_ordered.append(s)

def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract

@property
def elems_ordered(self) -> List["StructureVariable"]:
ret = []
Expand Down
12 changes: 12 additions & 0 deletions slither/core/declarations/structure_contract.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
from slither.core.children.child_contract import ChildContract
from slither.core.declarations import Structure


class StructureContract(Structure, ChildContract):
def is_declared_by(self, contract):
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract == contract
6 changes: 6 additions & 0 deletions slither/core/declarations/structure_top_level.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
from slither.core.declarations import Structure
from slither.core.declarations.top_level import TopLevel


class StructureTopLevel(Structure, TopLevel):
pass
5 changes: 5 additions & 0 deletions slither/core/declarations/top_level.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
from slither.core.source_mapping.source_mapping import SourceMapping


class TopLevel(SourceMapping):
pass
29 changes: 16 additions & 13 deletions slither/core/slither_core.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,11 @@
"""
Main module
"""
import os
import logging
import json
import re
import logging
import math
import os
import re
from collections import defaultdict
from typing import Optional, Dict, List, Set, Union, Tuple

Expand All @@ -18,9 +18,9 @@
Import,
Function,
Modifier,
Structure,
Enum,
)
from slither.core.declarations.enum_top_level import EnumTopLevel
from slither.core.declarations.structure_top_level import StructureTopLevel
from slither.core.variables.state_variable import StateVariable
from slither.slithir.operations import InternalCall
from slither.slithir.variables import Constant
Expand All @@ -44,12 +44,17 @@ class SlitherCore(Context): # pylint: disable=too-many-instance-attributes,too-

def __init__(self):
super().__init__()

# Top level object
self._contracts: Dict[str, Contract] = {}
self._structures_top_level: List[StructureTopLevel] = []
self._enums_top_level: List[EnumTopLevel] = []
self._pragma_directives: List[Pragma] = []
self._import_directives: List[Import] = []

self._filename: Optional[str] = None
self._source_units: Dict[int, str] = {}
self._solc_version: Optional[str] = None # '0.3' or '0.4':!
self._pragma_directives: List[Pragma] = []
self._import_directives: List[Import] = []
self._raw_source_code: Dict[str, str] = {}
self._all_functions: Set[Function] = set()
self._all_modifiers: Set[Modifier] = set()
Expand Down Expand Up @@ -234,14 +239,12 @@ def state_variables(self) -> List[StateVariable]:
###################################################################################

@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]
def structures_top_level(self) -> List[StructureTopLevel]:
return self._structures_top_level

@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]
def enums_top_level(self) -> List[EnumTopLevel]:
return self._enums_top_level

# endregion
###################################################################################
Expand Down
6 changes: 3 additions & 3 deletions slither/slither.py
Original file line number Diff line number Diff line change
Expand Up @@ -78,7 +78,7 @@ def __init__(self, target, **kwargs):
# pylint: disable=raise-missing-from
raise SlitherError(f"Invalid compilation: \n{str(e)}")
for path, ast in crytic_compile.asts.items():
self._parser.parse_contracts_from_loaded_json(ast, path)
self._parser.parse_top_level_from_loaded_json(ast, path)
self.add_source_code(path)

if kwargs.get("generate_patches", False):
Expand Down Expand Up @@ -120,7 +120,7 @@ def _init_from_raw_json(self, filename):
self._parser = SlitherSolc(filename, self)

for c in contracts_json:
self._parser.parse_contracts_from_json(c)
self._parser.parse_top_level_from_json(c)

def _init_from_list(self, contract):
self._parser = SlitherSolc("", self)
Expand All @@ -129,7 +129,7 @@ def _init_from_list(self, contract):
path = c["absolutePath"]
else:
path = c["attributes"]["absolutePath"]
self._parser.parse_contracts_from_loaded_json(c, path)
self._parser.parse_top_level_from_loaded_json(c, path)

@property
def detectors(self):
Expand Down
32 changes: 8 additions & 24 deletions slither/solc_parsing/declarations/contract.py
Original file line number Diff line number Diff line change
@@ -1,15 +1,14 @@
import logging
from typing import List, Dict, Callable, TYPE_CHECKING, Union

from slither.core.declarations import Modifier, Structure, Event
from slither.core.declarations import Modifier, Event, EnumContract, StructureContract
from slither.core.declarations.contract import Contract
from slither.core.declarations.enum import Enum
from slither.core.declarations.function import Function
from slither.core.variables.state_variable import StateVariable
from slither.solc_parsing.declarations.event import EventSolc
from slither.solc_parsing.declarations.function import FunctionSolc
from slither.solc_parsing.declarations.modifier import ModifierSolc
from slither.solc_parsing.declarations.structure import StructureSolc
from slither.solc_parsing.declarations.structure_contract import StructureContractSolc
from slither.solc_parsing.exceptions import ParsingError, VariableNotFound
from slither.solc_parsing.solidity_types.type_parsing import parse_type
from slither.solc_parsing.variables.state_variable import StateVariableSolc
Expand Down Expand Up @@ -44,7 +43,7 @@ def __init__(self, slither_parser: "SlitherSolc", contract: Contract, data):

self._functions_parser: List[FunctionSolc] = []
self._modifiers_parser: List[ModifierSolc] = []
self._structures_parser: List[StructureSolc] = []
self._structures_parser: List[StructureContractSolc] = []

self._is_analyzed: bool = False

Expand Down Expand Up @@ -252,28 +251,13 @@ def _parse_contract_items(self):
return

def _parse_struct(self, struct: Dict):
if self.is_compact_ast:
name = struct["name"]
attributes = struct
else:
name = struct["attributes"][self.get_key()]
attributes = struct["attributes"]
if "canonicalName" in attributes:
canonicalName = attributes["canonicalName"]
else:
canonicalName = self._contract.name + "." + name

if self.get_children("members") in struct:
children = struct[self.get_children("members")]
else:
children = [] # empty struct

st = Structure()
st = StructureContract()
st.set_contract(self._contract)
st.set_offset(struct["src"], self._contract.slither)

st_parser = StructureSolc(st, name, canonicalName, children, self)
self._contract.structures_as_dict[name] = st
st_parser = StructureContractSolc(st, struct, self)
self._contract.structures_as_dict[st.name] = st
self._structures_parser.append(st_parser)

def parse_structs(self):
Expand Down Expand Up @@ -573,12 +557,12 @@ def _analyze_enum(self, enum):
else:
values.append(child["attributes"][self.get_key()])

new_enum = Enum(name, canonicalName, values)
new_enum = EnumContract(name, canonicalName, values)
new_enum.set_contract(self._contract)
new_enum.set_offset(enum["src"], self._contract.slither)
self._contract.enums_as_dict[canonicalName] = new_enum

def _analyze_struct(self, struct: StructureSolc): # pylint: disable=no-self-use
def _analyze_struct(self, struct: StructureContractSolc): # pylint: disable=no-self-use
struct.analyze()

def analyze_structs(self):
Expand Down
Loading

0 comments on commit 0a7738d

Please sign in to comment.