Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Improve top level objects support #728

Merged
merged 8 commits into from
Dec 17, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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
29 changes: 15 additions & 14 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 Expand Up @@ -1090,11 +1089,13 @@ def is_incorrectly_constructed(self, incorrect: bool):
self._is_incorrectly_parsed = incorrect

def add_constructor_variables(self):
from slither.core.declarations.function_contract import FunctionContract

if self.state_variables:
for (idx, variable_candidate) in enumerate(self.state_variables):
if variable_candidate.expression and not variable_candidate.is_constant:

constructor_variable = Function()
constructor_variable = FunctionContract(self.slither)
constructor_variable.set_function_type(FunctionType.CONSTRUCTOR_VARIABLES)
constructor_variable.set_contract(self)
constructor_variable.set_contract_declarer(self)
Expand All @@ -1120,7 +1121,7 @@ def add_constructor_variables(self):
for (idx, variable_candidate) in enumerate(self.state_variables):
if variable_candidate.expression and variable_candidate.is_constant:

constructor_variable = Function()
constructor_variable = FunctionContract(self.slither)
constructor_variable.set_function_type(
FunctionType.CONSTRUCTOR_CONSTANT_VARIABLES
)
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
80 changes: 19 additions & 61 deletions slither/core/declarations/function.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,12 @@
Function module
"""
import logging
from abc import ABCMeta, abstractmethod
from collections import namedtuple
from enum import Enum
from itertools import groupby
from typing import Dict, TYPE_CHECKING, List, Optional, Set, Union, Callable, Tuple

from slither.core.children.child_contract import ChildContract
from slither.core.children.child_inheritance import ChildInheritance
from slither.core.declarations.solidity_variables import (
SolidityFunction,
SolidityVariable,
Expand All @@ -24,7 +23,6 @@
from slither.core.solidity_types.type import Type
from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.local_variable import LocalVariable

from slither.core.variables.state_variable import StateVariable
from slither.utils.utils import unroll

Expand All @@ -46,6 +44,7 @@
from slither.slithir.operations import Operation
from slither.slither import Slither
from slither.core.cfg.node import NodeType
from slither.core.slither_core import SlitherCore

LOGGER = logging.getLogger("Function")
ReacheableNode = namedtuple("ReacheableNode", ["node", "ir"])
Expand Down Expand Up @@ -103,14 +102,12 @@ def _filter_state_variables_written(expressions: List["Expression"]):
return ret


class Function(
ChildContract, ChildInheritance, SourceMapping
): # pylint: disable=too-many-public-methods
class Function(metaclass=ABCMeta): # pylint: disable=too-many-public-methods
"""
Function class
"""

def __init__(self):
def __init__(self, slither: "SlitherCore"):
super().__init__()
self._scope: List[str] = []
self._name: Optional[str] = None
Expand Down Expand Up @@ -206,6 +203,8 @@ def __init__(self):
self._canonical_name: Optional[str] = None
self._is_protected: Optional[bool] = None

self._slither: "SlitherCore" = slither

###################################################################################
###################################################################################
# region General properties
Expand Down Expand Up @@ -260,20 +259,13 @@ def full_name(self) -> str:
return self._full_name

@property
@abstractmethod
def canonical_name(self) -> str:
"""
str: contract.func_name(type1,type2)
Return the function signature without the return values
"""
if self._canonical_name is None:
name, parameters, _ = self.signature
self._canonical_name = (
".".join([self.contract_declarer.name] + self._scope + [name])
+ "("
+ ",".join(parameters)
+ ")"
)
return self._canonical_name
return ""

@property
def contains_assembly(self) -> bool:
Expand Down Expand Up @@ -320,16 +312,12 @@ def can_send_eth(self) -> bool:
return self._can_reenter

@property
def slither(self) -> "Slither":
return self.contract.slither
def slither(self) -> "SlitherCore":
return self._slither

def is_declared_by(self, contract: "Contract") -> bool:
"""
Check if the element is declared by the contract
:param contract:
:return:
"""
return self.contract_declarer == contract
@slither.setter
def slither(self, sl: "SlitherCore"):
self._slither = sl

# endregion
###################################################################################
Expand Down Expand Up @@ -978,16 +966,9 @@ def signature_str(self) -> str:
###################################################################################

@property
@abstractmethod
def functions_shadowed(self) -> List["Function"]:
"""
Return the list of functions shadowed
Returns:
list(core.Function)

"""
candidates = [c.functions_declared for c in self.contract.inheritance]
candidates = [candidate for sublist in candidates for candidate in sublist]
return [f for f in candidates if f.full_name == self.full_name]
pass

# endregion
###################################################################################
Expand Down Expand Up @@ -1400,25 +1381,11 @@ def is_writing(self, variable: "Variable") -> bool:
"""
return variable in self.variables_written

@abstractmethod
def get_summary(
self,
) -> Tuple[str, str, str, List[str], List[str], List[str], List[str], List[str]]:
"""
Return the function summary
Returns:
(str, str, str, list(str), list(str), listr(str), list(str), list(str);
contract_name, name, visibility, modifiers, vars read, vars written, internal_calls, external_calls_as_expressions
"""
return (
self.contract_declarer.name,
self.full_name,
self.visibility,
[str(x) for x in self.modifiers],
[str(x) for x in self.state_variables_read + self.solidity_variables_read],
[str(x) for x in self.state_variables_written],
[str(x) for x in self.internal_calls],
[str(x) for x in self.external_calls_as_expressions],
)
pass

def is_protected(self) -> bool:
"""
Expand Down Expand Up @@ -1684,18 +1651,9 @@ def generate_slithir_and_analyze(self):
self._analyze_read_write()
self._analyze_calls()

@abstractmethod
def generate_slithir_ssa(self, all_ssa_state_variables_instances):
from slither.slithir.utils.ssa import add_ssa_ir, transform_slithir_vars_to_ssa
from slither.core.dominators.utils import (
compute_dominance_frontier,
compute_dominators,
)

compute_dominators(self.nodes)
compute_dominance_frontier(self.nodes)
transform_slithir_vars_to_ssa(self)
if not self.contract.is_incorrectly_constructed:
add_ssa_ir(self, all_ssa_state_variables_instances)
pass

def update_read_write_using_ssa(self):
for node in self.nodes:
Expand Down
Loading