diff --git a/.github/workflows/black.yml b/.github/workflows/black.yml index 33a1666b26..6017255b26 100644 --- a/.github/workflows/black.yml +++ b/.github/workflows/black.yml @@ -26,7 +26,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Full git history is needed to get a proper list of changed files within `super-linter` fetch-depth: 0 diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index b59aacd66e..f04436bd38 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -53,7 +53,7 @@ jobs: - os: windows-2022 type: truffle steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v4 with: @@ -67,7 +67,7 @@ jobs: - name: Set up nix if: matrix.type == 'dapp' - uses: cachix/install-nix-action@v22 + uses: cachix/install-nix-action@v23 - name: Set up cachix if: matrix.type == 'dapp' diff --git a/.github/workflows/docker.yml b/.github/workflows/docker.yml index 4cb1adcb1c..05406d0edc 100644 --- a/.github/workflows/docker.yml +++ b/.github/workflows/docker.yml @@ -17,7 +17,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Set up QEMU uses: docker/setup-qemu-action@v2 diff --git a/.github/workflows/docs.yml b/.github/workflows/docs.yml index f6d66aa0a0..29356c0c6b 100644 --- a/.github/workflows/docs.yml +++ b/.github/workflows/docs.yml @@ -28,7 +28,7 @@ jobs: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Setup Pages uses: actions/configure-pages@v3 - uses: actions/setup-python@v4 @@ -37,7 +37,7 @@ jobs: - run: pip install -e ".[doc]" - run: pdoc -o html/ slither '!slither.tools' #TODO fix import errors on pdoc run - name: Upload artifact - uses: actions/upload-pages-artifact@v1 + uses: actions/upload-pages-artifact@v2 with: # Upload the doc path: './html/' diff --git a/.github/workflows/doctor.yml b/.github/workflows/doctor.yml index 85d79f214f..0a0eb896de 100644 --- a/.github/workflows/doctor.yml +++ b/.github/workflows/doctor.yml @@ -29,7 +29,7 @@ jobs: - os: windows-2022 python: 3.8 steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v4 diff --git a/.github/workflows/linter.yml b/.github/workflows/linter.yml index b352a8301d..5415b6d1be 100644 --- a/.github/workflows/linter.yml +++ b/.github/workflows/linter.yml @@ -9,8 +9,6 @@ defaults: on: pull_request: branches: [master, dev] - paths: - - "**/*.py" schedule: # run CI every day even if no PRs/merges occur @@ -27,7 +25,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Full git history is needed to get a proper list of changed files within `super-linter` fetch-depth: 0 @@ -42,6 +40,10 @@ jobs: mkdir -p .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 uses: super-linter/super-linter/slim@v4.9.2 if: always() @@ -55,7 +57,6 @@ jobs: VALIDATE_PYTHON_PYLINT: false VALIDATE_PYTHON_BLACK: false VALIDATE_PYTHON_ISORT: false - # Always false VALIDATE_JSON: false VALIDATE_JAVASCRIPT_STANDARD: false VALIDATE_PYTHON_FLAKE8: false diff --git a/.github/workflows/matchers/pylint.json b/.github/workflows/matchers/pylint.json new file mode 100644 index 0000000000..4d9e13fca7 --- /dev/null +++ b/.github/workflows/matchers/pylint.json @@ -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 + } + ] + } + ] +} \ No newline at end of file diff --git a/.github/workflows/matchers/yamllint.json b/.github/workflows/matchers/yamllint.json new file mode 100644 index 0000000000..b0b2f125c6 --- /dev/null +++ b/.github/workflows/matchers/yamllint.json @@ -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 + } + ] + } + ] + } \ No newline at end of file diff --git a/.github/workflows/pip-audit.yml b/.github/workflows/pip-audit.yml index 4fbc1a3fdc..a98f6ab58b 100644 --- a/.github/workflows/pip-audit.yml +++ b/.github/workflows/pip-audit.yml @@ -18,7 +18,7 @@ jobs: steps: - name: Checkout repository - uses: actions/checkout@v3 + uses: actions/checkout@v4 - name: Install Python uses: actions/setup-python@v4 diff --git a/.github/workflows/publish.yml b/.github/workflows/publish.yml index f7d9ff9e7b..fef0a4a2eb 100644 --- a/.github/workflows/publish.yml +++ b/.github/workflows/publish.yml @@ -10,7 +10,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python uses: actions/setup-python@v4 @@ -44,11 +44,10 @@ jobs: path: dist/ - name: publish - uses: pypa/gh-action-pypi-publish@v1.8.7 + uses: pypa/gh-action-pypi-publish@v1.8.10 - name: sign - uses: sigstore/gh-action-sigstore-python@v1.2.3 + uses: sigstore/gh-action-sigstore-python@v2.0.1 with: inputs: ./dist/*.tar.gz ./dist/*.whl release-signing-artifacts: true - bundle-only: true diff --git a/.github/workflows/pylint.yml b/.github/workflows/pylint.yml index 207f98eac0..7e990371ff 100644 --- a/.github/workflows/pylint.yml +++ b/.github/workflows/pylint.yml @@ -9,6 +9,8 @@ defaults: on: pull_request: branches: [master, dev] + paths: + - "**/*.py" concurrency: group: ${{ github.workflow }}-${{ github.ref }} @@ -21,7 +23,7 @@ jobs: steps: - name: Checkout Code - uses: actions/checkout@v3 + uses: actions/checkout@v4 with: # Full git history is needed to get a proper list of changed files within `super-linter` fetch-depth: 0 @@ -36,6 +38,10 @@ jobs: mkdir -p .github/linters cp pyproject.toml .github/linters + - name: Register pylint problem matcher + run: | + echo "::add-matcher::.github/workflows/matchers/pylint.json" + - name: Pylint uses: super-linter/super-linter/slim@v4.9.2 if: always() diff --git a/.github/workflows/test.yml b/.github/workflows/test.yml index b3754bfd78..6b911eb92f 100644 --- a/.github/workflows/test.yml +++ b/.github/workflows/test.yml @@ -27,7 +27,7 @@ jobs: type: ["unit", "integration", "tool"] python: ${{ (github.event_name == 'pull_request' && fromJSON('["3.8", "3.11"]')) || fromJSON('["3.8", "3.9", "3.10", "3.11"]') }} steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python ${{ matrix.python }} uses: actions/setup-python@v4 with: @@ -84,7 +84,7 @@ jobs: runs-on: ubuntu-latest steps: - - uses: actions/checkout@v3 + - uses: actions/checkout@v4 - name: Set up Python 3.8 uses: actions/setup-python@v4 with: diff --git a/CITATION.cff b/CITATION.cff new file mode 100644 index 0000000000..605bd60e5f --- /dev/null +++ b/CITATION.cff @@ -0,0 +1,64 @@ +cff-version: 1.2.0 +title: Slither Analyzer +message: >- + If you use this software, please cite it using the + metadata from this file. +type: software +authors: + - given-names: Josselin + family-names: Feist + - given-names: Gustavo + family-names: Grieco + - given-names: Alex + family-names: Groce +identifiers: + - type: doi + value: 10.48550/arXiv.1908.09878 + description: arXiv.1908.09878 + - type: url + value: 'https://arxiv.org/abs/1908.09878' + description: arxiv + - type: doi + value: 10.1109/wetseb.2019.00008 +repository-code: 'https://github.com/crytic/slither' +url: 'https://www.trailofbits.com/' +repository-artifact: 'https://github.com/crytic/slither/releases' +abstract: >- + Slither is a static analysis framework designed to provide + rich information about Ethereum smart contracts. + + It works by converting Solidity smart contracts into an + intermediate representation called SlithIR. + + SlithIR uses Static Single Assignment (SSA) form and a + reduced instruction set to ease implementation of analyses + while preserving semantic information that would be lost + in transforming Solidity to bytecode. + + Slither allows for the application of commonly used + program analysis techniques like dataflow and taint + tracking. + + + Our framework has four main use cases: + + (1) automated detection of vulnerabilities, + + (2) automated detection of code optimization + opportunities, + + (3) improvement of the user's understanding of the + contracts, and + + (4) assistance with code review. +keywords: + - Ethereum + - Static Analysis + - Smart contracts + - EVM + - bug detection + - Software Engineering +license: AGPL-3.0-only +commit: 3d4f934d3228f072b7df2c5e7252c64df4601bc8 +version: 0.9.5 +date-released: '2023-06-28' diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 5cf02136bd..ae7951c7f9 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -96,8 +96,8 @@ For each new detector, at least one regression tests must be present. #### Adding parsing tests 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. -3. Update `ALL_TESTS` in `tests/e2e/solc_parsing/test_ast_parsing.py`. +2. 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. 5. Run `pytest tests/e2e/solc_parsing/test_ast_parsing.py` and check that everything worked. diff --git a/README.md b/README.md index cb815561e8..1a0d203c7d 100644 --- a/README.md +++ b/README.md @@ -1,42 +1,57 @@ -# Slither, the Solidity source analyzer +# [Slither, the Solidity source analyzer](https://crytic.github.io/slither/slither.html) -Logo +Slither Static Analysis Framework Logo [![Build Status](https://img.shields.io/github/actions/workflow/status/crytic/slither/ci.yml?branch=master)](https://github.com/crytic/slither/actions?query=workflow%3ACI) -[![Slack Status](https://empireslacking.herokuapp.com/badge.svg)](https://empireslacking.herokuapp.com) -[![PyPI version](https://badge.fury.io/py/slither-analyzer.svg)](https://badge.fury.io/py/slither-analyzer) - -Slither is a Solidity static analysis framework written in Python3. It runs a suite of vulnerability detectors, prints visual information about contract details, and provides an API to easily write custom analyses. Slither enables developers to find vulnerabilities, enhance their code comprehension, and quickly prototype custom analyses. - -- [Features](#features) -- [Usage](#usage) -- [How to Install](#how-to-install) -- [Detectors](#detectors) -- [Printers](#printers) -- [Tools](#tools) -- [API Documentation](#api-documentation) -- [Getting Help](#getting-help) -- [FAQ](#faq) -- [Publications](#publications) +![PyPI](https://img.shields.io/pypi/v/slither-analyzer?logo=python&logoColor=white&label=slither-analyzer) +[![Slither - Read the Docs](https://img.shields.io/badge/Slither-Read_the_Docs-2ea44f)](https://crytic.github.io/slither/slither.html) +[![Slither - Wiki](https://img.shields.io/badge/Slither-Wiki-2ea44f)](https://github.com/crytic/slither/wiki/SlithIR) + +> Join the Empire Hacking Slack +> +> [![Slack Status](https://slack.empirehacking.nyc/badge.svg)](https://slack.empirehacking.nyc/) +> > - Discussions and Support + +**Slither** is a Solidity static analysis framework written in Python3. It runs a suite of vulnerability detectors, prints visual information about contract details, and provides an API to easily write custom analyses. Slither enables developers to find vulnerabilities, enhance their code comprehension, and quickly prototype custom analyses. + +* [Features](#features) +* [Usage](#usage) +* [How to install](#how-to-install) + * [Using Pip](#using-pip) + * [Using Git](#using-git) + * [Using Docker](#using-docker) + * [Integration](#integration) +* [Detectors](#detectors) +* [Printers](#printers) + * [Quick Review Printers](#quick-review-printers) + * [In-Depth Review Printers](#in-depth-review-printers) +* [Tools](#tools) +* [API Documentation](#api-documentation) +* [Getting Help](#getting-help) +* [FAQ](#faq) +* [License](#license) +* [Publications](#publications) + * [Trail of Bits publication](#trail-of-bits-publication) + * [External publications](#external-publications) ## Features -- Detects vulnerable Solidity code with low false positives (see the list of [trophies](./trophies.md)) -- Identifies where the error condition occurs in the source code -- Easily integrates into continuous integration and Hardhat/Foundry builds -- Built-in 'printers' quickly report crucial contract information -- Detector API to write custom analyses in Python -- Ability to analyze contracts written with Solidity >= 0.4 -- Intermediate representation ([SlithIR](https://github.com/trailofbits/slither/wiki/SlithIR)) enables simple, high-precision analyses -- Correctly parses 99.9% of all public Solidity code -- Average execution time of less than 1 second per contract -- Integrates with Github's code scanning in [CI](https://github.com/marketplace/actions/slither-action) +* Detects vulnerable Solidity code with low false positives (see the list of [trophies](./trophies.md)) +* Identifies where the error condition occurs in the source code +* Easily integrates into continuous integration and Hardhat/Foundry builds +* Built-in 'printers' quickly report crucial contract information +* Detector API to write custom analyses in Python +* Ability to analyze contracts written with Solidity >= 0.4 +* Intermediate representation ([SlithIR](https://github.com/trailofbits/slither/wiki/SlithIR)) enables simple, high-precision analyses +* Correctly parses 99.9% of all public Solidity code +* Average execution time of less than 1 second per contract +* Integrates with Github's code scanning in [CI](https://github.com/marketplace/actions/slither-action) ## Usage Run Slither on a Hardhat/Foundry/Dapp/Brownie application: -```bash +```console slither . ``` @@ -44,18 +59,19 @@ This is the preferred option if your project has dependencies as Slither relies However, you can run Slither on a single file that does not import dependencies: -```bash +```console slither tests/uninitialized.sol ``` ## How to install -Slither requires Python 3.8+. +> **Note**
+> Slither requires Python 3.8+. If you're **not** going to use one of the [supported compilation frameworks](https://github.com/crytic/crytic-compile), you need [solc](https://github.com/ethereum/solidity/), the Solidity compiler; we recommend using [solc-select](https://github.com/crytic/solc-select) to conveniently switch between solc versions. ### Using Pip -```bash +```console pip3 install slither-analyzer ``` @@ -84,9 +100,9 @@ docker run -it -v /home/share:/share trailofbits/eth-security-toolbox ### Integration -- For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action). -- To generate a Markdown report, use `slither [target] --checklist`. -- To generate a Markdown with GitHub source code highlighting, use `slither [target] --checklist --markdown-root https://github.com/ORG/REPO/blob/COMMIT/` (replace `ORG`, `REPO`, `COMMIT`) +* For GitHub action integration, use [slither-action](https://github.com/marketplace/actions/slither-action). +* To generate a Markdown report, use `slither [target] --checklist`. +* To generate a Markdown with GitHub source code highlighting, use `slither [target] --checklist --markdown-root https://github.com/ORG/REPO/blob/COMMIT/` (replace `ORG`, `REPO`, `COMMIT`) ## Detectors @@ -182,23 +198,24 @@ Num | Detector | What it Detects | Impact | Confidence For more information, see -- The [Detector Documentation](https://github.com/crytic/slither/wiki/Detector-Documentation) for details on each detector -- The [Detection Selection](https://github.com/crytic/slither/wiki/Usage#detector-selection) to run only selected detectors. By default, all the detectors are run. -- The [Triage Mode](https://github.com/crytic/slither/wiki/Usage#triage-mode) to filter individual results +* The [Detector Documentation](https://github.com/crytic/slither/wiki/Detector-Documentation) for details on each detector +* The [Detection Selection](https://github.com/crytic/slither/wiki/Usage#detector-selection) to run only selected detectors. By default, all the detectors are run. +* The [Triage Mode](https://github.com/crytic/slither/wiki/Usage#triage-mode) to filter individual results ## Printers + ### Quick Review Printers -- `human-summary`: [Print a human-readable summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#human-summary) -- `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) -- `contract-summary`: [Print a summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#contract-summary) -- `loc`: [Count the total number lines of code (LOC), source lines of code (SLOC), and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), and test files (TEST).](https://github.com/trailofbits/slither/wiki/Printer-documentation#loc) +* `human-summary`: [Print a human-readable summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#human-summary) +* `inheritance-graph`: [Export the inheritance graph of each contract to a dot file](https://github.com/trailofbits/slither/wiki/Printer-documentation#inheritance-graph) +* `contract-summary`: [Print a summary of the contracts](https://github.com/trailofbits/slither/wiki/Printer-documentation#contract-summary) +* `loc`: [Count the total number lines of code (LOC), source lines of code (SLOC), and comment lines of code (CLOC) found in source files (SRC), dependencies (DEP), and test files (TEST).](https://github.com/trailofbits/slither/wiki/Printer-documentation#loc) ### In-Depth Review Printers -- `call-graph`: [Export the call-graph of the contracts to a dot file](https://github.com/trailofbits/slither/wiki/Printer-documentation#call-graph) -- `cfg`: [Export the CFG of each functions](https://github.com/trailofbits/slither/wiki/Printer-documentation#cfg) -- `function-summary`: [Print a summary of the functions](https://github.com/trailofbits/slither/wiki/Printer-documentation#function-summary) -- `vars-and-auth`: [Print the state variables written and the authorization of the functions](https://github.com/crytic/slither/wiki/Printer-documentation#variables-written-and-authorization) -- `not-pausable`: [Print functions that do not use `whenNotPaused` modifier](https://github.com/trailofbits/slither/wiki/Printer-documentation#when-not-paused). +* `call-graph`: [Export the call-graph of the contracts to a dot file](https://github.com/trailofbits/slither/wiki/Printer-documentation#call-graph) +* `cfg`: [Export the CFG of each functions](https://github.com/trailofbits/slither/wiki/Printer-documentation#cfg) +* `function-summary`: [Print a summary of the functions](https://github.com/trailofbits/slither/wiki/Printer-documentation#function-summary) +* `vars-and-auth`: [Print the state variables written and the authorization of the functions](https://github.com/crytic/slither/wiki/Printer-documentation#variables-written-and-authorization) +* `not-pausable`: [Print functions that do not use `whenNotPaused` modifier](https://github.com/trailofbits/slither/wiki/Printer-documentation#when-not-paused). To run a printer, use `--print` and a comma-separated list of printers. @@ -206,13 +223,13 @@ See the [Printer documentation](https://github.com/crytic/slither/wiki/Printer-d ## Tools -- `slither-check-upgradeability`: [Review `delegatecall`-based upgradeability](https://github.com/crytic/slither/wiki/Upgradeability-Checks) -- `slither-prop`: [Automatic unit test and property generation](https://github.com/crytic/slither/wiki/Property-generation) -- `slither-flat`: [Flatten a codebase](https://github.com/crytic/slither/wiki/Contract-Flattening) -- `slither-check-erc`: [Check the ERC's conformance](https://github.com/crytic/slither/wiki/ERC-Conformance) -- `slither-format`: [Automatic patch generation](https://github.com/crytic/slither/wiki/Slither-format) -- `slither-read-storage`: [Read storage values from contracts](./slither/tools/read_storage/README.md) -- `slither-interface`: [Generate an interface for a contract](./slither/tools/interface/README.md) +* `slither-check-upgradeability`: [Review `delegatecall`-based upgradeability](https://github.com/crytic/slither/wiki/Upgradeability-Checks) +* `slither-prop`: [Automatic unit test and property generation](https://github.com/crytic/slither/wiki/Property-generation) +* `slither-flat`: [Flatten a codebase](https://github.com/crytic/slither/wiki/Contract-Flattening) +* `slither-check-erc`: [Check the ERC's conformance](https://github.com/crytic/slither/wiki/ERC-Conformance) +* `slither-format`: [Automatic patch generation](https://github.com/crytic/slither/wiki/Slither-format) +* `slither-read-storage`: [Read storage values from contracts](./slither/tools/read_storage/README.md) +* `slither-interface`: [Generate an interface for a contract](./slither/tools/interface/README.md) See the [Tool documentation](https://github.com/crytic/slither/wiki/Tool-Documentation) for additional tools. @@ -226,23 +243,23 @@ Documentation on Slither's internals is available [here](https://crytic.github.i Feel free to stop by our [Slack channel](https://empireslacking.herokuapp.com) (#ethereum) for help using or extending Slither. -- The [Printer documentation](https://github.com/trailofbits/slither/wiki/Printer-documentation) describes the information Slither is capable of visualizing for each contract. +* The [Printer documentation](https://github.com/trailofbits/slither/wiki/Printer-documentation) describes the information Slither is capable of visualizing for each contract. -- The [Detector documentation](https://github.com/trailofbits/slither/wiki/Adding-a-new-detector) describes how to write a new vulnerability analyses. +* The [Detector documentation](https://github.com/trailofbits/slither/wiki/Adding-a-new-detector) describes how to write a new vulnerability analyses. -- The [API documentation](https://github.com/crytic/slither/wiki/Python-API) describes the methods and objects available for custom analyses. +* The [API documentation](https://github.com/crytic/slither/wiki/Python-API) describes the methods and objects available for custom analyses. -- The [SlithIR documentation](https://github.com/trailofbits/slither/wiki/SlithIR) describes the SlithIR intermediate representation. +* The [SlithIR documentation](https://github.com/trailofbits/slither/wiki/SlithIR) describes the SlithIR intermediate representation. ## FAQ How do I exclude mocks or tests? -- View our documentation on [path filtering](https://github.com/crytic/slither/wiki/Usage#path-filtering). +* View our documentation on [path filtering](https://github.com/crytic/slither/wiki/Usage#path-filtering). How do I fix "unknown file" or compilation issues? -- Because slither requires the solc AST, it must have all dependencies available. +* Because slither requires the solc AST, it must have all dependencies available. If a contract has dependencies, `slither contract.sol` will fail. Instead, use `slither .` in the parent directory of `contracts/` (you should see `contracts/` when you run `ls`). If you have a `node_modules/` folder, it must be in the same directory as `contracts/`. To verify that this issue is related to slither, @@ -257,7 +274,7 @@ Slither is licensed and distributed under the AGPLv3 license. [Contact us](mailt ### Trail of Bits publication -- [Slither: A Static Analysis Framework For Smart Contracts](https://arxiv.org/abs/1908.09878), Josselin Feist, Gustavo Grieco, Alex Groce - WETSEB '19 +* [Slither: A Static Analysis Framework For Smart Contracts](https://arxiv.org/abs/1908.09878), Josselin Feist, Gustavo Grieco, Alex Groce - WETSEB '19 ### External publications diff --git a/setup.py b/setup.py index 70d4f71fd4..182b91d35b 100644 --- a/setup.py +++ b/setup.py @@ -8,15 +8,15 @@ description="Slither is a Solidity static analysis framework written in Python 3.", url="https://github.com/crytic/slither", author="Trail of Bits", - version="0.9.3", + version="0.9.6", packages=find_packages(), python_requires=">=3.8", install_requires=[ "packaging", "prettytable>=3.3.0", "pycryptodome>=3.4.6", - # "crytic-compile>=0.3.1,<0.4.0", - "crytic-compile@git+https://github.com/crytic/crytic-compile.git@dev#egg=crytic-compile", + "crytic-compile>=0.3.3,<0.4.0", + # "crytic-compile@git+https://github.com/crytic/crytic-compile.git@dev#egg=crytic-compile", "web3>=6.0.0", "eth-abi>=4.0.0", "eth-typing>=3.0.0", @@ -36,7 +36,6 @@ "coverage[toml]", "filelock", "pytest-insta", - "solc-select@git+https://github.com/crytic/solc-select.git@query-artifact-path#egg=solc-select", ], "doc": [ "pdoc", diff --git a/slither/core/compilation_unit.py b/slither/core/compilation_unit.py index 6d24786eb1..35180cefc0 100644 --- a/slither/core/compilation_unit.py +++ b/slither/core/compilation_unit.py @@ -47,7 +47,7 @@ def __init__(self, core: "SlitherCore", crytic_compilation_unit: CompilationUnit self._pragma_directives: List[Pragma] = [] self._import_directives: List[Import] = [] self._custom_errors: List[CustomErrorTopLevel] = [] - self._user_defined_value_types: Dict[str, TypeAliasTopLevel] = {} + self._type_aliases: Dict[str, TypeAliasTopLevel] = {} self._all_functions: Set[Function] = set() self._all_modifiers: Set[Modifier] = set() @@ -220,8 +220,8 @@ def custom_errors(self) -> List[CustomErrorTopLevel]: return self._custom_errors @property - def user_defined_value_types(self) -> Dict[str, TypeAliasTopLevel]: - return self._user_defined_value_types + def type_aliases(self) -> Dict[str, TypeAliasTopLevel]: + return self._type_aliases # endregion ################################################################################### diff --git a/slither/core/declarations/__init__.py b/slither/core/declarations/__init__.py index 92e0b9eca3..f341187518 100644 --- a/slither/core/declarations/__init__.py +++ b/slither/core/declarations/__init__.py @@ -18,3 +18,5 @@ from .function_contract import FunctionContract from .function_top_level import FunctionTopLevel from .custom_error_contract import CustomErrorContract +from .custom_error_top_level import CustomErrorTopLevel +from .custom_error import CustomError diff --git a/slither/core/declarations/contract.py b/slither/core/declarations/contract.py index fd2cdd4684..f9bf153064 100644 --- a/slither/core/declarations/contract.py +++ b/slither/core/declarations/contract.py @@ -45,6 +45,7 @@ from slither.core.compilation_unit import SlitherCompilationUnit from slither.core.scope.scope import FileScope from slither.core.cfg.node import Node + from slither.core.solidity_types import TypeAliasContract LOGGER = logging.getLogger("Contract") @@ -81,6 +82,7 @@ def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope self._functions: Dict[str, "FunctionContract"] = {} self._linearizedBaseContracts: List[int] = [] self._custom_errors: Dict[str, "CustomErrorContract"] = {} + self._type_aliases: Dict[str, "TypeAliasContract"] = {} # The only str is "*" self._using_for: Dict[USING_FOR_KEY, USING_FOR_ITEM] = {} @@ -364,6 +366,38 @@ def custom_errors_declared(self) -> List["CustomErrorContract"]: def custom_errors_as_dict(self) -> Dict[str, "CustomErrorContract"]: return self._custom_errors + # endregion + ################################################################################### + ################################################################################### + # region Custom Errors + ################################################################################### + ################################################################################### + + @property + def type_aliases(self) -> List["TypeAliasContract"]: + """ + list(TypeAliasContract): List of the contract's custom errors + """ + return list(self._type_aliases.values()) + + @property + def type_aliases_inherited(self) -> List["TypeAliasContract"]: + """ + list(TypeAliasContract): List of the inherited custom errors + """ + return [s for s in self.type_aliases if s.contract != self] + + @property + def type_aliases_declared(self) -> List["TypeAliasContract"]: + """ + list(TypeAliasContract): List of the custom errors declared within the contract (not inherited) + """ + return [s for s in self.type_aliases if s.contract == self] + + @property + def type_aliases_as_dict(self) -> Dict[str, "TypeAliasContract"]: + return self._type_aliases + # endregion ################################################################################### ################################################################################### @@ -861,7 +895,7 @@ def get_state_variable_from_canonical_name( Returns: 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"]: """ diff --git a/slither/core/declarations/custom_error_contract.py b/slither/core/declarations/custom_error_contract.py index cd279a3a62..2c8bec9efa 100644 --- a/slither/core/declarations/custom_error_contract.py +++ b/slither/core/declarations/custom_error_contract.py @@ -16,3 +16,7 @@ def is_declared_by(self, contract: "Contract") -> bool: :return: """ return self.contract == contract + + @property + def canonical_name(self) -> str: + return self.contract.name + "." + self.full_name diff --git a/slither/core/declarations/custom_error_top_level.py b/slither/core/declarations/custom_error_top_level.py index 64a6a85353..b80356b245 100644 --- a/slither/core/declarations/custom_error_top_level.py +++ b/slither/core/declarations/custom_error_top_level.py @@ -12,3 +12,7 @@ class CustomErrorTopLevel(CustomError, TopLevel): def __init__(self, compilation_unit: "SlitherCompilationUnit", scope: "FileScope") -> None: super().__init__(compilation_unit) self.file_scope: "FileScope" = scope + + @property + def canonical_name(self) -> str: + return self.full_name diff --git a/slither/core/expressions/call_expression.py b/slither/core/expressions/call_expression.py index 6708dda7e2..ec2b2cfceb 100644 --- a/slither/core/expressions/call_expression.py +++ b/slither/core/expressions/call_expression.py @@ -4,12 +4,32 @@ class CallExpression(Expression): # pylint: disable=too-many-instance-attributes - def __init__(self, called: Expression, arguments: List[Any], type_call: str) -> None: + def __init__( + self, + called: Expression, + arguments: List[Any], + type_call: str, + names: Optional[List[str]] = None, + ) -> None: + """ + #### Parameters + called - + The expression denoting the function to be called + arguments - + List of argument expressions + type_call - + A string formatting of the called function's return type + names - + For calls with named fields, list fields in call order. + For calls without named fields, None. + """ assert isinstance(called, Expression) + assert (names is None) or isinstance(names, list) super().__init__() self._called: Expression = called self._arguments: List[Expression] = arguments self._type_call: str = type_call + self._names: Optional[List[str]] = names # gas and value are only available if the syntax is {gas: , value: } # For the .gas().value(), the member are considered as function call # And converted later to the correct info (convert.py) @@ -17,6 +37,14 @@ def __init__(self, called: Expression, arguments: List[Any], type_call: str) -> self._value: Optional[Expression] = None self._salt: Optional[Expression] = None + @property + def names(self) -> Optional[List[str]]: + """ + For calls with named fields, list fields in call order. + For calls without named fields, None. + """ + return self._names + @property def call_value(self) -> Optional[Expression]: return self._value @@ -62,4 +90,9 @@ def __str__(self) -> str: if gas or value or salt: options = [gas, value, salt] txt += "{" + ",".join([o for o in options if o != ""]) + "}" - return txt + "(" + ",".join([str(a) for a in self._arguments]) + ")" + args = ( + "{" + ",".join([f"{n}:{str(a)}" for (a, n) in zip(self._arguments, self._names)]) + "}" + if self._names is not None + else ",".join([str(a) for a in self._arguments]) + ) + return txt + "(" + args + ")" diff --git a/slither/core/expressions/unary_operation.py b/slither/core/expressions/unary_operation.py index 6572249278..4051326131 100644 --- a/slither/core/expressions/unary_operation.py +++ b/slither/core/expressions/unary_operation.py @@ -106,8 +106,6 @@ def __init__( UnaryOperationType.MINUSMINUS_PRE, UnaryOperationType.PLUSPLUS_POST, UnaryOperationType.MINUSMINUS_POST, - UnaryOperationType.PLUS_PRE, - UnaryOperationType.MINUS_PRE, ]: expression.set_lvalue() diff --git a/slither/core/scope/scope.py b/slither/core/scope/scope.py index cafeb3585d..937a051361 100644 --- a/slither/core/scope/scope.py +++ b/slither/core/scope/scope.py @@ -52,7 +52,7 @@ def __init__(self, filename: Filename) -> None: # User defined types # Name -> type alias - self.user_defined_types: Dict[str, TypeAlias] = {} + self.type_aliases: Dict[str, TypeAlias] = {} def add_accesible_scopes(self) -> bool: """ @@ -95,8 +95,8 @@ def add_accesible_scopes(self) -> bool: if not _dict_contain(new_scope.renaming, self.renaming): self.renaming.update(new_scope.renaming) learn_something = True - if not _dict_contain(new_scope.user_defined_types, self.user_defined_types): - self.user_defined_types.update(new_scope.user_defined_types) + if not _dict_contain(new_scope.type_aliases, self.type_aliases): + self.type_aliases.update(new_scope.type_aliases) learn_something = True return learn_something diff --git a/slither/detectors/naming_convention/naming_convention.py b/slither/detectors/naming_convention/naming_convention.py index 02deb719e7..0633799e56 100644 --- a/slither/detectors/naming_convention/naming_convention.py +++ b/slither/detectors/naming_convention/naming_convention.py @@ -167,7 +167,7 @@ def _detect(self) -> List[Output]: results.append(res) else: - if var.visibility == "private": + if var.visibility in ["private", "internal"]: correct_naming = self.is_mixed_case_with_underscore(var.name) else: correct_naming = self.is_mixed_case(var.name) diff --git a/slither/detectors/operations/cache_array_length.py b/slither/detectors/operations/cache_array_length.py index e4d8cf2c69..59289ed0f7 100644 --- a/slither/detectors/operations/cache_array_length.py +++ b/slither/detectors/operations/cache_array_length.py @@ -216,9 +216,8 @@ def _detect(self): for usage in non_optimal_array_len_usages: info = [ "Loop condition ", - f"`{usage.source_mapping.content}` ", - f"({usage.source_mapping}) ", - "should use cached array length instead of referencing `length` member " + usage, + " should use cached array length instead of referencing `length` member " "of the storage array.\n ", ] res = self.generate_result(info) diff --git a/slither/detectors/statements/divide_before_multiply.py b/slither/detectors/statements/divide_before_multiply.py index 6f199db414..334da592c0 100644 --- a/slither/detectors/statements/divide_before_multiply.py +++ b/slither/detectors/statements/divide_before_multiply.py @@ -2,7 +2,7 @@ Module detecting possible loss of precision due to divide before multiple """ from collections import defaultdict -from typing import DefaultDict, List, Set, Tuple +from typing import DefaultDict, List, Tuple from slither.core.cfg.node import Node from slither.core.declarations.contract import Contract @@ -63,7 +63,7 @@ def is_assert(node: Node) -> bool: # pylint: disable=too-many-branches def _explore( - to_explore: Set[Node], f_results: List[List[Node]], divisions: DefaultDict[LVALUE, List[Node]] + to_explore: List[Node], f_results: List[List[Node]], divisions: DefaultDict[LVALUE, List[Node]] ) -> None: explored = set() while to_explore: # pylint: disable=too-many-nested-blocks @@ -114,7 +114,7 @@ def _explore( f_results.append(node_results) for son in node.sons: - to_explore.add(son) + to_explore.append(son) def detect_divide_before_multiply( @@ -145,7 +145,7 @@ def detect_divide_before_multiply( # track all the division results (and the assignment of the division results) divisions: DefaultDict[LVALUE, List[Node]] = defaultdict(list) - _explore({function.entry_point}, f_results, divisions) + _explore([function.entry_point], f_results, divisions) for f_result in f_results: results.append((function, f_result)) diff --git a/slither/detectors/statements/mapping_deletion.py b/slither/detectors/statements/mapping_deletion.py index 4cdac72400..0940d5a07b 100644 --- a/slither/detectors/statements/mapping_deletion.py +++ b/slither/detectors/statements/mapping_deletion.py @@ -6,6 +6,7 @@ from slither.core.cfg.node import Node from slither.core.declarations import Structure from slither.core.declarations.contract import Contract +from slither.core.variables.variable import Variable from slither.core.declarations.function_contract import FunctionContract from slither.core.solidity_types import MappingType, UserDefinedType from slither.detectors.abstract_detector import ( @@ -69,14 +70,25 @@ def detect_mapping_deletion( for ir in node.irs: if isinstance(ir, Delete): value = ir.variable - if isinstance(value.type, UserDefinedType) and isinstance( - value.type.type, Structure - ): - st = value.type.type - if any(isinstance(e.type, MappingType) for e in st.elems.values()): - ret.append((f, st, node)) + MappingDeletionDetection.check_if_mapping(value, ret, f, node) + return ret + @staticmethod + def check_if_mapping( + value: Variable, + ret: List[Tuple[FunctionContract, Structure, Node]], + f: FunctionContract, + node: Node, + ): + if isinstance(value.type, UserDefinedType) and isinstance(value.type.type, Structure): + st = value.type.type + if any(isinstance(e.type, MappingType) for e in st.elems.values()): + ret.append((f, st, node)) + return + for e in st.elems.values(): + MappingDeletionDetection.check_if_mapping(e, ret, f, node) + def _detect(self) -> List[Output]: """Detect mapping deletion diff --git a/slither/printers/guidance/echidna.py b/slither/printers/guidance/echidna.py index 25e0968cdb..73a9c5619d 100644 --- a/slither/printers/guidance/echidna.py +++ b/slither/printers/guidance/echidna.py @@ -126,15 +126,24 @@ def _extract_constant_functions(slither: SlitherCore) -> Dict[str, List[str]]: return ret -def _extract_assert(slither: SlitherCore) -> Dict[str, List[str]]: - ret: Dict[str, List[str]] = {} +def _extract_assert(slither: SlitherCore) -> Dict[str, Dict[str, List[Dict]]]: + """ + Return the list of contract -> function name -> List(source mapping of the assert)) + + Args: + slither: + + Returns: + + """ + ret: Dict[str, Dict[str, List[Dict]]] = {} for contract in slither.contracts: - functions_using_assert = [] + functions_using_assert: Dict[str, List[Dict]] = defaultdict(list) for f in contract.functions_entry_points: - for v in f.all_solidity_calls(): - if v == SolidityFunction("assert(bool)"): - functions_using_assert.append(_get_name(f)) - break + for node in f.all_nodes(): + if SolidityFunction("assert(bool)") in node.solidity_calls and node.source_mapping: + func_name = _get_name(f) + functions_using_assert[func_name].append(node.source_mapping.to_json()) if functions_using_assert: ret[contract.name] = functions_using_assert return ret diff --git a/slither/slithir/convert.py b/slither/slithir/convert.py index d40715c4f3..4cb508fae6 100644 --- a/slither/slithir/convert.py +++ b/slither/slithir/convert.py @@ -385,6 +385,70 @@ def integrate_value_gas(result: List[Operation]) -> List[Operation]: ################################################################################### +def get_declared_param_names( + ins: Union[ + NewStructure, + NewContract, + InternalCall, + LibraryCall, + HighLevelCall, + InternalDynamicCall, + EventCall, + ] +) -> Optional[List[str]]: + """ + Given a call operation, return the list of parameter names, in the order + listed in the function declaration. + #### Parameters + ins - + The call instruction + #### Possible Returns + List[str] - + A list of the parameters in declaration order + None - + Workaround: Unable to obtain list of parameters in declaration order + """ + if isinstance(ins, NewStructure): + return [x.name for x in ins.structure.elems_ordered if not isinstance(x.type, MappingType)] + if isinstance(ins, (InternalCall, LibraryCall, HighLevelCall)): + if isinstance(ins.function, Function): + return [p.name for p in ins.function.parameters] + return None + if isinstance(ins, InternalDynamicCall): + return [p.name for p in ins.function_type.params] + + assert isinstance(ins, (EventCall, NewContract)) + return None + + +def reorder_arguments( + args: List[Variable], call_names: List[str], decl_names: List[str] +) -> List[Variable]: + """ + Reorder named struct constructor arguments so that they match struct declaration ordering rather + than call ordering + E.g. for `struct S { int x; int y; }` we reorder `S({y : 2, x : 3})` to `S(3, 2)` + #### Parameters + args - + Arguments to constructor call, in call order + names - + Parameter names in call order + decl_names - + Parameter names in declaration order + #### Returns + Reordered arguments to constructor call, now in declaration order + """ + assert len(args) == len(call_names) + assert len(call_names) == len(decl_names) + + args_ret = [] + for n in decl_names: + ind = call_names.index(n) + args_ret.append(args[ind]) + + return args_ret + + def propagate_type_and_convert_call(result: List[Operation], node: "Node") -> List[Operation]: """ Propagate the types variables and convert tmp call to real call operation @@ -434,6 +498,23 @@ def propagate_type_and_convert_call(result: List[Operation], node: "Node") -> Li if ins.call_id in calls_gas and isinstance(ins, (HighLevelCall, InternalDynamicCall)): ins.call_gas = calls_gas[ins.call_id] + if isinstance(ins, Call) and (ins.names is not None): + assert isinstance( + ins, + ( + NewStructure, + NewContract, + InternalCall, + LibraryCall, + HighLevelCall, + InternalDynamicCall, + EventCall, + ), + ) + decl_param_names = get_declared_param_names(ins) + if decl_param_names is not None: + call_data = reorder_arguments(call_data, ins.names, decl_param_names) + if isinstance(ins, (Call, NewContract, NewStructure)): # We might have stored some arguments for libraries if ins.arguments: @@ -855,7 +936,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> Union[Call, if isinstance(ins.ori.variable_left, Contract): st = ins.ori.variable_left.get_structure_from_name(ins.ori.variable_right) if st: - op = NewStructure(st, ins.lvalue) + op = NewStructure(st, ins.lvalue, names=ins.names) op.set_expression(ins.expression) op.call_id = ins.call_id return op @@ -892,6 +973,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> Union[Call, ins.nbr_arguments, ins.lvalue, ins.type_call, + names=ins.names, ) libcall.set_expression(ins.expression) libcall.call_id = ins.call_id @@ -950,6 +1032,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> Union[Call, len(lib_func.parameters), ins.lvalue, "d", + names=ins.names, ) lib_call.set_expression(ins.expression) lib_call.set_node(ins.node) @@ -1031,6 +1114,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> Union[Call, ins.nbr_arguments, ins.lvalue, ins.type_call, + names=ins.names, ) msgcall.call_id = ins.call_id @@ -1082,7 +1166,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> Union[Call, return n if isinstance(ins.called, Structure): - op = NewStructure(ins.called, ins.lvalue) + op = NewStructure(ins.called, ins.lvalue, names=ins.names) op.set_expression(ins.expression) op.call_id = ins.call_id op.set_expression(ins.expression) @@ -1106,7 +1190,7 @@ def extract_tmp_call(ins: TmpCall, contract: Optional[Contract]) -> Union[Call, if len(ins.called.constructor.parameters) != ins.nbr_arguments: return Nop() internalcall = InternalCall( - ins.called.constructor, ins.nbr_arguments, ins.lvalue, ins.type_call + ins.called.constructor, ins.nbr_arguments, ins.lvalue, ins.type_call, ins.names ) internalcall.call_id = ins.call_id internalcall.set_expression(ins.expression) @@ -1440,6 +1524,7 @@ def look_for_library_or_top_level( ir.nbr_arguments, ir.lvalue, ir.type_call, + names=ir.names, ) lib_call.set_expression(ir.expression) lib_call.set_node(ir.node) @@ -1857,7 +1942,7 @@ def convert_constant_types(irs: List[Operation]) -> None: if isinstance(ir.lvalue.type.type, ElementaryType): if ir.lvalue.type.type.type in ElementaryTypeInt: for r in ir.read: - if r.type.type not in ElementaryTypeInt: + if r.type.type.type not in ElementaryTypeInt: r.set_type(ElementaryType(ir.lvalue.type.type.type)) was_changed = True diff --git a/slither/slithir/operations/call.py b/slither/slithir/operations/call.py index 816c56e1d9..a4f9f6d722 100644 --- a/slither/slithir/operations/call.py +++ b/slither/slithir/operations/call.py @@ -6,9 +6,25 @@ class Call(Operation): - def __init__(self) -> None: + def __init__(self, names: Optional[List[str]] = None) -> None: + """ + #### Parameters + names - + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ + assert (names is None) or isinstance(names, list) super().__init__() self._arguments: List[Variable] = [] + self._names = names + + @property + def names(self) -> Optional[List[str]]: + """ + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ + return self._names @property def arguments(self) -> List[Variable]: diff --git a/slither/slithir/operations/high_level_call.py b/slither/slithir/operations/high_level_call.py index 5d654fc800..c60443f199 100644 --- a/slither/slithir/operations/high_level_call.py +++ b/slither/slithir/operations/high_level_call.py @@ -28,11 +28,18 @@ def __init__( nbr_arguments: int, result: Optional[Union[TemporaryVariable, TupleVariable, TemporaryVariableSSA]], type_call: str, + names: Optional[List[str]] = None, ) -> None: + """ + #### Parameters + names - + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ assert isinstance(function_name, Constant) assert is_valid_lvalue(result) or result is None self._check_destination(destination) - super().__init__() + super().__init__(names=names) # Contract is only possible for library call, which inherits from highlevelcall self._destination: Union[Variable, SolidityVariable, Contract] = destination # type: ignore self._function_name = function_name diff --git a/slither/slithir/operations/init_array.py b/slither/slithir/operations/init_array.py index e0754c7705..ec2a63ef00 100644 --- a/slither/slithir/operations/init_array.py +++ b/slither/slithir/operations/init_array.py @@ -44,4 +44,4 @@ def convert(elem): return f"{elem}({elem.type})" init_values = convert(self.init_values) - return f"{self.lvalue}({self.lvalue.type}) = {init_values}" + return f"{self.lvalue}({self.lvalue.type}) = {init_values}" diff --git a/slither/slithir/operations/internal_call.py b/slither/slithir/operations/internal_call.py index 1983b885fe..06e75136e6 100644 --- a/slither/slithir/operations/internal_call.py +++ b/slither/slithir/operations/internal_call.py @@ -20,8 +20,16 @@ def __init__( Union[TupleVariableSSA, TemporaryVariableSSA, TupleVariable, TemporaryVariable] ], type_call: str, + names: Optional[List[str]] = None, ) -> None: - super().__init__() + # pylint: disable=too-many-arguments + """ + #### Parameters + names - + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ + super().__init__(names=names) self._contract_name = "" if isinstance(function, Function): self._function: Optional[Function] = function diff --git a/slither/slithir/operations/new_array.py b/slither/slithir/operations/new_array.py index 39b989459f..917bb11ee9 100644 --- a/slither/slithir/operations/new_array.py +++ b/slither/slithir/operations/new_array.py @@ -33,4 +33,4 @@ def read(self) -> List["Constant"]: def __str__(self): args = [str(a) for a in self.arguments] lvalue = self.lvalue - return f"{lvalue}{lvalue.type}) = new {self.array_type}({','.join(args)})" + return f"{lvalue}({lvalue.type}) = new {self.array_type}({','.join(args)})" diff --git a/slither/slithir/operations/new_contract.py b/slither/slithir/operations/new_contract.py index 518a097cb5..9ed00b1ac0 100644 --- a/slither/slithir/operations/new_contract.py +++ b/slither/slithir/operations/new_contract.py @@ -12,11 +12,20 @@ class NewContract(Call, OperationWithLValue): # pylint: disable=too-many-instance-attributes def __init__( - self, contract_name: Constant, lvalue: Union[TemporaryVariableSSA, TemporaryVariable] + self, + contract_name: Constant, + lvalue: Union[TemporaryVariableSSA, TemporaryVariable], + names: Optional[List[str]] = None, ) -> None: + """ + #### Parameters + names - + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ assert isinstance(contract_name, Constant) assert is_valid_lvalue(lvalue) - super().__init__() + super().__init__(names=names) self._contract_name = contract_name # todo create analyze to add the contract instance self._lvalue = lvalue diff --git a/slither/slithir/operations/new_structure.py b/slither/slithir/operations/new_structure.py index c50cd6a3e0..2aaba28ff7 100644 --- a/slither/slithir/operations/new_structure.py +++ b/slither/slithir/operations/new_structure.py @@ -1,4 +1,4 @@ -from typing import List, Union +from typing import List, Optional, Union from slither.slithir.operations.call import Call from slither.slithir.operations.lvalue import OperationWithLValue @@ -17,8 +17,15 @@ def __init__( self, structure: StructureContract, lvalue: Union[TemporaryVariableSSA, TemporaryVariable], + names: Optional[List[str]] = None, ) -> None: - super().__init__() + """ + #### Parameters + names - + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ + super().__init__(names=names) assert isinstance(structure, Structure) assert is_valid_lvalue(lvalue) self._structure = structure diff --git a/slither/slithir/operations/unary.py b/slither/slithir/operations/unary.py index c6493921dc..72e7ac63ae 100644 --- a/slither/slithir/operations/unary.py +++ b/slither/slithir/operations/unary.py @@ -5,7 +5,6 @@ from slither.slithir.operations.lvalue import OperationWithLValue from slither.slithir.utils.utils import is_valid_lvalue, is_valid_rvalue from slither.slithir.exceptions import SlithIRError -from slither.core.expressions.unary_operation import UnaryOperationType from slither.core.variables.local_variable import LocalVariable from slither.slithir.variables.constant import Constant from slither.slithir.variables.local_variable import LocalIRVariable @@ -35,7 +34,7 @@ def __init__( self, result: Union[TemporaryVariableSSA, TemporaryVariable], variable: Union[Constant, LocalIRVariable, LocalVariable], - operation_type: UnaryOperationType, + operation_type: UnaryType, ) -> None: assert is_valid_rvalue(variable) assert is_valid_lvalue(result) @@ -53,7 +52,7 @@ def rvalue(self) -> Union[Constant, LocalVariable]: return self._variable @property - def type(self) -> UnaryOperationType: + def type(self) -> UnaryType: return self._type @property diff --git a/slither/slithir/tmp_operations/tmp_call.py b/slither/slithir/tmp_operations/tmp_call.py index 2137ebd819..a7bd614c74 100644 --- a/slither/slithir/tmp_operations/tmp_call.py +++ b/slither/slithir/tmp_operations/tmp_call.py @@ -1,4 +1,4 @@ -from typing import Optional, Union +from typing import List, Optional, Union from slither.core.declarations import ( Event, @@ -25,7 +25,15 @@ def __init__( nbr_arguments: int, result: Union[TupleVariable, TemporaryVariable], type_call: str, + names: Optional[List[str]] = None, ) -> None: + # pylint: disable=too-many-arguments + """ + #### Parameters + names - + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ assert isinstance( called, ( @@ -42,6 +50,7 @@ def __init__( self._called = called self._nbr_arguments = nbr_arguments self._type_call = type_call + self._names = names self._lvalue = result self._ori = None # self._callid = None @@ -49,6 +58,14 @@ def __init__( self._value = None self._salt = None + @property + def names(self) -> Optional[List[str]]: + """ + For calls of the form f({argName1 : arg1, ...}), the names of parameters listed in call order. + Otherwise, None. + """ + return self._names + @property def call_value(self): return self._value diff --git a/slither/slithir/utils/ssa.py b/slither/slithir/utils/ssa.py index 4c958798b4..ef908820eb 100644 --- a/slither/slithir/utils/ssa.py +++ b/slither/slithir/utils/ssa.py @@ -735,12 +735,17 @@ def copy_ir(ir: Operation, *instances) -> Operation: destination = get_variable(ir, lambda x: x.destination, *instances) function_name = ir.function_name nbr_arguments = ir.nbr_arguments + names = ir.names lvalue = get_variable(ir, lambda x: x.lvalue, *instances) type_call = ir.type_call if isinstance(ir, LibraryCall): - new_ir = LibraryCall(destination, function_name, nbr_arguments, lvalue, type_call) + new_ir = LibraryCall( + destination, function_name, nbr_arguments, lvalue, type_call, names=names + ) else: - new_ir = HighLevelCall(destination, function_name, nbr_arguments, lvalue, type_call) + new_ir = HighLevelCall( + destination, function_name, nbr_arguments, lvalue, type_call, names=names + ) new_ir.call_id = ir.call_id new_ir.call_value = get_variable(ir, lambda x: x.call_value, *instances) new_ir.call_gas = get_variable(ir, lambda x: x.call_gas, *instances) @@ -761,7 +766,8 @@ def copy_ir(ir: Operation, *instances) -> Operation: nbr_arguments = ir.nbr_arguments lvalue = get_variable(ir, lambda x: x.lvalue, *instances) type_call = ir.type_call - new_ir = InternalCall(function, nbr_arguments, lvalue, type_call) + names = ir.names + new_ir = InternalCall(function, nbr_arguments, lvalue, type_call, names=names) new_ir.arguments = get_arguments(ir, *instances) return new_ir if isinstance(ir, InternalDynamicCall): @@ -811,7 +817,8 @@ def copy_ir(ir: Operation, *instances) -> Operation: if isinstance(ir, NewStructure): structure = ir.structure lvalue = get_variable(ir, lambda x: x.lvalue, *instances) - new_ir = NewStructure(structure, lvalue) + names = ir.names + new_ir = NewStructure(structure, lvalue, names=names) new_ir.arguments = get_arguments(ir, *instances) return new_ir if isinstance(ir, Nop): diff --git a/slither/solc_parsing/declarations/contract.py b/slither/solc_parsing/declarations/contract.py index 74a1cbcf0d..e7d2745c69 100644 --- a/slither/solc_parsing/declarations/contract.py +++ b/slither/solc_parsing/declarations/contract.py @@ -291,10 +291,10 @@ def _parse_type_alias(self, item: Dict) -> None: alias = item["name"] alias_canonical = self._contract.name + "." + item["name"] - user_defined_type = TypeAliasContract(original_type, alias, self.underlying_contract) - user_defined_type.set_offset(item["src"], self.compilation_unit) - self._contract.file_scope.user_defined_types[alias] = user_defined_type - self._contract.file_scope.user_defined_types[alias_canonical] = user_defined_type + type_alias = TypeAliasContract(original_type, alias, self.underlying_contract) + type_alias.set_offset(item["src"], self.compilation_unit) + self._contract.type_aliases_as_dict[alias] = type_alias + self._contract.file_scope.type_aliases[alias_canonical] = type_alias def _parse_struct(self, struct: Dict) -> None: @@ -319,7 +319,7 @@ def _parse_custom_error(self, custom_error: Dict) -> None: ce.set_contract(self._contract) ce.set_offset(custom_error["src"], self.compilation_unit) - ce_parser = CustomErrorSolc(ce, custom_error, self._slither_parser) + ce_parser = CustomErrorSolc(ce, custom_error, self, self._slither_parser) self._contract.custom_errors_as_dict[ce.name] = ce self._custom_errors_parser.append(ce_parser) diff --git a/slither/solc_parsing/declarations/custom_error.py b/slither/solc_parsing/declarations/custom_error.py index 8cd4592623..34b7ca402f 100644 --- a/slither/solc_parsing/declarations/custom_error.py +++ b/slither/solc_parsing/declarations/custom_error.py @@ -1,4 +1,4 @@ -from typing import TYPE_CHECKING, Dict +from typing import TYPE_CHECKING, Dict, Optional from slither.core.declarations.custom_error import CustomError from slither.core.declarations.custom_error_contract import CustomErrorContract @@ -10,6 +10,7 @@ if TYPE_CHECKING: from slither.solc_parsing.slither_compilation_unit_solc import SlitherCompilationUnitSolc from slither.core.compilation_unit import SlitherCompilationUnit + from slither.solc_parsing.declarations.contract import ContractSolc # Part of the code was copied from the function parsing @@ -21,11 +22,13 @@ def __init__( self, custom_error: CustomError, custom_error_data: dict, + contract_parser: Optional["ContractSolc"], slither_parser: "SlitherCompilationUnitSolc", ) -> None: self._slither_parser: "SlitherCompilationUnitSolc" = slither_parser self._custom_error = custom_error custom_error.name = custom_error_data["name"] + self._contract_parser = contract_parser self._params_was_analyzed = False if not self._slither_parser.is_compact_ast: @@ -56,6 +59,10 @@ def analyze_params(self) -> None: if params: self._parse_params(params) + @property + def contract_parser(self) -> Optional["ContractSolc"]: + return self._contract_parser + @property def is_compact_ast(self) -> bool: return self._slither_parser.is_compact_ast diff --git a/slither/solc_parsing/declarations/using_for_top_level.py b/slither/solc_parsing/declarations/using_for_top_level.py index fe72e57809..bfed3c417c 100644 --- a/slither/solc_parsing/declarations/using_for_top_level.py +++ b/slither/solc_parsing/declarations/using_for_top_level.py @@ -152,7 +152,7 @@ def _propagate_global(self, type_name: Union[TypeAliasTopLevel, UserDefinedType] if self._global: for scope in self.compilation_unit.scopes.values(): if isinstance(type_name, TypeAliasTopLevel): - for alias in scope.user_defined_types.values(): + for alias in scope.type_aliases.values(): if alias == type_name: scope.using_for_directives.add(self._using_for) elif isinstance(type_name, UserDefinedType): diff --git a/slither/solc_parsing/expressions/expression_parsing.py b/slither/solc_parsing/expressions/expression_parsing.py index a0bce044c2..74ff593c70 100644 --- a/slither/solc_parsing/expressions/expression_parsing.py +++ b/slither/solc_parsing/expressions/expression_parsing.py @@ -179,7 +179,8 @@ def parse_call( sp = SuperCallExpression(called, arguments, type_return) sp.set_offset(expression["src"], caller_context.compilation_unit) return sp - call_expression = CallExpression(called, arguments, type_return) + names = expression["names"] if "names" in expression and len(expression["names"]) > 0 else None + call_expression = CallExpression(called, arguments, type_return, names=names) call_expression.set_offset(src, caller_context.compilation_unit) # Only available if the syntax {gas:, value:} was used diff --git a/slither/solc_parsing/expressions/find_variable.py b/slither/solc_parsing/expressions/find_variable.py index 32f5afc584..0a1275f411 100644 --- a/slither/solc_parsing/expressions/find_variable.py +++ b/slither/solc_parsing/expressions/find_variable.py @@ -3,6 +3,8 @@ from slither.core.declarations import Event, Enum, Structure from slither.core.declarations.contract import Contract from slither.core.declarations.custom_error import CustomError +from slither.core.declarations.custom_error_contract import CustomErrorContract +from slither.core.declarations.custom_error_top_level import CustomErrorTopLevel from slither.core.declarations.function import Function from slither.core.declarations.function_contract import FunctionContract from slither.core.declarations.function_top_level import FunctionTopLevel @@ -114,6 +116,8 @@ def find_top_level( :return: :rtype: """ + if var_name in scope.type_aliases: + return scope.type_aliases[var_name], False if var_name in scope.structures: return scope.structures[var_name], False @@ -205,6 +209,10 @@ def _find_in_contract( if sig == var_name: return modifier + type_aliases = contract.type_aliases_as_dict + if var_name in type_aliases: + return type_aliases[var_name] + # structures are looked on the contract declarer structures = contract.structures_as_dict if var_name in structures: @@ -240,6 +248,7 @@ def _find_in_contract( return None +# pylint: disable=too-many-statements def _find_variable_init( caller_context: CallerContextExpression, ) -> Tuple[List[Contract], List["Function"], FileScope,]: @@ -247,6 +256,7 @@ def _find_variable_init( from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.structure_top_level import StructureTopLevelSolc from slither.solc_parsing.variables.top_level_variable import TopLevelVariableSolc + from slither.solc_parsing.declarations.custom_error import CustomErrorSolc direct_contracts: List[Contract] direct_functions_parser: List[Function] @@ -289,6 +299,24 @@ def _find_variable_init( direct_contracts = [] direct_functions_parser = [] scope = caller_context.underlying_variable.file_scope + elif isinstance(caller_context, CustomErrorSolc): + if caller_context.contract_parser: + direct_contracts = [caller_context.contract_parser.underlying_contract] + direct_functions_parser = [ + f.underlying_function + for f in caller_context.contract_parser.functions_parser + + caller_context.contract_parser.modifiers_parser + ] + else: + # Top level custom error + direct_contracts = [] + direct_functions_parser = [] + underlying_custom_error = caller_context.underlying_custom_error + if isinstance(underlying_custom_error, CustomErrorTopLevel): + scope = underlying_custom_error.file_scope + else: + assert isinstance(underlying_custom_error, CustomErrorContract) + scope = underlying_custom_error.contract.file_scope else: raise SlitherError( f"{type(caller_context)} ({caller_context} is not valid for find_variable" @@ -337,6 +365,7 @@ def find_variable( """ from slither.solc_parsing.declarations.function import FunctionSolc from slither.solc_parsing.declarations.contract import ContractSolc + from slither.solc_parsing.declarations.custom_error import CustomErrorSolc # variable are looked from the contract declarer # functions can be shadowed, but are looked from the contract instance, rather than the contract declarer @@ -362,9 +391,6 @@ def find_variable( if var_name in current_scope.renaming: var_name = current_scope.renaming[var_name] - if var_name in current_scope.user_defined_types: - return current_scope.user_defined_types[var_name], False - # Use ret0/ret1 to help mypy ret0 = _find_variable_from_ref_declaration( referenced_declaration, direct_contracts, direct_functions @@ -391,6 +417,15 @@ def find_variable( contract_declarer = underlying_func.contract_declarer else: assert isinstance(underlying_func, FunctionTopLevel) + elif isinstance(caller_context, CustomErrorSolc): + underlying_custom_error = caller_context.underlying_custom_error + if isinstance(underlying_custom_error, CustomErrorContract): + contract = underlying_custom_error.contract + # We check for contract variables here because _find_in_contract + # will return since in this case the contract_declarer is None + for var in contract.variables: + if var_name == var.name: + return var, False ret = _find_in_contract(var_name, contract, contract_declarer, is_super, is_identifier_path) if ret: diff --git a/slither/solc_parsing/slither_compilation_unit_solc.py b/slither/solc_parsing/slither_compilation_unit_solc.py index 00ac3a5192..2d04a70a63 100644 --- a/slither/solc_parsing/slither_compilation_unit_solc.py +++ b/slither/solc_parsing/slither_compilation_unit_solc.py @@ -326,7 +326,7 @@ def parse_top_level_from_loaded_json(self, data_loaded: Dict, filename: str) -> custom_error = CustomErrorTopLevel(self._compilation_unit, scope) custom_error.set_offset(top_level_data["src"], self._compilation_unit) - custom_error_parser = CustomErrorSolc(custom_error, top_level_data, self) + custom_error_parser = CustomErrorSolc(custom_error, top_level_data, None, self) scope.custom_errors.add(custom_error) self._compilation_unit.custom_errors.append(custom_error) self._custom_error_parser.append(custom_error_parser) @@ -344,10 +344,10 @@ def parse_top_level_from_loaded_json(self, data_loaded: Dict, filename: str) -> original_type = ElementaryType(underlying_type["name"]) - user_defined_type = TypeAliasTopLevel(original_type, alias, scope) - user_defined_type.set_offset(top_level_data["src"], self._compilation_unit) - self._compilation_unit.user_defined_value_types[alias] = user_defined_type - scope.user_defined_types[alias] = user_defined_type + type_alias = TypeAliasTopLevel(original_type, alias, scope) + type_alias.set_offset(top_level_data["src"], self._compilation_unit) + self._compilation_unit.type_aliases[alias] = type_alias + scope.type_aliases[alias] = type_alias else: raise SlitherException(f"Top level {top_level_data[self.get_key()]} not supported") diff --git a/slither/solc_parsing/solidity_types/type_parsing.py b/slither/solc_parsing/solidity_types/type_parsing.py index e12290722f..c03b8e6562 100644 --- a/slither/solc_parsing/solidity_types/type_parsing.py +++ b/slither/solc_parsing/solidity_types/type_parsing.py @@ -235,7 +235,7 @@ def parse_type( sl: "SlitherCompilationUnit" renaming: Dict[str, str] - user_defined_types: Dict[str, TypeAlias] + type_aliases: Dict[str, TypeAlias] enums_direct_access: List["Enum"] = [] # Note: for convenicence top level functions use the same parser than function in contract # but contract_parser is set to None @@ -247,13 +247,13 @@ def parse_type( sl = caller_context.compilation_unit next_context = caller_context renaming = {} - user_defined_types = sl.user_defined_value_types + type_aliases = sl.type_aliases else: assert isinstance(caller_context, FunctionSolc) sl = caller_context.underlying_function.compilation_unit next_context = caller_context.slither_parser renaming = caller_context.underlying_function.file_scope.renaming - user_defined_types = caller_context.underlying_function.file_scope.user_defined_types + type_aliases = caller_context.underlying_function.file_scope.type_aliases structures_direct_access = sl.structures_top_level all_structuress = [c.structures for c in sl.contracts] all_structures = [item for sublist in all_structuress for item in sublist] @@ -299,7 +299,7 @@ def parse_type( functions = list(scope.functions) renaming = scope.renaming - user_defined_types = scope.user_defined_types + type_aliases = scope.type_aliases elif isinstance(caller_context, (ContractSolc, FunctionSolc)): sl = caller_context.compilation_unit if isinstance(caller_context, FunctionSolc): @@ -329,7 +329,7 @@ def parse_type( functions = contract.functions + contract.modifiers renaming = scope.renaming - user_defined_types = scope.user_defined_types + type_aliases = scope.type_aliases else: raise ParsingError(f"Incorrect caller context: {type(caller_context)}") @@ -343,8 +343,8 @@ def parse_type( name = t.name if name in renaming: name = renaming[name] - if name in user_defined_types: - return user_defined_types[name] + if name in type_aliases: + return type_aliases[name] return _find_from_type_name( name, functions, @@ -365,9 +365,9 @@ def parse_type( name = t["typeDescriptions"]["typeString"] if name in renaming: name = renaming[name] - if name in user_defined_types: - _add_type_references(user_defined_types[name], t["src"], sl) - return user_defined_types[name] + if name in type_aliases: + _add_type_references(type_aliases[name], t["src"], sl) + return type_aliases[name] type_found = _find_from_type_name( name, functions, @@ -386,9 +386,9 @@ def parse_type( name = t["attributes"][type_name_key] if name in renaming: name = renaming[name] - if name in user_defined_types: - _add_type_references(user_defined_types[name], t["src"], sl) - return user_defined_types[name] + if name in type_aliases: + _add_type_references(type_aliases[name], t["src"], sl) + return type_aliases[name] type_found = _find_from_type_name( name, functions, @@ -407,8 +407,8 @@ def parse_type( name = t["name"] if name in renaming: name = renaming[name] - if name in user_defined_types: - return user_defined_types[name] + if name in type_aliases: + return type_aliases[name] type_found = _find_from_type_name( name, functions, diff --git a/slither/utils/expression_manipulations.py b/slither/utils/expression_manipulations.py index 75d97042c2..32b88e9b32 100644 --- a/slither/utils/expression_manipulations.py +++ b/slither/utils/expression_manipulations.py @@ -147,7 +147,7 @@ def convert_expressions( for next_expr in expression.expressions: # TODO: can we get rid of `NoneType` expressions in `TupleExpression`? # montyly: this might happen with unnamed tuple (ex: (,,,) = f()), but it needs to be checked - if next_expr: + if next_expr is not None: if self.conditional_not_ahead( next_expr, true_expression, false_expression, f_expressions @@ -158,6 +158,9 @@ def convert_expressions( true_expression.expressions[-1], false_expression.expressions[-1], ) + else: + true_expression.expressions.append(None) + false_expression.expressions.append(None) def convert_index_access( self, next_expr: IndexAccess, true_expression: Expression, false_expression: Expression diff --git a/slither/utils/output.py b/slither/utils/output.py index 84c9ac65a1..4a91ca9b9b 100644 --- a/slither/utils/output.py +++ b/slither/utils/output.py @@ -18,6 +18,7 @@ Structure, Pragma, FunctionContract, + CustomError, ) from slither.core.source_mapping.source_mapping import SourceMapping from slither.core.variables.local_variable import LocalVariable @@ -438,6 +439,8 @@ def add(self, add: SupportedOutput, additional_fields: Optional[Dict] = None) -> self.add_event(add, additional_fields=additional_fields) elif isinstance(add, Structure): 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): self.add_pragma(add, additional_fields=additional_fields) elif isinstance(add, Node): @@ -585,6 +588,32 @@ def add_event(self, event: Event, additional_fields: Optional[Dict] = None) -> N 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 ################################################################################### ################################################################################### diff --git a/slither/visitors/slithir/expression_to_slithir.py b/slither/visitors/slithir/expression_to_slithir.py index 005ad81a44..534b157c34 100644 --- a/slither/visitors/slithir/expression_to_slithir.py +++ b/slither/visitors/slithir/expression_to_slithir.py @@ -50,6 +50,7 @@ Member, TypeConversion, Unary, + UnaryType, Unpack, Return, SolidityCall, @@ -109,6 +110,13 @@ def set_val(expression: Expression, val: Any) -> None: BinaryOperationType.OROR: BinaryType.OROR, } + +_unary_to_unary = { + UnaryOperationType.BANG: UnaryType.BANG, + UnaryOperationType.TILD: UnaryType.TILD, +} + + _signed_to_unsigned = { BinaryOperationType.DIVISION_SIGNED: BinaryType.DIVISION, BinaryOperationType.MODULO_SIGNED: BinaryType.MODULO, @@ -304,7 +312,9 @@ def _post_call_expression(self, expression: CallExpression) -> None: val = TupleVariable(self._node) else: val = TemporaryVariable(self._node) - internal_call = InternalCall(called, len(args), val, expression.type_call) + internal_call = InternalCall( + called, len(args), val, expression.type_call, names=expression.names + ) internal_call.set_expression(expression) self._result.append(internal_call) set_val(expression, val) @@ -373,7 +383,9 @@ def _post_call_expression(self, expression: CallExpression) -> None: else: val = TemporaryVariable(self._node) - message_call = TmpCall(called, len(args), val, expression.type_call) + message_call = TmpCall( + called, len(args), val, expression.type_call, names=expression.names + ) message_call.set_expression(expression) # Gas/value are only accessible here if the syntax {gas: , value: } # Is used over .gas().value() @@ -516,8 +528,8 @@ def _post_member_access(self, expression: MemberAccess) -> None: # contract A { type MyInt is int} # contract B { function f() public{ A.MyInt test = A.MyInt.wrap(1);}} # The logic is handled by _post_call_expression - if expression.member_name in expr.file_scope.user_defined_types: - set_val(expression, expr.file_scope.user_defined_types[expression.member_name]) + if expression.member_name in expr.file_scope.type_aliases: + set_val(expression, expr.file_scope.type_aliases[expression.member_name]) return # Lookup errors referred to as member of contract e.g. Test.myError.selector if expression.member_name in expr.custom_errors_as_dict: @@ -585,7 +597,7 @@ def _post_unary_operation(self, expression: UnaryOperation) -> None: operation: Operation if expression.type in [UnaryOperationType.BANG, UnaryOperationType.TILD]: lvalue = TemporaryVariable(self._node) - operation = Unary(lvalue, value, expression.type) + operation = Unary(lvalue, value, _unary_to_unary[expression.type]) operation.set_expression(expression) self._result.append(operation) set_val(expression, lvalue) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_CacheArrayLength_0_8_17_CacheArrayLength_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_CacheArrayLength_0_8_17_CacheArrayLength_sol__0.txt index 456c702a58..c2a5023a6f 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_CacheArrayLength_0_8_17_CacheArrayLength_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_CacheArrayLength_0_8_17_CacheArrayLength_sol__0.txt @@ -1,20 +1,20 @@ -Loop condition `j < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#109) should use cached array length instead of referencing `length` member of the storage array. +Loop condition k_scope_17 < array2.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#133) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `i < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#161) should use cached array length instead of referencing `length` member of the storage array. +Loop condition i_scope_23 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#172) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `i < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#172) should use cached array length instead of referencing `length` member of the storage array. +Loop condition i < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#37) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `j < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#126) should use cached array length instead of referencing `length` member of the storage array. +Loop condition j_scope_11 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#109) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `k < array2.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#133) should use cached array length instead of referencing `length` member of the storage array. +Loop condition i_scope_4 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#68) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `i < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#68) should use cached array length instead of referencing `length` member of the storage array. +Loop condition i_scope_22 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#167) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `k < array2.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#99) should use cached array length instead of referencing `length` member of the storage array. +Loop condition k_scope_9 < array2.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#99) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `i < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#167) should use cached array length instead of referencing `length` member of the storage array. +Loop condition i_scope_6 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#80) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `i < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#37) should use cached array length instead of referencing `length` member of the storage array. +Loop condition j_scope_15 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#126) should use cached array length instead of referencing `length` member of the storage array. -Loop condition `i < array.length` (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#80) should use cached array length instead of referencing `length` member of the storage array. +Loop condition i_scope_21 < array.length (tests/e2e/detectors/test_data/cache-array-length/0.8.17/CacheArrayLength.sol#161) should use cached array length instead of referencing `length` member of the storage array. diff --git a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_4_25_MappingDeletion_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_4_25_MappingDeletion_sol__0.txt index 902f966688..4d47bb5709 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_4_25_MappingDeletion_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_4_25_MappingDeletion_sol__0.txt @@ -1,6 +1,9 @@ +Balances.deleteNestedBalance() (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#40-42) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#17-20) which contains a mapping: + -delete nestedStackBalance (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#41) + Lib.deleteSt(Lib.MyStruct[1]) (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#9-11) deletes Lib.MyStruct (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#5-7) which contains a mapping: -delete st[0] (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#10) -Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#28-31) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#17-20) which contains a mapping: - -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#30) +Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#35-38) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#17-20) which contains a mapping: + -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol#37) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_5_16_MappingDeletion_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_5_16_MappingDeletion_sol__0.txt index fec236e1c2..88e4ac554f 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_5_16_MappingDeletion_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_5_16_MappingDeletion_sol__0.txt @@ -1,6 +1,9 @@ Lib.deleteSt(Lib.MyStruct[1]) (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#9-11) deletes Lib.MyStruct (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#5-7) which contains a mapping: -delete st[0] (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#10) -Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#29-32) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#17-20) which contains a mapping: - -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#31) +Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#35-38) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#17-20) which contains a mapping: + -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#37) + +Balances.deleteNestedBalance() (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#40-42) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#17-20) which contains a mapping: + -delete nestedStackBalance (tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol#41) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_6_11_MappingDeletion_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_6_11_MappingDeletion_sol__0.txt index 7f0372c36d..4270f0d86c 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_6_11_MappingDeletion_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_6_11_MappingDeletion_sol__0.txt @@ -1,6 +1,9 @@ -Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#29-32) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#17-20) which contains a mapping: - -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#31) +Balances.deleteNestedBalance() (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#40-42) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#17-20) which contains a mapping: + -delete nestedStackBalance (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#41) Lib.deleteSt(Lib.MyStruct[1]) (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#9-11) deletes Lib.MyStruct (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#5-7) which contains a mapping: -delete st[0] (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#10) +Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#35-38) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#17-20) which contains a mapping: + -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol#37) + diff --git a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_7_6_MappingDeletion_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_7_6_MappingDeletion_sol__0.txt index f519a046f1..ea6ed2dd6a 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_7_6_MappingDeletion_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_MappingDeletionDetection_0_7_6_MappingDeletion_sol__0.txt @@ -1,5 +1,8 @@ -Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#29-32) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#17-20) which contains a mapping: - -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#31) +Balances.deleteNestedBalance() (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#40-42) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#17-20) which contains a mapping: + -delete nestedStackBalance (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#41) + +Balances.deleteBalance(uint256) (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#35-38) deletes Balances.BalancesStruct (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#17-20) which contains a mapping: + -delete stackBalance[idx] (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#37) Lib.deleteSt(Lib.MyStruct[1]) (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#9-11) deletes Lib.MyStruct (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#5-7) which contains a mapping: -delete st[0] (tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol#10) diff --git a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_4_25_naming_convention_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_4_25_naming_convention_sol__0.txt index ed4177ca17..e4a643678d 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_4_25_naming_convention_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_4_25_naming_convention_sol__0.txt @@ -1,10 +1,10 @@ Struct naming.test (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#14-16) is not in CapWords -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#69) is not in mixedCase +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#70) is not in mixedCase -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#69) is single letter l, O, or I, which should not be used +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#70) is single letter l, O, or I, which should not be used -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#68) is not in mixedCase +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#69) is not in mixedCase Variable naming.Var_One (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#11) is not in mixedCase @@ -14,11 +14,11 @@ Contract naming (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_c Enum naming.numbers (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#6) is not in CapWords -Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#59) is not in mixedCase +Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#60) is not in mixedCase -Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#56) is not in mixedCase +Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#57) is not in mixedCase -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#68) is single letter l, O, or I, which should not be used +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#69) is single letter l, O, or I, which should not be used Event naming.event_(uint256) (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#23) is not in CapWords @@ -26,7 +26,7 @@ Modifier naming.CantDo() (tests/e2e/detectors/test_data/naming-convention/0.4.25 Function naming.GetOne() (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#30-33) is not in mixedCase -Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#67) is single letter l, O, or I, which should not be used +Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#68) is single letter l, O, or I, which should not be used Parameter naming.setInt(uint256,uint256).Number2 (tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol#35) is not in mixedCase diff --git a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_5_16_naming_convention_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_5_16_naming_convention_sol__0.txt index 35c11193f5..96f6aab3c6 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_5_16_naming_convention_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_5_16_naming_convention_sol__0.txt @@ -1,10 +1,10 @@ Struct naming.test (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#14-16) is not in CapWords -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#69) is not in mixedCase +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#70) is not in mixedCase -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#69) is single letter l, O, or I, which should not be used +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#70) is single letter l, O, or I, which should not be used -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#68) is not in mixedCase +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#69) is not in mixedCase Variable naming.Var_One (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#11) is not in mixedCase @@ -14,11 +14,11 @@ Contract naming (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_c Enum naming.numbers (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#6) is not in CapWords -Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#59) is not in mixedCase +Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#60) is not in mixedCase -Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#56) is not in mixedCase +Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#57) is not in mixedCase -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#68) is single letter l, O, or I, which should not be used +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#69) is single letter l, O, or I, which should not be used Event naming.event_(uint256) (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#23) is not in CapWords @@ -26,7 +26,7 @@ Modifier naming.CantDo() (tests/e2e/detectors/test_data/naming-convention/0.5.16 Function naming.GetOne() (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#30-33) is not in mixedCase -Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#67) is single letter l, O, or I, which should not be used +Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#68) is single letter l, O, or I, which should not be used Parameter naming.setInt(uint256,uint256).Number2 (tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol#35) is not in mixedCase diff --git a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_6_11_naming_convention_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_6_11_naming_convention_sol__0.txt index f692e211b8..f1986fb781 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_6_11_naming_convention_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_6_11_naming_convention_sol__0.txt @@ -1,10 +1,10 @@ Struct naming.test (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#14-16) is not in CapWords -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#69) is not in mixedCase +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#70) is not in mixedCase -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#69) is single letter l, O, or I, which should not be used +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#70) is single letter l, O, or I, which should not be used -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#68) is not in mixedCase +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#69) is not in mixedCase Variable naming.Var_One (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#11) is not in mixedCase @@ -14,11 +14,11 @@ Contract naming (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_c Enum naming.numbers (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#6) is not in CapWords -Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#59) is not in mixedCase +Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#60) is not in mixedCase -Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#56) is not in mixedCase +Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#57) is not in mixedCase -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#68) is single letter l, O, or I, which should not be used +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#69) is single letter l, O, or I, which should not be used Event naming.event_(uint256) (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#23) is not in CapWords @@ -26,7 +26,7 @@ Modifier naming.CantDo() (tests/e2e/detectors/test_data/naming-convention/0.6.11 Function naming.GetOne() (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#30-33) is not in mixedCase -Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#67) is single letter l, O, or I, which should not be used +Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#68) is single letter l, O, or I, which should not be used Parameter naming.setInt(uint256,uint256).Number2 (tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol#35) is not in mixedCase diff --git a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_7_6_naming_convention_sol__0.txt b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_7_6_naming_convention_sol__0.txt index af17cabe8f..b471cbfa2f 100644 --- a/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_7_6_naming_convention_sol__0.txt +++ b/tests/e2e/detectors/snapshots/detectors__detector_NamingConvention_0_7_6_naming_convention_sol__0.txt @@ -1,10 +1,10 @@ Struct naming.test (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#14-16) is not in CapWords -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#69) is not in mixedCase +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#70) is not in mixedCase -Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#69) is single letter l, O, or I, which should not be used +Variable T.I (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#70) is single letter l, O, or I, which should not be used -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#68) is not in mixedCase +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#69) is not in mixedCase Variable naming.Var_One (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#11) is not in mixedCase @@ -14,11 +14,11 @@ Contract naming (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_co Enum naming.numbers (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#6) is not in CapWords -Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#59) is not in mixedCase +Parameter T.test(uint256,uint256)._used (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#60) is not in mixedCase -Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#56) is not in mixedCase +Variable T._myPublicVar (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#57) is not in mixedCase -Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#68) is single letter l, O, or I, which should not be used +Variable T.O (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#69) is single letter l, O, or I, which should not be used Event naming.event_(uint256) (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#23) is not in CapWords @@ -26,7 +26,7 @@ Modifier naming.CantDo() (tests/e2e/detectors/test_data/naming-convention/0.7.6/ Function naming.GetOne() (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#30-33) is not in mixedCase -Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#67) is single letter l, O, or I, which should not be used +Variable T.l (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#68) is single letter l, O, or I, which should not be used Parameter naming.setInt(uint256,uint256).Number2 (tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol#35) is not in mixedCase diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol b/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol index bedbb64a8f..bcbc86c9d1 100644 --- a/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol +++ b/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol @@ -6,7 +6,7 @@ library Lib{ mapping(address => uint) maps; } - function deleteSt(MyStruct[1] storage st){ + function deleteSt(MyStruct[1] storage st) internal { delete st[0]; } @@ -17,18 +17,29 @@ contract Balances { struct BalancesStruct{ address owner; mapping(address => uint) balances; - } + } + + struct NestedBalanceStruct { + BalancesStruct balanceStruct; + } mapping(uint => BalancesStruct) public stackBalance; + NestedBalanceStruct internal nestedStackBalance; + function createBalance(uint idx) public { - require(stackBalance[idx].owner == 0); - stackBalance[idx] = BalancesStruct(msg.sender); + require(stackBalance[idx].owner == address(0)); + BalancesStruct storage str = stackBalance[idx]; + str.owner = msg.sender; } function deleteBalance(uint idx) public { require(stackBalance[idx].owner == msg.sender); delete stackBalance[idx]; } + + function deleteNestedBalance() public { + delete nestedStackBalance; + } function setBalance(uint idx, address addr, uint val) public { require(stackBalance[idx].owner == msg.sender); diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol-0.4.25.zip b/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol-0.4.25.zip index be3e13807a..5885936995 100644 Binary files a/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol-0.4.25.zip and b/tests/e2e/detectors/test_data/mapping-deletion/0.4.25/MappingDeletion.sol-0.4.25.zip differ diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol b/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol index e1b608a463..bcbc86c9d1 100644 --- a/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol +++ b/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol @@ -17,9 +17,15 @@ contract Balances { struct BalancesStruct{ address owner; mapping(address => uint) balances; - } + } + + struct NestedBalanceStruct { + BalancesStruct balanceStruct; + } mapping(uint => BalancesStruct) public stackBalance; + NestedBalanceStruct internal nestedStackBalance; + function createBalance(uint idx) public { require(stackBalance[idx].owner == address(0)); BalancesStruct storage str = stackBalance[idx]; @@ -30,6 +36,10 @@ contract Balances { require(stackBalance[idx].owner == msg.sender); delete stackBalance[idx]; } + + function deleteNestedBalance() public { + delete nestedStackBalance; + } function setBalance(uint idx, address addr, uint val) public { require(stackBalance[idx].owner == msg.sender); diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol-0.5.16.zip b/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol-0.5.16.zip index 0ad84a5889..2e57890461 100644 Binary files a/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol-0.5.16.zip and b/tests/e2e/detectors/test_data/mapping-deletion/0.5.16/MappingDeletion.sol-0.5.16.zip differ diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol b/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol index e1b608a463..bcbc86c9d1 100644 --- a/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol +++ b/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol @@ -17,9 +17,15 @@ contract Balances { struct BalancesStruct{ address owner; mapping(address => uint) balances; - } + } + + struct NestedBalanceStruct { + BalancesStruct balanceStruct; + } mapping(uint => BalancesStruct) public stackBalance; + NestedBalanceStruct internal nestedStackBalance; + function createBalance(uint idx) public { require(stackBalance[idx].owner == address(0)); BalancesStruct storage str = stackBalance[idx]; @@ -30,6 +36,10 @@ contract Balances { require(stackBalance[idx].owner == msg.sender); delete stackBalance[idx]; } + + function deleteNestedBalance() public { + delete nestedStackBalance; + } function setBalance(uint idx, address addr, uint val) public { require(stackBalance[idx].owner == msg.sender); diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol-0.6.11.zip b/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol-0.6.11.zip index 5f66da0617..8f532ea669 100644 Binary files a/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol-0.6.11.zip and b/tests/e2e/detectors/test_data/mapping-deletion/0.6.11/MappingDeletion.sol-0.6.11.zip differ diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol b/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol index e1b608a463..bcbc86c9d1 100644 --- a/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol +++ b/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol @@ -17,9 +17,15 @@ contract Balances { struct BalancesStruct{ address owner; mapping(address => uint) balances; - } + } + + struct NestedBalanceStruct { + BalancesStruct balanceStruct; + } mapping(uint => BalancesStruct) public stackBalance; + NestedBalanceStruct internal nestedStackBalance; + function createBalance(uint idx) public { require(stackBalance[idx].owner == address(0)); BalancesStruct storage str = stackBalance[idx]; @@ -30,6 +36,10 @@ contract Balances { require(stackBalance[idx].owner == msg.sender); delete stackBalance[idx]; } + + function deleteNestedBalance() public { + delete nestedStackBalance; + } function setBalance(uint idx, address addr, uint val) public { require(stackBalance[idx].owner == msg.sender); diff --git a/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol-0.7.6.zip b/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol-0.7.6.zip index 5888e0e534..c685454ce6 100644 Binary files a/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol-0.7.6.zip and b/tests/e2e/detectors/test_data/mapping-deletion/0.7.6/MappingDeletion.sol-0.7.6.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol b/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol index 7181ca9110..add7867e07 100644 --- a/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol +++ b/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol @@ -53,7 +53,8 @@ contract Test { contract T { uint private _myPrivateVar; - uint _myPublicVar; + uint internal _myInternalVar; + uint public _myPublicVar; function test(uint _unused, uint _used) public returns(uint){ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol-0.4.25.zip b/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol-0.4.25.zip index c7aaae071d..fe35f0c006 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol-0.4.25.zip and b/tests/e2e/detectors/test_data/naming-convention/0.4.25/naming_convention.sol-0.4.25.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.4.25/no_warning_for_public_constants.sol-0.4.25.zip b/tests/e2e/detectors/test_data/naming-convention/0.4.25/no_warning_for_public_constants.sol-0.4.25.zip index 2726a771d1..b8c6c58c1d 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.4.25/no_warning_for_public_constants.sol-0.4.25.zip and b/tests/e2e/detectors/test_data/naming-convention/0.4.25/no_warning_for_public_constants.sol-0.4.25.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol b/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol index 7181ca9110..add7867e07 100644 --- a/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol +++ b/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol @@ -53,7 +53,8 @@ contract Test { contract T { uint private _myPrivateVar; - uint _myPublicVar; + uint internal _myInternalVar; + uint public _myPublicVar; function test(uint _unused, uint _used) public returns(uint){ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol-0.5.16.zip b/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol-0.5.16.zip index da900f1f69..6c732f786e 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol-0.5.16.zip and b/tests/e2e/detectors/test_data/naming-convention/0.5.16/naming_convention.sol-0.5.16.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.5.16/no_warning_for_public_constants.sol-0.5.16.zip b/tests/e2e/detectors/test_data/naming-convention/0.5.16/no_warning_for_public_constants.sol-0.5.16.zip index 160fee3a22..600f68386b 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.5.16/no_warning_for_public_constants.sol-0.5.16.zip and b/tests/e2e/detectors/test_data/naming-convention/0.5.16/no_warning_for_public_constants.sol-0.5.16.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol b/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol index 7181ca9110..add7867e07 100644 --- a/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol +++ b/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol @@ -53,7 +53,8 @@ contract Test { contract T { uint private _myPrivateVar; - uint _myPublicVar; + uint internal _myInternalVar; + uint public _myPublicVar; function test(uint _unused, uint _used) public returns(uint){ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol-0.6.11.zip b/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol-0.6.11.zip index 3e6277ac1b..b916970874 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol-0.6.11.zip and b/tests/e2e/detectors/test_data/naming-convention/0.6.11/naming_convention.sol-0.6.11.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.6.11/no_warning_for_public_constants.sol-0.6.11.zip b/tests/e2e/detectors/test_data/naming-convention/0.6.11/no_warning_for_public_constants.sol-0.6.11.zip index 67f8eff7ee..ed813d07b9 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.6.11/no_warning_for_public_constants.sol-0.6.11.zip and b/tests/e2e/detectors/test_data/naming-convention/0.6.11/no_warning_for_public_constants.sol-0.6.11.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol b/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol index 7181ca9110..add7867e07 100644 --- a/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol +++ b/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol @@ -53,7 +53,8 @@ contract Test { contract T { uint private _myPrivateVar; - uint _myPublicVar; + uint internal _myInternalVar; + uint public _myPublicVar; function test(uint _unused, uint _used) public returns(uint){ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol-0.7.6.zip b/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol-0.7.6.zip index cc9d43c582..f1e3a8ad55 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol-0.7.6.zip and b/tests/e2e/detectors/test_data/naming-convention/0.7.6/naming_convention.sol-0.7.6.zip differ diff --git a/tests/e2e/detectors/test_data/naming-convention/0.7.6/no_warning_for_public_constants.sol-0.7.6.zip b/tests/e2e/detectors/test_data/naming-convention/0.7.6/no_warning_for_public_constants.sol-0.7.6.zip index 7b304b5c0c..9f2c1a1a7d 100644 Binary files a/tests/e2e/detectors/test_data/naming-convention/0.7.6/no_warning_for_public_constants.sol-0.7.6.zip and b/tests/e2e/detectors/test_data/naming-convention/0.7.6/no_warning_for_public_constants.sol-0.7.6.zip differ diff --git a/tests/e2e/solc_parsing/test_ast_parsing.py b/tests/e2e/solc_parsing/test_ast_parsing.py index 307e6736ff..28ac79986d 100644 --- a/tests/e2e/solc_parsing/test_ast_parsing.py +++ b/tests/e2e/solc_parsing/test_ast_parsing.py @@ -459,6 +459,7 @@ def make_version(minor: int, patch_min: int, patch_max: int) -> List[str]: ["0.6.9", "0.7.6", "0.8.16"], ), Test("user_defined_operators-0.8.19.sol", ["0.8.19"]), + Test("type-aliases.sol", ["0.8.19"]), ] # create the output folder if needed try: diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.10-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.10-compact.zip index fc45cb40e2..c88ab3209e 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.10-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.10-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.11-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.11-compact.zip index 853879cf56..f49cefb4fa 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.11-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.11-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.12-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.12-compact.zip index c72629231a..11e9f5c769 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.12-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.12-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.13-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.13-compact.zip index 9ada2c3351..bfe3abf69d 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.13-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.13-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.14-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.14-compact.zip index e36f5b94e5..fcb0fd1f45 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.14-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.14-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.15-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.15-compact.zip index 1023ab1d45..2050e256ab 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.15-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.15-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.4-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.4-compact.zip index 5ecf2b037a..d31650594c 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.4-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.4-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.5-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.5-compact.zip index 357554c09b..a5551ea094 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.5-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.5-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.6-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.6-compact.zip index c5f05ef201..006cd15705 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.6-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.6-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.7-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.7-compact.zip index 51828bce7f..95f411a302 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.7-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.7-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.8-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.8-compact.zip index eb6ba091b4..f0da5dfc49 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.8-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.8-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.9-compact.zip b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.9-compact.zip index 17e7520185..f407956184 100644 Binary files a/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.9-compact.zip and b/tests/e2e/solc_parsing/test_data/compile/custom_error-0.8.4.sol-0.8.9-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/compile/type-aliases.sol-0.8.19-compact.zip b/tests/e2e/solc_parsing/test_data/compile/type-aliases.sol-0.8.19-compact.zip new file mode 100644 index 0000000000..0c4d2b1c5e Binary files /dev/null and b/tests/e2e/solc_parsing/test_data/compile/type-aliases.sol-0.8.19-compact.zip differ diff --git a/tests/e2e/solc_parsing/test_data/custom_error-0.8.4.sol b/tests/e2e/solc_parsing/test_data/custom_error-0.8.4.sol index 4e1e388fb1..e638b8d41c 100644 --- a/tests/e2e/solc_parsing/test_data/custom_error-0.8.4.sol +++ b/tests/e2e/solc_parsing/test_data/custom_error-0.8.4.sol @@ -8,13 +8,19 @@ struct St{ uint v; } +uint256 constant MAX = 5; + error ErrorSimple(); error ErrorWithArgs(uint, uint); error ErrorWithStruct(St s); +error ErrorWithConst(uint256[MAX]); contract VendingMachine is I { + uint256 constant CMAX = 10; + error CErrorWithConst(uint256[CMAX]); + function err0() public { revert ErrorSimple(); } @@ -32,6 +38,14 @@ contract VendingMachine is I { function err4() public { revert ErrorWithEnum(SomeEnum.ONE); } + function err5(uint256[MAX] calldata a) public { + revert ErrorWithConst(a); + } + function err6(uint256[CMAX] calldata a) public { + revert CErrorWithConst(a); + } + + } contract A{ diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.10-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.10-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.10-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.10-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.11-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.11-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.11-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.11-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.12-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.12-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.12-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.12-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.13-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.13-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.13-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.13-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.14-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.14-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.14-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.14-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.15-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.15-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.15-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.15-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.4-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.4-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.4-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.4-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.5-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.5-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.5-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.5-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.6-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.6-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.6-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.6-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.7-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.7-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.7-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.7-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.8-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.8-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.8-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.8-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.9-compact.json b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.9-compact.json index 9020c8d522..0707fa1498 100644 --- a/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.9-compact.json +++ b/tests/e2e/solc_parsing/test_data/expected/custom_error-0.8.4.sol-0.8.9-compact.json @@ -5,7 +5,9 @@ "err1()": "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: EXPRESSION 2\n\"];\n}\n", "err2()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n1->2;\n2[label=\"Node Type: EXPRESSION 2\n\"];\n}\n", "err3()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", - "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" + "err4()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err5(uint256[5])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n", + "err6(uint256[10])": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" }, "A": { "f()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: EXPRESSION 1\n\"];\n}\n" diff --git a/tests/e2e/solc_parsing/test_data/expected/type-aliases.sol-0.8.19-compact.json b/tests/e2e/solc_parsing/test_data/expected/type-aliases.sol-0.8.19-compact.json new file mode 100644 index 0000000000..e76cc99ffd --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/expected/type-aliases.sol-0.8.19-compact.json @@ -0,0 +1,6 @@ +{ + "OtherTest": { + "myfunc()": "digraph{\n0[label=\"Node Type: ENTRY_POINT 0\n\"];\n0->1;\n1[label=\"Node Type: NEW VARIABLE 1\n\"];\n}\n" + }, + "DeleteTest": {} +} \ No newline at end of file diff --git a/tests/e2e/solc_parsing/test_data/type-aliases.sol b/tests/e2e/solc_parsing/test_data/type-aliases.sol new file mode 100644 index 0000000000..53fdaabeb8 --- /dev/null +++ b/tests/e2e/solc_parsing/test_data/type-aliases.sol @@ -0,0 +1,20 @@ + +struct Z { + int x; + int y; +} + +contract OtherTest { + struct Z { + int x; + int y; + } + + function myfunc() external { + Z memory z = Z(2,3); + } +} + +contract DeleteTest { + type Z is int; +} diff --git a/tests/unit/core/test_source_mapping.py b/tests/unit/core/test_source_mapping.py index fe53359777..55eb082950 100644 --- a/tests/unit/core/test_source_mapping.py +++ b/tests/unit/core/test_source_mapping.py @@ -85,15 +85,13 @@ def test_references_user_defined_aliases(solc_binary_path): file = Path(SRC_MAPPING_TEST_ROOT, "ReferencesUserDefinedAliases.sol").as_posix() slither = Slither(file, solc=solc_path) - alias_top_level = slither.compilation_units[0].user_defined_value_types["aliasTopLevel"] + alias_top_level = slither.compilation_units[0].type_aliases["aliasTopLevel"] assert len(alias_top_level.references) == 2 lines = _sort_references_lines(alias_top_level.references) assert lines == [12, 16] alias_contract_level = ( - slither.compilation_units[0] - .contracts[0] - .file_scope.user_defined_types["C.aliasContractLevel"] + slither.compilation_units[0].contracts[0].file_scope.type_aliases["C.aliasContractLevel"] ) assert len(alias_contract_level.references) == 2 lines = _sort_references_lines(alias_contract_level.references) diff --git a/tests/unit/slithir/test_argument_reorder.py b/tests/unit/slithir/test_argument_reorder.py new file mode 100644 index 0000000000..12f5bd7f28 --- /dev/null +++ b/tests/unit/slithir/test_argument_reorder.py @@ -0,0 +1,65 @@ +from pathlib import Path + +from slither import Slither +from slither.slithir.operations.internal_call import InternalCall +from slither.slithir.operations.new_structure import NewStructure +from slither.slithir.variables.constant import Constant + +TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" +ARG_REORDER_TEST_ROOT = Path(TEST_DATA_DIR, "argument_reorder") + + +def test_struct_constructor_reorder(solc_binary_path) -> None: + solc_path = solc_binary_path("0.8.15") + slither = Slither( + Path(ARG_REORDER_TEST_ROOT, "test_struct_constructor.sol").as_posix(), solc=solc_path + ) + + operations = slither.contracts[0].functions[0].slithir_operations + constructor_calls = [x for x in operations if isinstance(x, NewStructure)] + assert len(constructor_calls) == 2 + + # Arguments to first call are 2, 3 + assert ( + isinstance(constructor_calls[0].arguments[0], Constant) + and constructor_calls[0].arguments[0].value == 2 + ) + assert ( + isinstance(constructor_calls[0].arguments[1], Constant) + and constructor_calls[0].arguments[1].value == 3 + ) + + # Arguments to second call are 5, 4 (note the reversed order) + assert ( + isinstance(constructor_calls[1].arguments[0], Constant) + and constructor_calls[1].arguments[0].value == 5 + ) + assert ( + isinstance(constructor_calls[1].arguments[1], Constant) + and constructor_calls[1].arguments[1].value == 4 + ) + + +def test_internal_call_reorder(solc_binary_path) -> None: + solc_path = solc_binary_path("0.8.15") + slither = Slither( + Path(ARG_REORDER_TEST_ROOT, "test_internal_call_reorder.sol").as_posix(), solc=solc_path + ) + + operations = slither.contracts[0].functions[1].slithir_operations + internal_calls = [x for x in operations if isinstance(x, InternalCall)] + assert len(internal_calls) == 1 + + # Arguments to call are 3, true, 5 + assert ( + isinstance(internal_calls[0].arguments[0], Constant) + and internal_calls[0].arguments[0].value == 3 + ) + assert ( + isinstance(internal_calls[0].arguments[1], Constant) + and internal_calls[0].arguments[1].value is True + ) + assert ( + isinstance(internal_calls[0].arguments[2], Constant) + and internal_calls[0].arguments[2].value == 5 + ) diff --git a/tests/unit/slithir/test_data/argument_reorder/test_internal_call_reorder.sol b/tests/unit/slithir/test_data/argument_reorder/test_internal_call_reorder.sol new file mode 100644 index 0000000000..4c4f658da8 --- /dev/null +++ b/tests/unit/slithir/test_data/argument_reorder/test_internal_call_reorder.sol @@ -0,0 +1,8 @@ +contract InternalCallReorderTest { + function internal_func(uint256 a, bool b, uint256 c) internal { + } + + function caller() external { + internal_func({a: 3, c: 5, b: true}); + } +} diff --git a/tests/unit/slithir/test_data/argument_reorder/test_struct_constructor.sol b/tests/unit/slithir/test_data/argument_reorder/test_struct_constructor.sol new file mode 100644 index 0000000000..05dbb50b0f --- /dev/null +++ b/tests/unit/slithir/test_data/argument_reorder/test_struct_constructor.sol @@ -0,0 +1,11 @@ +contract StructConstructorTest { + struct S { + int x; + int y; + } + + function test() external { + S memory p = S({x: 2, y: 3}); + S memory q = S({y: 4, x: 5}); + } +} diff --git a/tests/unit/slithir/test_data/ternary_expressions.sol b/tests/unit/slithir/test_data/ternary_expressions.sol index ebfb96e801..1ccd51d34d 100644 --- a/tests/unit/slithir/test_data/ternary_expressions.sol +++ b/tests/unit/slithir/test_data/ternary_expressions.sol @@ -1,6 +1,6 @@ interface Test { function test() external payable returns (uint); - function testTuple() external payable returns (uint, uint); + function testTuple(uint) external payable returns (uint, uint); } contract C { // TODO @@ -36,21 +36,23 @@ contract C { } // Unused tuple variable - function g(address one) public { - (, uint x) = Test(one).testTuple(); - } - uint[] myIntegers; - function _h(uint c) internal returns(uint) { - return c; - } - function h(bool cond, uint a, uint b) public { - uint d = _h( - myIntegers[cond ? a : b] - ); + function g(address one, bool cond, uint a, uint b) public { + (, uint x) = Test(one).testTuple(myIntegers[cond ? a : b]); } - - function i(bool cond) public { + + function h(bool cond) public { bytes memory a = new bytes(cond ? 1 : 2); } } + +contract D { + function values(uint n) internal returns (uint, uint) { + return (0, 1); + } + + function a(uint n) external { + uint a; + (a,) = values(n > 0 ? 1 : 0); + } +} diff --git a/tests/unit/slithir/test_ssa_generation.py b/tests/unit/slithir/test_ssa_generation.py index 3c7e84973f..b8772ca612 100644 --- a/tests/unit/slithir/test_ssa_generation.py +++ b/tests/unit/slithir/test_ssa_generation.py @@ -11,7 +11,7 @@ from slither import Slither from slither.core.cfg.node import Node, NodeType from slither.core.declarations import Function, Contract -from slither.core.solidity_types import ArrayType +from slither.core.solidity_types import ArrayType, ElementaryType from slither.core.variables.local_variable import LocalVariable from slither.core.variables.state_variable import StateVariable from slither.slithir.operations import ( @@ -1116,3 +1116,23 @@ def test_issue_1846_ternary_in_ternary(slither_from_source): assert node.type == NodeType.IF assert node.son_true.type == NodeType.IF assert node.son_false.type == NodeType.EXPRESSION + + +def test_issue_2016(slither_from_source): + source = """ + contract Contract { + function test() external { + int[] memory a = new int[](5); + } + } + """ + with slither_from_source(source) as slither: + c = slither.get_contract_from_name("Contract")[0] + f = c.functions[0] + operations = f.slithir_operations + new_op = operations[0] + lvalue = new_op.lvalue + lvalue_type = lvalue.type + assert isinstance(lvalue_type, ArrayType) + assert lvalue_type.type == ElementaryType("int256") + assert lvalue_type.is_dynamic diff --git a/tests/unit/slithir/test_ternary_expressions.py b/tests/unit/slithir/test_ternary_expressions.py index 0acd9345d7..bf8556f85d 100644 --- a/tests/unit/slithir/test_ternary_expressions.py +++ b/tests/unit/slithir/test_ternary_expressions.py @@ -1,8 +1,13 @@ from pathlib import Path from slither import Slither from slither.core.cfg.node import NodeType -from slither.slithir.operations import Assignment -from slither.core.expressions import AssignmentOperation, TupleExpression +from slither.slithir.operations import Assignment, Unpack +from slither.core.expressions import ( + AssignmentOperation, + TupleExpression, + NewElementaryType, + CallExpression, +) TEST_DATA_DIR = Path(__file__).resolve().parent / "test_data" @@ -11,28 +16,53 @@ def test_ternary_conversions(solc_binary_path) -> None: """This tests that true and false sons define the same number of variables that the father node declares""" solc_path = solc_binary_path("0.8.0") slither = Slither(Path(TEST_DATA_DIR, "ternary_expressions.sol").as_posix(), solc=solc_path) - for contract in slither.contracts: - for function in contract.functions: - vars_declared = 0 - vars_assigned = 0 - for node in function.nodes: - if node.type in [NodeType.IF, NodeType.IFLOOP]: - - # Iterate over true and false son - for inner_node in node.sons: - # Count all variables declared - expression = inner_node.expression - if isinstance(expression, AssignmentOperation): - var_expr = expression.expression_left - # Only tuples declare more than one var - if isinstance(var_expr, TupleExpression): - vars_declared += len(var_expr.expressions) - else: - vars_declared += 1 - - for ir in inner_node.irs: - # Count all variables defined - if isinstance(ir, Assignment): - vars_assigned += 1 - - assert vars_declared == vars_assigned + contract = next(c for c in slither.contracts if c.name == "C") + for function in contract.functions: + vars_declared = 0 + vars_assigned = 0 + for node in function.nodes: + if node.type in [NodeType.IF, NodeType.IFLOOP]: + + # Iterate over true and false son + for inner_node in node.sons: + # Count all variables declared + expression = inner_node.expression + if isinstance( + expression, (AssignmentOperation, NewElementaryType, CallExpression) + ): + var_expr = expression.expression_left + # Only tuples declare more than one var + if isinstance(var_expr, TupleExpression): + vars_declared += len(var_expr.expressions) + else: + vars_declared += 1 + + for ir in inner_node.irs: + # Count all variables defined + if isinstance(ir, (Assignment, Unpack)): + vars_assigned += 1 + assert vars_declared == vars_assigned and vars_assigned != 0 + + +def test_ternary_tuple(solc_binary_path) -> None: + """ + Test that in the ternary liftings of an assignment of the form `(z, ) = ...`, + we obtain `z` from an unpack operation in both lifitings + """ + solc_path = solc_binary_path("0.8.0") + slither = Slither(Path(TEST_DATA_DIR, "ternary_expressions.sol").as_posix(), solc=solc_path) + contract = next(c for c in slither.contracts if c.name == "D") + fn = next(f for f in contract.functions if f.name == "a") + + if_nodes = [n for n in fn.nodes if n.type == NodeType.IF] + assert len(if_nodes) == 1 + + if_node = if_nodes[0] + assert isinstance(if_node.son_true.expression, AssignmentOperation) + assert ( + len([ir for ir in if_node.son_true.all_slithir_operations() if isinstance(ir, Unpack)]) == 1 + ) + assert ( + len([ir for ir in if_node.son_false.all_slithir_operations() if isinstance(ir, Unpack)]) + == 1 + )