Merge branch 'fix-continue-bug' of https://github.com/cast-tech/slither into fix-continue-bug

pull/2047/head
Tigran Avagyan 1 year ago
commit 7e6a8aadde
  1. 2
      .github/workflows/docs.yml
  2. 7
      .github/workflows/linter.yml
  3. 32
      .github/workflows/matchers/pylint.json
  4. 22
      .github/workflows/matchers/yamllint.json
  5. 5
      .github/workflows/publish.yml
  6. 6
      .github/workflows/pylint.yml
  7. 4
      CONTRIBUTING.md
  8. 2
      slither/core/declarations/__init__.py
  9. 2
      slither/core/declarations/contract.py
  10. 4
      slither/core/declarations/custom_error_contract.py
  11. 4
      slither/core/declarations/custom_error_top_level.py
  12. 2
      slither/core/expressions/unary_operation.py
  13. 29
      slither/utils/output.py
  14. 55
      tests/unit/slithir/test_ternary_expressions.py

@ -37,7 +37,7 @@ jobs:
- run: pip install -e ".[doc]" - run: pip install -e ".[doc]"
- run: pdoc -o html/ slither '!slither.tools' #TODO fix import errors on pdoc run - run: pdoc -o html/ slither '!slither.tools' #TODO fix import errors on pdoc run
- name: Upload artifact - name: Upload artifact
uses: actions/upload-pages-artifact@v1 uses: actions/upload-pages-artifact@v2
with: with:
# Upload the doc # Upload the doc
path: './html/' path: './html/'

@ -9,8 +9,6 @@ defaults:
on: on:
pull_request: pull_request:
branches: [master, dev] branches: [master, dev]
paths:
- "**/*.py"
schedule: schedule:
# run CI every day even if no PRs/merges occur # run CI every day even if no PRs/merges occur
@ -42,6 +40,10 @@ jobs:
mkdir -p .github/linters mkdir -p .github/linters
cp pyproject.toml .github/linters cp pyproject.toml .github/linters
- name: Register yamllint problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/yamllint.json"
- name: Lint everything else - name: Lint everything else
uses: super-linter/super-linter/slim@v4.9.2 uses: super-linter/super-linter/slim@v4.9.2
if: always() if: always()
@ -55,7 +57,6 @@ jobs:
VALIDATE_PYTHON_PYLINT: false VALIDATE_PYTHON_PYLINT: false
VALIDATE_PYTHON_BLACK: false VALIDATE_PYTHON_BLACK: false
VALIDATE_PYTHON_ISORT: false VALIDATE_PYTHON_ISORT: false
# Always false
VALIDATE_JSON: false VALIDATE_JSON: false
VALIDATE_JAVASCRIPT_STANDARD: false VALIDATE_JAVASCRIPT_STANDARD: false
VALIDATE_PYTHON_FLAKE8: false VALIDATE_PYTHON_FLAKE8: false

@ -0,0 +1,32 @@
{
"problemMatcher": [
{
"owner": "pylint-error",
"severity": "error",
"pattern": [
{
"regexp": "^(.+):(\\d+):(\\d+):\\s(([EF]\\d{4}):\\s.+)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4,
"code": 5
}
]
},
{
"owner": "pylint-warning",
"severity": "warning",
"pattern": [
{
"regexp": "^(.+):(\\d+):(\\d+):\\s(([CRW]\\d{4}):\\s.+)$",
"file": 1,
"line": 2,
"column": 3,
"message": 4,
"code": 5
}
]
}
]
}

@ -0,0 +1,22 @@
{
"problemMatcher": [
{
"owner": "yamllint",
"pattern": [
{
"regexp": "^(.*\\.ya?ml)$",
"file": 1
},
{
"regexp": "^\\s{2}(\\d+):(\\d+)\\s+(error|warning)\\s+(.*?)\\s+\\((.*)\\)$",
"line": 1,
"column": 2,
"severity": 3,
"message": 4,
"code": 5,
"loop": true
}
]
}
]
}

@ -44,11 +44,10 @@ jobs:
path: dist/ path: dist/
- name: publish - name: publish
uses: pypa/gh-action-pypi-publish@v1.8.7 uses: pypa/gh-action-pypi-publish@v1.8.10
- name: sign - name: sign
uses: sigstore/gh-action-sigstore-python@v1.2.3 uses: sigstore/gh-action-sigstore-python@v2.0.1
with: with:
inputs: ./dist/*.tar.gz ./dist/*.whl inputs: ./dist/*.tar.gz ./dist/*.whl
release-signing-artifacts: true release-signing-artifacts: true
bundle-only: true

@ -9,6 +9,8 @@ defaults:
on: on:
pull_request: pull_request:
branches: [master, dev] branches: [master, dev]
paths:
- "**/*.py"
concurrency: concurrency:
group: ${{ github.workflow }}-${{ github.ref }} group: ${{ github.workflow }}-${{ github.ref }}
@ -36,6 +38,10 @@ jobs:
mkdir -p .github/linters mkdir -p .github/linters
cp pyproject.toml .github/linters cp pyproject.toml .github/linters
- name: Register pylint problem matcher
run: |
echo "::add-matcher::.github/workflows/matchers/pylint.json"
- name: Pylint - name: Pylint
uses: super-linter/super-linter/slim@v4.9.2 uses: super-linter/super-linter/slim@v4.9.2
if: always() if: always()

@ -96,8 +96,8 @@ For each new detector, at least one regression tests must be present.
#### Adding parsing tests #### Adding parsing tests
1. Create a test in `tests/e2e/solc_parsing/` 1. Create a test in `tests/e2e/solc_parsing/`
2. Run `python tests/e2e/solc_parsing/test_ast_parsing.py --compile`. This will compile the artifact in `tests/e2e/solc_parsing/compile`. Add the compiled artifact to git. 2. Update `ALL_TESTS` in `tests/e2e/solc_parsing/test_ast_parsing.py`.
3. Update `ALL_TESTS` in `tests/e2e/solc_parsing/test_ast_parsing.py`. 3. Run `python tests/e2e/solc_parsing/test_ast_parsing.py --compile`. This will compile the artifact in `tests/e2e/solc_parsing/compile`. Add the compiled artifact to git.
4. Run `python tests/e2e/solc_parsing/test_ast_parsing.py --generate`. This will generate the json artifacts in `tests/e2e/solc_parsing/expected_json`. Add the generated files to git. 4. Run `python tests/e2e/solc_parsing/test_ast_parsing.py --generate`. This will generate the json artifacts in `tests/e2e/solc_parsing/expected_json`. Add the generated files to git.
5. Run `pytest tests/e2e/solc_parsing/test_ast_parsing.py` and check that everything worked. 5. Run `pytest tests/e2e/solc_parsing/test_ast_parsing.py` and check that everything worked.

@ -18,3 +18,5 @@ from .structure_top_level import StructureTopLevel
from .function_contract import FunctionContract from .function_contract import FunctionContract
from .function_top_level import FunctionTopLevel from .function_top_level import FunctionTopLevel
from .custom_error_contract import CustomErrorContract from .custom_error_contract import CustomErrorContract
from .custom_error_top_level import CustomErrorTopLevel
from .custom_error import CustomError

@ -861,7 +861,7 @@ class Contract(SourceMapping): # pylint: disable=too-many-public-methods
Returns: Returns:
StateVariable StateVariable
""" """
return next((v for v in self.state_variables if v.name == canonical_name), None) return next((v for v in self.state_variables if v.canonical_name == canonical_name), None)
def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]: def get_structure_from_name(self, structure_name: str) -> Optional["StructureContract"]:
""" """

@ -16,3 +16,7 @@ class CustomErrorContract(CustomError, ContractLevel):
:return: :return:
""" """
return self.contract == contract return self.contract == contract
@property
def canonical_name(self) -> str:
return self.contract.name + "." + self.full_name

@ -12,3 +12,7 @@ class CustomErrorTopLevel(CustomError, TopLevel):
def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None: def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None:
super().__init__(compilation_unit) super().__init__(compilation_unit)
self.file_scope: "FileScope" = scope self.file_scope: "FileScope" = scope
@property
def canonical_name(self) -> str:
return self.full_name

@ -106,8 +106,6 @@ class UnaryOperation(Expression):
UnaryOperationType.MINUSMINUS_PRE, UnaryOperationType.MINUSMINUS_PRE,
UnaryOperationType.PLUSPLUS_POST, UnaryOperationType.PLUSPLUS_POST,
UnaryOperationType.MINUSMINUS_POST, UnaryOperationType.MINUSMINUS_POST,
UnaryOperationType.PLUS_PRE,
UnaryOperationType.MINUS_PRE,
]: ]:
expression.set_lvalue() expression.set_lvalue()

@ -18,6 +18,7 @@ from slither.core.declarations import (
Structure, Structure,
Pragma, Pragma,
FunctionContract, FunctionContract,
CustomError,
) )
from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.source_mapping.source_mapping import SourceMapping
from slither.core.variables.local_variable import LocalVariable from slither.core.variables.local_variable import LocalVariable
@ -438,6 +439,8 @@ class Output:
self.add_event(add, additional_fields=additional_fields) self.add_event(add, additional_fields=additional_fields)
elif isinstance(add, Structure): elif isinstance(add, Structure):
self.add_struct(add, additional_fields=additional_fields) self.add_struct(add, additional_fields=additional_fields)
elif isinstance(add, CustomError):
self.add_custom_error(add, additional_fields=additional_fields)
elif isinstance(add, Pragma): elif isinstance(add, Pragma):
self.add_pragma(add, additional_fields=additional_fields) self.add_pragma(add, additional_fields=additional_fields)
elif isinstance(add, Node): elif isinstance(add, Node):
@ -585,6 +588,32 @@ class Output:
self._data["elements"].append(element) self._data["elements"].append(element)
# endregion
###################################################################################
###################################################################################
# region CustomError
###################################################################################
###################################################################################
def add_custom_error(
self, custom_error: CustomError, additional_fields: Optional[Dict] = None
) -> None:
if additional_fields is None:
additional_fields = {}
type_specific_fields = {
"parent": _create_parent_element(custom_error),
"signature": custom_error.full_name,
}
element = _create_base_element(
"custom_error",
custom_error.name,
custom_error.source_mapping.to_json(),
type_specific_fields,
additional_fields,
)
self._data["elements"].append(element)
# endregion # endregion
################################################################################### ###################################################################################
################################################################################### ###################################################################################

@ -1,8 +1,13 @@
from pathlib import Path from pathlib import Path
from slither import Slither from slither import Slither
from slither.core.cfg.node import NodeType from slither.core.cfg.node import NodeType
from slither.slithir.operations import Assignment from slither.slithir.operations import Assignment, Unpack
from slither.core.expressions import AssignmentOperation, TupleExpression from slither.core.expressions import (
AssignmentOperation,
TupleExpression,
NewElementaryType,
CallExpression,
)
TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data"
@ -12,27 +17,29 @@ def test_ternary_conversions(solc_binary_path) -> None:
solc_path = solc_binary_path("0.8.0") solc_path = solc_binary_path("0.8.0")
slither = Slither(Path(TEST_DATA_DIR, "ternary_expressions.sol").as_posix(), solc=solc_path) slither = Slither(Path(TEST_DATA_DIR, "ternary_expressions.sol").as_posix(), solc=solc_path)
for contract in slither.contracts: for contract in slither.contracts:
for function in contract.functions: if not contract.is_signature_only:
vars_declared = 0 for function in contract.functions:
vars_assigned = 0 vars_declared = 0
for node in function.nodes: vars_assigned = 0
if node.type in [NodeType.IF, NodeType.IFLOOP]: for node in function.nodes:
if node.type in [NodeType.IF, NodeType.IFLOOP]:
# Iterate over true and false son # Iterate over true and false son
for inner_node in node.sons: for inner_node in node.sons:
# Count all variables declared # Count all variables declared
expression = inner_node.expression expression = inner_node.expression
if isinstance(expression, AssignmentOperation): if isinstance(
var_expr = expression.expression_left expression, (AssignmentOperation, NewElementaryType, CallExpression)
# Only tuples declare more than one var ):
if isinstance(var_expr, TupleExpression): var_expr = expression.expression_left
vars_declared += len(var_expr.expressions) # Only tuples declare more than one var
else: if isinstance(var_expr, TupleExpression):
vars_declared += 1 vars_declared += len(var_expr.expressions)
else:
vars_declared += 1
for ir in inner_node.irs: for ir in inner_node.irs:
# Count all variables defined # Count all variables defined
if isinstance(ir, Assignment): if isinstance(ir, (Assignment, Unpack)):
vars_assigned += 1 vars_assigned += 1
assert vars_declared == vars_assigned and vars_assigned != 0
assert vars_declared == vars_assigned

Loading…
Cancel
Save