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

make slither-flat work for top level errors, structs, enums #1852

Merged
merged 5 commits into from
May 12, 2023
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
10 changes: 8 additions & 2 deletions examples/flat/a.sol
Original file line number Diff line number Diff line change
@@ -1,3 +1,9 @@
contract A{
pragma solidity 0.8.19;

}
error RevertIt();

contract Example {
function reverts() external pure {
revert RevertIt();
}
}
13 changes: 12 additions & 1 deletion examples/flat/b.sol
Original file line number Diff line number Diff line change
@@ -1,5 +1,16 @@
import "./a.sol";

contract B is A{
pragma solidity 0.8.19;

enum B {
a,
b
}

contract T {
Example e = new Example();
function b() public returns(uint) {
B b = B.a;
return 4;
}
}
10 changes: 9 additions & 1 deletion scripts/ci_test_flat.sh
Original file line number Diff line number Diff line change
@@ -1,12 +1,20 @@
#!/usr/bin/env bash
shopt -s extglob

### Test slither-prop
### Test slither-flat
solc-select use 0.8.19 --always-install

cd examples/flat || exit 1

if ! slither-flat b.sol; then
echo "slither-flat failed"
exit 1
fi

SUFFIX="@(sol)"
if ! solc "crytic-export/flattening/"*$SUFFIX; then
echo "solc failed on flattened files"
exit 1
fi

exit 0
6 changes: 3 additions & 3 deletions slither/core/compilation_unit.py
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@
Function,
Modifier,
)
from slither.core.declarations.custom_error import CustomError
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
Expand Down Expand Up @@ -46,7 +46,7 @@ def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit
self._using_for_top_level: List[UsingForTopLevel] = []
self._pragma_directives: List[Pragma] = []
self._import_directives: List[Import] = []
self._custom_errors: List[CustomError] = []
self._custom_errors: List[CustomErrorTopLevel] = []
self._user_defined_value_types: Dict[str, TypeAliasTopLevel] = {}

self._all_functions: Set[Function] = set()
Expand Down Expand Up @@ -216,7 +216,7 @@ def using_for_top_level(self) -> List[UsingForTopLevel]:
return self._using_for_top_level

@property
def custom_errors(self) -> List[CustomError]:
def custom_errors(self) -> List[CustomErrorTopLevel]:
return self._custom_errors

@property
Expand Down
4 changes: 4 additions & 0 deletions slither/core/declarations/solidity_variables.py
Original file line number Diff line number Diff line change
Expand Up @@ -201,6 +201,10 @@ def __init__(self, custom_error: CustomError) -> None: # pylint: disable=super-
self._custom_error = custom_error
self._return_type: List[Union[TypeInformation, ElementaryType]] = []

@property
def custom_error(self) -> CustomError:
return self._custom_error

def __eq__(self, other: Any) -> bool:
return (
self.__class__ == other.__class__
Expand Down
2 changes: 1 addition & 1 deletion slither/tools/flattening/export/export.py
Original file line number Diff line number Diff line change
Expand Up @@ -15,7 +15,7 @@

Export = namedtuple("Export", ["filename", "content"])

logger = logging.getLogger("Slither")
logger = logging.getLogger("Slither-flat")


def save_to_zip(files: List[Export], zip_filename: str, zip_type: str = "lzma"):
Expand Down
45 changes: 26 additions & 19 deletions slither/tools/flattening/flattening.py
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
from slither.core.declarations.contract import Contract
from slither.core.declarations.function_top_level import FunctionTopLevel
from slither.core.declarations.top_level import TopLevel
from slither.core.declarations.solidity_variables import SolidityCustomRevert
from slither.core.solidity_types import MappingType, ArrayType
from slither.core.solidity_types.type import Type
from slither.core.solidity_types.user_defined_type import UserDefinedType
Expand All @@ -23,7 +24,8 @@
save_to_disk,
)

logger = logging.getLogger("Slither-flattening")
logger = logging.getLogger("Slither-flat")
logger.setLevel(logging.INFO)

# index: where to start
# patch_type:
Expand Down Expand Up @@ -75,6 +77,7 @@ def __init__(

self._get_source_code_top_level(compilation_unit.structures_top_level)
self._get_source_code_top_level(compilation_unit.enums_top_level)
self._get_source_code_top_level(compilation_unit.custom_errors)
self._get_source_code_top_level(compilation_unit.variables_top_level)
self._get_source_code_top_level(compilation_unit.functions_top_level)

Expand Down Expand Up @@ -249,12 +252,14 @@ def _export_from_type(
t: Type,
contract: Contract,
exported: Set[str],
list_contract: List[Contract],
list_top_level: List[TopLevel],
list_contract: Set[Contract],
list_top_level: Set[TopLevel],
):
if isinstance(t, UserDefinedType):
t_type = t.type
if isinstance(t_type, (EnumContract, StructureContract)):
if isinstance(t_type, TopLevel):
list_top_level.add(t_type)
elif isinstance(t_type, (EnumContract, StructureContract)):
if t_type.contract != contract and t_type.contract not in exported:
self._export_list_used_contracts(
t_type.contract, exported, list_contract, list_top_level
Expand All @@ -275,8 +280,8 @@ def _export_list_used_contracts( # pylint: disable=too-many-branches
self,
contract: Contract,
exported: Set[str],
list_contract: List[Contract],
list_top_level: List[TopLevel],
list_contract: Set[Contract],
list_top_level: Set[TopLevel],
):
# TODO: investigate why this happen
if not isinstance(contract, Contract):
Expand Down Expand Up @@ -332,19 +337,21 @@ def _export_list_used_contracts( # pylint: disable=too-many-branches

for read in ir.read:
if isinstance(read, TopLevel):
if read not in list_top_level:
list_top_level.append(read)
if isinstance(ir, InternalCall):
function_called = ir.function
if isinstance(function_called, FunctionTopLevel):
list_top_level.append(function_called)

if contract not in list_contract:
list_contract.append(contract)
list_top_level.add(read)
if isinstance(ir, InternalCall) and isinstance(ir.function, FunctionTopLevel):
list_top_level.add(ir.function)
if (
isinstance(ir, SolidityCall)
and isinstance(ir.function, SolidityCustomRevert)
and isinstance(ir.function.custom_error, TopLevel)
):
list_top_level.add(ir.function.custom_error)

list_contract.add(contract)

def _export_contract_with_inheritance(self, contract) -> Export:
list_contracts: List[Contract] = [] # will contain contract itself
list_top_level: List[TopLevel] = []
list_contracts: Set[Contract] = set() # will contain contract itself
list_top_level: Set[TopLevel] = set()
self._export_list_used_contracts(contract, set(), list_contracts, list_top_level)
path = Path(self._export_path, f"{contract.name}_{uuid.uuid4()}.sol")

Expand Down Expand Up @@ -401,8 +408,8 @@ def _export_all(self) -> List[Export]:
def _export_with_import(self) -> List[Export]:
exports: List[Export] = []
for contract in self._compilation_unit.contracts:
list_contracts: List[Contract] = [] # will contain contract itself
list_top_level: List[TopLevel] = []
list_contracts: Set[Contract] = set() # will contain contract itself
list_top_level: Set[TopLevel] = set()
self._export_list_used_contracts(contract, set(), list_contracts, list_top_level)

if list_top_level:
Expand Down