add another test and fix pylint issues

pull/2403/head
alpharush 8 months ago
parent 5a6ef0d5a6
commit 0165614270
  1. 44
      slither/slither.py
  2. 28
      slither/solc_parsing/slither_compilation_unit_solc.py
  3. 1
      tests/e2e/solc_parsing/test_ast_parsing.py
  4. BIN
      tests/e2e/solc_parsing/test_data/compile/using_for_global_user_defined_operator_1.sol-0.8.24-compact.zip
  5. 9
      tests/e2e/solc_parsing/test_data/expected/using_for_global_user_defined_operator_1.sol-0.8.24-compact.json
  6. 43
      tests/e2e/solc_parsing/test_data/using_for_global_user_defined_operator.sol
  7. 9
      tests/e2e/solc_parsing/test_data/using_for_global_user_defined_operator_1.sol

@ -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
@ -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.
@ -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:

@ -83,13 +83,13 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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
@ -217,7 +217,7 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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:
@ -321,7 +321,7 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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)
@ -335,7 +335,7 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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
@ -350,7 +350,7 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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)
@ -371,7 +371,7 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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
@ -391,7 +391,7 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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)
@ -402,7 +402,7 @@ class SlitherCompilationUnitSolc(CallerContextExpression):
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")

@ -474,6 +474,7 @@ ALL_TESTS = [
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:

@ -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"
}
}

@ -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
}
}
}

@ -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();
}
}
Loading…
Cancel
Save