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)
-
+
[![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
+ )