Skip to content

Commit

Permalink
add another test and fix pylint issues
Browse files Browse the repository at this point in the history
  • Loading branch information
0xalpharush committed Apr 7, 2024
1 parent 5a6ef0d commit 0165614
Show file tree
Hide file tree
Showing 7 changed files with 98 additions and 36 deletions.
44 changes: 22 additions & 22 deletions slither/slither.py
Original file line number Diff line number Diff line change
@@ -1,11 +1,10 @@
import logging
from typing import Union, List, ValuesView, Type, Dict, Optional
from typing import Union, List, Type, Dict, Optional

from crytic_compile import CryticCompile, InvalidCompilation

# pylint: disable= no-name-in-module
from slither.core.compilation_unit import SlitherCompilationUnit
from slither.core.scope.scope import FileScope
from slither.core.slither_core import SlitherCore
from slither.detectors.abstract_detector import AbstractDetector, DetectorClassification
from slither.exceptions import SlitherError
Expand Down Expand Up @@ -35,7 +34,9 @@ def _check_common_things(
raise SlitherError(f"You can't register {cls!r} twice.")


def _update_file_scopes(sol_parser: SlitherCompilationUnitSolc):
def _update_file_scopes(
sol_parser: SlitherCompilationUnitSolc,
): # pylint: disable=too-many-branches
"""
Since all definitions in a file are exported by default, including definitions from its (transitive) dependencies,
we can identify all top level items that could possibly be referenced within the file from its exportedSymbols.
Expand All @@ -59,38 +60,37 @@ def _update_file_scopes(sol_parser: SlitherCompilationUnitSolc):
elif refId in sol_parser.functions_by_id:
functions = sol_parser.functions_by_id[refId]
assert len(functions) == 1
function = functions[0]
scope.functions.add(function)
elif refId in sol_parser._imports_by_id:
import_directive = sol_parser._imports_by_id[refId]
scope.functions.add(functions[0])
elif refId in sol_parser.imports_by_id:
import_directive = sol_parser.imports_by_id[refId]
scope.imports.add(import_directive)
elif refId in sol_parser._top_level_variables_by_id:
top_level_variable = sol_parser._top_level_variables_by_id[refId]
elif refId in sol_parser.top_level_variables_by_id:
top_level_variable = sol_parser.top_level_variables_by_id[refId]
scope.variables[top_level_variable.name] = top_level_variable
elif refId in sol_parser._top_level_events_by_id:
top_level_event = sol_parser._top_level_events_by_id[refId]
elif refId in sol_parser.top_level_events_by_id:
top_level_event = sol_parser.top_level_events_by_id[refId]
scope.events.add(top_level_event)
elif refId in sol_parser._top_level_structures_by_id:
top_level_struct = sol_parser._top_level_structures_by_id[refId]
elif refId in sol_parser.top_level_structures_by_id:
top_level_struct = sol_parser.top_level_structures_by_id[refId]
scope.structures[top_level_struct.name] = top_level_struct
elif refId in sol_parser._top_level_type_aliases_by_id:
top_level_type_alias = sol_parser._top_level_type_aliases_by_id[refId]
elif refId in sol_parser.top_level_type_aliases_by_id:
top_level_type_alias = sol_parser.top_level_type_aliases_by_id[refId]
scope.type_aliases[top_level_type_alias.name] = top_level_type_alias
elif refId in sol_parser._top_level_enums_by_id:
top_level_enum = sol_parser._top_level_enums_by_id[refId]
elif refId in sol_parser.top_level_enums_by_id:
top_level_enum = sol_parser.top_level_enums_by_id[refId]
scope.enums[top_level_enum.name] = top_level_enum
elif refId in sol_parser._top_level_errors_by_id:
top_level_custom_error = sol_parser._top_level_errors_by_id[refId]
elif refId in sol_parser.top_level_errors_by_id:
top_level_custom_error = sol_parser.top_level_errors_by_id[refId]
scope.custom_errors.add(top_level_custom_error)
else:
logger.warning(
f"Failed to resolved name for reference id {refId} in {scope.filename}."
logger.error(
f"Failed to resolved name for reference id {refId} in {scope.filename.absolute}."
)


class Slither(
SlitherCore
): # pylint: disable=too-many-instance-attributes,too-many-locals,too-many-statements
): # pylint: disable=too-many-instance-attributes,too-many-locals,too-many-statements,too-many-branches
def __init__(self, target: Union[str, CryticCompile], **kwargs) -> None:
"""
Args:
Expand Down
28 changes: 14 additions & 14 deletions slither/solc_parsing/slither_compilation_unit_solc.py
Original file line number Diff line number Diff line change
Expand Up @@ -83,13 +83,13 @@ def __init__(self, compilation_unit: SlitherCompilationUnit) -> None:
self._contracts_by_id: Dict[int, Contract] = {}
# For top level functions, there should only be one `Function` since they can't be virtual and therefore can't be overridden.
self._functions_by_id: Dict[int, List[Function]] = defaultdict(list)
self._imports_by_id: Dict[int, Import] = {}
self._top_level_events_by_id: Dict[int, EventTopLevel] = {}
self._top_level_errors_by_id: Dict[int, EventTopLevel] = {}
self._top_level_structures_by_id: Dict[int, StructureTopLevel] = {}
self._top_level_variables_by_id: Dict[int, TopLevelVariable] = {}
self._top_level_type_aliases_by_id: Dict[int, TypeAliasTopLevel] = {}
self._top_level_enums_by_id: Dict[int, EnumTopLevel] = {}
self.imports_by_id: Dict[int, Import] = {}
self.top_level_events_by_id: Dict[int, EventTopLevel] = {}
self.top_level_errors_by_id: Dict[int, EventTopLevel] = {}
self.top_level_structures_by_id: Dict[int, StructureTopLevel] = {}
self.top_level_variables_by_id: Dict[int, TopLevelVariable] = {}
self.top_level_type_aliases_by_id: Dict[int, TypeAliasTopLevel] = {}
self.top_level_enums_by_id: Dict[int, EnumTopLevel] = {}

self._parsed = False
self._analyzed = False
Expand Down Expand Up @@ -217,7 +217,7 @@ def _parse_enum(self, top_level_data: Dict, filename: str) -> None:
self._compilation_unit.enums_top_level.append(enum)
scope.enums[name] = enum
refId = top_level_data["id"]
self._top_level_enums_by_id[refId] = enum
self.top_level_enums_by_id[refId] = enum

# pylint: disable=too-many-branches,too-many-statements,too-many-locals
def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None:
Expand Down Expand Up @@ -321,7 +321,7 @@ def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None:
import_directive.alias = top_level_data["attributes"]["unitAlias"]
import_directive.set_offset(top_level_data["src"], self._compilation_unit)
self._compilation_unit.import_directives.append(import_directive)
self._imports_by_id[referenceId] = import_directive
self.imports_by_id[referenceId] = import_directive

get_imported_scope = self.compilation_unit.get_scope(import_directive.filename)
scope.accessible_scopes.append(get_imported_scope)
Expand All @@ -335,7 +335,7 @@ def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None:
self._compilation_unit.structures_top_level.append(st)
self._structures_top_level_parser.append(st_parser)
referenceId = top_level_data["id"]
self._top_level_structures_by_id[referenceId] = st
self.top_level_structures_by_id[referenceId] = st

elif top_level_data[self.get_key()] == "EnumDefinition":
# Note enum don't need a complex parser, so everything is directly done
Expand All @@ -350,7 +350,7 @@ def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None:
self._variables_top_level_parser.append(var_parser)
scope.variables[var.name] = var
referenceId = top_level_data["id"]
self._top_level_variables_by_id[referenceId] = var
self.top_level_variables_by_id[referenceId] = var

elif top_level_data[self.get_key()] == "FunctionDefinition":
func = FunctionTopLevel(self._compilation_unit, scope)
Expand All @@ -371,7 +371,7 @@ def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None:
self._compilation_unit.custom_errors.append(custom_error)
self._custom_error_parser.append(custom_error_parser)
referenceId = top_level_data["id"]
self._top_level_errors_by_id[referenceId] = custom_error
self.top_level_errors_by_id[referenceId] = custom_error

elif top_level_data[self.get_key()] == "UserDefinedValueTypeDefinition":
assert "name" in top_level_data
Expand All @@ -391,7 +391,7 @@ def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None:
self._compilation_unit.type_aliases[alias] = type_alias
scope.type_aliases[alias] = type_alias
referenceId = top_level_data["id"]
self._top_level_type_aliases_by_id[referenceId] = type_alias
self.top_level_type_aliases_by_id[referenceId] = type_alias

elif top_level_data[self.get_key()] == "EventDefinition":
event = EventTopLevel(scope)
Expand All @@ -402,7 +402,7 @@ def parse_top_level_items(self, data_loaded: Dict, filename: str) -> None:
scope.events.add(event)
self._compilation_unit.events_top_level.append(event)
referenceId = top_level_data["id"]
self._top_level_events_by_id[referenceId] = event
self.top_level_events_by_id[referenceId] = event

else:
raise SlitherException(f"Top level {top_level_data[self.get_key()]} not supported")
Expand Down
1 change: 1 addition & 0 deletions tests/e2e/solc_parsing/test_ast_parsing.py
Original file line number Diff line number Diff line change
Expand Up @@ -474,6 +474,7 @@ def make_version(minor: int, patch_min: int, patch_max: int) -> List[str]:
Test("event-top-level.sol", ["0.8.22"]),
Test("solidity-0.8.24.sol", ["0.8.24"], solc_args="--evm-version cancun"),
Test("scope/inherited_function_scope.sol", ["0.8.24"]),
Test("using_for_global_user_defined_operator_1.sol", ["0.8.24"]),
]
# create the output folder if needed
try:
Expand Down
Binary file not shown.
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
{
"BalanceDeltaLibrary": {
"amount0(BalanceDelta)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: INLINE ASM 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n2->3;\n3[label=\"Node Type: END INLINE ASM 3\n\"];\n3->4;\n4[label=\"Node Type: RETURN 4\n\"];\n}\n",
"amount1(BalanceDelta)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: INLINE ASM 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n2->3;\n3[label=\"Node Type: END INLINE ASM 3\n\"];\n3->4;\n4[label=\"Node Type: RETURN 4\n\"];\n}\n"
},
"X": {
"get(BalanceDelta)": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n1->2;\n2[label=\"Node Type: NEW VARIABLE 2\n\"];\n}\n"
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,43 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.20;

type BalanceDelta is int256;

using {add as +, sub as -, eq as ==} for BalanceDelta global;
using BalanceDeltaLibrary for BalanceDelta global;

function toBalanceDelta(int128 _amount0, int128 _amount1) pure returns (BalanceDelta balanceDelta) {
/// @solidity memory-safe-assembly
assembly {
balanceDelta :=
or(shl(128, _amount0), and(0x00000000000000000000000000000000ffffffffffffffffffffffffffffffff, _amount1))
}
}

function add(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) {
return toBalanceDelta(a.amount0() + b.amount0(), a.amount1() + b.amount1());
}

function sub(BalanceDelta a, BalanceDelta b) pure returns (BalanceDelta) {
return toBalanceDelta(a.amount0() - b.amount0(), a.amount1() - b.amount1());
}

function eq(BalanceDelta a, BalanceDelta b) pure returns (bool) {
return a.amount0() == b.amount0() && a.amount1() == b.amount1();
}

library BalanceDeltaLibrary {
function amount0(BalanceDelta balanceDelta) internal pure returns (int128 _amount0) {
/// @solidity memory-safe-assembly
assembly {
_amount0 := shr(128, balanceDelta)
}
}

function amount1(BalanceDelta balanceDelta) internal pure returns (int128 _amount1) {
/// @solidity memory-safe-assembly
assembly {
_amount1 := balanceDelta
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@

import {BalanceDelta} from "./using_for_global_user_defined_operator.sol";
contract X {

function get(BalanceDelta delta) external {
int128 amount0 = delta.amount0();
int128 amount1 = delta.amount1();
}
}

0 comments on commit 0165614

Please sign in to comment.