mirror of https://github.com/crytic/slither
Merge pull request #990 from crytic/dev-scope-file
Refactor core objects to add a file scope.pull/994/head
commit
1c127979d9
@ -0,0 +1,47 @@ |
|||||||
|
--- |
||||||
|
name: Features tests |
||||||
|
|
||||||
|
defaults: |
||||||
|
run: |
||||||
|
# To load bashrc |
||||||
|
shell: bash -ieo pipefail {0} |
||||||
|
|
||||||
|
on: |
||||||
|
pull_request: |
||||||
|
branches: [master, dev] |
||||||
|
schedule: |
||||||
|
# run CI every day even if no PRs/merges occur |
||||||
|
- cron: '0 12 * * *' |
||||||
|
|
||||||
|
jobs: |
||||||
|
build: |
||||||
|
name: Features tests |
||||||
|
runs-on: ubuntu-latest |
||||||
|
|
||||||
|
steps: |
||||||
|
- name: Checkout Code |
||||||
|
uses: actions/checkout@v2 |
||||||
|
|
||||||
|
- name: Set up Python 3.6 |
||||||
|
uses: actions/setup-python@v2 |
||||||
|
with: |
||||||
|
python-version: 3.6 |
||||||
|
|
||||||
|
- name: Install dependencies |
||||||
|
run: | |
||||||
|
python setup.py install |
||||||
|
pip install deepdiff |
||||||
|
pip install pytest |
||||||
|
|
||||||
|
pip install solc-select |
||||||
|
solc-select install all |
||||||
|
solc-select use 0.8.0 |
||||||
|
|
||||||
|
cd tests/test_node_modules/ |
||||||
|
npm install hardhat |
||||||
|
cd ../.. |
||||||
|
|
||||||
|
- name: Test with pytest |
||||||
|
run: | |
||||||
|
pytest tests/test_features.py |
||||||
|
|
@ -1,6 +1,14 @@ |
|||||||
|
from typing import TYPE_CHECKING |
||||||
|
|
||||||
from slither.core.declarations.custom_error import CustomError |
from slither.core.declarations.custom_error import CustomError |
||||||
from slither.core.declarations.top_level import TopLevel |
from slither.core.declarations.top_level import TopLevel |
||||||
|
|
||||||
|
if TYPE_CHECKING: |
||||||
|
from slither.core.compilation_unit import SlitherCompilationUnit |
||||||
|
from slither.core.scope.scope import FileScope |
||||||
|
|
||||||
|
|
||||||
class CustomErrorTopLevel(CustomError, TopLevel): |
class CustomErrorTopLevel(CustomError, TopLevel): |
||||||
pass |
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): |
||||||
|
super().__init__(compilation_unit) |
||||||
|
self.file_scope: "FileScope" = scope |
||||||
|
@ -1,6 +1,13 @@ |
|||||||
|
from typing import TYPE_CHECKING, List |
||||||
|
|
||||||
from slither.core.declarations import Enum |
from slither.core.declarations import Enum |
||||||
from slither.core.declarations.top_level import TopLevel |
from slither.core.declarations.top_level import TopLevel |
||||||
|
|
||||||
|
if TYPE_CHECKING: |
||||||
|
from slither.core.scope.scope import FileScope |
||||||
|
|
||||||
|
|
||||||
class EnumTopLevel(Enum, TopLevel): |
class EnumTopLevel(Enum, TopLevel): |
||||||
pass |
def __init__(self, name: str, canonical_name: str, values: List[str], scope: "FileScope"): |
||||||
|
super().__init__(name, canonical_name, values) |
||||||
|
self.file_scope: "FileScope" = scope |
||||||
|
@ -1,6 +1,14 @@ |
|||||||
|
from typing import TYPE_CHECKING |
||||||
|
|
||||||
from slither.core.declarations import Structure |
from slither.core.declarations import Structure |
||||||
from slither.core.declarations.top_level import TopLevel |
from slither.core.declarations.top_level import TopLevel |
||||||
|
|
||||||
|
if TYPE_CHECKING: |
||||||
|
from slither.core.scope.scope import FileScope |
||||||
|
from slither.core.compilation_unit import SlitherCompilationUnit |
||||||
|
|
||||||
|
|
||||||
class StructureTopLevel(Structure, TopLevel): |
class StructureTopLevel(Structure, TopLevel): |
||||||
pass |
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope"): |
||||||
|
super().__init__(compilation_unit) |
||||||
|
self.file_scope: "FileScope" = scope |
||||||
|
@ -0,0 +1,100 @@ |
|||||||
|
from typing import List, Any, Dict, Optional, Union, Set |
||||||
|
from crytic_compile.utils.naming import Filename |
||||||
|
|
||||||
|
from slither.core.declarations import Contract, Import, Pragma |
||||||
|
from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel |
||||||
|
from slither.core.declarations.enum_top_level import EnumTopLevel |
||||||
|
from slither.core.declarations.function_top_level import FunctionTopLevel |
||||||
|
from slither.core.declarations.structure_top_level import StructureTopLevel |
||||||
|
from slither.slithir.variables import Constant |
||||||
|
|
||||||
|
|
||||||
|
def _dict_contain(d1: Dict, d2: Dict) -> bool: |
||||||
|
""" |
||||||
|
Return true if d1 is included in d2 |
||||||
|
""" |
||||||
|
d2_keys = d2.keys() |
||||||
|
return all(item in d2_keys for item in d1.keys()) |
||||||
|
|
||||||
|
|
||||||
|
# pylint: disable=too-many-instance-attributes |
||||||
|
class FileScope: |
||||||
|
def __init__(self, filename: Filename): |
||||||
|
self.filename = filename |
||||||
|
self.accessible_scopes: List[FileScope] = [] |
||||||
|
|
||||||
|
self.contracts: Dict[str, Contract] = dict() |
||||||
|
# Custom error are a list instead of a dict |
||||||
|
# Because we parse the function signature later on |
||||||
|
# So we simplify the logic and have the scope fields all populated |
||||||
|
self.custom_errors: Set[CustomErrorTopLevel] = set() |
||||||
|
self.enums: Dict[str, EnumTopLevel] = dict() |
||||||
|
# Functions is a list instead of a dict |
||||||
|
# Because we parse the function signature later on |
||||||
|
# So we simplify the logic and have the scope fields all populated |
||||||
|
self.functions: Set[FunctionTopLevel] = set() |
||||||
|
self.imports: Set[Import] = set() |
||||||
|
self.pragmas: Set[Pragma] = set() |
||||||
|
self.structures: Dict[str, StructureTopLevel] = dict() |
||||||
|
|
||||||
|
def add_accesible_scopes(self) -> bool: |
||||||
|
""" |
||||||
|
Add information from accessible scopes. Return true if new information was obtained |
||||||
|
|
||||||
|
:return: |
||||||
|
:rtype: |
||||||
|
""" |
||||||
|
|
||||||
|
learn_something = False |
||||||
|
|
||||||
|
for new_scope in self.accessible_scopes: |
||||||
|
if not _dict_contain(new_scope.contracts, self.contracts): |
||||||
|
self.contracts.update(new_scope.contracts) |
||||||
|
learn_something = True |
||||||
|
if not new_scope.custom_errors.issubset(self.custom_errors): |
||||||
|
self.custom_errors |= new_scope.custom_errors |
||||||
|
learn_something = True |
||||||
|
if not _dict_contain(new_scope.enums, self.enums): |
||||||
|
self.enums.update(new_scope.enums) |
||||||
|
learn_something = True |
||||||
|
if not new_scope.functions.issubset(self.functions): |
||||||
|
self.functions |= new_scope.functions |
||||||
|
learn_something = True |
||||||
|
if not new_scope.imports.issubset(self.imports): |
||||||
|
self.imports |= new_scope.imports |
||||||
|
learn_something = True |
||||||
|
if not new_scope.pragmas.issubset(self.pragmas): |
||||||
|
self.pragmas |= new_scope.pragmas |
||||||
|
learn_something = True |
||||||
|
if not _dict_contain(new_scope.structures, self.structures): |
||||||
|
self.structures.update(new_scope.structures) |
||||||
|
learn_something = True |
||||||
|
|
||||||
|
return learn_something |
||||||
|
|
||||||
|
def get_contract_from_name(self, name: Union[str, Constant]) -> Optional[Contract]: |
||||||
|
if isinstance(name, Constant): |
||||||
|
return self.contracts.get(name.name, None) |
||||||
|
return self.contracts.get(name, None) |
||||||
|
|
||||||
|
# region Built in definitions |
||||||
|
################################################################################### |
||||||
|
################################################################################### |
||||||
|
|
||||||
|
def __eq__(self, other: Any) -> bool: |
||||||
|
if isinstance(other, str): |
||||||
|
return other == self.filename |
||||||
|
return NotImplemented |
||||||
|
|
||||||
|
def __neq__(self, other: Any) -> bool: |
||||||
|
if isinstance(other, str): |
||||||
|
return other != self.filename |
||||||
|
return NotImplemented |
||||||
|
|
||||||
|
def __str__(self) -> str: |
||||||
|
return str(self.filename.relative) |
||||||
|
|
||||||
|
def __hash__(self) -> int: |
||||||
|
return hash(self.filename.relative) |
||||||
|
|
||||||
|
# endregion |
@ -0,0 +1,35 @@ |
|||||||
|
import abc |
||||||
|
from typing import TYPE_CHECKING |
||||||
|
|
||||||
|
if TYPE_CHECKING: |
||||||
|
from slither.core.compilation_unit import SlitherCompilationUnit |
||||||
|
from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc |
||||||
|
|
||||||
|
|
||||||
|
class CallerContextExpression(metaclass=abc.ABCMeta): |
||||||
|
""" |
||||||
|
This class is inherited by all the declarations class that can be used in the expression/type parsing |
||||||
|
As a source of context/scope |
||||||
|
|
||||||
|
It is used by any declaration class that can be top-level and require complex parsing |
||||||
|
|
||||||
|
""" |
||||||
|
|
||||||
|
@property |
||||||
|
@abc.abstractmethod |
||||||
|
def is_compact_ast(self) -> bool: |
||||||
|
pass |
||||||
|
|
||||||
|
@property |
||||||
|
@abc.abstractmethod |
||||||
|
def compilation_unit(self) -> "SlitherCompilationUnit": |
||||||
|
pass |
||||||
|
|
||||||
|
@abc.abstractmethod |
||||||
|
def get_key(self) -> str: |
||||||
|
pass |
||||||
|
|
||||||
|
@property |
||||||
|
@abc.abstractmethod |
||||||
|
def slither_parser(self) -> "SlitherCompilationUnitSolc": |
||||||
|
pass |
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in new issue