Compare commits

..

No commits in common. "develop" and "v0.8.21" have entirely different histories.

840 changed files with 12246 additions and 16123 deletions

View File

@ -179,199 +179,47 @@ commands:
paths: paths:
- << parameters.install_path >> - << parameters.install_path >>
# -------------------------------------------------------------------------- defaults:
# Build Commands
setup_prerelease_commit_hash: # --------------------------------------------------------------------------
steps: # Build Templates
- run:
- setup_prerelease_commit_hash: &setup_prerelease_commit_hash
name: Store commit hash and prerelease name: Store commit hash and prerelease
command: | command: |
if [[ $CIRCLE_BRANCH == release || -n $CIRCLE_TAG ]]; then if [ "$CIRCLE_BRANCH" = release -o -n "$CIRCLE_TAG" ]; then echo -n > prerelease.txt; else date -u +"nightly.%Y.%-m.%-d" > prerelease.txt; fi
echo -n > prerelease.txt;
else
date -u +"nightly.%Y.%-m.%-d" > prerelease.txt;
fi
echo -n "$CIRCLE_SHA1" > commit_hash.txt echo -n "$CIRCLE_SHA1" > commit_hash.txt
run_build: - run_build: &run_build
steps:
- run:
name: Build name: Build
command: scripts/ci/build.sh command: scripts/ci/build.sh
run_build_ossfuzz: - run_build_ossfuzz: &run_build_ossfuzz
steps:
- run:
name: Build_ossfuzz name: Build_ossfuzz
command: scripts/ci/build_ossfuzz.sh command: scripts/ci/build_ossfuzz.sh
run_proofs: - run_proofs: &run_proofs
steps:
- run:
name: Correctness proofs for optimization rules name: Correctness proofs for optimization rules
command: scripts/run_proofs.sh command: scripts/run_proofs.sh
run_soltest: - run_soltest: &run_soltest
steps:
- run:
name: soltest name: soltest
no_output_timeout: 30m no_output_timeout: 30m
command: .circleci/soltest.sh command: ./.circleci/soltest.sh
run_soltest_all: - run_soltest_all: &run_soltest_all
steps:
- run:
name: soltest_all name: soltest_all
no_output_timeout: 30m no_output_timeout: 30m
command: .circleci/soltest_all.sh command: ./.circleci/soltest_all.sh
run_cmdline_tests: - run_cmdline_tests: &run_cmdline_tests
steps:
- run:
name: command line tests name: command line tests
no_output_timeout: 30m no_output_timeout: 30m
command: .circleci/parallel_cli_tests.py command: .circleci/parallel_cli_tests.py
run_docs_pragma_min_version: - run_docs_pragma_min_version: &run_docs_pragma_min_version
steps:
- run:
name: docs pragma version check name: docs pragma version check
command: scripts/docs_version_pragma_check.sh command: ./scripts/docs_version_pragma_check.sh
# --------------------------------------------------------------------------
# Artifact Commands
store_artifacts_solc:
description: Store compiled solc executable as artifact
steps:
- store_artifacts:
path: build/solc/solc
destination: solc
store_artifacts_yul_phaser:
steps:
- store_artifacts:
path: build/tools/yul-phaser
destination: yul-phaser
persist_executables_to_workspace:
description: Persist compiled target executables to workspace
steps:
- persist_to_workspace:
root: build
paths:
- solc/solc
- test/soltest
- test/tools/solfuzzer
persist_executables_to_workspace_osx:
description: Persist compiled target executables to workspace on macOS
steps:
- persist_to_workspace:
root: .
paths:
- build/solc/solc
- build/test/soltest
- build/test/tools/solfuzzer
persist_ossfuzz_executables_to_workspace:
description: Persist compiled OSSFUZZ executables to workspace
steps:
- persist_to_workspace:
root: build
paths:
- test/tools/ossfuzz/abiv2_proto_ossfuzz
- test/tools/ossfuzz/abiv2_isabelle_ossfuzz
- test/tools/ossfuzz/const_opt_ossfuzz
- test/tools/ossfuzz/solc_mutator_ossfuzz
- test/tools/ossfuzz/solc_ossfuzz
- test/tools/ossfuzz/stack_reuse_codegen_ossfuzz
- test/tools/ossfuzz/strictasm_assembly_ossfuzz
- test/tools/ossfuzz/strictasm_diff_ossfuzz
- test/tools/ossfuzz/strictasm_opt_ossfuzz
- test/tools/ossfuzz/yul_proto_diff_ossfuzz
- test/tools/ossfuzz/yul_proto_diff_custom_mutate_ossfuzz
- test/tools/ossfuzz/yul_proto_ossfuzz
- test/tools/ossfuzz/sol_proto_ossfuzz
store_artifacts_test_results:
description: Store test output dir as artifact
steps:
- store_artifacts:
path: test_results/
destination: test_results/
# --------------------------------------------------------------------------
# Complex Build Commands
soltest:
steps:
- checkout
- attach_workspace:
at: build
# NOTE: Different build jobs produce different soltest executables (release/debug,
# clang/gcc, windows/linux/macos, etc.). The executable used by these steps comes from the
# attached workspace and we only see the items added to the workspace by jobs we depend on.
- run_soltest
- store_test_results:
path: test_results/
- store_artifacts_test_results
- matrix_notify_failure_unless_pr
test_lsp:
steps:
- checkout
- attach_workspace:
at: build
- run:
name: Install dependencies
command: pip install --user deepdiff colorama
- run:
name: Executing solc LSP test suite
command: test/lsp.py build/solc/solc --non-interactive
- matrix_notify_failure_unless_pr
build:
steps:
- checkout
- run_build
- store_artifacts_solc
- store_artifacts_yul_phaser
- persist_executables_to_workspace
- matrix_notify_failure_unless_pr
soltest_all:
steps:
- checkout
- attach_workspace:
at: build
- run_soltest_all
- store_test_results:
path: test_results/
- store_artifacts_test_results
- matrix_notify_failure_unless_pr
cmdline_tests:
steps:
- checkout
- attach_workspace:
at: build
- run_cmdline_tests
- store_test_results:
path: test_results/
- store_artifacts_test_results
- matrix_notify_failure_unless_pr
install_dependencies_osx:
steps:
# FIXME: We used to cache dependencies on macOS but now it takes longer than just installing
# them each time. See https://github.com/ethereum/solidity/issues/12925.
- run:
name: Install build dependencies
command: .circleci/osx_install_dependencies.sh
defaults:
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Matrix templates # Matrix templates
@ -393,6 +241,122 @@ defaults:
- via-ir-no-optimize - via-ir-no-optimize
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Artifacts Templates
# compiled solc executable target
- artifacts_solc: &artifacts_solc
path: build/solc/solc
destination: solc
# windows artifacts
- artifact_solc_windows: &artifact_solc_windows
path: upload/
- artifact_yul_phaser: &artifact_yul_phaser
path: build/tools/yul-phaser
destination: yul-phaser
# compiled executable targets
- artifacts_executables: &artifacts_executables
root: build
paths:
- solc/solc
- test/soltest
- test/tools/solfuzzer
# compiled OSSFUZZ targets
- artifacts_executables_ossfuzz: &artifacts_executables_ossfuzz
root: build
paths:
- test/tools/ossfuzz/abiv2_proto_ossfuzz
- test/tools/ossfuzz/abiv2_isabelle_ossfuzz
- test/tools/ossfuzz/const_opt_ossfuzz
- test/tools/ossfuzz/solc_mutator_ossfuzz
- test/tools/ossfuzz/solc_ossfuzz
- test/tools/ossfuzz/stack_reuse_codegen_ossfuzz
- test/tools/ossfuzz/strictasm_assembly_ossfuzz
- test/tools/ossfuzz/strictasm_diff_ossfuzz
- test/tools/ossfuzz/strictasm_opt_ossfuzz
- test/tools/ossfuzz/yul_proto_diff_ossfuzz
- test/tools/ossfuzz/yul_proto_diff_custom_mutate_ossfuzz
- test/tools/ossfuzz/yul_proto_ossfuzz
- test/tools/ossfuzz/sol_proto_ossfuzz
# test result output directory
- artifacts_test_results: &artifacts_test_results
path: test_results/
destination: test_results/
# --------------------------------------------------------------------------
# Step Templates
# store_test_results helper
- store_test_results: &store_test_results
path: test_results/
- steps_soltest: &steps_soltest
steps:
- checkout
- attach_workspace:
at: build
# NOTE: Different build jobs produce different soltest executables (release/debug,
# clang/gcc, windows/linux/macos, etc.). The executable used by these steps comes from the
# attached workspace and we only see the items added to the workspace by jobs we depend on.
- run: *run_soltest
- store_test_results: *store_test_results
- store_artifacts: *artifacts_test_results
- matrix_notify_failure_unless_pr
- steps_test_lsp: &steps_test_lsp
steps:
- checkout
- attach_workspace:
at: build
- run:
name: Install dependencies
command: pip install --user deepdiff colorama
- run:
name: Executing solc LSP test suite
command: ./test/lsp.py ./build/solc/solc --non-interactive
- matrix_notify_failure_unless_pr
- steps_build: &steps_build
steps:
- checkout
- run: *run_build
- store_artifacts: *artifacts_solc
- store_artifacts: *artifact_yul_phaser
- persist_to_workspace: *artifacts_executables
- matrix_notify_failure_unless_pr
- steps_soltest_all: &steps_soltest_all
steps:
- checkout
- attach_workspace:
at: build
- run: *run_soltest_all
- store_test_results: *store_test_results
- store_artifacts: *artifacts_test_results
- matrix_notify_failure_unless_pr
- steps_cmdline_tests: &steps_cmdline_tests
steps:
- checkout
- attach_workspace:
at: build
- run: *run_cmdline_tests
- store_test_results: *store_test_results
- store_artifacts: *artifacts_test_results
- matrix_notify_failure_unless_pr
- steps_install_dependencies_osx: &steps_install_dependencies_osx
steps:
# FIXME: We used to cache dependencies on macOS but now it takes longer than just installing
# them each time. See https://github.com/ethereum/solidity/issues/12925.
- run:
name: Install build dependencies
command: ./.circleci/osx_install_dependencies.sh
# -------------------------------------------------------------------------- # --------------------------------------------------------------------------
# Base Image Templates # Base Image Templates
@ -402,7 +366,6 @@ defaults:
environment: &base_archlinux_env environment: &base_archlinux_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 3 MAKEFLAGS: -j 3
CPUs: 3
- base_archlinux_large: &base_archlinux_large - base_archlinux_large: &base_archlinux_large
<<: *base_archlinux <<: *base_archlinux
@ -410,7 +373,6 @@ defaults:
environment: &base_archlinux_large_env environment: &base_archlinux_large_env
<<: *base_archlinux_env <<: *base_archlinux_env
MAKEFLAGS: -j 5 MAKEFLAGS: -j 5
CPUs: 5
- base_cimg_small: &base_cimg_small - base_cimg_small: &base_cimg_small
docker: docker:
@ -419,7 +381,6 @@ defaults:
environment: &base_cimg_small_env environment: &base_cimg_small_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 2 MAKEFLAGS: -j 2
CPUs: 2
- base_ems_large: &base_ems_large - base_ems_large: &base_ems_large
docker: docker:
@ -428,7 +389,6 @@ defaults:
environment: &base_ems_large_env environment: &base_ems_large_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 5 MAKEFLAGS: -j 5
CPUs: 5
- base_node_small: &base_node_small - base_node_small: &base_node_small
docker: docker:
@ -437,7 +397,6 @@ defaults:
environment: &base_node_small_env environment: &base_node_small_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 2 MAKEFLAGS: -j 2
CPUs: 2
- base_osx: &base_osx - base_osx: &base_osx
macos: macos:
@ -446,7 +405,6 @@ defaults:
environment: &base_osx_env environment: &base_osx_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j5 MAKEFLAGS: -j5
CPUs: 5
- base_osx_large: &base_osx_large - base_osx_large: &base_osx_large
<<: *base_osx <<: *base_osx
@ -454,7 +412,6 @@ defaults:
environment: &base_osx_large_env environment: &base_osx_large_env
<<: *base_osx_env <<: *base_osx_env
MAKEFLAGS: -j10 MAKEFLAGS: -j10
CPUs: 10
- base_python_small: &base_python_small - base_python_small: &base_python_small
docker: docker:
@ -463,7 +420,6 @@ defaults:
environment: &base_python_small_env environment: &base_python_small_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 2 MAKEFLAGS: -j 2
CPUs: 2
- base_ubuntu_clang: &base_ubuntu_clang - base_ubuntu_clang: &base_ubuntu_clang
docker: docker:
@ -471,7 +427,6 @@ defaults:
environment: &base_ubuntu_clang_env environment: &base_ubuntu_clang_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 3 MAKEFLAGS: -j 3
CPUs: 3
- base_ubuntu_clang_small: &base_ubuntu_clang_small - base_ubuntu_clang_small: &base_ubuntu_clang_small
<<: *base_ubuntu_clang <<: *base_ubuntu_clang
@ -479,7 +434,6 @@ defaults:
environment: &base_ubuntu_clang_small_env environment: &base_ubuntu_clang_small_env
<<: *base_ubuntu_clang_env <<: *base_ubuntu_clang_env
MAKEFLAGS: -j 2 MAKEFLAGS: -j 2
CPUs: 2
- base_ubuntu2004: &base_ubuntu2004 - base_ubuntu2004: &base_ubuntu2004
docker: docker:
@ -487,7 +441,6 @@ defaults:
environment: &base_ubuntu2004_env environment: &base_ubuntu2004_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 3 MAKEFLAGS: -j 3
CPUs: 3
- base_ubuntu2004_small: &base_ubuntu2004_small - base_ubuntu2004_small: &base_ubuntu2004_small
<<: *base_ubuntu2004 <<: *base_ubuntu2004
@ -495,7 +448,6 @@ defaults:
environment: &base_ubuntu2004_small_env environment: &base_ubuntu2004_small_env
<<: *base_ubuntu2004_env <<: *base_ubuntu2004_env
MAKEFLAGS: -j 2 MAKEFLAGS: -j 2
CPUs: 2
- base_ubuntu2004_xlarge: &base_ubuntu2004_xlarge - base_ubuntu2004_xlarge: &base_ubuntu2004_xlarge
<<: *base_ubuntu2004 <<: *base_ubuntu2004
@ -503,7 +455,6 @@ defaults:
environment: &base_ubuntu2004_xlarge_env environment: &base_ubuntu2004_xlarge_env
<<: *base_ubuntu2004_env <<: *base_ubuntu2004_env
MAKEFLAGS: -j 10 MAKEFLAGS: -j 10
CPUs: 10
- base_ubuntu2204: &base_ubuntu2204 - base_ubuntu2204: &base_ubuntu2204
docker: docker:
@ -511,7 +462,6 @@ defaults:
environment: &base_ubuntu2204_env environment: &base_ubuntu2204_env
TERM: xterm TERM: xterm
MAKEFLAGS: -j 3 MAKEFLAGS: -j 3
CPUs: 3
- base_ubuntu2204_clang: &base_ubuntu2204_clang - base_ubuntu2204_clang: &base_ubuntu2204_clang
docker: docker:
@ -521,7 +471,6 @@ defaults:
CC: clang CC: clang
CXX: clang++ CXX: clang++
MAKEFLAGS: -j 3 MAKEFLAGS: -j 3
CPUs: 3
- base_ubuntu2204_clang_large: &base_ubuntu2204_clang_large - base_ubuntu2204_clang_large: &base_ubuntu2204_clang_large
<<: *base_ubuntu2204_clang <<: *base_ubuntu2204_clang
@ -529,7 +478,6 @@ defaults:
environment: &base_ubuntu2204_clang_large_env environment: &base_ubuntu2204_clang_large_env
<<: *base_ubuntu2204_clang_env <<: *base_ubuntu2204_clang_env
MAKEFLAGS: -j 5 MAKEFLAGS: -j 5
CPUs: 5
- base_ubuntu2204_small: &base_ubuntu2204_small - base_ubuntu2204_small: &base_ubuntu2204_small
<<: *base_ubuntu2204 <<: *base_ubuntu2204
@ -537,7 +485,6 @@ defaults:
environment: &base_ubuntu2204_small_env environment: &base_ubuntu2204_small_env
<<: *base_ubuntu2204_env <<: *base_ubuntu2204_env
MAKEFLAGS: -j 2 MAKEFLAGS: -j 2
CPUs: 2
- base_ubuntu2204_large: &base_ubuntu2204_large - base_ubuntu2204_large: &base_ubuntu2204_large
<<: *base_ubuntu2204 <<: *base_ubuntu2204
@ -545,7 +492,6 @@ defaults:
environment: &base_ubuntu2204_large_env environment: &base_ubuntu2204_large_env
<<: *base_ubuntu2204_env <<: *base_ubuntu2204_env
MAKEFLAGS: -j 5 MAKEFLAGS: -j 5
CPUs: 5
- base_ubuntu2204_xlarge: &base_ubuntu2204_xlarge - base_ubuntu2204_xlarge: &base_ubuntu2204_xlarge
<<: *base_ubuntu2204 <<: *base_ubuntu2204
@ -553,7 +499,6 @@ defaults:
environment: &base_ubuntu2204_xlarge_env environment: &base_ubuntu2204_xlarge_env
<<: *base_ubuntu2204_env <<: *base_ubuntu2204_env
MAKEFLAGS: -j 10 MAKEFLAGS: -j 10
CPUs: 10
- base_win: &base_win - base_win: &base_win
executor: executor:
@ -746,7 +691,7 @@ defaults:
name: t_native_test_ext_prb_math name: t_native_test_ext_prb_math
project: prb-math project: prb-math
binary_type: native binary_type: native
image: cimg/rust:1.70 image: cimg/node:18.16
- job_native_test_ext_elementfi: &job_native_test_ext_elementfi - job_native_test_ext_elementfi: &job_native_test_ext_elementfi
<<: *requires_b_ubu_static <<: *requires_b_ubu_static
@ -803,11 +748,7 @@ jobs:
pip install --user codespell pip install --user codespell
- run: - run:
name: Check spelling name: Check spelling
command: | command: ~/.local/bin/codespell --skip "*.enc,.git,Dockerfile*,LICENSE,codespell_whitelist.txt,codespell_ignored_lines.txt" --ignore-words ./scripts/codespell_whitelist.txt --exclude-file ./scripts/codespell_ignored_lines.txt
~/.local/bin/codespell \
--skip "*.enc,.git,Dockerfile*,LICENSE,codespell_whitelist.txt,codespell_ignored_lines.txt" \
--ignore-words scripts/codespell_whitelist.txt \
--exclude-file scripts/codespell_ignored_lines.txt
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_docs_examples: chk_docs_examples:
@ -821,7 +762,7 @@ jobs:
command: sudo npm install -g solhint command: sudo npm install -g solhint
- run: - run:
name: Test Docs examples name: Test Docs examples
command: test/docsCodeStyle.sh command: ./test/docsCodeStyle.sh
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_coding_style: chk_coding_style:
@ -835,13 +776,13 @@ jobs:
sudo apt install -y shellcheck sudo apt install -y shellcheck
- run: - run:
name: Check for C++ coding style name: Check for C++ coding style
command: scripts/check_style.sh command: ./scripts/check_style.sh
- run: - run:
name: checking shell scripts name: checking shell scripts
command: scripts/chk_shellscripts/chk_shellscripts.sh command: ./scripts/chk_shellscripts/chk_shellscripts.sh
- run: - run:
name: Check for broken symlinks name: Check for broken symlinks
command: scripts/check_symlinks.sh command: ./scripts/check_symlinks.sh
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_errorcodes: chk_errorcodes:
@ -850,7 +791,7 @@ jobs:
- checkout - checkout
- run: - run:
name: Check for error codes name: Check for error codes
command: scripts/error_codes.py --check command: ./scripts/error_codes.py --check
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_pylint: chk_pylint:
@ -870,7 +811,7 @@ jobs:
- run: pylint --version - run: pylint --version
- run: - run:
name: Linting Python Scripts name: Linting Python Scripts
command: scripts/pylint_all.py command: ./scripts/pylint_all.py
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_antlr_grammar: chk_antlr_grammar:
@ -884,7 +825,7 @@ jobs:
sudo apt install -y openjdk-17-jdk sudo apt install -y openjdk-17-jdk
- run: - run:
name: Run tests name: Run tests
command: scripts/test_antlr_grammar.sh command: ./scripts/test_antlr_grammar.sh
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_buglist: chk_buglist:
@ -899,7 +840,7 @@ jobs:
npm install mktemp npm install mktemp
- run: - run:
name: Test buglist name: Test buglist
command: test/buglistTests.js command: ./test/buglistTests.js
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_proofs: chk_proofs:
@ -908,14 +849,14 @@ jobs:
- checkout - checkout
- install_python3: - install_python3:
packages: z3-solver packages: z3-solver
- run_proofs - run: *run_proofs
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
chk_docs_pragma_min_version: chk_docs_pragma_min_version:
<<: *base_ubuntu2204_small <<: *base_ubuntu2204_small
steps: steps:
- checkout - checkout
- run_docs_pragma_min_version - run: *run_docs_pragma_min_version
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
t_ubu_pyscripts: t_ubu_pyscripts:
@ -941,8 +882,7 @@ jobs:
# this runs 2x faster on xlarge but takes 4x more resources (compared to medium). # this runs 2x faster on xlarge but takes 4x more resources (compared to medium).
# Enough other jobs depend on it that it's worth it though. # Enough other jobs depend on it that it's worth it though.
<<: *base_ubuntu2204_xlarge <<: *base_ubuntu2204_xlarge
steps: <<: *steps_build
- build
# x64 ASAN build, for testing for memory related bugs # x64 ASAN build, for testing for memory related bugs
b_ubu_asan: &b_ubu_asan b_ubu_asan: &b_ubu_asan
@ -952,16 +892,14 @@ jobs:
<<: *base_ubuntu2204_env <<: *base_ubuntu2204_env
CMAKE_OPTIONS: -DSANITIZE=address CMAKE_OPTIONS: -DSANITIZE=address
CMAKE_BUILD_TYPE: Release CMAKE_BUILD_TYPE: Release
steps: <<: *steps_build
- build
b_ubu_clang: &b_ubu_clang b_ubu_clang: &b_ubu_clang
<<: *base_ubuntu2204_clang_large <<: *base_ubuntu2204_clang_large
environment: environment:
<<: *base_ubuntu2204_clang_large_env <<: *base_ubuntu2204_clang_large_env
MAKEFLAGS: -j 10 MAKEFLAGS: -j 10
steps: <<: *steps_build
- build
b_ubu_san_clang: b_ubu_san_clang:
# This runs a bit faster on large and xlarge but on nightly efficiency matters more. # This runs a bit faster on large and xlarge but on nightly efficiency matters more.
@ -972,8 +910,7 @@ jobs:
environment: environment:
<<: *base_ubuntu2204_clang_env <<: *base_ubuntu2204_clang_env
CMAKE_OPTIONS: << parameters.cmake_options >> CMAKE_OPTIONS: << parameters.cmake_options >>
steps: <<: *steps_build
- build
b_ubu_force_release: &b_ubu_force_release b_ubu_force_release: &b_ubu_force_release
<<: *b_ubu <<: *b_ubu
@ -992,7 +929,7 @@ jobs:
CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Release -DUSE_Z3_DLOPEN=ON -DUSE_CVC4=OFF -DSOLC_STATIC_STDLIBS=ON CMAKE_OPTIONS: -DCMAKE_BUILD_TYPE=Release -DUSE_Z3_DLOPEN=ON -DUSE_CVC4=OFF -DSOLC_STATIC_STDLIBS=ON
steps: steps:
- checkout - checkout
- run_build - run: *run_build
- run: - run:
name: strip binary name: strip binary
command: strip build/solc/solc command: strip build/solc/solc
@ -1015,8 +952,8 @@ jobs:
CMAKE_BUILD_TYPE: Debug CMAKE_BUILD_TYPE: Debug
steps: steps:
- checkout - checkout
- run_build - run: *run_build
- persist_executables_to_workspace - persist_to_workspace: *artifacts_executables
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
t_ubu_codecov: t_ubu_codecov:
@ -1035,11 +972,11 @@ jobs:
- run: - run:
name: "Code Coverage: Syntax Tests" name: "Code Coverage: Syntax Tests"
command: codecov --flags syntax --gcov-root build command: codecov --flags syntax --gcov-root build
- run_soltest - run: *run_soltest
- run: - run:
name: "Coverage: All" name: "Coverage: All"
command: codecov --flags all --gcov-root build command: codecov --flags all --gcov-root build
- store_artifacts_test_results - store_artifacts: *artifacts_test_results
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
# Builds in C++20 mode and uses debug build in order to speed up. # Builds in C++20 mode and uses debug build in order to speed up.
@ -1053,16 +990,16 @@ jobs:
MAKEFLAGS: -j 10 MAKEFLAGS: -j 10
steps: steps:
- checkout - checkout
- run_build - run: *run_build
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
b_ubu_ossfuzz: &b_ubu_ossfuzz b_ubu_ossfuzz: &b_ubu_ossfuzz
<<: *base_ubuntu_clang <<: *base_ubuntu_clang
steps: steps:
- checkout - checkout
- setup_prerelease_commit_hash - run: *setup_prerelease_commit_hash
- run_build_ossfuzz - run: *run_build_ossfuzz
- persist_ossfuzz_executables_to_workspace - persist_to_workspace: *artifacts_executables_ossfuzz
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
t_ubu_ossfuzz: &t_ubu_ossfuzz t_ubu_ossfuzz: &t_ubu_ossfuzz
@ -1077,9 +1014,8 @@ jobs:
git clone https://github.com/ethereum/solidity-fuzzing-corpus /tmp/solidity-fuzzing-corpus git clone https://github.com/ethereum/solidity-fuzzing-corpus /tmp/solidity-fuzzing-corpus
mkdir -p test_results mkdir -p test_results
scripts/regressions.py -o test_results scripts/regressions.py -o test_results
- store_test_results: - store_test_results: *store_test_results
path: test_results/ - store_artifacts: *artifacts_test_results
- store_artifacts_test_results
b_archlinux: b_archlinux:
<<: *base_archlinux_large <<: *base_archlinux_large
@ -1093,9 +1029,9 @@ jobs:
command: | command: |
pacman --noconfirm -Syu --noprogressbar --needed base-devel boost cmake cvc4 git openssh tar pacman --noconfirm -Syu --noprogressbar --needed base-devel boost cmake cvc4 git openssh tar
- checkout - checkout
- run_build - run: *run_build
- store_artifacts_solc - store_artifacts: *artifacts_solc
- persist_executables_to_workspace - persist_to_workspace: *artifacts_executables
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
b_osx: b_osx:
@ -1105,11 +1041,18 @@ jobs:
CMAKE_BUILD_TYPE: Release CMAKE_BUILD_TYPE: Release
steps: steps:
- checkout - checkout
- install_dependencies_osx - when:
- run_build condition: true
- store_artifacts_solc <<: *steps_install_dependencies_osx
- store_artifacts_yul_phaser - run: *run_build
- persist_executables_to_workspace_osx - store_artifacts: *artifacts_solc
- store_artifacts: *artifact_yul_phaser
- persist_to_workspace:
root: .
paths:
- build/solc/solc
- build/test/soltest
- build/test/tools/solfuzzer
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
t_osx_soltest: &t_osx_soltest t_osx_soltest: &t_osx_soltest
@ -1120,13 +1063,14 @@ jobs:
OPTIMIZE: 0 OPTIMIZE: 0
steps: steps:
- checkout - checkout
- install_dependencies_osx - when:
condition: true
<<: *steps_install_dependencies_osx
- attach_workspace: - attach_workspace:
at: . at: .
- run_soltest - run: *run_soltest
- store_test_results: - store_test_results: *store_test_results
path: test_results/ - store_artifacts: *artifacts_test_results
- store_artifacts_test_results
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
t_osx_cli: t_osx_cli:
@ -1134,11 +1078,13 @@ jobs:
parallelism: 7 # Should match number of tests in .circleci/cli.sh parallelism: 7 # Should match number of tests in .circleci/cli.sh
steps: steps:
- checkout - checkout
- install_dependencies_osx - when:
condition: true
<<: *steps_install_dependencies_osx
- attach_workspace: - attach_workspace:
at: . at: .
- run_cmdline_tests - run: *run_cmdline_tests
- store_artifacts_test_results - store_artifacts: *artifacts_test_results
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
b_ems: b_ems:
@ -1169,10 +1115,10 @@ jobs:
<<: *base_ubuntu2204_small <<: *base_ubuntu2204_small
steps: steps:
- checkout - checkout
- setup_prerelease_commit_hash - run: *setup_prerelease_commit_hash
- run: - run:
name: Build documentation name: Build documentation
command: docs/docs.sh command: ./docs/docs.sh
- store_artifacts: - store_artifacts:
path: docs/_build/html/ path: docs/_build/html/
destination: docs-html destination: docs-html
@ -1181,13 +1127,11 @@ jobs:
t_ubu_soltest_all: &t_ubu_soltest_all t_ubu_soltest_all: &t_ubu_soltest_all
<<: *base_ubuntu2204_large <<: *base_ubuntu2204_large
parallelism: 50 parallelism: 50
steps: <<: *steps_soltest_all
- soltest_all
t_ubu_lsp: &t_ubu_lsp t_ubu_lsp: &t_ubu_lsp
<<: *base_ubuntu2204_small <<: *base_ubuntu2204_small
steps: <<: *steps_test_lsp
- test_lsp
t_archlinux_soltest: &t_archlinux_soltest t_archlinux_soltest: &t_archlinux_soltest
<<: *base_archlinux <<: *base_archlinux
@ -1204,7 +1148,9 @@ jobs:
name: Install runtime dependencies name: Install runtime dependencies
command: | command: |
pacman --noconfirm -Syu --noprogressbar --needed base-devel boost cmake z3 cvc4 git openssh tar pacman --noconfirm -Syu --noprogressbar --needed base-devel boost cmake z3 cvc4 git openssh tar
- soltest - when:
condition: true
<<: *steps_soltest
t_ubu_clang_soltest: &t_ubu_clang_soltest t_ubu_clang_soltest: &t_ubu_clang_soltest
<<: *base_ubuntu2204_clang <<: *base_ubuntu2204_clang
@ -1216,8 +1162,7 @@ jobs:
# The high parallelism in this job is causing the SMT tests to run out of memory, # The high parallelism in this job is causing the SMT tests to run out of memory,
# so disabling for now. # so disabling for now.
SOLTEST_FLAGS: --no-smt SOLTEST_FLAGS: --no-smt
steps: <<: *steps_soltest
- soltest
t_ubu_force_release_soltest_all: &t_ubu_force_release_soltest_all t_ubu_force_release_soltest_all: &t_ubu_force_release_soltest_all
# NOTE: This definition is identical to t_ubu_soltest_all but in the workflow we make it depend on # NOTE: This definition is identical to t_ubu_soltest_all but in the workflow we make it depend on
@ -1227,8 +1172,7 @@ jobs:
t_ubu_cli: &t_ubu_cli t_ubu_cli: &t_ubu_cli
<<: *base_ubuntu2204_small <<: *base_ubuntu2204_small
parallelism: 7 # Should match number of tests in .circleci/cli.sh parallelism: 7 # Should match number of tests in .circleci/cli.sh
steps: <<: *steps_cmdline_tests
- cmdline_tests
t_ubu_force_release_cli: &t_ubu_force_release_cli t_ubu_force_release_cli: &t_ubu_force_release_cli
<<: *t_ubu_cli <<: *t_ubu_cli
@ -1252,8 +1196,7 @@ jobs:
# Suppress CLN memory leak. # Suppress CLN memory leak.
# See: https://github.com/ethereum/solidity/issues/13891 for details. # See: https://github.com/ethereum/solidity/issues/13891 for details.
LSAN_OPTIONS: suppressions=/root/project/.circleci/cln-asan.supp:print_suppressions=0 LSAN_OPTIONS: suppressions=/root/project/.circleci/cln-asan.supp:print_suppressions=0
steps: <<: *steps_cmdline_tests
- cmdline_tests
t_ubu_asan_soltest: t_ubu_asan_soltest:
<<: *base_ubuntu2204 <<: *base_ubuntu2204
@ -1267,8 +1210,7 @@ jobs:
# Suppress CLN memory leak. # Suppress CLN memory leak.
# See: https://github.com/ethereum/solidity/issues/13891 for details. # See: https://github.com/ethereum/solidity/issues/13891 for details.
LSAN_OPTIONS: suppressions=/root/project/.circleci/cln-asan.supp LSAN_OPTIONS: suppressions=/root/project/.circleci/cln-asan.supp
steps: <<: *steps_soltest
- soltest
t_ubu_asan_clang_soltest: t_ubu_asan_clang_soltest:
<<: *base_ubuntu2204_clang <<: *base_ubuntu2204_clang
@ -1279,8 +1221,7 @@ jobs:
OPTIMIZE: 0 OPTIMIZE: 0
SOLTEST_FLAGS: --no-smt SOLTEST_FLAGS: --no-smt
ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2 ASAN_OPTIONS: check_initialization_order=true:detect_stack_use_after_return=true:strict_init_order=true:strict_string_checks=true:detect_invalid_pointer_pairs=2
steps: <<: *steps_soltest
- soltest
t_ubu_ubsan_clang_soltest: t_ubu_ubsan_clang_soltest:
<<: *base_ubuntu2204_clang <<: *base_ubuntu2204_clang
@ -1289,14 +1230,12 @@ jobs:
<<: *base_ubuntu2204_clang_env <<: *base_ubuntu2204_clang_env
EVM: << pipeline.parameters.evm-version >> EVM: << pipeline.parameters.evm-version >>
SOLTEST_FLAGS: --no-smt SOLTEST_FLAGS: --no-smt
steps: <<: *steps_soltest
- soltest
t_ubu_ubsan_clang_cli: t_ubu_ubsan_clang_cli:
<<: *base_ubuntu2204_clang <<: *base_ubuntu2204_clang
parallelism: 7 # Should match number of tests in .circleci/cli.sh parallelism: 7 # Should match number of tests in .circleci/cli.sh
steps: <<: *steps_cmdline_tests
- cmdline_tests
t_ems_solcjs: t_ems_solcjs:
# Unlike other t_ems jobs this one actually runs 2x faster on medium (compared to small). # Unlike other t_ems jobs this one actually runs 2x faster on medium (compared to small).
@ -1520,8 +1459,7 @@ jobs:
name: "Run solc.exe to make sure build was successful." name: "Run solc.exe to make sure build was successful."
command: .\build\solc\Release\solc.exe --version command: .\build\solc\Release\solc.exe --version
shell: powershell.exe shell: powershell.exe
- store_artifacts: - store_artifacts: *artifact_solc_windows
path: upload/
- persist_to_workspace: - persist_to_workspace:
root: build root: build
paths: paths:
@ -1550,11 +1488,10 @@ jobs:
command: python -m pip install --user deepdiff colorama command: python -m pip install --user deepdiff colorama
- run: - run:
name: Executing solc LSP test suite name: Executing solc LSP test suite
command: python test/lsp.py build\solc\Release\solc.exe --non-interactive command: python ./test/lsp.py .\build\solc\Release\solc.exe --non-interactive
shell: powershell.exe shell: powershell.exe
- store_test_results: - store_test_results: *store_test_results
path: test_results/ - store_artifacts: *artifacts_test_results
- store_artifacts_test_results
- matrix_notify_failure_unless_pr - matrix_notify_failure_unless_pr
# Note: b_bytecode_ubu_static is required because b_ubu_static and b_ubu # Note: b_bytecode_ubu_static is required because b_ubu_static and b_ubu
@ -1787,13 +1724,11 @@ workflows:
- t_native_test_ext_yield_liquidator - t_native_test_ext_yield_liquidator
- t_native_test_ext_perpetual_pools - t_native_test_ext_perpetual_pools
- t_native_test_ext_uniswap - t_native_test_ext_uniswap
- t_native_test_ext_prb_math
- t_native_test_ext_elementfi - t_native_test_ext_elementfi
- t_native_test_ext_brink - t_native_test_ext_brink
# NOTE: We are disabling gp2 tests due to constant failures. # NOTE: We are disabling gp2 tests due to constant failures.
#- t_native_test_ext_gp2 #- t_native_test_ext_gp2
# TODO: Dropping prb-math from the benchmarks since it is not implemented yet
# in the new Foundry external testing infrastructure.
# - t_native_test_ext_prb_math
# NOTE: The external tests below were commented because they # NOTE: The external tests below were commented because they
# depend on a specific version of hardhat which does not support shanghai EVM. # depend on a specific version of hardhat which does not support shanghai EVM.
#- t_native_test_ext_trident #- t_native_test_ext_trident

View File

@ -52,8 +52,6 @@ function validate_checksum {
if [ ! -f /usr/local/lib/libz3.a ] # if this file does not exists (cache was not restored), rebuild dependencies if [ ! -f /usr/local/lib/libz3.a ] # if this file does not exists (cache was not restored), rebuild dependencies
then then
brew update
brew upgrade
brew install boost brew install boost
brew install cmake brew install cmake
brew install wget brew install wget

View File

@ -36,7 +36,6 @@ set -e
OPTIMIZE=${OPTIMIZE:-"0"} OPTIMIZE=${OPTIMIZE:-"0"}
EVM=${EVM:-"invalid"} EVM=${EVM:-"invalid"}
CPUs=${CPUs:-3}
REPODIR="$(realpath "$(dirname "$0")/..")" REPODIR="$(realpath "$(dirname "$0")/..")"
IFS=" " read -r -a BOOST_TEST_ARGS <<< "$BOOST_TEST_ARGS" IFS=" " read -r -a BOOST_TEST_ARGS <<< "$BOOST_TEST_ARGS"
@ -68,6 +67,7 @@ get_logfile_basename() {
# long-running test cases are next to each other. # long-running test cases are next to each other.
CIRCLE_NODE_INDEX=$(((CIRCLE_NODE_INDEX + 23 * INDEX_SHIFT) % CIRCLE_NODE_TOTAL)) CIRCLE_NODE_INDEX=$(((CIRCLE_NODE_INDEX + 23 * INDEX_SHIFT) % CIRCLE_NODE_TOTAL))
CPUs=3
PIDs=() PIDs=()
for run in $(seq 0 $((CPUs - 1))) for run in $(seq 0 $((CPUs - 1)))
do do

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.13.0) cmake_minimum_required(VERSION 3.13.0)
set(ETH_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "The path to the cmake directory") set(ETH_CMAKE_DIR "${CMAKE_CURRENT_LIST_DIR}/cmake" CACHE PATH "The the path to the cmake directory")
list(APPEND CMAKE_MODULE_PATH ${ETH_CMAKE_DIR}) list(APPEND CMAKE_MODULE_PATH ${ETH_CMAKE_DIR})
# Set the build type, if none was specified. # Set the build type, if none was specified.
@ -21,7 +21,7 @@ include(EthPolicy)
eth_policy() eth_policy()
# project name and version should be set after cmake_policy CMP0048 # project name and version should be set after cmake_policy CMP0048
set(PROJECT_VERSION "0.8.22") set(PROJECT_VERSION "0.8.21")
# OSX target needed in order to support std::visit # OSX target needed in order to support std::visit
set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14") set(CMAKE_OSX_DEPLOYMENT_TARGET "10.14")
project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX) project(solidity VERSION ${PROJECT_VERSION} LANGUAGES C CXX)

View File

@ -1,23 +1,3 @@
### 0.8.22 (unreleased)
Language Features:
* Allow defining events at file level.
Compiler Features:
* Parser: Remove the experimental error recovery mode (``--error-recovery`` / ``settings.parserErrorRecovery``).
* Yul Optimizer: If ``PUSH0`` is supported, favor zero literals over storing zero values in variables.
* Yul Optimizer: Run the ``Rematerializer`` and ``UnusedPruner`` steps at the end of the default clean-up sequence.
Bugfixes:
* AST: Fix wrong initial ID for Yul nodes in the AST.
* Code Generator: Fix output from via-IR code generator being dependent on which files were discovered by import callback. In some cases, a different AST ID assignment would alter the order of functions in internal dispatch, resulting in superficially different but semantically equivalent bytecode.
* NatSpec: Fix internal error when requesting userdoc or devdoc for a contract that emits an event defined in a foreign contract or interface.
* SMTChecker: Fix encoding error that causes loops to unroll after completion.
* SMTChecker: Fix inconsistency on constant condition checks when ``while`` or ``for`` loops are unrolled before the condition check.
### 0.8.21 (2023-07-19) ### 0.8.21 (2023-07-19)
Important Bugfixes: Important Bugfixes:

View File

@ -3,9 +3,9 @@
### Requirements ### Requirements
- [ ] GitHub account with access to [solidity](https://github.com/ethereum/solidity), [solc-js](https://github.com/ethereum/solc-js), - [ ] GitHub account with access to [solidity](https://github.com/ethereum/solidity), [solc-js](https://github.com/ethereum/solc-js),
[solc-bin](https://github.com/ethereum/solc-bin), [homebrew-ethereum](https://github.com/ethereum/homebrew-ethereum), [solc-bin](https://github.com/ethereum/solc-bin), [homebrew-ethereum](https://github.com/ethereum/homebrew-ethereum),
[solidity-website](https://github.com/ethereum/solidity-website). [solidity-blog](https://github.com/ethereum/solidity-blog) and [solidity-portal](https://github.com/ethereum/solidity-portal) repositories.
- [ ] DockerHub account with push rights to the [``solc`` image](https://hub.docker.com/r/ethereum/solc). - [ ] DockerHub account with push rights to the [``solc`` image](https://hub.docker.com/r/ethereum/solc).
- [ ] Launchpad (Ubuntu One) account with a membership in the ["Ethereum" team](https://launchpad.net/~ethereum) and - [ ] Lauchpad (Ubuntu One) account with a membership in the ["Ethereum" team](https://launchpad.net/~ethereum) and
a gnupg key for your email in the ``ethereum.org`` domain (has to be version 1, gpg2 won't work). a gnupg key for your email in the ``ethereum.org`` domain (has to be version 1, gpg2 won't work).
- [ ] Ubuntu/Debian dependencies of the PPA scripts: ``devscripts``, ``debhelper``, ``dput``, ``git``, ``wget``, ``ca-certificates``. - [ ] Ubuntu/Debian dependencies of the PPA scripts: ``devscripts``, ``debhelper``, ``dput``, ``git``, ``wget``, ``ca-certificates``.
- [ ] [npm Registry](https://www.npmjs.com) account added as a collaborator for the [``solc`` package](https://www.npmjs.com/package/solc). - [ ] [npm Registry](https://www.npmjs.com) account added as a collaborator for the [``solc`` package](https://www.npmjs.com/package/solc).
@ -37,8 +37,8 @@ At least a day before the release:
- [ ] Prepare drafts of Twitter, Reddit and Solidity Forum announcements. - [ ] Prepare drafts of Twitter, Reddit and Solidity Forum announcements.
### Blog Post ### Blog Post
- [ ] Create a post on [solidity-website](https://github.com/ethereum/solidity-website/tree/main/src/posts) in the ``Releases`` category and explain some of the new features or concepts. - [ ] Create a post on [solidity-blog](https://github.com/ethereum/solidity-blog) in the ``Releases`` category and explain some of the new features or concepts.
- [ ] Create a post on [solidity-website](https://github.com/ethereum/solidity-website/tree/main/src/posts) in the ``Security Alerts`` category in case of important bug(s). - [ ] Create a post on [solidity-blog](https://github.com/ethereum/solidity-blog) in the ``Security Alerts`` category in case of important bug(s).
### Changelog ### Changelog
- [ ] Sort the changelog entries alphabetically and correct any errors you notice. Commit it. - [ ] Sort the changelog entries alphabetically and correct any errors you notice. Commit it.
@ -104,9 +104,9 @@ At least a day before the release:
- [ ] Make sure the documentation for the new release has been published successfully. - [ ] Make sure the documentation for the new release has been published successfully.
Go to the [documentation status page at ReadTheDocs](https://readthedocs.org/projects/solidity/) and verify that the new version is listed, works and is marked as default. Go to the [documentation status page at ReadTheDocs](https://readthedocs.org/projects/solidity/) and verify that the new version is listed, works and is marked as default.
- [ ] Remove "still in progress" warning from the [release notes](https://github.com/ethereum/solidity/releases). - [ ] Remove "still in progress" warning from the [release notes](https://github.com/ethereum/solidity/releases).
- [ ] Merge the [blog posts](https://github.com/ethereum/solidity-website/pulls) related to the release. - [ ] Merge the [blog posts](https://github.com/ethereum/solidity-blog/pulls) related to the release.
- [ ] Create a commit to increase the version number on ``develop`` in ``CMakeLists.txt`` and add a new skeleton changelog entry. - [ ] Create a commit to increase the version number on ``develop`` in ``CMakeLists.txt`` and add a new skeleton changelog entry.
- [ ] Update the release information section [in the source of soliditylang.org](https://github.com/ethereum/solidity-website/blob/main/src/pages/index.tsx). - [ ] Update the release information section [in the source of soliditylang.org](https://github.com/ethereum/solidity-portal/blob/master/index.html).
- [ ] Announce on [Twitter](https://twitter.com/solidity_lang), including links to the release and the blog post. - [ ] Announce on [Twitter](https://twitter.com/solidity_lang), including links to the release and the blog post.
- [ ] Announce on [Fosstodon](https://fosstodon.org/@solidity/), including links to the release and the blog post. - [ ] Announce on [Fosstodon](https://fosstodon.org/@solidity/), including links to the release and the blog post.
- [ ] Share the announcement on Reddit in [``/r/ethdev``](https://reddit.com/r/ethdev/), cross-posted to [``/r/ethereum``](https://reddit.com/r/ethereum/). - [ ] Share the announcement on Reddit in [``/r/ethdev``](https://reddit.com/r/ethdev/), cross-posted to [``/r/ethereum``](https://reddit.com/r/ethereum/).

View File

@ -4,9 +4,9 @@ FetchContent_Declare(
fmtlib fmtlib
PREFIX "${PROJECT_BINARY_DIR}/deps" PREFIX "${PROJECT_BINARY_DIR}/deps"
DOWNLOAD_DIR "${PROJECT_SOURCE_DIR}/deps/downloads" DOWNLOAD_DIR "${PROJECT_SOURCE_DIR}/deps/downloads"
DOWNLOAD_NAME fmt-9.1.0.tar.gz DOWNLOAD_NAME fmt-8.0.1.tar.gz
URL https://github.com/fmtlib/fmt/archive/9.1.0.tar.gz URL https://github.com/fmtlib/fmt/archive/8.0.1.tar.gz
URL_HASH SHA256=5dea48d1fcddc3ec571ce2058e13910a0d4a6bab4cc09a809d8b1dd1c88ae6f2 URL_HASH SHA256=b06ca3130158c625848f3fb7418f235155a4d389b2abc3a6245fb01cb0eb1e01
) )
if (CMAKE_VERSION VERSION_LESS "3.14.0") if (CMAKE_VERSION VERSION_LESS "3.14.0")

View File

@ -112,7 +112,7 @@ New Error Reporter
~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~
A new error reporter was introduced, which aims at producing more accessible error messages on the command-line. A new error reporter was introduced, which aims at producing more accessible error messages on the command-line.
It is enabled by default, but passing ``--old-reporter`` falls back to the deprecated old error reporter. It is enabled by default, but passing ``--old-reporter`` falls back to the the deprecated old error reporter.
Metadata Hash Options Metadata Hash Options
~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~

View File

@ -16,10 +16,6 @@
--navHeight: 4.5rem; --navHeight: 4.5rem;
--sideWidth: 300px; --sideWidth: 300px;
--maxWidth: 80rem;
--desktopInlinePadding: 2rem;
--mobileInlinePadding: 1rem;
--currentVersionHeight: 45px;
text-rendering: geometricPrecision; text-rendering: geometricPrecision;
-webkit-font-smoothing: antialiased; -webkit-font-smoothing: antialiased;
@ -60,6 +56,7 @@ html,
body, body,
.wy-grid-for-nav { .wy-grid-for-nav {
background-color: var(--color-f) !important; background-color: var(--color-f) !important;
position: relative;
} }
body { body {
@ -70,10 +67,6 @@ a {
color: var(--color-c); color: var(--color-c);
} }
a, section {
scroll-margin-top: calc(var(--navHeight) + 2rem);
}
hr { hr {
margin-block: 2rem; margin-block: 2rem;
border-color: var(--color-d) !important; border-color: var(--color-d) !important;
@ -334,6 +327,7 @@ ul.current ul,
.wy-breadcrumbs-aside a, .wy-breadcrumbs-aside a,
.wy-breadcrumbs-aside a:visited, .wy-breadcrumbs-aside a:visited,
/* .wy-breadcrumbs-aside a:not(:visited), */
a.fa.fa-github, a.fa.fa-github,
a.fa.fa-github:visited, a.fa.fa-github:visited,
a.fa.fa-github:not(:visited), a.fa.fa-github:not(:visited),
@ -367,11 +361,10 @@ footer .rst-footer-buttons {
/* Site wrapper, and two children: header and rest */ /* Site wrapper, and two children: header and rest */
.unified-wrapper { .unified-wrapper {
position: relative; position: fixed;
display: flex;
flex-direction: column;
inset: 0; inset: 0;
max-width: var(--maxWidth); top: var(--navHeight);
max-width: 80rem;
margin-inline: auto; margin-inline: auto;
} }
@ -384,16 +377,17 @@ footer .rst-footer-buttons {
display: flex; display: flex;
align-items: center; align-items: center;
box-shadow: var(--shadow); box-shadow: var(--shadow);
backdrop-filter: blur(3px);
} }
.unified-header .inner-header { .unified-header .inner-header {
display: flex; display: flex;
margin-inline: auto; margin-inline: auto;
width: 100%; width: 100%;
max-width: var(--maxWidth); max-width: 80rem;
align-items: center; align-items: center;
justify-content: space-between; justify-content: space-between;
padding-inline: var(--desktopInlinePadding); padding-inline: 2rem;
padding-block: 1rem; padding-block: 1rem;
} }
@ -404,7 +398,6 @@ footer .rst-footer-buttons {
opacity: 95%; opacity: 95%;
background: var(--color-f); background: var(--color-f);
z-index: -1; z-index: -1;
backdrop-filter: blur(3px);
} }
.unified-header .home-link { .unified-header .home-link {
@ -451,7 +444,6 @@ footer .rst-footer-buttons {
font-weight: 400; font-weight: 400;
box-sizing: content-box; box-sizing: content-box;
border-bottom: 1px solid transparent; border-bottom: 1px solid transparent;
white-space: nowrap;
} }
.unified-header .nav-link.active { .unified-header .nav-link.active {
@ -463,36 +455,34 @@ footer .rst-footer-buttons {
border-bottom: 1px solid var(--color-c); border-bottom: 1px solid var(--color-c);
} }
/* Rest: Flex-row, with two children: side bar, and content */ /* Rest: Grid, with two children: side bar, and content */
.unified-wrapper .wy-grid-for-nav { .unified-wrapper .wy-grid-for-nav {
position: relative !important; position: relative !important;
display: flex; display: grid !important;
margin-inline: auto; grid-template-columns: var(--sideWidth) 1fr;
gap: 1rem;
} }
/* First child: Side bar */ /* First child: Side bar */
.unified-wrapper .wy-grid-for-nav nav.wy-nav-side { .unified-wrapper .wy-grid-for-nav nav.wy-nav-side {
position: fixed; position: relative;
display: flex; display: flex;
flex-direction: column; flex-direction: column;
background: var(--color-f); background: var(--color-f);
color: var(--color-a); color: var(--color-a);
padding-bottom: unset !important; top: 0;
z-index: 10 !important;
min-height: unset !important;
width: var(--sideWidth) !important;
top: var(--navHeight);
bottom: 0; bottom: 0;
left: auto; left: 0;
overflow: auto; padding-bottom: unset !important;
min-height: unset !important;
z-index: 10 !important;
max-width: var(--sideWidth) !important;
} }
.unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll { .unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll {
position: static !important; position: relative !important;
width: unset !important; width: fit-content !important;
overflow: unset !important;
height: unset !important; height: unset !important;
padding-bottom: 2rem;
} }
.unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll .wy-side-nav-search { .unified-wrapper .wy-grid-for-nav nav.wy-nav-side .wy-side-scroll .wy-side-nav-search {
@ -526,15 +516,15 @@ footer .rst-footer-buttons {
/* Second child: Content */ /* Second child: Content */
.unified-wrapper .wy-grid-for-nav .wy-nav-content { .unified-wrapper .wy-grid-for-nav .wy-nav-content {
position: relative !important;
overflow-y: scroll !important;
width: 100%; width: 100%;
max-width: unset !important; /* override */ max-width: 100vw !important;
padding-inline: var(--desktopInlinePadding); padding-inline: 2rem;
margin-inline-start: var(--sideWidth);
margin-top: var(--navHeight);
} }
.unified-wrapper .wy-grid-for-nav .wy-nav-content .rst-content { .unified-wrapper .wy-grid-for-nav .wy-nav-content .rst-content {
max-width: min(70ch, calc(100vw - 2 * var(--desktopInlinePadding) - var(--sideWidth))); max-width: 70ch;
margin-inline: auto; margin-inline: auto;
} }
@ -575,15 +565,29 @@ footer .rst-footer-buttons {
} }
.unified-header .inner-header { .unified-header .inner-header {
padding-inline: var(--mobileInlinePadding); padding-inline: 1rem;
}
.unified-wrapper .wy-grid-for-nav {
grid-template-columns: 1fr;
} }
.unified-wrapper .wy-grid-for-nav nav.wy-nav-side { .unified-wrapper .wy-grid-for-nav nav.wy-nav-side {
position: absolute;
inset-block: 0;
inset-inline-start: 0;
width: var(--sideWidth);
overflow-y: scroll;
transform: translateX(-100%); transform: translateX(-100%);
transition: transform 200ms ease-in-out; transition: transform 200ms ease-in-out;
} }
/* Menu open styles */ /* Menu open styles */
.unified-wrapper .wy-grid-for-nav nav.wy-nav-side {
position: absolute;
}
.unified-wrapper.menu-open nav.wy-nav-side { .unified-wrapper.menu-open nav.wy-nav-side {
transform: translateX(0); transform: translateX(0);
transition: transform 200ms ease-in-out; transition: transform 200ms ease-in-out;
@ -608,18 +612,6 @@ footer .rst-footer-buttons {
a.skip-to-content { a.skip-to-content {
display: none; display: none;
} }
.wy-nav-content {
margin-inline-start: 0 !important;
}
.rst-content {
max-width: 100% !important;
}
.wy-side-scroll {
padding-bottom: 0 !important;
}
} }
ul.search .context { ul.search .context {
@ -666,8 +658,6 @@ ul.search .context {
.rst-other-versions { .rst-other-versions {
background: var(--white) !important; background: var(--white) !important;
color: var(--color-a) !important; color: var(--color-a) !important;
max-height: calc(100vh - var(--navHeight) - var(--currentVersionHeight));
overflow-y: scroll;
} }
.rst-other-versions a { .rst-other-versions a {
@ -788,8 +778,9 @@ button.mobile-menu-button {
font-family: 'Overpass Mono', monospace; font-family: 'Overpass Mono', monospace;
} }
.wy-breadcrumbs>li { .wy-breadcrumbs-aside {
padding-top: 8px; display: block;
padding-top: 0;
} }
.wy-breadcrumbs-aside a { .wy-breadcrumbs-aside a {
@ -810,9 +801,8 @@ a.skip-to-content {
padding: 2px 4px; padding: 2px 4px;
font-size: 14px; font-size: 14px;
margin-inline-end: auto; margin-inline-end: auto;
margin-inline-start: 1.5rem; margin-inline-start: 2rem;
color: var(--color-a); color: var(--color-a);
white-space: nowrap;
} }
a.skip-to-content:focus { a.skip-to-content:focus {

BIN
docs/_static/fonts/overpass-bold.otf vendored Normal file

Binary file not shown.

BIN
docs/_static/fonts/overpass-bold.woff2 vendored Normal file

Binary file not shown.

BIN
docs/_static/fonts/overpass-italic.otf vendored Normal file

Binary file not shown.

BIN
docs/_static/fonts/overpass-light.otf vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

BIN
docs/_static/fonts/overpass-regular.otf vendored Normal file

Binary file not shown.

Binary file not shown.

BIN
docs/_static/fonts/overpass-semibold.otf vendored Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -1,18 +1,11 @@
// Site URL
const SITE_URL = "https://docs.soliditylang.org"
const { origin, pathname } = location;
const pathSplit = pathname.split("/");
const rootPath = origin.includes(SITE_URL) && pathSplit.length > 3 ? pathSplit.splice(1, 2).join("/") : ''
const ROOT_URL = `${origin}/${rootPath}`;
// Color mode constants // Color mode constants
const [DARK, LIGHT] = ["dark", "light"]; const [DARK, LIGHT] = ["dark", "light"];
const LIGHT_LOGO_PATH = `${ROOT_URL}/_static/img/logo.svg`; const LIGHT_LOGO_PATH = "_static/img/logo.svg";
const DARK_LOGO_PATH = `${ROOT_URL}/_static/img/logo-dark.svg`; const DARK_LOGO_PATH = "_static/img/logo-dark.svg";
const SUN_ICON_PATH = `${ROOT_URL}/_static/img/sun.svg`; const SUN_ICON_PATH = "_static/img/sun.svg";
const MOON_ICON_PATH = `${ROOT_URL}/_static/img/moon.svg`; const MOON_ICON_PATH = "_static/img/moon.svg";
const LIGHT_HAMBURGER_PATH = `${ROOT_URL}/_static/img/hamburger-light.svg`; const LIGHT_HAMBURGER_PATH = "_static/img/hamburger-light.svg";
const DARK_HAMBURGER_PATH = `${ROOT_URL}/_static/img/hamburger-dark.svg`; const DARK_HAMBURGER_PATH = "_static/img/hamburger-dark.svg";
const COLOR_TOGGLE_ICON_CLASS = "color-toggle-icon"; const COLOR_TOGGLE_ICON_CLASS = "color-toggle-icon";
const SOLIDITY_LOGO_CLASS = "solidity-logo"; const SOLIDITY_LOGO_CLASS = "solidity-logo";
const LS_COLOR_SCHEME = "color-scheme"; const LS_COLOR_SCHEME = "color-scheme";

View File

@ -63,7 +63,7 @@ function buildHeader() {
const skipToContent = document.createElement("a"); const skipToContent = document.createElement("a");
skipToContent.classList.add("skip-to-content"); skipToContent.classList.add("skip-to-content");
skipToContent.href = "#content"; skipToContent.href = "#content";
skipToContent.innerText = "{skip to content}"; skipToContent.innerText = "{ skip to content }";
innerHeader.appendChild(skipToContent); innerHeader.appendChild(skipToContent);
const navBar = document.createElement("nav"); const navBar = document.createElement("nav");
@ -143,20 +143,23 @@ const updateActiveNavLink = () => {
document.addEventListener("locationchange", updateActiveNavLink); document.addEventListener("locationchange", updateActiveNavLink);
function updateGitHubEditPath() {
// Replaces the version number in the GitHub edit path with "develop"
const gitHubEditAnchor = document.querySelector(".wy-breadcrumbs-aside > a");
const url = new URL(gitHubEditAnchor.href);
const split = url.pathname.split("/");
const versionIndex = split.indexOf("blob") + 1;
split[versionIndex] = "develop";
url.pathname = split.join("/");
gitHubEditAnchor.setAttribute("href", url.toString());
gitHubEditAnchor.setAttribute("target", "_blank");
gitHubEditAnchor.setAttribute("rel", "noopener noreferrer");
}
function initialize() { function initialize() {
// Preload fonts
const fonts = [
"overpass-regular.otf",
"overpass-bold.otf",
"overpass-mono-regular.otf",
"overpass-mono-bold.otf",
];
fonts.forEach((filename) => {
const link = document.createElement("link");
link.rel = "preload";
link.as = "font";
link.href = `https://solidity-docs-dev.readthedocs.io/en/latest/_static/fonts/${filename}`;
link.crossOrigin = "";
document.head.appendChild(link);
});
// Rearrange DOM elements for styling // Rearrange DOM elements for styling
rearrangeDom(); rearrangeDom();
@ -211,9 +214,6 @@ function initialize() {
// Update active nav link // Update active nav link
updateActiveNavLink(); updateActiveNavLink();
// Update GitHub edit path to direct to `develop` branch
updateGitHubEditPath();
} }
document.addEventListener("DOMContentLoaded", initialize); document.addEventListener("DOMContentLoaded", initialize);

View File

@ -67,7 +67,7 @@ When using the Solidity logo, please respect the Solidity logo guidelines.
Solidity Logo Guidelines Solidity Logo Guidelines
======================== ========================
.. image:: solidity_logo.svg .. image:: logo.svg
:width: 256 :width: 256
*(Right click on the logo to download it.)* *(Right click on the logo to download it.)*

View File

@ -169,7 +169,7 @@ html_js_files = ["js/constants.js", "js/initialize.js", "js/toggle.js"]
# Add any extra paths that contain custom files (such as robots.txt or # Add any extra paths that contain custom files (such as robots.txt or
# .htaccess) here, relative to this directory. These files are copied # .htaccess) here, relative to this directory. These files are copied
# directly to the root of the documentation. # directly to the root of the documentation.
html_extra_path = ["_static/css"] html_extra_path = ["_static/css", "_static/fonts"]
# List of templates of static files to be included in the HTML output. # List of templates of static files to be included in the HTML output.
# Keys represent paths to input files and values are dicts containing: # Keys represent paths to input files and values are dicts containing:

View File

@ -9,10 +9,9 @@ Events
Solidity events give an abstraction on top of the EVM's logging functionality. Solidity events give an abstraction on top of the EVM's logging functionality.
Applications can subscribe and listen to these events through the RPC interface of an Ethereum client. Applications can subscribe and listen to these events through the RPC interface of an Ethereum client.
Events can be defined at file level or as inheritable members of contracts (including interfaces and libraries). Events are inheritable members of contracts. When you call them, they cause the
When you call them, they cause the
arguments to be stored in the transaction's log - a special data structure arguments to be stored in the transaction's log - a special data structure
in the blockchain. These logs are associated with the address of the contract that emitted them, in the blockchain. These logs are associated with the address of the contract,
are incorporated into the blockchain, and stay there as long as a block is are incorporated into the blockchain, and stay there as long as a block is
accessible (forever as of now, but this might accessible (forever as of now, but this might
change with Serenity). The Log and its event data is not accessible from within change with Serenity). The Log and its event data is not accessible from within

View File

@ -132,7 +132,7 @@ variables are set to their :ref:`default values<default-value>` just as if the f
body. body.
The ``_`` symbol can appear in the modifier multiple times. Each occurrence is replaced with The ``_`` symbol can appear in the modifier multiple times. Each occurrence is replaced with
the function body, and the function returns the return value of the final occurrence. the function body.
Arbitrary expressions are allowed for modifier arguments and in this context, Arbitrary expressions are allowed for modifier arguments and in this context,
all symbols visible from the function are visible in the modifier. Symbols all symbols visible from the function are visible in the modifier. Symbols

View File

@ -22,7 +22,6 @@ sourceUnit: (
| enumDefinition | enumDefinition
| userDefinedValueTypeDefinition | userDefinedValueTypeDefinition
| errorDefinition | errorDefinition
| eventDefinition
)* EOF; )* EOF;
//@doc: inline //@doc: inline

View File

@ -323,7 +323,7 @@ The following are dependencies for all builds of Solidity:
| `CMake`_ (version 3.21.3+ on | Cross-platform build file generator. | | `CMake`_ (version 3.21.3+ on | Cross-platform build file generator. |
| Windows, 3.13+ otherwise) | | | Windows, 3.13+ otherwise) | |
+-----------------------------------+-------------------------------------------------------+ +-----------------------------------+-------------------------------------------------------+
| `Boost`_ (version 1.77+ on | C++ libraries. | | `Boost`_ (version 1.77 on | C++ libraries. |
| Windows, 1.65+ otherwise) | | | Windows, 1.65+ otherwise) | |
+-----------------------------------+-------------------------------------------------------+ +-----------------------------------+-------------------------------------------------------+
| `Git`_ | Command-line tool for retrieving source code. | | `Git`_ | Command-line tool for retrieving source code. |
@ -410,7 +410,7 @@ You need to install the following dependencies for Windows builds of Solidity:
+-----------------------------------+-------------------------------------------------------+ +-----------------------------------+-------------------------------------------------------+
| `Visual Studio 2019`_ (Optional) | C++ compiler and dev environment. | | `Visual Studio 2019`_ (Optional) | C++ compiler and dev environment. |
+-----------------------------------+-------------------------------------------------------+ +-----------------------------------+-------------------------------------------------------+
| `Boost`_ (version 1.77+) | C++ libraries. | | `Boost`_ (version 1.77) | C++ libraries. |
+-----------------------------------+-------------------------------------------------------+ +-----------------------------------+-------------------------------------------------------+
If you already have one IDE and only need the compiler and libraries, If you already have one IDE and only need the compiler and libraries,

View File

@ -338,7 +338,7 @@ You can override this sequence and supply your own using the ``--yul-optimizatio
.. code-block:: bash .. code-block:: bash
solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul:fDnTOcmu' solc --optimize --ir-optimized --yul-optimizations 'dhfoD[xarrscLMcCTU]uljmul:fDnTOc'
The order of steps is significant and affects the quality of the output. The order of steps is significant and affects the quality of the output.
Moreover, applying a step may uncover new optimization opportunities for others that were already applied, Moreover, applying a step may uncover new optimization opportunities for others that were already applied,

View File

@ -515,7 +515,7 @@ you can use the following in your source file:
The compiler will look for the file in the VFS under ``dapp-bin/library/math.sol``. The compiler will look for the file in the VFS under ``dapp-bin/library/math.sol``.
If the file is not available there, the source unit name will be passed to the Host Filesystem If the file is not available there, the source unit name will be passed to the Host Filesystem
Loader, which will then look in ``/project/dapp-bin/library/math.sol``. Loader, which will then look in ``/project/dapp-bin/library/iterable_mapping.sol``.
.. warning:: .. warning::

View File

@ -1,27 +0,0 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Generator: Adobe Illustrator 16.0.3, SVG Export Plug-In . SVG Version: 6.00 Build 0) -->
<!DOCTYPE svg PUBLIC "-//W3C//DTD SVG 1.1//EN" "http://www.w3.org/Graphics/SVG/1.1/DTD/svg11.dtd">
<svg version="1.1" id="Layer_1" xmlns:sketch="http://www.bohemiancoding.com/sketch/ns"
xmlns="http://www.w3.org/2000/svg" xmlns:xlink="http://www.w3.org/1999/xlink" x="0px" y="0px" width="1300px" height="1300px"
viewBox="0 0 1300 1300" enable-background="new 0 0 1300 1300" xml:space="preserve">
<title>Vector 1</title>
<desc>Created with Sketch.</desc>
<g id="Page-1" sketch:type="MSPage">
<g id="solidity" transform="translate(402.000000, 118.000000)" sketch:type="MSLayerGroup">
<g id="Group" sketch:type="MSShapeGroup">
<path id="Shape" opacity="0.45" enable-background="new " d="M371.772,135.308L241.068,367.61H-20.158l130.614-232.302
H371.772"/>
<path id="Shape_1_" opacity="0.6" enable-background="new " d="M241.068,367.61h261.318L371.772,135.308H110.456
L241.068,367.61z"/>
<path id="Shape_2_" opacity="0.8" enable-background="new " d="M110.456,599.822L241.068,367.61L110.456,135.308
L-20.158,367.61L110.456,599.822z"/>
<path id="Shape_3_" opacity="0.45" enable-background="new " d="M111.721,948.275l130.704-232.303h261.318L373.038,948.275
H111.721"/>
<path id="Shape_4_" opacity="0.6" enable-background="new " d="M242.424,715.973H-18.893l130.613,232.303h261.317
L242.424,715.973z"/>
<path id="Shape_5_" opacity="0.8" enable-background="new " d="M373.038,483.761L242.424,715.973l130.614,232.303
l130.704-232.303L373.038,483.761z"/>
</g>
</g>
</g>
</svg>

Before

Width:  |  Height:  |  Size: 1.6 KiB

View File

@ -112,11 +112,11 @@ Events are convenience interfaces with the EVM logging facilities.
.. code-block:: solidity .. code-block:: solidity
// SPDX-License-Identifier: GPL-3.0 // SPDX-License-Identifier: GPL-3.0
pragma solidity ^0.8.22; pragma solidity >=0.4.21 <0.9.0;
event HighestBidIncreased(address bidder, uint amount); // Event
contract SimpleAuction { contract SimpleAuction {
event HighestBidIncreased(address bidder, uint amount); // Event
function bid() public payable { function bid() public payable {
// ... // ...
emit HighestBidIncreased(msg.sender, msg.value); // Triggering event emit HighestBidIncreased(msg.sender, msg.value); // Triggering event

View File

@ -372,7 +372,7 @@ Array Members
.. note:: .. note::
In EVM versions before Byzantium, it was not possible to access In EVM versions before Byzantium, it was not possible to access
dynamic arrays returned from function calls. If you call functions dynamic arrays return from function calls. If you call functions
that return dynamic arrays, make sure to use an EVM that is set to that return dynamic arrays, make sure to use an EVM that is set to
Byzantium mode. Byzantium mode.

View File

@ -359,7 +359,7 @@ Input Description
// Addresses of the libraries. If not all libraries are given here, // Addresses of the libraries. If not all libraries are given here,
// it can result in unlinked objects whose output data is different. // it can result in unlinked objects whose output data is different.
"libraries": { "libraries": {
// The top level key is the name of the source file where the library is used. // The top level key is the the name of the source file where the library is used.
// If remappings are used, this source file should match the global path // If remappings are used, this source file should match the global path
// after remappings were applied. // after remappings were applied.
// If this key is an empty string, that refers to a global level. // If this key is an empty string, that refers to a global level.
@ -408,7 +408,7 @@ Input Description
// evm.methodIdentifiers - The list of function hashes // evm.methodIdentifiers - The list of function hashes
// evm.gasEstimates - Function gas estimates // evm.gasEstimates - Function gas estimates
// //
// Note that using `evm`, `evm.bytecode`, etc. will select every // Note that using a using `evm`, `evm.bytecode`, etc. will select every
// target part of that output. Additionally, `*` can be used as a wildcard to request everything. // target part of that output. Additionally, `*` can be used as a wildcard to request everything.
// //
"outputSelection": { "outputSelection": {

View File

@ -741,7 +741,7 @@ EVM Dialect
----------- -----------
The default dialect of Yul currently is the EVM dialect for the currently selected version of the EVM. The default dialect of Yul currently is the EVM dialect for the currently selected version of the EVM.
The only type available in this dialect with a version of the EVM. The only type available in this dialect
is ``u256``, the 256-bit native type of the Ethereum Virtual Machine. is ``u256``, the 256-bit native type of the Ethereum Virtual Machine.
Since it is the default type of this dialect, it can be omitted. Since it is the default type of this dialect, it can be omitted.

View File

@ -109,7 +109,7 @@ public:
/// Resets any knowledge about storage. /// Resets any knowledge about storage.
void resetStorage() { m_storageContent.clear(); } void resetStorage() { m_storageContent.clear(); }
/// Resets any knowledge about memory. /// Resets any knowledge about storage.
void resetMemory() { m_memoryContent.clear(); } void resetMemory() { m_memoryContent.clear(); }
/// Resets known Keccak-256 hashes /// Resets known Keccak-256 hashes
void resetKnownKeccak256Hashes() { m_knownKeccak256Hashes.clear(); } void resetKnownKeccak256Hashes() { m_knownKeccak256Hashes.clear(); }

View File

@ -170,8 +170,6 @@ class Error: virtual public util::Exception
public: public:
enum class Type enum class Type
{ {
Info,
Warning,
CodeGenerationError, CodeGenerationError,
DeclarationError, DeclarationError,
DocstringParsingError, DocstringParsingError,
@ -187,14 +185,15 @@ public:
UnimplementedFeatureError, UnimplementedFeatureError,
YulException, YulException,
SMTLogicException, SMTLogicException,
Warning,
Info
}; };
enum class Severity enum class Severity
{ {
// NOTE: We rely on these being ordered from least to most severe.
Info,
Warning,
Error, Error,
Warning,
Info
}; };
Error( Error(
@ -207,7 +206,6 @@ public:
ErrorId errorId() const { return m_errorId; } ErrorId errorId() const { return m_errorId; }
Type type() const { return m_type; } Type type() const { return m_type; }
Severity severity() const { return errorSeverity(m_type); }
SourceLocation const* sourceLocation() const noexcept; SourceLocation const* sourceLocation() const noexcept;
SecondarySourceLocation const* secondarySourceLocation() const noexcept; SecondarySourceLocation const* secondarySourceLocation() const noexcept;

View File

@ -74,10 +74,56 @@ void ParserBase::expectToken(Token _value, bool _advance)
{ {
Token tok = m_scanner->currentToken(); Token tok = m_scanner->currentToken();
if (tok != _value) if (tok != _value)
fatalParserError( {
2314_error, std::string const expectedToken = ParserBase::tokenName(_value);
"Expected " + ParserBase::tokenName(_value) + " but got " + tokenName(tok) if (m_parserErrorRecovery)
); parserError(6635_error, "Expected " + expectedToken + " but got " + tokenName(tok));
else
fatalParserError(2314_error, "Expected " + expectedToken + " but got " + tokenName(tok));
// Do not advance so that recovery can sync or make use of the current token.
// This is especially useful if the expected token
// is the only one that is missing and is at the end of a construct.
// "{ ... ; }" is such an example.
// ^
_advance = false;
}
if (_advance)
advance();
}
void ParserBase::expectTokenOrConsumeUntil(Token _value, std::string const& _currentNodeName, bool _advance)
{
solAssert(m_inParserRecovery, "The function is supposed to be called during parser recovery only.");
Token tok = m_scanner->currentToken();
if (tok != _value)
{
SourceLocation errorLoc = currentLocation();
int startPosition = errorLoc.start;
while (m_scanner->currentToken() != _value && m_scanner->currentToken() != Token::EOS)
advance();
std::string const expectedToken = ParserBase::tokenName(_value);
if (m_scanner->currentToken() == Token::EOS)
{
// rollback to where the token started, and raise exception to be caught at a higher level.
m_scanner->setPosition(static_cast<size_t>(startPosition));
std::string const msg = "In " + _currentNodeName + ", " + expectedToken + "is expected; got " + ParserBase::tokenName(tok) + " instead.";
fatalParserError(1957_error, errorLoc, msg);
}
else
{
parserWarning(3796_error, "Recovered in " + _currentNodeName + " at " + expectedToken + ".");
m_inParserRecovery = false;
}
}
else
{
std::string expectedToken = ParserBase::tokenName(_value);
parserWarning(3347_error, "Recovered in " + _currentNodeName + " at " + expectedToken + ".");
m_inParserRecovery = false;
}
if (_advance) if (_advance)
advance(); advance();
} }

View File

@ -38,9 +38,14 @@ struct ErrorId;
class ParserBase class ParserBase
{ {
public: public:
explicit ParserBase(ErrorReporter& errorReporter): /// Set @a _parserErrorRecovery to true for additional error
m_errorReporter(errorReporter) /// recovery. This is experimental and intended for use
{} /// by front-end tools that need partial AST information even
/// when errors occur.
explicit ParserBase(ErrorReporter& errorReporter, bool _parserErrorRecovery = false): m_errorReporter(errorReporter)
{
m_parserErrorRecovery = _parserErrorRecovery;
}
virtual ~ParserBase() = default; virtual ~ParserBase() = default;
@ -65,9 +70,13 @@ protected:
///@{ ///@{
///@name Helper functions ///@name Helper functions
/// If current token value is not @a _value, throw exception otherwise advance token /// If current token value is not @a _value, throw exception otherwise advance token
// if @a _advance is true // @a if _advance is true and error recovery is in effect.
void expectToken(Token _value, bool _advance = true); void expectToken(Token _value, bool _advance = true);
/// Like expectToken but if there is an error ignores tokens until
/// the expected token or EOS is seen. If EOS is encountered, back up to the error point,
/// and throw an exception so that a higher grammar rule has an opportunity to recover.
void expectTokenOrConsumeUntil(Token _value, std::string const& _currentNodeName, bool _advance = true);
Token currentToken() const; Token currentToken() const;
Token peekNextToken() const; Token peekNextToken() const;
std::string tokenName(Token _token); std::string tokenName(Token _token);
@ -99,6 +108,10 @@ protected:
ErrorReporter& m_errorReporter; ErrorReporter& m_errorReporter;
/// Current recursion depth during parsing. /// Current recursion depth during parsing.
size_t m_recursionDepth = 0; size_t m_recursionDepth = 0;
/// True if we are in parser error recovery. Usually this means we are scanning for
/// a synchronization token like ';', or '}'. We use this to reduce cascaded error messages.
bool m_inParserRecovery = false;
bool m_parserErrorRecovery = false;
}; };
} }

View File

@ -1019,28 +1019,15 @@ std::tuple<Token, unsigned, unsigned> Scanner::scanIdentifierOrKeyword()
while (isIdentifierPart(m_char) || (m_char == '.' && m_kind == ScannerKind::Yul)) while (isIdentifierPart(m_char) || (m_char == '.' && m_kind == ScannerKind::Yul))
addLiteralCharAndAdvance(); addLiteralCharAndAdvance();
literal.complete(); literal.complete();
auto const token = TokenTraits::fromIdentifierOrKeyword(m_tokens[NextNext].literal); auto const token = TokenTraits::fromIdentifierOrKeyword(m_tokens[NextNext].literal);
switch (m_kind) if (m_kind == ScannerKind::Yul)
{ {
case ScannerKind::Solidity:
// Turn experimental Solidity keywords that are not keywords in legacy Solidity into identifiers.
if (TokenTraits::isExperimentalSolidityOnlyKeyword(std::get<0>(token)))
return std::make_tuple(Token::Identifier, 0, 0);
break;
case ScannerKind::Yul:
// Turn Solidity identifier into a Yul keyword // Turn Solidity identifier into a Yul keyword
if (m_tokens[NextNext].literal == "leave") if (m_tokens[NextNext].literal == "leave")
return std::make_tuple(Token::Leave, 0, 0); return std::make_tuple(Token::Leave, 0, 0);
// Turn non-Yul keywords into identifiers. // Turn non-Yul keywords into identifiers.
if (!TokenTraits::isYulKeyword(std::get<0>(token))) if (!TokenTraits::isYulKeyword(std::get<0>(token)))
return std::make_tuple(Token::Identifier, 0, 0); return std::make_tuple(Token::Identifier, 0, 0);
break;
case ScannerKind::ExperimentalSolidity:
// Turn legacy Solidity keywords that are not keywords in experimental Solidity into identifiers.
if (!TokenTraits::isExperimentalSolidityKeyword(std::get<0>(token)))
return std::make_tuple(Token::Identifier, 0, 0);
break;
} }
return token; return token;
} }

View File

@ -69,8 +69,7 @@ class ParserRecorder;
enum class ScannerKind enum class ScannerKind
{ {
Solidity, Solidity,
Yul, Yul
ExperimentalSolidity
}; };
enum class ScannerError enum class ScannerError

View File

@ -46,16 +46,9 @@ public:
bool _colored, bool _colored,
bool _withErrorIds bool _withErrorIds
): ):
m_stream(_stream), m_stream(_stream), m_charStreamProvider(_charStreamProvider), m_colored(_colored), m_withErrorIds(_withErrorIds)
m_charStreamProvider(_charStreamProvider),
m_colored(_colored),
m_withErrorIds(_withErrorIds)
{} {}
// WARNING: Use the xyzErrorInformation() variants over xyzExceptionInformation() when you
// do have access to an Error instance. Error is implicitly convertible to util::Exception
// but the conversion loses the error ID.
/// Prints source location if it is given. /// Prints source location if it is given.
void printSourceLocation(SourceReference const& _ref); void printSourceLocation(SourceReference const& _ref);
void printExceptionInformation(SourceReferenceExtractor::Message const& _msg); void printExceptionInformation(SourceReferenceExtractor::Message const& _msg);
@ -68,11 +61,12 @@ public:
util::Exception const& _exception, util::Exception const& _exception,
Error::Type _type, Error::Type _type,
CharStreamProvider const& _charStreamProvider, CharStreamProvider const& _charStreamProvider,
bool _colored = false bool _colored = false,
bool _withErrorIds = false
) )
{ {
std::ostringstream errorOutput; std::ostringstream errorOutput;
SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, false /* _withErrorIds */); SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, _withErrorIds);
formatter.printExceptionInformation(_exception, _type); formatter.printExceptionInformation(_exception, _type);
return errorOutput.str(); return errorOutput.str();
} }
@ -81,39 +75,26 @@ public:
util::Exception const& _exception, util::Exception const& _exception,
Error::Severity _severity, Error::Severity _severity,
CharStreamProvider const& _charStreamProvider, CharStreamProvider const& _charStreamProvider,
bool _colored = false bool _colored = false,
bool _withErrorIds = false
) )
{ {
std::ostringstream errorOutput; std::ostringstream errorOutput;
SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, false /* _withErrorIds */); SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, _withErrorIds);
formatter.printExceptionInformation(_exception, _severity); formatter.printExceptionInformation(_exception, _severity);
return errorOutput.str(); return errorOutput.str();
} }
static std::string formatErrorInformation( static std::string formatErrorInformation(
Error const& _error, Error const& _error,
CharStreamProvider const& _charStreamProvider, CharStreamProvider const& _charStreamProvider
bool _colored = false,
bool _withErrorIds = false
) )
{ {
std::ostringstream errorOutput; return formatExceptionInformation(
SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, _withErrorIds); _error,
formatter.printErrorInformation(_error); Error::errorSeverity(_error.type()),
return errorOutput.str(); _charStreamProvider
} );
static std::string formatErrorInformation(
langutil::ErrorList const& _errors,
CharStreamProvider const& _charStreamProvider,
bool _colored = false,
bool _withErrorIds = false
)
{
std::ostringstream errorOutput;
SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, _withErrorIds);
formatter.printErrorInformation(_errors);
return errorOutput.str();
} }
static std::string formatErrorInformation(Error const& _error, CharStream const& _charStream); static std::string formatErrorInformation(Error const& _error, CharStream const& _charStream);

View File

@ -268,8 +268,6 @@ namespace solidity::langutil
/* Yul-specific tokens, but not keywords. */ \ /* Yul-specific tokens, but not keywords. */ \
T(Leave, "leave", 0) \ T(Leave, "leave", 0) \
\ \
T(NonExperimentalEnd, nullptr, 0) /* used as non-experimental enum end marker */ \
T(ExperimentalEnd, nullptr, 0) /* used as experimental enum end marker */ \
/* Illegal token - not able to scan. */ \ /* Illegal token - not able to scan. */ \
T(Illegal, "ILLEGAL", 0) \ T(Illegal, "ILLEGAL", 0) \
\ \
@ -325,39 +323,6 @@ namespace TokenTraits
tok == Token::TrueLiteral || tok == Token::FalseLiteral || tok == Token::HexStringLiteral || tok == Token::Hex; tok == Token::TrueLiteral || tok == Token::FalseLiteral || tok == Token::HexStringLiteral || tok == Token::Hex;
} }
constexpr bool isExperimentalSolidityKeyword(Token token)
{
return
token == Token::Assembly ||
token == Token::Contract ||
token == Token::External ||
token == Token::Fallback ||
token == Token::Pragma ||
token == Token::Import ||
token == Token::As ||
token == Token::Function ||
token == Token::Let ||
token == Token::Return ||
token == Token::Type ||
token == Token::If ||
token == Token::Else ||
token == Token::Do ||
token == Token::While ||
token == Token::For ||
token == Token::Continue ||
token == Token::Break;
// TODO: see isExperimentalSolidityKeyword below
// || (token > Token::NonExperimentalEnd && token < Token::ExperimentalEnd);
}
constexpr bool isExperimentalSolidityOnlyKeyword(Token)
{
// TODO: use token > Token::NonExperimentalEnd && token < Token::ExperimentalEnd
// as soon as other experimental tokens are added. For now the comparison generates
// a warning from clang because it is always false.
return false;
}
bool isYulKeyword(std::string const& _literal); bool isYulKeyword(std::string const& _literal);
Token AssignmentToBinaryOp(Token op); Token AssignmentToBinaryOp(Token op);

View File

@ -101,8 +101,6 @@ set(sources
codegen/ir/IRLValue.h codegen/ir/IRLValue.h
codegen/ir/IRVariable.cpp codegen/ir/IRVariable.cpp
codegen/ir/IRVariable.h codegen/ir/IRVariable.h
experimental/analysis/Analysis.cpp
experimental/analysis/Analysis.h
formal/ArraySlicePredicate.cpp formal/ArraySlicePredicate.cpp
formal/ArraySlicePredicate.h formal/ArraySlicePredicate.h
formal/BMC.cpp formal/BMC.cpp
@ -188,3 +186,4 @@ set(sources
add_library(solidity ${sources}) add_library(solidity ${sources})
target_link_libraries(solidity PUBLIC yul evmasm langutil smtutil solutil Boost::boost fmt::fmt-header-only Threads::Threads) target_link_libraries(solidity PUBLIC yul evmasm langutil smtutil solutil Boost::boost fmt::fmt-header-only Threads::Threads)

View File

@ -29,6 +29,7 @@
#include <limits> #include <limits>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::langutil; using namespace solidity::langutil;
@ -46,9 +47,9 @@ bool fitsPrecisionExp(bigint const& _base, bigint const& _exp)
solAssert(_base > 0, ""); solAssert(_base > 0, "");
std::size_t const bitsMax = 4096; size_t const bitsMax = 4096;
std::size_t mostSignificantBaseBit = static_cast<std::size_t>(boost::multiprecision::msb(_base)); size_t mostSignificantBaseBit = static_cast<size_t>(boost::multiprecision::msb(_base));
if (mostSignificantBaseBit == 0) // _base == 1 if (mostSignificantBaseBit == 0) // _base == 1
return true; return true;
if (mostSignificantBaseBit > bitsMax) // _base >= 2 ^ 4096 if (mostSignificantBaseBit > bitsMax) // _base >= 2 ^ 4096
@ -67,7 +68,7 @@ bool fitsPrecisionBase2(bigint const& _mantissa, uint32_t _expBase2)
} }
std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operator, rational const& _left, rational const& _right) optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operator, rational const& _left, rational const& _right)
{ {
bool fractional = _left.denominator() != 1 || _right.denominator() != 1; bool fractional = _left.denominator() != 1 || _right.denominator() != 1;
switch (_operator) switch (_operator)
@ -75,17 +76,17 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
//bit operations will only be enabled for integers and fixed types that resemble integers //bit operations will only be enabled for integers and fixed types that resemble integers
case Token::BitOr: case Token::BitOr:
if (fractional) if (fractional)
return std::nullopt; return nullopt;
else else
return _left.numerator() | _right.numerator(); return _left.numerator() | _right.numerator();
case Token::BitXor: case Token::BitXor:
if (fractional) if (fractional)
return std::nullopt; return nullopt;
else else
return _left.numerator() ^ _right.numerator(); return _left.numerator() ^ _right.numerator();
case Token::BitAnd: case Token::BitAnd:
if (fractional) if (fractional)
return std::nullopt; return nullopt;
else else
return _left.numerator() & _right.numerator(); return _left.numerator() & _right.numerator();
case Token::Add: return _left + _right; case Token::Add: return _left + _right;
@ -93,12 +94,12 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
case Token::Mul: return _left * _right; case Token::Mul: return _left * _right;
case Token::Div: case Token::Div:
if (_right == rational(0)) if (_right == rational(0))
return std::nullopt; return nullopt;
else else
return _left / _right; return _left / _right;
case Token::Mod: case Token::Mod:
if (_right == rational(0)) if (_right == rational(0))
return std::nullopt; return nullopt;
else if (fractional) else if (fractional)
{ {
rational tempValue = _left / _right; rational tempValue = _left / _right;
@ -110,7 +111,7 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
case Token::Exp: case Token::Exp:
{ {
if (_right.denominator() != 1) if (_right.denominator() != 1)
return std::nullopt; return nullopt;
bigint const& exp = _right.numerator(); bigint const& exp = _right.numerator();
// x ** 0 = 1 // x ** 0 = 1
@ -126,13 +127,13 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
} }
else else
{ {
if (abs(exp) > std::numeric_limits<uint32_t>::max()) if (abs(exp) > numeric_limits<uint32_t>::max())
return std::nullopt; // This will need too much memory to represent. return nullopt; // This will need too much memory to represent.
uint32_t absExp = bigint(abs(exp)).convert_to<uint32_t>(); uint32_t absExp = bigint(abs(exp)).convert_to<uint32_t>();
if (!fitsPrecisionExp(abs(_left.numerator()), absExp) || !fitsPrecisionExp(abs(_left.denominator()), absExp)) if (!fitsPrecisionExp(abs(_left.numerator()), absExp) || !fitsPrecisionExp(abs(_left.denominator()), absExp))
return std::nullopt; return nullopt;
static auto const optimizedPow = [](bigint const& _base, uint32_t _exponent) -> bigint { static auto const optimizedPow = [](bigint const& _base, uint32_t _exponent) -> bigint {
if (_base == 1) if (_base == 1)
@ -157,18 +158,18 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
case Token::SHL: case Token::SHL:
{ {
if (fractional) if (fractional)
return std::nullopt; return nullopt;
else if (_right < 0) else if (_right < 0)
return std::nullopt; return nullopt;
else if (_right > std::numeric_limits<uint32_t>::max()) else if (_right > numeric_limits<uint32_t>::max())
return std::nullopt; return nullopt;
if (_left.numerator() == 0) if (_left.numerator() == 0)
return 0; return 0;
else else
{ {
uint32_t exponent = _right.numerator().convert_to<uint32_t>(); uint32_t exponent = _right.numerator().convert_to<uint32_t>();
if (!fitsPrecisionBase2(abs(_left.numerator()), exponent)) if (!fitsPrecisionBase2(abs(_left.numerator()), exponent))
return std::nullopt; return nullopt;
return _left.numerator() * boost::multiprecision::pow(bigint(2), exponent); return _left.numerator() * boost::multiprecision::pow(bigint(2), exponent);
} }
break; break;
@ -178,11 +179,11 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
case Token::SAR: case Token::SAR:
{ {
if (fractional) if (fractional)
return std::nullopt; return nullopt;
else if (_right < 0) else if (_right < 0)
return std::nullopt; return nullopt;
else if (_right > std::numeric_limits<uint32_t>::max()) else if (_right > numeric_limits<uint32_t>::max())
return std::nullopt; return nullopt;
if (_left.numerator() == 0) if (_left.numerator() == 0)
return 0; return 0;
else else
@ -208,60 +209,60 @@ std::optional<rational> ConstantEvaluator::evaluateBinaryOperator(Token _operato
break; break;
} }
default: default:
return std::nullopt; return nullopt;
} }
} }
std::optional<rational> ConstantEvaluator::evaluateUnaryOperator(Token _operator, rational const& _input) optional<rational> ConstantEvaluator::evaluateUnaryOperator(Token _operator, rational const& _input)
{ {
switch (_operator) switch (_operator)
{ {
case Token::BitNot: case Token::BitNot:
if (_input.denominator() != 1) if (_input.denominator() != 1)
return std::nullopt; return nullopt;
else else
return ~_input.numerator(); return ~_input.numerator();
case Token::Sub: case Token::Sub:
return -_input; return -_input;
default: default:
return std::nullopt; return nullopt;
} }
} }
namespace namespace
{ {
std::optional<TypedRational> convertType(rational const& _value, Type const& _type) optional<TypedRational> convertType(rational const& _value, Type const& _type)
{ {
if (_type.category() == Type::Category::RationalNumber) if (_type.category() == Type::Category::RationalNumber)
return TypedRational{TypeProvider::rationalNumber(_value), _value}; return TypedRational{TypeProvider::rationalNumber(_value), _value};
else if (auto const* integerType = dynamic_cast<IntegerType const*>(&_type)) else if (auto const* integerType = dynamic_cast<IntegerType const*>(&_type))
{ {
if (_value > integerType->maxValue() || _value < integerType->minValue()) if (_value > integerType->maxValue() || _value < integerType->minValue())
return std::nullopt; return nullopt;
else else
return TypedRational{&_type, _value.numerator() / _value.denominator()}; return TypedRational{&_type, _value.numerator() / _value.denominator()};
} }
else else
return std::nullopt; return nullopt;
} }
std::optional<TypedRational> convertType(std::optional<TypedRational> const& _value, Type const& _type) optional<TypedRational> convertType(optional<TypedRational> const& _value, Type const& _type)
{ {
return _value ? convertType(_value->value, _type) : std::nullopt; return _value ? convertType(_value->value, _type) : nullopt;
} }
std::optional<TypedRational> constantToTypedValue(Type const& _type) optional<TypedRational> constantToTypedValue(Type const& _type)
{ {
if (_type.category() == Type::Category::RationalNumber) if (_type.category() == Type::Category::RationalNumber)
return TypedRational{&_type, dynamic_cast<RationalNumberType const&>(_type).value()}; return TypedRational{&_type, dynamic_cast<RationalNumberType const&>(_type).value()};
else else
return std::nullopt; return nullopt;
} }
} }
std::optional<TypedRational> ConstantEvaluator::evaluate( optional<TypedRational> ConstantEvaluator::evaluate(
langutil::ErrorReporter& _errorReporter, langutil::ErrorReporter& _errorReporter,
Expression const& _expr Expression const& _expr
) )
@ -270,7 +271,7 @@ std::optional<TypedRational> ConstantEvaluator::evaluate(
} }
std::optional<TypedRational> ConstantEvaluator::evaluate(ASTNode const& _node) optional<TypedRational> ConstantEvaluator::evaluate(ASTNode const& _node)
{ {
if (!m_values.count(&_node)) if (!m_values.count(&_node))
{ {
@ -279,7 +280,7 @@ std::optional<TypedRational> ConstantEvaluator::evaluate(ASTNode const& _node)
solAssert(varDecl->isConstant(), ""); solAssert(varDecl->isConstant(), "");
// In some circumstances, we do not yet have a type for the variable. // In some circumstances, we do not yet have a type for the variable.
if (!varDecl->value() || !varDecl->type()) if (!varDecl->value() || !varDecl->type())
m_values[&_node] = std::nullopt; m_values[&_node] = nullopt;
else else
{ {
m_depth++; m_depth++;
@ -297,7 +298,7 @@ std::optional<TypedRational> ConstantEvaluator::evaluate(ASTNode const& _node)
{ {
expression->accept(*this); expression->accept(*this);
if (!m_values.count(&_node)) if (!m_values.count(&_node))
m_values[&_node] = std::nullopt; m_values[&_node] = nullopt;
} }
} }
return m_values.at(&_node); return m_values.at(&_node);
@ -305,7 +306,7 @@ std::optional<TypedRational> ConstantEvaluator::evaluate(ASTNode const& _node)
void ConstantEvaluator::endVisit(UnaryOperation const& _operation) void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
{ {
std::optional<TypedRational> value = evaluate(_operation.subExpression()); optional<TypedRational> value = evaluate(_operation.subExpression());
if (!value) if (!value)
return; return;
@ -316,9 +317,9 @@ void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
if (!value) if (!value)
return; return;
if (std::optional<rational> result = evaluateUnaryOperator(_operation.getOperator(), value->value)) if (optional<rational> result = evaluateUnaryOperator(_operation.getOperator(), value->value))
{ {
std::optional<TypedRational> convertedValue = convertType(*result, *resultType); optional<TypedRational> convertedValue = convertType(*result, *resultType);
if (!convertedValue) if (!convertedValue)
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
3667_error, 3667_error,
@ -331,8 +332,8 @@ void ConstantEvaluator::endVisit(UnaryOperation const& _operation)
void ConstantEvaluator::endVisit(BinaryOperation const& _operation) void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
{ {
std::optional<TypedRational> left = evaluate(_operation.leftExpression()); optional<TypedRational> left = evaluate(_operation.leftExpression());
std::optional<TypedRational> right = evaluate(_operation.rightExpression()); optional<TypedRational> right = evaluate(_operation.rightExpression());
if (!left || !right) if (!left || !right)
return; return;
@ -348,7 +349,7 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
6020_error, 6020_error,
_operation.location(), _operation.location(),
"Operator " + "Operator " +
std::string(TokenTraits::toString(_operation.getOperator())) + string(TokenTraits::toString(_operation.getOperator())) +
" not compatible with types " + " not compatible with types " +
left->type->toString() + left->type->toString() +
" and " + " and " +
@ -362,9 +363,9 @@ void ConstantEvaluator::endVisit(BinaryOperation const& _operation)
if (!left || !right) if (!left || !right)
return; return;
if (std::optional<rational> value = evaluateBinaryOperator(_operation.getOperator(), left->value, right->value)) if (optional<rational> value = evaluateBinaryOperator(_operation.getOperator(), left->value, right->value))
{ {
std::optional<TypedRational> convertedValue = convertType(*value, *resultType); optional<TypedRational> convertedValue = convertType(*value, *resultType);
if (!convertedValue) if (!convertedValue)
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
2643_error, 2643_error,

View File

@ -32,6 +32,7 @@
#include <range/v3/view/reverse.hpp> #include <range/v3/view/reverse.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -48,10 +49,10 @@ bool hasEqualExternalCallableParameters(T const& _a, B const& _b)
} }
template<typename T> template<typename T>
std::map<ASTString, std::vector<T const*>> filterDeclarations( map<ASTString, vector<T const*>> filterDeclarations(
std::map<ASTString, std::vector<Declaration const*>> const& _declarations) map<ASTString, vector<Declaration const*>> const& _declarations)
{ {
std::map<ASTString, std::vector<T const*>> filteredDeclarations; map<ASTString, vector<T const*>> filteredDeclarations;
for (auto const& [name, overloads]: _declarations) for (auto const& [name, overloads]: _declarations)
for (auto const* declaration: overloads) for (auto const* declaration: overloads)
if (auto typedDeclaration = dynamic_cast<T const*>(declaration)) if (auto typedDeclaration = dynamic_cast<T const*>(declaration))
@ -105,7 +106,7 @@ void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _co
{ {
/// Checks that two functions with the same name defined in this contract have different /// Checks that two functions with the same name defined in this contract have different
/// argument types and that there is at most one constructor. /// argument types and that there is at most one constructor.
std::map<std::string, std::vector<FunctionDefinition const*>> functions; map<string, vector<FunctionDefinition const*>> functions;
FunctionDefinition const* constructor = nullptr; FunctionDefinition const* constructor = nullptr;
FunctionDefinition const* fallback = nullptr; FunctionDefinition const* fallback = nullptr;
FunctionDefinition const* receive = nullptr; FunctionDefinition const* receive = nullptr;
@ -156,7 +157,7 @@ void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contr
{ {
/// Checks that two events with the same name defined in this contract have different /// Checks that two events with the same name defined in this contract have different
/// argument types /// argument types
std::map<std::string, std::vector<EventDefinition const*>> events; map<string, vector<EventDefinition const*>> events;
for (auto const* contract: _contract.annotation().linearizedBaseContracts) for (auto const* contract: _contract.annotation().linearizedBaseContracts)
for (EventDefinition const* event: contract->events()) for (EventDefinition const* event: contract->events())
events[event->name()].push_back(event); events[event->name()].push_back(event);
@ -194,12 +195,12 @@ void ContractLevelChecker::checkReceiveFunction(ContractDefinition const& _contr
} }
template <class T> template <class T>
void ContractLevelChecker::findDuplicateDefinitions(std::map<std::string, std::vector<T>> const& _definitions) void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions)
{ {
for (auto const& it: _definitions) for (auto const& it: _definitions)
{ {
std::vector<T> const& overloads = it.second; vector<T> const& overloads = it.second;
std::set<size_t> reported; set<size_t> reported;
for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i) for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
{ {
SecondarySourceLocation ssl; SecondarySourceLocation ssl;
@ -227,15 +228,15 @@ void ContractLevelChecker::findDuplicateDefinitions(std::map<std::string, std::v
if (ssl.infos.size() > 0) if (ssl.infos.size() > 0)
{ {
ErrorId error; ErrorId error;
std::string message; string message;
if constexpr (std::is_same_v<T, FunctionDefinition const*>) if constexpr (is_same_v<T, FunctionDefinition const*>)
{ {
error = 1686_error; error = 1686_error;
message = "Function with same name and parameter types defined twice."; message = "Function with same name and parameter types defined twice.";
} }
else else
{ {
static_assert(std::is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\""); static_assert(is_same_v<T, EventDefinition const*>, "Expected \"FunctionDefinition const*\" or \"EventDefinition const*\"");
error = 5883_error; error = 5883_error;
message = "Event with same name and parameter types defined twice."; message = "Event with same name and parameter types defined twice.";
} }
@ -257,7 +258,7 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c
{ {
// Collects functions, static variable getters and modifiers. If they // Collects functions, static variable getters and modifiers. If they
// override (unimplemented) base class ones, they are replaced. // override (unimplemented) base class ones, they are replaced.
std::set<OverrideProxy, OverrideProxy::CompareBySignature> proxies; set<OverrideProxy, OverrideProxy::CompareBySignature> proxies;
auto registerProxy = [&proxies](OverrideProxy const& _overrideProxy) auto registerProxy = [&proxies](OverrideProxy const& _overrideProxy)
{ {
@ -322,7 +323,7 @@ void ContractLevelChecker::checkAbstractDefinitions(ContractDefinition const& _c
void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition const& _contract) void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition const& _contract)
{ {
std::vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts; vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
// Determine the arguments that are used for the base constructors. // Determine the arguments that are used for the base constructors.
for (ContractDefinition const* contract: bases) for (ContractDefinition const* contract: bases)
@ -429,7 +430,7 @@ void ContractLevelChecker::annotateBaseConstructorArguments(
void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _contract) void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _contract)
{ {
std::map<std::string, std::vector<std::pair<Declaration const*, FunctionTypePointer>>> externalDeclarations; map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
{ {
for (FunctionDefinition const* f: contract->definedFunctions()) for (FunctionDefinition const* f: contract->definedFunctions())
@ -466,7 +467,7 @@ void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _c
void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contract) void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contract)
{ {
std::set<util::FixedHash<4>> hashes; set<util::FixedHash<4>> hashes;
for (auto const& it: _contract.interfaceFunctionList()) for (auto const& it: _contract.interfaceFunctionList())
{ {
util::FixedHash<4> const& hash = it.first; util::FixedHash<4> const& hash = it.first;
@ -474,7 +475,7 @@ void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contra
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
1860_error, 1860_error,
_contract.location(), _contract.location(),
std::string("Function signature hash collision for ") + it.second->externalSignature() string("Function signature hash collision for ") + it.second->externalSignature()
); );
hashes.insert(hash); hashes.insert(hash);
} }

View File

@ -25,6 +25,7 @@
#include <functional> #include <functional>
using namespace std;
using namespace std::placeholders; using namespace std::placeholders;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -43,7 +44,7 @@ void ControlFlowAnalyzer::analyze(FunctionDefinition const& _function, ContractD
if (!_function.isImplemented()) if (!_function.isImplemented())
return; return;
std::optional<std::string> mostDerivedContractName; optional<string> mostDerivedContractName;
// The name of the most derived contract only required if it differs from // The name of the most derived contract only required if it differs from
// the functions contract // the functions contract
@ -60,13 +61,13 @@ void ControlFlowAnalyzer::analyze(FunctionDefinition const& _function, ContractD
} }
void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNode const* _exit, bool _emptyBody, std::optional<std::string> _contractName) void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNode const* _exit, bool _emptyBody, optional<string> _contractName)
{ {
struct NodeInfo struct NodeInfo
{ {
std::set<VariableDeclaration const*> unassignedVariablesAtEntry; set<VariableDeclaration const*> unassignedVariablesAtEntry;
std::set<VariableDeclaration const*> unassignedVariablesAtExit; set<VariableDeclaration const*> unassignedVariablesAtExit;
std::set<VariableOccurrence const*> uninitializedVariableAccesses; set<VariableOccurrence const*> uninitializedVariableAccesses;
/// Propagate the information from another node to this node. /// Propagate the information from another node to this node.
/// To be used to propagate information from a node to its exit nodes. /// To be used to propagate information from a node to its exit nodes.
/// Returns true, if new variables were added and thus the current node has /// Returns true, if new variables were added and thus the current node has
@ -83,8 +84,8 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
; ;
} }
}; };
std::map<CFGNode const*, NodeInfo> nodeInfos; map<CFGNode const*, NodeInfo> nodeInfos;
std::set<CFGNode const*> nodesToTraverse; set<CFGNode const*> nodesToTraverse;
nodesToTraverse.insert(_entry); nodesToTraverse.insert(_entry);
// Walk all paths starting from the nodes in ``nodesToTraverse`` until ``NodeInfo::propagateFrom`` // Walk all paths starting from the nodes in ``nodesToTraverse`` until ``NodeInfo::propagateFrom``
@ -137,7 +138,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
auto const& exitInfo = nodeInfos[_exit]; auto const& exitInfo = nodeInfos[_exit];
if (!exitInfo.uninitializedVariableAccesses.empty()) if (!exitInfo.uninitializedVariableAccesses.empty())
{ {
std::vector<VariableOccurrence const*> uninitializedAccessesOrdered( vector<VariableOccurrence const*> uninitializedAccessesOrdered(
exitInfo.uninitializedVariableAccesses.begin(), exitInfo.uninitializedVariableAccesses.begin(),
exitInfo.uninitializedVariableAccesses.end() exitInfo.uninitializedVariableAccesses.end()
); );
@ -167,7 +168,7 @@ void ControlFlowAnalyzer::checkUninitializedAccess(CFGNode const* _entry, CFGNod
varDecl.location(), varDecl.location(),
ssl, ssl,
"This variable is of " + "This variable is of " +
std::string(isStorage ? "storage" : "calldata") + string(isStorage ? "storage" : "calldata") +
" pointer type and can be " + " pointer type and can be " +
(variableOccurrence->kind() == VariableOccurrence::Kind::Return ? "returned" : "accessed") + (variableOccurrence->kind() == VariableOccurrence::Kind::Return ? "returned" : "accessed") +
" without prior assignment, which would lead to undefined behaviour." " without prior assignment, which would lead to undefined behaviour."

View File

@ -21,8 +21,10 @@
#include <libyul/AST.h> #include <libyul/AST.h>
#include <libyul/backends/evm/EVMDialect.h> #include <libyul/backends/evm/EVMDialect.h>
using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace std;
ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow, ContractDefinition const* _contract): ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow, ContractDefinition const* _contract):
m_nodeContainer(_nodeContainer), m_nodeContainer(_nodeContainer),
@ -35,13 +37,13 @@ ControlFlowBuilder::ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, Funct
} }
std::unique_ptr<FunctionFlow> ControlFlowBuilder::createFunctionFlow( unique_ptr<FunctionFlow> ControlFlowBuilder::createFunctionFlow(
CFG::NodeContainer& _nodeContainer, CFG::NodeContainer& _nodeContainer,
FunctionDefinition const& _function, FunctionDefinition const& _function,
ContractDefinition const* _contract ContractDefinition const* _contract
) )
{ {
auto functionFlow = std::make_unique<FunctionFlow>(); auto functionFlow = make_unique<FunctionFlow>();
functionFlow->entry = _nodeContainer.newNode(); functionFlow->entry = _nodeContainer.newNode();
functionFlow->exit = _nodeContainer.newNode(); functionFlow->exit = _nodeContainer.newNode();
functionFlow->revert = _nodeContainer.newNode(); functionFlow->revert = _nodeContainer.newNode();

View File

@ -20,6 +20,7 @@
#include <libsolidity/analysis/ControlFlowBuilder.h> #include <libsolidity/analysis/ControlFlowBuilder.h>
using namespace std;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;

View File

@ -29,6 +29,7 @@
#include <range/v3/view/filter.hpp> #include <range/v3/view/filter.hpp>
#include <range/v3/range/conversion.hpp> #include <range/v3/range/conversion.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -40,7 +41,7 @@ Declaration const* DeclarationContainer::conflictingDeclaration(
if (!_name) if (!_name)
_name = &_declaration.name(); _name = &_declaration.name();
solAssert(!_name->empty(), ""); solAssert(!_name->empty(), "");
std::vector<Declaration const*> declarations; vector<Declaration const*> declarations;
if (m_declarations.count(*_name)) if (m_declarations.count(*_name))
declarations += m_declarations.at(*_name); declarations += m_declarations.at(*_name);
if (m_invisibleDeclarations.count(*_name)) if (m_invisibleDeclarations.count(*_name))
@ -126,7 +127,7 @@ bool DeclarationContainer::registerDeclaration(
m_homonymCandidates.emplace_back(*_name, _location ? _location : &_declaration.location()); m_homonymCandidates.emplace_back(*_name, _location ? _location : &_declaration.location());
} }
std::vector<Declaration const*>& decls = _invisible ? m_invisibleDeclarations[*_name] : m_declarations[*_name]; vector<Declaration const*>& decls = _invisible ? m_invisibleDeclarations[*_name] : m_declarations[*_name];
if (!util::contains(decls, &_declaration)) if (!util::contains(decls, &_declaration))
decls.push_back(&_declaration); decls.push_back(&_declaration);
return true; return true;
@ -141,13 +142,13 @@ bool DeclarationContainer::registerDeclaration(
return registerDeclaration(_declaration, nullptr, nullptr, _invisible, _update); return registerDeclaration(_declaration, nullptr, nullptr, _invisible, _update);
} }
std::vector<Declaration const*> DeclarationContainer::resolveName( vector<Declaration const*> DeclarationContainer::resolveName(
ASTString const& _name, ASTString const& _name,
ResolvingSettings _settings ResolvingSettings _settings
) const ) const
{ {
solAssert(!_name.empty(), "Attempt to resolve empty name."); solAssert(!_name.empty(), "Attempt to resolve empty name.");
std::vector<Declaration const*> result; vector<Declaration const*> result;
if (m_declarations.count(_name)) if (m_declarations.count(_name))
{ {
@ -171,24 +172,24 @@ std::vector<Declaration const*> DeclarationContainer::resolveName(
return result; return result;
} }
std::vector<ASTString> DeclarationContainer::similarNames(ASTString const& _name) const vector<ASTString> DeclarationContainer::similarNames(ASTString const& _name) const
{ {
// because the function below has quadratic runtime - it will not magically improve once a better algorithm is discovered ;) // because the function below has quadratic runtime - it will not magically improve once a better algorithm is discovered ;)
// since 80 is the suggested line length limit, we use 80^2 as length threshold // since 80 is the suggested line length limit, we use 80^2 as length threshold
static size_t const MAXIMUM_LENGTH_THRESHOLD = 80 * 80; static size_t const MAXIMUM_LENGTH_THRESHOLD = 80 * 80;
std::vector<ASTString> similar; vector<ASTString> similar;
size_t maximumEditDistance = _name.size() > 3 ? 2 : _name.size() / 2; size_t maximumEditDistance = _name.size() > 3 ? 2 : _name.size() / 2;
for (auto const& declaration: m_declarations) for (auto const& declaration: m_declarations)
{ {
std::string const& declarationName = declaration.first; string const& declarationName = declaration.first;
if (util::stringWithinDistance(_name, declarationName, maximumEditDistance, MAXIMUM_LENGTH_THRESHOLD)) if (util::stringWithinDistance(_name, declarationName, maximumEditDistance, MAXIMUM_LENGTH_THRESHOLD))
similar.push_back(declarationName); similar.push_back(declarationName);
} }
for (auto const& declaration: m_invisibleDeclarations) for (auto const& declaration: m_invisibleDeclarations)
{ {
std::string const& declarationName = declaration.first; string const& declarationName = declaration.first;
if (util::stringWithinDistance(_name, declarationName, maximumEditDistance, MAXIMUM_LENGTH_THRESHOLD)) if (util::stringWithinDistance(_name, declarationName, maximumEditDistance, MAXIMUM_LENGTH_THRESHOLD))
similar.push_back(declarationName); similar.push_back(declarationName);
} }
@ -199,7 +200,7 @@ std::vector<ASTString> DeclarationContainer::similarNames(ASTString const& _name
return similar; return similar;
} }
void DeclarationContainer::populateHomonyms(std::back_insert_iterator<Homonyms> _it) const void DeclarationContainer::populateHomonyms(back_insert_iterator<Homonyms> _it) const
{ {
for (DeclarationContainer const* innerContainer: m_innerContainers) for (DeclarationContainer const* innerContainer: m_innerContainers)
innerContainer->populateHomonyms(_it); innerContainer->populateHomonyms(_it);
@ -209,7 +210,7 @@ void DeclarationContainer::populateHomonyms(std::back_insert_iterator<Homonyms>
ResolvingSettings settings; ResolvingSettings settings;
settings.recursive = true; settings.recursive = true;
settings.alsoInvisible = true; settings.alsoInvisible = true;
std::vector<Declaration const*> const& declarations = m_enclosingContainer->resolveName(name, std::move(settings)); vector<Declaration const*> const& declarations = m_enclosingContainer->resolveName(name, std::move(settings));
if (!declarations.empty()) if (!declarations.empty())
_it = make_pair(location, declarations); _it = make_pair(location, declarations);
} }

View File

@ -29,6 +29,7 @@
#include <range/v3/view/transform.hpp> #include <range/v3/view/transform.hpp>
using namespace std;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -335,10 +336,10 @@ void DeclarationTypeChecker::endVisit(ArrayTypeName const& _typeName)
if (Expression const* length = _typeName.length()) if (Expression const* length = _typeName.length())
{ {
std::optional<rational> lengthValue; optional<rational> lengthValue;
if (length->annotation().type && length->annotation().type->category() == Type::Category::RationalNumber) if (length->annotation().type && length->annotation().type->category() == Type::Category::RationalNumber)
lengthValue = dynamic_cast<RationalNumberType const&>(*length->annotation().type).value(); lengthValue = dynamic_cast<RationalNumberType const&>(*length->annotation().type).value();
else if (std::optional<ConstantEvaluator::TypedRational> value = ConstantEvaluator::evaluate(m_errorReporter, *length)) else if (optional<ConstantEvaluator::TypedRational> value = ConstantEvaluator::evaluate(m_errorReporter, *length))
lengthValue = value->value; lengthValue = value->value;
if (!lengthValue) if (!lengthValue)
@ -398,10 +399,10 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
Location varLoc = _variable.referenceLocation(); Location varLoc = _variable.referenceLocation();
DataLocation typeLoc = DataLocation::Memory; DataLocation typeLoc = DataLocation::Memory;
std::set<Location> allowedDataLocations = _variable.allowedDataLocations(); set<Location> allowedDataLocations = _variable.allowedDataLocations();
if (!allowedDataLocations.count(varLoc)) if (!allowedDataLocations.count(varLoc))
{ {
auto locationToString = [](VariableDeclaration::Location _location) -> std::string auto locationToString = [](VariableDeclaration::Location _location) -> string
{ {
switch (_location) switch (_location)
{ {
@ -413,7 +414,7 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
return {}; return {};
}; };
std::string errorString; string errorString;
if (!_variable.hasReferenceOrMappingType()) if (!_variable.hasReferenceOrMappingType())
errorString = "Data location can only be specified for array, struct or mapping types"; errorString = "Data location can only be specified for array, struct or mapping types";
else else
@ -429,9 +430,9 @@ void DeclarationTypeChecker::endVisit(VariableDeclaration const& _variable)
else if (_variable.isCallableOrCatchParameter()) else if (_variable.isCallableOrCatchParameter())
errorString += errorString +=
" for " + " for " +
std::string(_variable.isReturnParameter() ? "return " : "") + string(_variable.isReturnParameter() ? "return " : "") +
"parameter in" + "parameter in" +
std::string(_variable.isExternalCallableParameter() ? " external" : "") + string(_variable.isExternalCallableParameter() ? " external" : "") +
" function"; " function";
else else
errorString += " for variable"; errorString += " for variable";

View File

@ -30,6 +30,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -37,7 +38,7 @@ using namespace solidity::frontend;
namespace namespace
{ {
void copyMissingTags(std::set<CallableDeclaration const*> const& _baseFunctions, StructurallyDocumentedAnnotation& _target, FunctionType const* _functionType = nullptr) void copyMissingTags(set<CallableDeclaration const*> const& _baseFunctions, StructurallyDocumentedAnnotation& _target, FunctionType const* _functionType = nullptr)
{ {
// Only copy if there is exactly one direct base function. // Only copy if there is exactly one direct base function.
if (_baseFunctions.size() != 1) if (_baseFunctions.size() != 1)
@ -49,7 +50,7 @@ void copyMissingTags(std::set<CallableDeclaration const*> const& _baseFunctions,
for (auto it = sourceDoc.docTags.begin(); it != sourceDoc.docTags.end();) for (auto it = sourceDoc.docTags.begin(); it != sourceDoc.docTags.end();)
{ {
std::string const& tag = it->first; string const& tag = it->first;
// Don't copy tag "inheritdoc", custom tags or already existing tags // Don't copy tag "inheritdoc", custom tags or already existing tags
if (tag == "inheritdoc" || _target.docTags.count(tag) || boost::starts_with(tag, "custom")) if (tag == "inheritdoc" || _target.docTags.count(tag) || boost::starts_with(tag, "custom"))
{ {
@ -67,7 +68,7 @@ void copyMissingTags(std::set<CallableDeclaration const*> const& _baseFunctions,
if (_functionType && tag == "return") if (_functionType && tag == "return")
{ {
size_t docParaNameEndPos = content.content.find_first_of(" \t"); size_t docParaNameEndPos = content.content.find_first_of(" \t");
std::string const docParameterName = content.content.substr(0, docParaNameEndPos); string const docParameterName = content.content.substr(0, docParaNameEndPos);
if ( if (
_functionType->returnParameterNames().size() > n && _functionType->returnParameterNames().size() > n &&
@ -79,10 +80,10 @@ void copyMissingTags(std::set<CallableDeclaration const*> const& _baseFunctions,
baseFunction.returnParameters().size() > n && baseFunction.returnParameters().size() > n &&
baseFunction.returnParameters().at(n)->name().empty(); baseFunction.returnParameters().at(n)->name().empty();
std::string paramName = _functionType->returnParameterNames().at(n); string paramName = _functionType->returnParameterNames().at(n);
content.content = content.content =
(paramName.empty() ? "" : std::move(paramName) + " ") + ( (paramName.empty() ? "" : std::move(paramName) + " ") + (
std::string::npos == docParaNameEndPos || baseHasNoName ? string::npos == docParaNameEndPos || baseHasNoName ?
content.content : content.content :
content.content.substr(docParaNameEndPos + 1) content.content.substr(docParaNameEndPos + 1)
); );
@ -94,7 +95,7 @@ void copyMissingTags(std::set<CallableDeclaration const*> const& _baseFunctions,
} }
} }
CallableDeclaration const* findBaseCallable(std::set<CallableDeclaration const*> const& _baseFunctions, int64_t _contractId) CallableDeclaration const* findBaseCallable(set<CallableDeclaration const*> const& _baseFunctions, int64_t _contractId)
{ {
for (CallableDeclaration const* baseFuncCandidate: _baseFunctions) for (CallableDeclaration const* baseFuncCandidate: _baseFunctions)
if (baseFuncCandidate->annotation().contract->id() == _contractId) if (baseFuncCandidate->annotation().contract->id() == _contractId)
@ -180,7 +181,7 @@ void DocStringAnalyser::handleCallable(
} }
CallableDeclaration const* DocStringAnalyser::resolveInheritDoc( CallableDeclaration const* DocStringAnalyser::resolveInheritDoc(
std::set<CallableDeclaration const*> const& _baseFuncs, set<CallableDeclaration const*> const& _baseFuncs,
StructurallyDocumented const& _node, StructurallyDocumented const& _node,
StructurallyDocumentedAnnotation& _annotation StructurallyDocumentedAnnotation& _annotation
) )

View File

@ -37,6 +37,7 @@
#include <regex> #include <regex>
#include <string_view> #include <string_view>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -66,7 +67,7 @@ bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceU
if (tagName == "return") if (tagName == "return")
{ {
returnTagsVisited++; returnTagsVisited++;
std::vector<std::string> returnParameterNames; vector<string> returnParameterNames;
if (auto const* varDecl = dynamic_cast<VariableDeclaration const*>(&_node)) if (auto const* varDecl = dynamic_cast<VariableDeclaration const*>(&_node))
{ {
@ -81,8 +82,8 @@ bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceU
else else
continue; continue;
std::string content = tagValue.content; string content = tagValue.content;
std::string firstWord = content.substr(0, content.find_first_of(" \t")); string firstWord = content.substr(0, content.find_first_of(" \t"));
if (returnTagsVisited > returnParameterNames.size()) if (returnTagsVisited > returnParameterNames.size())
m_errorReporter.docstringParsingError( m_errorReporter.docstringParsingError(
@ -93,7 +94,7 @@ bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceU
); );
else else
{ {
std::string const& parameter = returnParameterNames.at(returnTagsVisited - 1); string const& parameter = returnParameterNames.at(returnTagsVisited - 1);
if (!parameter.empty() && parameter != firstWord) if (!parameter.empty() && parameter != firstWord)
m_errorReporter.docstringParsingError( m_errorReporter.docstringParsingError(
5856_error, 5856_error,
@ -112,7 +113,7 @@ bool DocStringTagParser::validateDocStringsUsingTypes(SourceUnit const& _sourceU
bool DocStringTagParser::visit(ContractDefinition const& _contract) bool DocStringTagParser::visit(ContractDefinition const& _contract)
{ {
static std::set<std::string> const validTags = std::set<std::string>{"author", "title", "dev", "notice"}; static set<string> const validTags = set<string>{"author", "title", "dev", "notice"};
parseDocStrings(_contract, _contract.annotation(), validTags, "contracts"); parseDocStrings(_contract, _contract.annotation(), validTags, "contracts");
return true; return true;
@ -192,12 +193,12 @@ bool DocStringTagParser::visit(InlineAssembly const& _assembly)
{ {
if (tagName == "solidity") if (tagName == "solidity")
{ {
std::vector<std::string> values; vector<string> values;
boost::split(values, tagValue.content, isWhiteSpace); boost::split(values, tagValue.content, isWhiteSpace);
std::set<std::string> valuesSeen; set<string> valuesSeen;
std::set<std::string> duplicates; set<string> duplicates;
for (auto const& value: values | ranges::views::filter(not_fn(&std::string::empty))) for (auto const& value: values | ranges::views::filter(not_fn(&string::empty)))
if (valuesSeen.insert(value).second) if (valuesSeen.insert(value).second)
{ {
if (value == "memory-safe-assembly") if (value == "memory-safe-assembly")
@ -243,7 +244,7 @@ void DocStringTagParser::checkParameters(
StructurallyDocumentedAnnotation& _annotation StructurallyDocumentedAnnotation& _annotation
) )
{ {
std::set<std::string> validParams; set<string> validParams;
for (auto const& p: _callable.parameters()) for (auto const& p: _callable.parameters())
validParams.insert(p->name()); validParams.insert(p->name());
if (_callable.returnParameterList()) if (_callable.returnParameterList())
@ -267,7 +268,7 @@ void DocStringTagParser::handleConstructor(
StructurallyDocumentedAnnotation& _annotation StructurallyDocumentedAnnotation& _annotation
) )
{ {
static std::set<std::string> const validTags = std::set<std::string>{"author", "dev", "notice", "param"}; static set<string> const validTags = set<string>{"author", "dev", "notice", "param"};
parseDocStrings(_node, _annotation, validTags, "constructor"); parseDocStrings(_node, _annotation, validTags, "constructor");
checkParameters(_callable, _node, _annotation); checkParameters(_callable, _node, _annotation);
} }
@ -278,10 +279,10 @@ void DocStringTagParser::handleCallable(
StructurallyDocumentedAnnotation& _annotation StructurallyDocumentedAnnotation& _annotation
) )
{ {
static std::set<std::string> const validEventTags = std::set<std::string>{"dev", "notice", "return", "param"}; static set<string> const validEventTags = set<string>{"dev", "notice", "return", "param"};
static std::set<std::string> const validErrorTags = std::set<std::string>{"dev", "notice", "param"}; static set<string> const validErrorTags = set<string>{"dev", "notice", "param"};
static std::set<std::string> const validModifierTags = std::set<std::string>{"dev", "notice", "param", "inheritdoc"}; static set<string> const validModifierTags = set<string>{"dev", "notice", "param", "inheritdoc"};
static std::set<std::string> const validTags = std::set<std::string>{"dev", "notice", "return", "param", "inheritdoc"}; static set<string> const validTags = set<string>{"dev", "notice", "return", "param", "inheritdoc"};
if (dynamic_cast<EventDefinition const*>(&_callable)) if (dynamic_cast<EventDefinition const*>(&_callable))
parseDocStrings(_node, _annotation, validEventTags, "events"); parseDocStrings(_node, _annotation, validEventTags, "events");
@ -298,8 +299,8 @@ void DocStringTagParser::handleCallable(
void DocStringTagParser::parseDocStrings( void DocStringTagParser::parseDocStrings(
StructurallyDocumented const& _node, StructurallyDocumented const& _node,
StructurallyDocumentedAnnotation& _annotation, StructurallyDocumentedAnnotation& _annotation,
std::set<std::string> const& _validTags, set<string> const& _validTags,
std::string const& _nodeName string const& _nodeName
) )
{ {
if (!_node.documentation()) if (!_node.documentation())
@ -309,7 +310,7 @@ void DocStringTagParser::parseDocStrings(
for (auto const& [tagName, tagValue]: _annotation.docTags) for (auto const& [tagName, tagValue]: _annotation.docTags)
{ {
std::string_view static constexpr customPrefix("custom:"); string_view static constexpr customPrefix("custom:");
if (tagName == "custom" || tagName == "custom:") if (tagName == "custom" || tagName == "custom:")
m_errorReporter.docstringParsingError( m_errorReporter.docstringParsingError(
6564_error, 6564_error,
@ -318,7 +319,7 @@ void DocStringTagParser::parseDocStrings(
); );
else if (boost::starts_with(tagName, customPrefix) && tagName.size() > customPrefix.size()) else if (boost::starts_with(tagName, customPrefix) && tagName.size() > customPrefix.size())
{ {
std::regex static const customRegex("^custom:[a-z][a-z-]*$"); regex static const customRegex("^custom:[a-z][a-z-]*$");
if (!regex_match(tagName, customRegex)) if (!regex_match(tagName, customRegex))
m_errorReporter.docstringParsingError( m_errorReporter.docstringParsingError(
2968_error, 2968_error,

View File

@ -24,6 +24,7 @@
#include <range/v3/view/reverse.hpp> #include <range/v3/view/reverse.hpp>
#include <range/v3/view/transform.hpp> #include <range/v3/view/transform.hpp>
using namespace std;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::util; using namespace solidity::util;
@ -71,7 +72,7 @@ CallGraph FunctionCallGraphBuilder::buildDeployedGraph(
FunctionCallGraphBuilder builder(_contract); FunctionCallGraphBuilder builder(_contract);
solAssert(builder.m_currentNode == CallGraph::Node(CallGraph::SpecialNode::Entry), ""); solAssert(builder.m_currentNode == CallGraph::Node(CallGraph::SpecialNode::Entry), "");
auto getSecondElement = [](auto const& _tuple){ return std::get<1>(_tuple); }; auto getSecondElement = [](auto const& _tuple){ return get<1>(_tuple); };
// Create graph for all publicly reachable functions // Create graph for all publicly reachable functions
for (FunctionTypePointer functionType: _contract.interfaceFunctionList() | ranges::views::transform(getSecondElement)) for (FunctionTypePointer functionType: _contract.interfaceFunctionList() | ranges::views::transform(getSecondElement))
@ -95,14 +96,14 @@ CallGraph FunctionCallGraphBuilder::buildDeployedGraph(
// All functions present in internal dispatch at creation time could potentially be pointers // All functions present in internal dispatch at creation time could potentially be pointers
// assigned to state variables and as such may be reachable after deployment as well. // assigned to state variables and as such may be reachable after deployment as well.
builder.m_currentNode = CallGraph::SpecialNode::InternalDispatch; builder.m_currentNode = CallGraph::SpecialNode::InternalDispatch;
std::set<CallGraph::Node, CallGraph::CompareByID> defaultNode; set<CallGraph::Node, CallGraph::CompareByID> defaultNode;
for (CallGraph::Node const& dispatchTarget: util::valueOrDefault(_creationGraph.edges, CallGraph::SpecialNode::InternalDispatch, defaultNode)) for (CallGraph::Node const& dispatchTarget: util::valueOrDefault(_creationGraph.edges, CallGraph::SpecialNode::InternalDispatch, defaultNode))
{ {
solAssert(!std::holds_alternative<CallGraph::SpecialNode>(dispatchTarget), ""); solAssert(!holds_alternative<CallGraph::SpecialNode>(dispatchTarget), "");
solAssert(std::get<CallableDeclaration const*>(dispatchTarget) != nullptr, ""); solAssert(get<CallableDeclaration const*>(dispatchTarget) != nullptr, "");
// Visit the callable to add not only it but also everything it calls too // Visit the callable to add not only it but also everything it calls too
builder.functionReferenced(*std::get<CallableDeclaration const*>(dispatchTarget), false); builder.functionReferenced(*get<CallableDeclaration const*>(dispatchTarget), false);
} }
builder.m_currentNode = CallGraph::SpecialNode::Entry; builder.m_currentNode = CallGraph::SpecialNode::Entry;
@ -261,10 +262,10 @@ void FunctionCallGraphBuilder::processQueue()
while (!m_visitQueue.empty()) while (!m_visitQueue.empty())
{ {
m_currentNode = m_visitQueue.front(); m_currentNode = m_visitQueue.front();
solAssert(std::holds_alternative<CallableDeclaration const*>(m_currentNode), ""); solAssert(holds_alternative<CallableDeclaration const*>(m_currentNode), "");
m_visitQueue.pop_front(); m_visitQueue.pop_front();
std::get<CallableDeclaration const*>(m_currentNode)->accept(*this); get<CallableDeclaration const*>(m_currentNode)->accept(*this);
} }
m_currentNode = CallGraph::SpecialNode::Entry; m_currentNode = CallGraph::SpecialNode::Entry;
@ -280,7 +281,7 @@ void FunctionCallGraphBuilder::functionReferenced(CallableDeclaration const& _ca
if (_calledDirectly) if (_calledDirectly)
{ {
solAssert( solAssert(
std::holds_alternative<CallGraph::SpecialNode>(m_currentNode) || m_graph.edges.count(m_currentNode) > 0, holds_alternative<CallGraph::SpecialNode>(m_currentNode) || m_graph.edges.count(m_currentNode) > 0,
"Adding an edge from a node that has not been visited yet." "Adding an edge from a node that has not been visited yet."
); );
@ -292,10 +293,10 @@ void FunctionCallGraphBuilder::functionReferenced(CallableDeclaration const& _ca
enqueueCallable(_callable); enqueueCallable(_callable);
} }
std::ostream& solidity::frontend::operator<<(std::ostream& _out, CallGraph::Node const& _node) ostream& solidity::frontend::operator<<(ostream& _out, CallGraph::Node const& _node)
{ {
if (std::holds_alternative<CallGraph::SpecialNode>(_node)) if (holds_alternative<CallGraph::SpecialNode>(_node))
switch (std::get<CallGraph::SpecialNode>(_node)) switch (get<CallGraph::SpecialNode>(_node))
{ {
case CallGraph::SpecialNode::InternalDispatch: case CallGraph::SpecialNode::InternalDispatch:
_out << "InternalDispatch"; _out << "InternalDispatch";
@ -308,19 +309,19 @@ std::ostream& solidity::frontend::operator<<(std::ostream& _out, CallGraph::Node
} }
else else
{ {
solAssert(std::holds_alternative<CallableDeclaration const*>(_node), ""); solAssert(holds_alternative<CallableDeclaration const*>(_node), "");
auto const* callableDeclaration = std::get<CallableDeclaration const*>(_node); auto const* callableDeclaration = get<CallableDeclaration const*>(_node);
solAssert(callableDeclaration, ""); solAssert(callableDeclaration, "");
auto const* function = dynamic_cast<FunctionDefinition const *>(callableDeclaration); auto const* function = dynamic_cast<FunctionDefinition const *>(callableDeclaration);
auto const* event = dynamic_cast<EventDefinition const *>(callableDeclaration); auto const* event = dynamic_cast<EventDefinition const *>(callableDeclaration);
auto const* modifier = dynamic_cast<ModifierDefinition const *>(callableDeclaration); auto const* modifier = dynamic_cast<ModifierDefinition const *>(callableDeclaration);
auto typeToString = [](auto const& _var) -> std::string { return _var->type()->toString(true); }; auto typeToString = [](auto const& _var) -> string { return _var->type()->toString(true); };
std::vector<std::string> parameters = callableDeclaration->parameters() | ranges::views::transform(typeToString) | ranges::to<std::vector<std::string>>(); vector<string> parameters = callableDeclaration->parameters() | ranges::views::transform(typeToString) | ranges::to<vector<string>>();
std::string scopeName; string scopeName;
if (!function || !function->isFree()) if (!function || !function->isFree())
{ {
solAssert(callableDeclaration->annotation().scope, ""); solAssert(callableDeclaration->annotation().scope, "");

View File

@ -29,6 +29,8 @@
#include <libsolidity/ast/Types.h> #include <libsolidity/ast/Types.h>
#include <memory> #include <memory>
using namespace std;
namespace solidity::frontend namespace solidity::frontend
{ {
@ -63,10 +65,10 @@ int magicVariableToID(std::string const& _name)
solAssert(false, "Unknown magic variable: \"" + _name + "\"."); solAssert(false, "Unknown magic variable: \"" + _name + "\".");
} }
inline std::vector<std::shared_ptr<MagicVariableDeclaration const>> constructMagicVariables() inline vector<shared_ptr<MagicVariableDeclaration const>> constructMagicVariables()
{ {
static auto const magicVarDecl = [](std::string const& _name, Type const* _type) { static auto const magicVarDecl = [](string const& _name, Type const* _type) {
return std::make_shared<MagicVariableDeclaration>(magicVariableToID(_name), _name, _type); return make_shared<MagicVariableDeclaration>(magicVariableToID(_name), _name, _type);
}; };
return { return {
@ -114,9 +116,9 @@ void GlobalContext::setCurrentContract(ContractDefinition const& _contract)
m_currentContract = &_contract; m_currentContract = &_contract;
} }
std::vector<Declaration const*> GlobalContext::declarations() const vector<Declaration const*> GlobalContext::declarations() const
{ {
std::vector<Declaration const*> declarations; vector<Declaration const*> declarations;
declarations.reserve(m_magicVariables.size()); declarations.reserve(m_magicVariables.size());
for (ASTPointer<MagicVariableDeclaration const> const& variable: m_magicVariables) for (ASTPointer<MagicVariableDeclaration const> const& variable: m_magicVariables)
declarations.push_back(variable.get()); declarations.push_back(variable.get());
@ -131,7 +133,7 @@ MagicVariableDeclaration const* GlobalContext::currentThis() const
if (m_currentContract) if (m_currentContract)
type = TypeProvider::contract(*m_currentContract); type = TypeProvider::contract(*m_currentContract);
m_thisPointer[m_currentContract] = m_thisPointer[m_currentContract] =
std::make_shared<MagicVariableDeclaration>(magicVariableToID("this"), "this", type); make_shared<MagicVariableDeclaration>(magicVariableToID("this"), "this", type);
} }
return m_thisPointer[m_currentContract].get(); return m_thisPointer[m_currentContract].get();
} }
@ -144,7 +146,7 @@ MagicVariableDeclaration const* GlobalContext::currentSuper() const
if (m_currentContract) if (m_currentContract)
type = TypeProvider::typeType(TypeProvider::contract(*m_currentContract, true)); type = TypeProvider::typeType(TypeProvider::contract(*m_currentContract, true));
m_superPointer[m_currentContract] = m_superPointer[m_currentContract] =
std::make_shared<MagicVariableDeclaration>(magicVariableToID("super"), "super", type); make_shared<MagicVariableDeclaration>(magicVariableToID("super"), "super", type);
} }
return m_superPointer[m_currentContract].get(); return m_superPointer[m_currentContract].get();
} }

View File

@ -30,6 +30,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <unordered_set> #include <unordered_set>
using namespace std;
using namespace solidity::langutil; using namespace solidity::langutil;
namespace solidity::frontend namespace solidity::frontend
@ -44,7 +45,7 @@ NameAndTypeResolver::NameAndTypeResolver(
m_errorReporter(_errorReporter), m_errorReporter(_errorReporter),
m_globalContext(_globalContext) m_globalContext(_globalContext)
{ {
m_scopes[nullptr] = std::make_shared<DeclarationContainer>(); m_scopes[nullptr] = make_shared<DeclarationContainer>();
for (Declaration const* declaration: _globalContext.declarations()) for (Declaration const* declaration: _globalContext.declarations())
{ {
solAssert(m_scopes[nullptr]->registerDeclaration(*declaration, false, false), "Unable to register global declaration."); solAssert(m_scopes[nullptr]->registerDeclaration(*declaration, false, false), "Unable to register global declaration.");
@ -67,14 +68,14 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit, ASTNode
return true; return true;
} }
bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, std::map<std::string, SourceUnit const*> const& _sourceUnits) bool NameAndTypeResolver::performImports(SourceUnit& _sourceUnit, map<string, SourceUnit const*> const& _sourceUnits)
{ {
DeclarationContainer& target = *m_scopes.at(&_sourceUnit); DeclarationContainer& target = *m_scopes.at(&_sourceUnit);
bool error = false; bool error = false;
for (auto const& node: _sourceUnit.nodes()) for (auto const& node: _sourceUnit.nodes())
if (auto imp = dynamic_cast<ImportDirective const*>(node.get())) if (auto imp = dynamic_cast<ImportDirective const*>(node.get()))
{ {
std::string const& path = *imp->annotation().absolutePath; string const& path = *imp->annotation().absolutePath;
// The import resolution in CompilerStack enforces this. // The import resolution in CompilerStack enforces this.
solAssert(_sourceUnits.count(path), ""); solAssert(_sourceUnits.count(path), "");
auto scope = m_scopes.find(_sourceUnits.at(path)); auto scope = m_scopes.find(_sourceUnits.at(path));
@ -126,7 +127,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(SourceUnit& _source)
{ {
try try
{ {
for (std::shared_ptr<ASTNode> const& node: _source.nodes()) for (shared_ptr<ASTNode> const& node: _source.nodes())
{ {
setScope(&_source); setScope(&_source);
if (!resolveNamesAndTypesInternal(*node, true)) if (!resolveNamesAndTypesInternal(*node, true))
@ -158,7 +159,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
return true; return true;
} }
void NameAndTypeResolver::activateVariable(std::string const& _name) void NameAndTypeResolver::activateVariable(string const& _name)
{ {
solAssert(m_currentScope, ""); solAssert(m_currentScope, "");
// Scoped local variables are invisible before activation. // Scoped local variables are invisible before activation.
@ -170,15 +171,15 @@ void NameAndTypeResolver::activateVariable(std::string const& _name)
m_currentScope->activateVariable(_name); m_currentScope->activateVariable(_name);
} }
std::vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, ASTNode const* _scope) const vector<Declaration const*> NameAndTypeResolver::resolveName(ASTString const& _name, ASTNode const* _scope) const
{ {
auto iterator = m_scopes.find(_scope); auto iterator = m_scopes.find(_scope);
if (iterator == end(m_scopes)) if (iterator == end(m_scopes))
return std::vector<Declaration const*>({}); return vector<Declaration const*>({});
return iterator->second->resolveName(_name); return iterator->second->resolveName(_name);
} }
std::vector<Declaration const*> NameAndTypeResolver::nameFromCurrentScope(ASTString const& _name, bool _includeInvisibles) const vector<Declaration const*> NameAndTypeResolver::nameFromCurrentScope(ASTString const& _name, bool _includeInvisibles) const
{ {
ResolvingSettings settings; ResolvingSettings settings;
settings.recursive = true; settings.recursive = true;
@ -186,7 +187,7 @@ std::vector<Declaration const*> NameAndTypeResolver::nameFromCurrentScope(ASTStr
return m_currentScope->resolveName(_name, std::move(settings)); return m_currentScope->resolveName(_name, std::move(settings));
} }
Declaration const* NameAndTypeResolver::pathFromCurrentScope(std::vector<ASTString> const& _path) const Declaration const* NameAndTypeResolver::pathFromCurrentScope(vector<ASTString> const& _path) const
{ {
if (auto declarations = pathFromCurrentScopeWithAllDeclarations(_path); !declarations.empty()) if (auto declarations = pathFromCurrentScopeWithAllDeclarations(_path); !declarations.empty())
return declarations.back(); return declarations.back();
@ -200,13 +201,13 @@ std::vector<Declaration const*> NameAndTypeResolver::pathFromCurrentScopeWithAll
) const ) const
{ {
solAssert(!_path.empty(), ""); solAssert(!_path.empty(), "");
std::vector<Declaration const*> pathDeclarations; vector<Declaration const*> pathDeclarations;
ResolvingSettings settings; ResolvingSettings settings;
settings.recursive = true; settings.recursive = true;
settings.alsoInvisible = _includeInvisibles; settings.alsoInvisible = _includeInvisibles;
settings.onlyVisibleAsUnqualifiedNames = true; settings.onlyVisibleAsUnqualifiedNames = true;
std::vector<Declaration const*> candidates = m_currentScope->resolveName(_path.front(), settings); vector<Declaration const*> candidates = m_currentScope->resolveName(_path.front(), settings);
// inside the loop, use default settings, except for alsoInvisible // inside the loop, use default settings, except for alsoInvisible
settings.recursive = false; settings.recursive = false;
@ -304,7 +305,7 @@ bool NameAndTypeResolver::resolveNamesAndTypesInternal(ASTNode& _node, bool _res
if (success) if (success)
{ {
linearizeBaseContracts(*contract); linearizeBaseContracts(*contract);
std::vector<ContractDefinition const*> properBases( vector<ContractDefinition const*> properBases(
++contract->annotation().linearizedBaseContracts.begin(), ++contract->annotation().linearizedBaseContracts.begin(),
contract->annotation().linearizedBaseContracts.end() contract->annotation().linearizedBaseContracts.end()
); );
@ -404,7 +405,7 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract)
{ {
// order in the lists is from derived to base // order in the lists is from derived to base
// list of lists to linearize, the last element is the list of direct bases // list of lists to linearize, the last element is the list of direct bases
std::list<std::list<ContractDefinition const*>> input(1, std::list<ContractDefinition const*>{}); list<list<ContractDefinition const*>> input(1, list<ContractDefinition const*>{});
for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: _contract.baseContracts()) for (ASTPointer<InheritanceSpecifier> const& baseSpecifier: _contract.baseContracts())
{ {
IdentifierPath const& baseName = baseSpecifier->name(); IdentifierPath const& baseName = baseSpecifier->name();
@ -414,25 +415,25 @@ void NameAndTypeResolver::linearizeBaseContracts(ContractDefinition& _contract)
// "push_front" has the effect that bases mentioned later can overwrite members of bases // "push_front" has the effect that bases mentioned later can overwrite members of bases
// mentioned earlier // mentioned earlier
input.back().push_front(base); input.back().push_front(base);
std::vector<ContractDefinition const*> const& basesBases = base->annotation().linearizedBaseContracts; vector<ContractDefinition const*> const& basesBases = base->annotation().linearizedBaseContracts;
if (basesBases.empty()) if (basesBases.empty())
m_errorReporter.fatalTypeError(2449_error, baseName.location(), "Definition of base has to precede definition of derived contract"); m_errorReporter.fatalTypeError(2449_error, baseName.location(), "Definition of base has to precede definition of derived contract");
input.push_front(std::list<ContractDefinition const*>(basesBases.begin(), basesBases.end())); input.push_front(list<ContractDefinition const*>(basesBases.begin(), basesBases.end()));
} }
input.back().push_front(&_contract); input.back().push_front(&_contract);
std::vector<ContractDefinition const*> result = cThreeMerge(input); vector<ContractDefinition const*> result = cThreeMerge(input);
if (result.empty()) if (result.empty())
m_errorReporter.fatalTypeError(5005_error, _contract.location(), "Linearization of inheritance graph impossible"); m_errorReporter.fatalTypeError(5005_error, _contract.location(), "Linearization of inheritance graph impossible");
_contract.annotation().linearizedBaseContracts = result; _contract.annotation().linearizedBaseContracts = result;
} }
template <class T> template <class T>
std::vector<T const*> NameAndTypeResolver::cThreeMerge(std::list<std::list<T const*>>& _toMerge) vector<T const*> NameAndTypeResolver::cThreeMerge(list<list<T const*>>& _toMerge)
{ {
// returns true iff _candidate appears only as last element of the lists // returns true iff _candidate appears only as last element of the lists
auto appearsOnlyAtHead = [&](T const* _candidate) -> bool auto appearsOnlyAtHead = [&](T const* _candidate) -> bool
{ {
for (std::list<T const*> const& bases: _toMerge) for (list<T const*> const& bases: _toMerge)
{ {
solAssert(!bases.empty(), ""); solAssert(!bases.empty(), "");
if (find(++bases.begin(), bases.end(), _candidate) != bases.end()) if (find(++bases.begin(), bases.end(), _candidate) != bases.end())
@ -443,7 +444,7 @@ std::vector<T const*> NameAndTypeResolver::cThreeMerge(std::list<std::list<T con
// returns the next candidate to append to the linearized list or nullptr on failure // returns the next candidate to append to the linearized list or nullptr on failure
auto nextCandidate = [&]() -> T const* auto nextCandidate = [&]() -> T const*
{ {
for (std::list<T const*> const& bases: _toMerge) for (list<T const*> const& bases: _toMerge)
{ {
solAssert(!bases.empty(), ""); solAssert(!bases.empty(), "");
if (appearsOnlyAtHead(bases.front())) if (appearsOnlyAtHead(bases.front()))
@ -464,26 +465,26 @@ std::vector<T const*> NameAndTypeResolver::cThreeMerge(std::list<std::list<T con
} }
}; };
_toMerge.remove_if([](std::list<T const*> const& _bases) { return _bases.empty(); }); _toMerge.remove_if([](list<T const*> const& _bases) { return _bases.empty(); });
std::vector<T const*> result; vector<T const*> result;
while (!_toMerge.empty()) while (!_toMerge.empty())
{ {
T const* candidate = nextCandidate(); T const* candidate = nextCandidate();
if (!candidate) if (!candidate)
return std::vector<T const*>(); return vector<T const*>();
result.push_back(candidate); result.push_back(candidate);
removeCandidate(candidate); removeCandidate(candidate);
} }
return result; return result;
} }
std::string NameAndTypeResolver::similarNameSuggestions(ASTString const& _name) const string NameAndTypeResolver::similarNameSuggestions(ASTString const& _name) const
{ {
return util::quotedAlternativesList(m_currentScope->similarNames(_name)); return util::quotedAlternativesList(m_currentScope->similarNames(_name));
} }
DeclarationRegistrationHelper::DeclarationRegistrationHelper( DeclarationRegistrationHelper::DeclarationRegistrationHelper(
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes, map<ASTNode const*, shared_ptr<DeclarationContainer>>& _scopes,
ASTNode& _astRoot, ASTNode& _astRoot,
ErrorReporter& _errorReporter, ErrorReporter& _errorReporter,
GlobalContext& _globalContext, GlobalContext& _globalContext,
@ -501,7 +502,7 @@ DeclarationRegistrationHelper::DeclarationRegistrationHelper(
bool DeclarationRegistrationHelper::registerDeclaration( bool DeclarationRegistrationHelper::registerDeclaration(
DeclarationContainer& _container, DeclarationContainer& _container,
Declaration const& _declaration, Declaration const& _declaration,
std::string const* _name, string const* _name,
SourceLocation const* _errorLocation, SourceLocation const* _errorLocation,
bool _inactive, bool _inactive,
ErrorReporter& _errorReporter ErrorReporter& _errorReporter
@ -510,13 +511,13 @@ bool DeclarationRegistrationHelper::registerDeclaration(
if (!_errorLocation) if (!_errorLocation)
_errorLocation = &_declaration.location(); _errorLocation = &_declaration.location();
std::string name = _name ? *_name : _declaration.name(); string name = _name ? *_name : _declaration.name();
// We use "invisible" for both inactive variables in blocks and for members invisible in contracts. // We use "invisible" for both inactive variables in blocks and for members invisible in contracts.
// They cannot both be true at the same time. // They cannot both be true at the same time.
solAssert(!(_inactive && !_declaration.isVisibleInContract()), ""); solAssert(!(_inactive && !_declaration.isVisibleInContract()), "");
static std::set<std::string> illegalNames{"_", "super", "this"}; static set<string> illegalNames{"_", "super", "this"};
if (illegalNames.count(name)) if (illegalNames.count(name))
{ {
@ -579,7 +580,7 @@ bool DeclarationRegistrationHelper::visit(SourceUnit& _sourceUnit)
{ {
if (!m_scopes[&_sourceUnit]) if (!m_scopes[&_sourceUnit])
// By importing, it is possible that the container already exists. // By importing, it is possible that the container already exists.
m_scopes[&_sourceUnit] = std::make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get()); m_scopes[&_sourceUnit] = make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get());
return ASTVisitor::visit(_sourceUnit); return ASTVisitor::visit(_sourceUnit);
} }
@ -593,7 +594,7 @@ bool DeclarationRegistrationHelper::visit(ImportDirective& _import)
SourceUnit const* importee = _import.annotation().sourceUnit; SourceUnit const* importee = _import.annotation().sourceUnit;
solAssert(!!importee, ""); solAssert(!!importee, "");
if (!m_scopes[importee]) if (!m_scopes[importee])
m_scopes[importee] = std::make_shared<DeclarationContainer>(nullptr, m_scopes[nullptr].get()); m_scopes[importee] = make_shared<DeclarationContainer>(nullptr, m_scopes[nullptr].get());
m_scopes[&_import] = m_scopes[importee]; m_scopes[&_import] = m_scopes[importee];
ASTVisitor::visit(_import); ASTVisitor::visit(_import);
return false; // Do not recurse into child nodes (Identifier for symbolAliases) return false; // Do not recurse into child nodes (Identifier for symbolAliases)
@ -640,7 +641,7 @@ bool DeclarationRegistrationHelper::visitNode(ASTNode& _node)
if (auto* annotation = dynamic_cast<TypeDeclarationAnnotation*>(&_node.annotation())) if (auto* annotation = dynamic_cast<TypeDeclarationAnnotation*>(&_node.annotation()))
{ {
std::string canonicalName = dynamic_cast<Declaration const&>(_node).name(); string canonicalName = dynamic_cast<Declaration const&>(_node).name();
solAssert(!canonicalName.empty(), ""); solAssert(!canonicalName.empty(), "");
for ( for (
@ -683,7 +684,7 @@ void DeclarationRegistrationHelper::enterNewSubScope(ASTNode& _subScope)
{ {
bool newlyAdded = m_scopes.emplace( bool newlyAdded = m_scopes.emplace(
&_subScope, &_subScope,
std::make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get()) make_shared<DeclarationContainer>(m_currentScope, m_scopes[m_currentScope].get())
).second; ).second;
solAssert(newlyAdded, "Unable to add new scope."); solAssert(newlyAdded, "Unable to add new scope.");
} }

View File

@ -31,6 +31,7 @@
#include <boost/algorithm/string/predicate.hpp> #include <boost/algorithm/string/predicate.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::langutil; using namespace solidity::langutil;
@ -45,7 +46,7 @@ namespace
// Helper struct to do a search by name // Helper struct to do a search by name
struct MatchByName struct MatchByName
{ {
std::string const& m_name; string const& m_name;
bool operator()(OverrideProxy const& _item) bool operator()(OverrideProxy const& _item)
{ {
return _item.name() == m_name; return _item.name() == m_name;
@ -60,7 +61,7 @@ struct MatchByName
*/ */
struct OverrideGraph struct OverrideGraph
{ {
OverrideGraph(std::set<OverrideProxy> const& _baseCallables) OverrideGraph(set<OverrideProxy> const& _baseCallables)
{ {
for (auto const& baseFunction: _baseCallables) for (auto const& baseFunction: _baseCallables)
addEdge(0, visit(baseFunction)); addEdge(0, visit(baseFunction));
@ -130,17 +131,17 @@ private:
run(vInd, _depth + 1); run(vInd, _depth + 1);
if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1) if (m_low[vInd] >= m_depths[_u] && m_parent[_u] != -1)
m_cutVertices.insert(m_graph.nodeInv.at(static_cast<int>(_u))); m_cutVertices.insert(m_graph.nodeInv.at(static_cast<int>(_u)));
m_low[_u] = std::min(m_low[_u], m_low[vInd]); m_low[_u] = min(m_low[_u], m_low[vInd]);
} }
else if (v != m_parent[_u]) else if (v != m_parent[_u])
m_low[_u] = std::min(m_low[_u], m_depths[vInd]); m_low[_u] = min(m_low[_u], m_depths[vInd]);
} }
} }
}; };
std::vector<ContractDefinition const*> resolveDirectBaseContracts(ContractDefinition const& _contract) vector<ContractDefinition const*> resolveDirectBaseContracts(ContractDefinition const& _contract)
{ {
std::vector<ContractDefinition const*> resolvedContracts; vector<ContractDefinition const*> resolvedContracts;
for (ASTPointer<InheritanceSpecifier> const& specifier: _contract.baseContracts()) for (ASTPointer<InheritanceSpecifier> const& specifier: _contract.baseContracts())
{ {
@ -154,7 +155,7 @@ std::vector<ContractDefinition const*> resolveDirectBaseContracts(ContractDefini
return resolvedContracts; return resolvedContracts;
} }
std::vector<ASTPointer<IdentifierPath>> sortByContract(std::vector<ASTPointer<IdentifierPath>> const& _list) vector<ASTPointer<IdentifierPath>> sortByContract(vector<ASTPointer<IdentifierPath>> const& _list)
{ {
auto sorted = _list; auto sorted = _list;
@ -196,17 +197,17 @@ bool OverrideProxy::operator<(OverrideProxy const& _other) const
bool OverrideProxy::isVariable() const bool OverrideProxy::isVariable() const
{ {
return std::holds_alternative<VariableDeclaration const*>(m_item); return holds_alternative<VariableDeclaration const*>(m_item);
} }
bool OverrideProxy::isFunction() const bool OverrideProxy::isFunction() const
{ {
return std::holds_alternative<FunctionDefinition const*>(m_item); return holds_alternative<FunctionDefinition const*>(m_item);
} }
bool OverrideProxy::isModifier() const bool OverrideProxy::isModifier() const
{ {
return std::holds_alternative<ModifierDefinition const*>(m_item); return holds_alternative<ModifierDefinition const*>(m_item);
} }
bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, OverrideProxy const& _b) const bool OverrideProxy::CompareBySignature::operator()(OverrideProxy const& _a, OverrideProxy const& _b) const
@ -221,18 +222,18 @@ size_t OverrideProxy::id() const
}, m_item); }, m_item);
} }
std::shared_ptr<OverrideSpecifier> OverrideProxy::overrides() const shared_ptr<OverrideSpecifier> OverrideProxy::overrides() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](auto const* _item) { return _item->overrides(); } [&](auto const* _item) { return _item->overrides(); }
}, m_item); }, m_item);
} }
std::set<OverrideProxy> OverrideProxy::baseFunctions() const set<OverrideProxy> OverrideProxy::baseFunctions() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](auto const* _item) -> std::set<OverrideProxy> { [&](auto const* _item) -> set<OverrideProxy> {
std::set<OverrideProxy> ret; set<OverrideProxy> ret;
for (auto const* f: _item->annotation().baseFunctions) for (auto const* f: _item->annotation().baseFunctions)
ret.insert(makeOverrideProxy(*f)); ret.insert(makeOverrideProxy(*f));
return ret; return ret;
@ -255,10 +256,10 @@ void OverrideProxy::storeBaseFunction(OverrideProxy const& _base) const
}, m_item); }, m_item);
} }
std::string const& OverrideProxy::name() const string const& OverrideProxy::name() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](auto const* _item) -> std::string const& { return _item->name(); } [&](auto const* _item) -> string const& { return _item->name(); }
}, m_item); }, m_item);
} }
@ -271,7 +272,7 @@ ContractDefinition const& OverrideProxy::contract() const
}, m_item); }, m_item);
} }
std::string const& OverrideProxy::contractName() const string const& OverrideProxy::contractName() const
{ {
return contract().name(); return contract().name();
} }
@ -356,7 +357,7 @@ SourceLocation const& OverrideProxy::location() const
}, m_item); }, m_item);
} }
std::string OverrideProxy::astNodeName() const string OverrideProxy::astNodeName() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](FunctionDefinition const*) { return "function"; }, [&](FunctionDefinition const*) { return "function"; },
@ -365,7 +366,7 @@ std::string OverrideProxy::astNodeName() const
}, m_item); }, m_item);
} }
std::string OverrideProxy::astNodeNameCapitalized() const string OverrideProxy::astNodeNameCapitalized() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](FunctionDefinition const*) { return "Function"; }, [&](FunctionDefinition const*) { return "Function"; },
@ -374,7 +375,7 @@ std::string OverrideProxy::astNodeNameCapitalized() const
}, m_item); }, m_item);
} }
std::string OverrideProxy::distinguishingProperty() const string OverrideProxy::distinguishingProperty() const
{ {
return std::visit(GenericVisitor{ return std::visit(GenericVisitor{
[&](FunctionDefinition const*) { return "name and parameter types"; }, [&](FunctionDefinition const*) { return "name and parameter types"; },
@ -417,10 +418,10 @@ OverrideProxy::OverrideComparator const& OverrideProxy::overrideComparator() con
{ {
if (!m_comparator) if (!m_comparator)
{ {
m_comparator = std::make_shared<OverrideComparator>(std::visit(GenericVisitor{ m_comparator = make_shared<OverrideComparator>(std::visit(GenericVisitor{
[&](FunctionDefinition const* _function) [&](FunctionDefinition const* _function)
{ {
std::vector<std::string> paramTypes; vector<string> paramTypes;
for (Type const* t: externalFunctionType()->parameterTypes()) for (Type const* t: externalFunctionType()->parameterTypes())
paramTypes.emplace_back(t->richIdentifier()); paramTypes.emplace_back(t->richIdentifier());
return OverrideComparator{ return OverrideComparator{
@ -431,7 +432,7 @@ OverrideProxy::OverrideComparator const& OverrideProxy::overrideComparator() con
}, },
[&](VariableDeclaration const* _var) [&](VariableDeclaration const* _var)
{ {
std::vector<std::string> paramTypes; vector<string> paramTypes;
for (Type const* t: externalFunctionType()->parameterTypes()) for (Type const* t: externalFunctionType()->parameterTypes())
paramTypes.emplace_back(t->richIdentifier()); paramTypes.emplace_back(t->richIdentifier());
return OverrideComparator{ return OverrideComparator{
@ -673,21 +674,21 @@ void OverrideChecker::checkOverride(OverrideProxy const& _overriding, OverridePr
void OverrideChecker::overrideListError( void OverrideChecker::overrideListError(
OverrideProxy const& _item, OverrideProxy const& _item,
std::set<ContractDefinition const*, CompareByID> _secondary, set<ContractDefinition const*, CompareByID> _secondary,
ErrorId _error, ErrorId _error,
std::string const& _message1, string const& _message1,
std::string const& _message2 string const& _message2
) )
{ {
// Using a set rather than a vector so the order is always the same // Using a set rather than a vector so the order is always the same
std::set<std::string> names; set<string> names;
SecondarySourceLocation ssl; SecondarySourceLocation ssl;
for (Declaration const* c: _secondary) for (Declaration const* c: _secondary)
{ {
ssl.append("This contract: ", c->location()); ssl.append("This contract: ", c->location());
names.insert("\"" + c->name() + "\""); names.insert("\"" + c->name() + "\"");
} }
std::string contractSingularPlural = "contract "; string contractSingularPlural = "contract ";
if (_secondary.size() > 1) if (_secondary.size() > 1)
contractSingularPlural = "contracts "; contractSingularPlural = "contracts ";
@ -707,8 +708,8 @@ void OverrideChecker::overrideError(
OverrideProxy const& _overriding, OverrideProxy const& _overriding,
OverrideProxy const& _super, OverrideProxy const& _super,
ErrorId _error, ErrorId _error,
std::string const& _message, string const& _message,
std::optional<std::string> const& _secondaryMsg optional<string> const& _secondaryMsg
) )
{ {
m_errorReporter.typeError( m_errorReporter.typeError(
@ -765,7 +766,7 @@ void OverrideChecker::checkAmbiguousOverrides(ContractDefinition const& _contrac
} }
} }
void OverrideChecker::checkAmbiguousOverridesInternal(std::set<OverrideProxy> _baseCallables, SourceLocation const& _location) const void OverrideChecker::checkAmbiguousOverridesInternal(set<OverrideProxy> _baseCallables, SourceLocation const& _location) const
{ {
if (_baseCallables.size() <= 1) if (_baseCallables.size() <= 1)
return; return;
@ -798,17 +799,17 @@ void OverrideChecker::checkAmbiguousOverridesInternal(std::set<OverrideProxy> _b
for (OverrideProxy const& baseFunction: _baseCallables) for (OverrideProxy const& baseFunction: _baseCallables)
ssl.append("Definition in \"" + baseFunction.contractName() + "\": ", baseFunction.location()); ssl.append("Definition in \"" + baseFunction.contractName() + "\": ", baseFunction.location());
std::string callableName = _baseCallables.begin()->astNodeName(); string callableName = _baseCallables.begin()->astNodeName();
if (_baseCallables.begin()->isVariable()) if (_baseCallables.begin()->isVariable())
callableName = "function"; callableName = "function";
std::string distinguishigProperty = _baseCallables.begin()->distinguishingProperty(); string distinguishigProperty = _baseCallables.begin()->distinguishingProperty();
bool foundVariable = false; bool foundVariable = false;
for (auto const& base: _baseCallables) for (auto const& base: _baseCallables)
if (base.isVariable()) if (base.isVariable())
foundVariable = true; foundVariable = true;
std::string message = string message =
"Derived contract must override " + callableName + " \"" + "Derived contract must override " + callableName + " \"" +
_baseCallables.begin()->name() + _baseCallables.begin()->name() +
"\". Two or more base classes define " + callableName + " with same " + distinguishigProperty + "."; "\". Two or more base classes define " + callableName + " with same " + distinguishigProperty + ".";
@ -821,9 +822,9 @@ void OverrideChecker::checkAmbiguousOverridesInternal(std::set<OverrideProxy> _b
m_errorReporter.typeError(6480_error, _location, ssl, message); m_errorReporter.typeError(6480_error, _location, ssl, message);
} }
std::set<ContractDefinition const*, OverrideChecker::CompareByID> OverrideChecker::resolveOverrideList(OverrideSpecifier const& _overrides) const set<ContractDefinition const*, OverrideChecker::CompareByID> OverrideChecker::resolveOverrideList(OverrideSpecifier const& _overrides) const
{ {
std::set<ContractDefinition const*, CompareByID> resolved; set<ContractDefinition const*, CompareByID> resolved;
for (ASTPointer<IdentifierPath> const& override: _overrides.overrides()) for (ASTPointer<IdentifierPath> const& override: _overrides.overrides())
{ {
@ -841,7 +842,7 @@ std::set<ContractDefinition const*, OverrideChecker::CompareByID> OverrideChecke
void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySignatureMultiSet const& _inherited) void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySignatureMultiSet const& _inherited)
{ {
std::set<ContractDefinition const*, CompareByID> specifiedContracts = set<ContractDefinition const*, CompareByID> specifiedContracts =
_item.overrides() ? _item.overrides() ?
resolveOverrideList(*_item.overrides()) : resolveOverrideList(*_item.overrides()) :
decltype(specifiedContracts){}; decltype(specifiedContracts){};
@ -850,7 +851,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign
if (_item.overrides() && specifiedContracts.size() != _item.overrides()->overrides().size()) if (_item.overrides() && specifiedContracts.size() != _item.overrides()->overrides().size())
{ {
// Sort by contract id to find duplicate for error reporting // Sort by contract id to find duplicate for error reporting
std::vector<ASTPointer<IdentifierPath>> list = vector<ASTPointer<IdentifierPath>> list =
sortByContract(_item.overrides()->overrides()); sortByContract(_item.overrides()->overrides());
// Find duplicates and output error // Find duplicates and output error
@ -879,7 +880,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign
} }
} }
std::set<ContractDefinition const*, CompareByID> expectedContracts; set<ContractDefinition const*, CompareByID> expectedContracts;
// Build list of expected contracts // Build list of expected contracts
for (auto [begin, end] = _inherited.equal_range(_item); begin != end; begin++) for (auto [begin, end] = _inherited.equal_range(_item); begin != end; begin++)
@ -897,7 +898,7 @@ void OverrideChecker::checkOverrideList(OverrideProxy _item, OverrideProxyBySign
_item.astNodeNameCapitalized() + " has override specified but does not override anything." _item.astNodeNameCapitalized() + " has override specified but does not override anything."
); );
std::set<ContractDefinition const*, CompareByID> missingContracts; set<ContractDefinition const*, CompareByID> missingContracts;
// If we expect only one contract, no contract needs to be specified // If we expect only one contract, no contract needs to be specified
if (expectedContracts.size() > 1) if (expectedContracts.size() > 1)
missingContracts = expectedContracts - specifiedContracts; missingContracts = expectedContracts - specifiedContracts;
@ -930,7 +931,7 @@ OverrideChecker::OverrideProxyBySignatureMultiSet const& OverrideChecker::inheri
for (auto const* base: resolveDirectBaseContracts(_contract)) for (auto const* base: resolveDirectBaseContracts(_contract))
{ {
std::set<OverrideProxy, OverrideProxy::CompareBySignature> functionsInBase; set<OverrideProxy, OverrideProxy::CompareBySignature> functionsInBase;
for (FunctionDefinition const* fun: base->definedFunctions()) for (FunctionDefinition const* fun: base->definedFunctions())
if (!fun->isConstructor()) if (!fun->isConstructor())
functionsInBase.emplace(OverrideProxy{fun}); functionsInBase.emplace(OverrideProxy{fun});
@ -959,7 +960,7 @@ OverrideChecker::OverrideProxyBySignatureMultiSet const& OverrideChecker::inheri
for (auto const* base: resolveDirectBaseContracts(_contract)) for (auto const* base: resolveDirectBaseContracts(_contract))
{ {
std::set<OverrideProxy, OverrideProxy::CompareBySignature> modifiersInBase; set<OverrideProxy, OverrideProxy::CompareBySignature> modifiersInBase;
for (ModifierDefinition const* mod: base->functionModifiers()) for (ModifierDefinition const* mod: base->functionModifiers())
modifiersInBase.emplace(OverrideProxy{mod}); modifiersInBase.emplace(OverrideProxy{mod});

View File

@ -27,6 +27,7 @@
#include <memory> #include <memory>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -203,7 +204,7 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
// Iterating through the dependencies needs to be deterministic and thus cannot // Iterating through the dependencies needs to be deterministic and thus cannot
// depend on the memory layout. // depend on the memory layout.
// Because of that, we sort by AST node id. // Because of that, we sort by AST node id.
std::vector<VariableDeclaration const*> dependencies( vector<VariableDeclaration const*> dependencies(
m_constVariableDependencies[&_variable].begin(), m_constVariableDependencies[&_variable].begin(),
m_constVariableDependencies[&_variable].end() m_constVariableDependencies[&_variable].end()
); );
@ -426,10 +427,10 @@ struct ReservedErrorSelector: public PostTypeChecker::Checker
PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter)
{ {
m_checkers.push_back(std::make_shared<ConstStateVarCircularReferenceChecker>(_errorReporter)); m_checkers.push_back(make_shared<ConstStateVarCircularReferenceChecker>(_errorReporter));
m_checkers.push_back(std::make_shared<OverrideSpecifierChecker>(_errorReporter)); m_checkers.push_back(make_shared<OverrideSpecifierChecker>(_errorReporter));
m_checkers.push_back(std::make_shared<ModifierContextChecker>(_errorReporter)); m_checkers.push_back(make_shared<ModifierContextChecker>(_errorReporter));
m_checkers.push_back(std::make_shared<EventOutsideEmitErrorOutsideRevertChecker>(_errorReporter)); m_checkers.push_back(make_shared<EventOutsideEmitErrorOutsideRevertChecker>(_errorReporter));
m_checkers.push_back(std::make_shared<NoVariablesInInterfaceChecker>(_errorReporter)); m_checkers.push_back(make_shared<NoVariablesInInterfaceChecker>(_errorReporter));
m_checkers.push_back(std::make_shared<ReservedErrorSelector>(_errorReporter)); m_checkers.push_back(make_shared<ReservedErrorSelector>(_errorReporter));
} }

View File

@ -26,6 +26,7 @@
#include <libsolutil/FunctionSelector.h> #include <libsolutil/FunctionSelector.h>
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -47,10 +48,10 @@ bool PostTypeContractLevelChecker::check(ContractDefinition const& _contract)
"" ""
); );
std::map<uint32_t, std::map<std::string, SourceLocation>> errorHashes; map<uint32_t, map<string, SourceLocation>> errorHashes;
for (ErrorDefinition const* error: _contract.interfaceErrors()) for (ErrorDefinition const* error: _contract.interfaceErrors())
{ {
std::string signature = error->functionType(true)->externalSignature(); string signature = error->functionType(true)->externalSignature();
uint32_t hash = util::selectorFromSignatureU32(signature); uint32_t hash = util::selectorFromSignatureU32(signature);
// Fail if there is a different signature for the same hash. // Fail if there is a different signature for the same hash.
if (!errorHashes[hash].empty() && !errorHashes[hash].count(signature)) if (!errorHashes[hash].empty() && !errorHashes[hash].count(signature))

View File

@ -39,6 +39,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -120,8 +121,8 @@ bool ReferencesResolver::visit(Identifier const& _identifier)
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name()); auto declarations = m_resolver.nameFromCurrentScope(_identifier.name());
if (declarations.empty()) if (declarations.empty())
{ {
std::string suggestions = m_resolver.similarNameSuggestions(_identifier.name()); string suggestions = m_resolver.similarNameSuggestions(_identifier.name());
std::string errorMessage = "Undeclared identifier."; string errorMessage = "Undeclared identifier.";
if (!suggestions.empty()) if (!suggestions.empty())
{ {
if ("\"" + _identifier.name() + "\"" == suggestions) if ("\"" + _identifier.name() + "\"" == suggestions)
@ -191,10 +192,10 @@ bool ReferencesResolver::visit(UsingForDirective const& _usingFor)
// _includeInvisibles is enabled here because external library functions are marked invisible. // _includeInvisibles is enabled here because external library functions are marked invisible.
// As unintended side-effects other invisible names (eg.: super, this) may be returned as well. // As unintended side-effects other invisible names (eg.: super, this) may be returned as well.
// DeclarationTypeChecker should detect and report such situations. // DeclarationTypeChecker should detect and report such situations.
std::vector<Declaration const*> declarations = m_resolver.pathFromCurrentScopeWithAllDeclarations(path->path(), true /* _includeInvisibles */); vector<Declaration const*> declarations = m_resolver.pathFromCurrentScopeWithAllDeclarations(path->path(), true /* _includeInvisibles */);
if (declarations.empty()) if (declarations.empty())
{ {
std::string libraryOrFunctionNameErrorMessage = string libraryOrFunctionNameErrorMessage =
_usingFor.usesBraces() ? _usingFor.usesBraces() ?
"Identifier is not a function name or not unique." : "Identifier is not a function name or not unique." :
"Identifier is not a library name."; "Identifier is not a library name.";
@ -252,9 +253,9 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
{ {
solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), ""); solAssert(nativeLocationOf(_identifier) == originLocationOf(_identifier), "");
static std::set<std::string> suffixes{"slot", "offset", "length", "address", "selector"}; static set<string> suffixes{"slot", "offset", "length", "address", "selector"};
std::string suffix; string suffix;
for (std::string const& s: suffixes) for (string const& s: suffixes)
if (boost::algorithm::ends_with(_identifier.name.str(), "." + s)) if (boost::algorithm::ends_with(_identifier.name.str(), "." + s))
suffix = s; suffix = s;
@ -268,7 +269,7 @@ void ReferencesResolver::operator()(yul::Identifier const& _identifier)
if (!declarations.empty()) if (!declarations.empty())
// the special identifier exists itself, we should not allow that. // the special identifier exists itself, we should not allow that.
return; return;
std::string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - suffix.size() - 1); string realName = _identifier.name.str().substr(0, _identifier.name.str().size() - suffix.size() - 1);
solAssert(!realName.empty(), "Empty name."); solAssert(!realName.empty(), "Empty name.");
declarations = m_resolver.nameFromCurrentScope(realName); declarations = m_resolver.nameFromCurrentScope(realName);
if (!declarations.empty()) if (!declarations.empty())
@ -349,7 +350,7 @@ void ReferencesResolver::resolveInheritDoc(StructuredDocumentation const& _docum
break; break;
case 1: case 1:
{ {
std::string const& name = _annotation.docTags.find("inheritdoc")->second.content; string const& name = _annotation.docTags.find("inheritdoc")->second.content;
if (name.empty()) if (name.empty())
{ {
m_errorReporter.docstringParsingError( m_errorReporter.docstringParsingError(
@ -360,7 +361,7 @@ void ReferencesResolver::resolveInheritDoc(StructuredDocumentation const& _docum
return; return;
} }
std::vector<std::string> path; vector<string> path;
boost::split(path, name, boost::is_any_of(".")); boost::split(path, name, boost::is_any_of("."));
if (any_of(path.begin(), path.end(), [](auto& _str) { return _str.empty(); })) if (any_of(path.begin(), path.end(), [](auto& _str) { return _str.empty(); }))
{ {
@ -420,7 +421,7 @@ void ReferencesResolver::validateYulIdentifierName(yul::YulString _name, SourceL
"User-defined identifiers in inline assembly cannot contain '.'." "User-defined identifiers in inline assembly cannot contain '.'."
); );
if (std::set<std::string>{"this", "super", "_"}.count(_name.str())) if (set<string>{"this", "super", "_"}.count(_name.str()))
m_errorReporter.declarationError( m_errorReporter.declarationError(
4113_error, 4113_error,
_location, _location,

View File

@ -20,6 +20,7 @@
#include <libsolidity/ast/AST.h> #include <libsolidity/ast/AST.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;

View File

@ -28,6 +28,7 @@
#include <liblangutil/ErrorReporter.h> #include <liblangutil/ErrorReporter.h>
#include <memory> #include <memory>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -70,7 +71,7 @@ private:
return m_usesAssembly[&_contract]; return m_usesAssembly[&_contract];
} }
std::map<ContractDefinition const*, bool> m_usesAssembly; map<ContractDefinition const*, bool> m_usesAssembly;
}; };
StaticAnalyzer::StaticAnalyzer(ErrorReporter& _errorReporter): StaticAnalyzer::StaticAnalyzer(ErrorReporter& _errorReporter):
@ -123,7 +124,7 @@ void StaticAnalyzer::endVisit(FunctionDefinition const&)
5667_error, 5667_error,
var.first.second->location(), var.first.second->location(),
"Unused " + "Unused " +
std::string(var.first.second->isTryCatchParameter() ? "try/catch" : "function") + string(var.first.second->isTryCatchParameter() ? "try/catch" : "function") +
" parameter. Remove or comment out the variable name to silence this warning." " parameter. Remove or comment out the variable name to silence this warning."
); );
else else
@ -141,7 +142,7 @@ bool StaticAnalyzer::visit(Identifier const& _identifier)
{ {
solAssert(!var->name().empty(), ""); solAssert(!var->name().empty(), "");
if (var->isLocalVariable()) if (var->isLocalVariable())
m_localVarUseCount[std::make_pair(var->id(), var)] += 1; m_localVarUseCount[make_pair(var->id(), var)] += 1;
} }
return true; return true;
} }
@ -153,7 +154,7 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
solAssert(_variable.isLocalVariable(), ""); solAssert(_variable.isLocalVariable(), "");
if (_variable.name() != "") if (_variable.name() != "")
// This is not a no-op, the entry might pre-exist. // This is not a no-op, the entry might pre-exist.
m_localVarUseCount[std::make_pair(_variable.id(), &_variable)] += 0; m_localVarUseCount[make_pair(_variable.id(), &_variable)] += 0;
} }
if (_variable.isStateVariable() || _variable.referenceLocation() == VariableDeclaration::Location::Storage) if (_variable.isStateVariable() || _variable.referenceLocation() == VariableDeclaration::Location::Storage)
@ -161,7 +162,7 @@ bool StaticAnalyzer::visit(VariableDeclaration const& _variable)
for (Type const* type: varType->fullDecomposition()) for (Type const* type: varType->fullDecomposition())
if (type->storageSizeUpperBound() >= (bigint(1) << 64)) if (type->storageSizeUpperBound() >= (bigint(1) << 64))
{ {
std::string message = "Type " + type->toString(true) + string message = "Type " + type->toString(true) +
" covers a large part of storage and thus makes collisions likely." " covers a large part of storage and thus makes collisions likely."
" Either use mappings or dynamic arrays and allow their size to be increased only" " Either use mappings or dynamic arrays and allow their size to be increased only"
" in small quantities per transaction."; " in small quantities per transaction.";
@ -178,7 +179,7 @@ bool StaticAnalyzer::visit(Return const& _return)
if (m_currentFunction && _return.expression()) if (m_currentFunction && _return.expression())
for (auto const& var: m_currentFunction->returnParameters()) for (auto const& var: m_currentFunction->returnParameters())
if (!var->name().empty()) if (!var->name().empty())
m_localVarUseCount[std::make_pair(var->id(), var.get())] += 1; m_localVarUseCount[make_pair(var->id(), var.get())] += 1;
return true; return true;
} }
@ -213,7 +214,7 @@ bool StaticAnalyzer::visit(MemberAccess const& _memberAccess)
else if (type->kind() == MagicType::Kind::MetaType && _memberAccess.memberName() == "runtimeCode") else if (type->kind() == MagicType::Kind::MetaType && _memberAccess.memberName() == "runtimeCode")
{ {
if (!m_constructorUsesAssembly) if (!m_constructorUsesAssembly)
m_constructorUsesAssembly = std::make_unique<ConstructorUsesAssembly>(); m_constructorUsesAssembly = make_unique<ConstructorUsesAssembly>();
ContractType const& contract = dynamic_cast<ContractType const&>(*type->typeArgument()); ContractType const& contract = dynamic_cast<ContractType const&>(*type->typeArgument());
if (m_constructorUsesAssembly->check(contract.contractDefinition())) if (m_constructorUsesAssembly->check(contract.contractDefinition()))
m_errorReporter.warning( m_errorReporter.warning(
@ -287,7 +288,7 @@ bool StaticAnalyzer::visit(InlineAssembly const& _inlineAssembly)
{ {
solAssert(!var->name().empty(), ""); solAssert(!var->name().empty(), "");
if (var->isLocalVariable()) if (var->isLocalVariable())
m_localVarUseCount[std::make_pair(var->id(), var)] += 1; m_localVarUseCount[make_pair(var->id(), var)] += 1;
} }
} }

View File

@ -32,6 +32,7 @@
#include <string> #include <string>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -54,17 +55,17 @@ void SyntaxChecker::endVisit(SourceUnit const& _sourceUnit)
{ {
if (!m_versionPragmaFound) if (!m_versionPragmaFound)
{ {
std::string errorString("Source file does not specify required compiler version!"); string errorString("Source file does not specify required compiler version!");
SemVerVersion recommendedVersion{std::string(VersionString)}; SemVerVersion recommendedVersion{string(VersionString)};
if (!recommendedVersion.isPrerelease()) if (!recommendedVersion.isPrerelease())
errorString += errorString +=
" Consider adding \"pragma solidity ^" + " Consider adding \"pragma solidity ^" +
std::to_string(recommendedVersion.major()) + to_string(recommendedVersion.major()) +
std::string(".") + string(".") +
std::to_string(recommendedVersion.minor()) + to_string(recommendedVersion.minor()) +
std::string(".") + string(".") +
std::to_string(recommendedVersion.patch()) + to_string(recommendedVersion.patch()) +
std::string(";\""); string(";\"");
// when reporting the warning, print the source name only // when reporting the warning, print the source name only
m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().sourceName}, errorString); m_errorReporter.warning(3420_error, {-1, -1, _sourceUnit.location().sourceName}, errorString);
@ -83,7 +84,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
else if (_pragma.literals()[0] == "experimental") else if (_pragma.literals()[0] == "experimental")
{ {
solAssert(m_sourceUnit, ""); solAssert(m_sourceUnit, "");
std::vector<std::string> literals(_pragma.literals().begin() + 1, _pragma.literals().end()); vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
if (literals.empty()) if (literals.empty())
m_errorReporter.syntaxError( m_errorReporter.syntaxError(
9679_error, 9679_error,
@ -98,7 +99,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
); );
else else
{ {
std::string const literal = literals[0]; string const literal = literals[0];
if (literal.empty()) if (literal.empty())
m_errorReporter.syntaxError(3250_error, _pragma.location(), "Empty experimental feature name is invalid."); m_errorReporter.syntaxError(3250_error, _pragma.location(), "Empty experimental feature name is invalid.");
else if (!ExperimentalFeatureNames.count(literal)) else if (!ExperimentalFeatureNames.count(literal))
@ -134,7 +135,7 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
solAssert(m_sourceUnit, ""); solAssert(m_sourceUnit, "");
if ( if (
_pragma.literals().size() != 2 || _pragma.literals().size() != 2 ||
!std::set<std::string>{"v1", "v2"}.count(_pragma.literals()[1]) !set<string>{"v1", "v2"}.count(_pragma.literals()[1])
) )
m_errorReporter.syntaxError( m_errorReporter.syntaxError(
2745_error, 2745_error,
@ -154,12 +155,19 @@ bool SyntaxChecker::visit(PragmaDirective const& _pragma)
{ {
try try
{ {
std::vector<Token> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end()); vector<Token> tokens(_pragma.tokens().begin() + 1, _pragma.tokens().end());
std::vector<std::string> literals(_pragma.literals().begin() + 1, _pragma.literals().end()); vector<string> literals(_pragma.literals().begin() + 1, _pragma.literals().end());
SemVerMatchExpressionParser parser(tokens, literals); SemVerMatchExpressionParser parser(tokens, literals);
SemVerMatchExpression matchExpression = parser.parse(); SemVerMatchExpression matchExpression = parser.parse();
static SemVerVersion const currentVersion{std::string(VersionString)}; static SemVerVersion const currentVersion{string(VersionString)};
solAssert(matchExpression.matches(currentVersion)); if (!matchExpression.matches(currentVersion))
m_errorReporter.syntaxError(
3997_error,
_pragma.location(),
"Source file requires different compiler version (current compiler is " +
string(VersionString) + ") - note that nightly builds are considered to be "
"strictly less than the released version"
);
m_versionPragmaFound = true; m_versionPragmaFound = true;
} }
catch (SemVerError const&) catch (SemVerError const&)
@ -404,7 +412,7 @@ bool SyntaxChecker::visit(UsingForDirective const& _usingFor)
if (!_usingFor.usesBraces()) if (!_usingFor.usesBraces())
solAssert( solAssert(
_usingFor.functionsAndOperators().size() == 1 && _usingFor.functionsAndOperators().size() == 1 &&
!std::get<1>(_usingFor.functionsAndOperators().front()) !get<1>(_usingFor.functionsAndOperators().front())
); );
if (!m_currentContractKind && !_usingFor.typeName()) if (!m_currentContractKind && !_usingFor.typeName())
@ -447,7 +455,7 @@ bool SyntaxChecker::visit(FunctionDefinition const& _function)
if (!_function.isFree() && !_function.isConstructor() && _function.noVisibilitySpecified()) if (!_function.isFree() && !_function.isConstructor() && _function.noVisibilitySpecified())
{ {
std::string suggestedVisibility = string suggestedVisibility =
_function.isFallback() || _function.isFallback() ||
_function.isReceive() || _function.isReceive() ||
m_currentContractKind == ContractKind::Interface m_currentContractKind == ContractKind::Interface

View File

@ -51,6 +51,7 @@
#include <memory> #include <memory>
#include <vector> #include <vector>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::langutil; using namespace solidity::langutil;
@ -204,7 +205,7 @@ void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2) TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall const& _functionCall, bool _abiEncoderV2)
{ {
std::vector<ASTPointer<Expression const>> arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
if (arguments.size() != 2) if (arguments.size() != 2)
m_errorReporter.typeError( m_errorReporter.typeError(
5782_error, 5782_error,
@ -295,7 +296,7 @@ TypePointers TypeChecker::typeCheckABIDecodeAndRetrieveReturnType(FunctionCall c
TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(FunctionCall const& _functionCall) TypePointers TypeChecker::typeCheckMetaTypeFunctionAndRetrieveReturnType(FunctionCall const& _functionCall)
{ {
std::vector<ASTPointer<Expression const>> arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> arguments = _functionCall.arguments();
if (arguments.size() != 1) if (arguments.size() != 1)
m_errorReporter.fatalTypeError( m_errorReporter.fatalTypeError(
8885_error, 8885_error,
@ -441,7 +442,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
m_errorReporter.typeError(5587_error, _function.location(), "\"internal\" and \"private\" functions cannot be payable."); m_errorReporter.typeError(5587_error, _function.location(), "\"internal\" and \"private\" functions cannot be payable.");
} }
std::vector<VariableDeclaration const*> internalParametersInConstructor; vector<VariableDeclaration const*> internalParametersInConstructor;
auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& _var) { auto checkArgumentAndReturnParameter = [&](VariableDeclaration const& _var) {
if (type(_var)->containsNestedMapping()) if (type(_var)->containsNestedMapping())
@ -471,7 +472,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
if (!iType) if (!iType)
{ {
std::string message = iType.message(); string message = iType.message();
solAssert(!message.empty(), "Expected detailed error message!"); solAssert(!message.empty(), "Expected detailed error message!");
if (_function.isConstructor()) if (_function.isConstructor())
message += " You can make the contract abstract to avoid this problem."; message += " You can make the contract abstract to avoid this problem.";
@ -482,7 +483,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
!typeSupportedByOldABIEncoder(*type(_var), _function.libraryFunction()) !typeSupportedByOldABIEncoder(*type(_var), _function.libraryFunction())
) )
{ {
std::string message = string message =
"This type is only supported in ABI coder v2. " "This type is only supported in ABI coder v2. "
"Use \"pragma abicoder v2;\" to enable the feature."; "Use \"pragma abicoder v2;\" to enable the feature.";
if (_function.isConstructor()) if (_function.isConstructor())
@ -508,10 +509,10 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
var->accept(*this); var->accept(*this);
} }
std::set<Declaration const*> modifiers; set<Declaration const*> modifiers;
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers()) for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
{ {
std::vector<ContractDefinition const*> baseContracts; vector<ContractDefinition const*> baseContracts;
if (auto contract = dynamic_cast<ContractDefinition const*>(_function.scope())) if (auto contract = dynamic_cast<ContractDefinition const*>(_function.scope()))
{ {
baseContracts = contract->annotation().linearizedBaseContracts; baseContracts = contract->annotation().linearizedBaseContracts;
@ -521,7 +522,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
visitManually( visitManually(
*modifier, *modifier,
_function.isConstructor() ? baseContracts : std::vector<ContractDefinition const*>() _function.isConstructor() ? baseContracts : vector<ContractDefinition const*>()
); );
Declaration const* decl = &dereference(modifier->name()); Declaration const* decl = &dereference(modifier->name());
if (modifiers.count(decl)) if (modifiers.count(decl))
@ -641,7 +642,7 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
FunctionType getter(_variable); FunctionType getter(_variable);
if (!useABICoderV2()) if (!useABICoderV2())
{ {
std::vector<std::string> unsupportedTypes; vector<string> unsupportedTypes;
for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes()) for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes())
if (!typeSupportedByOldABIEncoder(*param, false /* isLibrary */)) if (!typeSupportedByOldABIEncoder(*param, false /* isLibrary */))
unsupportedTypes.emplace_back(param->humanReadableName()); unsupportedTypes.emplace_back(param->humanReadableName());
@ -712,7 +713,7 @@ void TypeChecker::endVisit(StructDefinition const& _struct)
void TypeChecker::visitManually( void TypeChecker::visitManually(
ModifierInvocation const& _modifier, ModifierInvocation const& _modifier,
std::vector<ContractDefinition const*> const& _bases vector<ContractDefinition const*> const& _bases
) )
{ {
std::vector<ASTPointer<Expression>> const& arguments = std::vector<ASTPointer<Expression>> const& arguments =
@ -723,8 +724,8 @@ void TypeChecker::visitManually(
_modifier.name().accept(*this); _modifier.name().accept(*this);
auto const* declaration = &dereference(_modifier.name()); auto const* declaration = &dereference(_modifier.name());
std::vector<ASTPointer<VariableDeclaration>> emptyParameterList; vector<ASTPointer<VariableDeclaration>> emptyParameterList;
std::vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr; vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
if (auto modifierDecl = dynamic_cast<ModifierDefinition const*>(declaration)) if (auto modifierDecl = dynamic_cast<ModifierDefinition const*>(declaration))
{ {
parameters = &modifierDecl->parameters(); parameters = &modifierDecl->parameters();
@ -919,8 +920,8 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
if (!identifierInfo.suffix.empty()) if (!identifierInfo.suffix.empty())
{ {
std::string const& suffix = identifierInfo.suffix; string const& suffix = identifierInfo.suffix;
solAssert((std::set<std::string>{"offset", "slot", "length", "selector", "address"}).count(suffix), ""); solAssert((set<string>{"offset", "slot", "length", "selector", "address"}).count(suffix), "");
if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage))) if (!var->isConstant() && (var->isStateVariable() || var->type()->dataStoredIn(DataLocation::Storage)))
{ {
if (suffix != "slot" && suffix != "offset") if (suffix != "slot" && suffix != "offset")
@ -1041,7 +1042,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
return true; return true;
}; };
solAssert(!_inlineAssembly.annotation().analysisInfo, ""); solAssert(!_inlineAssembly.annotation().analysisInfo, "");
_inlineAssembly.annotation().analysisInfo = std::make_shared<yul::AsmAnalysisInfo>(); _inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
yul::AsmAnalyzer analyzer( yul::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo, *_inlineAssembly.annotation().analysisInfo,
m_errorReporter, m_errorReporter,
@ -1112,9 +1113,9 @@ void TypeChecker::endVisit(TryStatement const& _tryStatement)
2800_error, 2800_error,
successClause.location(), successClause.location(),
"Function returns " + "Function returns " +
std::to_string(functionType.returnParameterTypes().size()) + to_string(functionType.returnParameterTypes().size()) +
" values, but returns clause has " + " values, but returns clause has " +
std::to_string(parameters.size()) + to_string(parameters.size()) +
" variables." " variables."
); );
for (auto&& [parameter, returnType]: ranges::views::zip(parameters, returnTypes)) for (auto&& [parameter, returnType]: ranges::views::zip(parameters, returnTypes))
@ -1362,7 +1363,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
else else
valueTypes = TypePointers{type(*_statement.initialValue())}; valueTypes = TypePointers{type(*_statement.initialValue())};
std::vector<ASTPointer<VariableDeclaration>> const& variables = _statement.declarations(); vector<ASTPointer<VariableDeclaration>> const& variables = _statement.declarations();
if (variables.empty()) if (variables.empty())
// We already have an error for this in the SyntaxChecker. // We already have an error for this in the SyntaxChecker.
solAssert(m_errorReporter.hasErrors(), ""); solAssert(m_errorReporter.hasErrors(), "");
@ -1377,7 +1378,7 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement)
")." ")."
); );
for (size_t i = 0; i < std::min(variables.size(), valueTypes.size()); ++i) for (size_t i = 0; i < min(variables.size(), valueTypes.size()); ++i)
{ {
if (!variables[i]) if (!variables[i])
continue; continue;
@ -1534,14 +1535,14 @@ void TypeChecker::checkExpressionAssignment(Type const& _type, Expression const&
m_errorReporter.typeError(5547_error, _expression.location(), "Empty tuple on the left hand side."); m_errorReporter.typeError(5547_error, _expression.location(), "Empty tuple on the left hand side.");
auto const* tupleType = dynamic_cast<TupleType const*>(&_type); auto const* tupleType = dynamic_cast<TupleType const*>(&_type);
auto const& types = tupleType && tupleExpression->components().size() != 1 ? tupleType->components() : std::vector<Type const*> { &_type }; auto const& types = tupleType && tupleExpression->components().size() != 1 ? tupleType->components() : vector<Type const*> { &_type };
solAssert( solAssert(
tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(), tupleExpression->components().size() == types.size() || m_errorReporter.hasErrors(),
"Array sizes don't match and no errors generated." "Array sizes don't match and no errors generated."
); );
for (size_t i = 0; i < std::min(tupleExpression->components().size(), types.size()); i++) for (size_t i = 0; i < min(tupleExpression->components().size(), types.size()); i++)
if (types[i]) if (types[i])
{ {
solAssert(!!tupleExpression->components()[i], ""); solAssert(!!tupleExpression->components()[i], "");
@ -1606,7 +1607,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
7366_error, 7366_error,
_assignment.location(), _assignment.location(),
"Operator " + "Operator " +
std::string(TokenTraits::friendlyName(_assignment.assignmentOperator())) + string(TokenTraits::friendlyName(_assignment.assignmentOperator())) +
" not compatible with types " + " not compatible with types " +
t->humanReadableName() + t->humanReadableName() +
" and " + " and " +
@ -1620,7 +1621,7 @@ bool TypeChecker::visit(Assignment const& _assignment)
bool TypeChecker::visit(TupleExpression const& _tuple) bool TypeChecker::visit(TupleExpression const& _tuple)
{ {
_tuple.annotation().isConstant = false; _tuple.annotation().isConstant = false;
std::vector<ASTPointer<Expression>> const& components = _tuple.components(); vector<ASTPointer<Expression>> const& components = _tuple.components();
TypePointers types; TypePointers types;
if (_tuple.annotation().willBeWrittenTo) if (_tuple.annotation().willBeWrittenTo)
@ -1733,7 +1734,7 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
// Check if the operator is built-in or user-defined. // Check if the operator is built-in or user-defined.
TypeResult builtinResult = operandType->unaryOperatorResult(op); TypeResult builtinResult = operandType->unaryOperatorResult(op);
std::set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = operandType->operatorDefinitions( set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = operandType->operatorDefinitions(
op, op,
*currentDefinitionScope(), *currentDefinitionScope(),
true // _unary true // _unary
@ -1759,7 +1760,7 @@ bool TypeChecker::visit(UnaryOperation const& _operation)
} }
else else
{ {
std::string description = fmt::format( string description = fmt::format(
"Built-in unary operator {} cannot be applied to type {}.", "Built-in unary operator {} cannot be applied to type {}.",
TokenTraits::friendlyName(op), TokenTraits::friendlyName(op),
operandType->humanReadableName() operandType->humanReadableName()
@ -1801,7 +1802,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
// Check if the operator is built-in or user-defined. // Check if the operator is built-in or user-defined.
TypeResult builtinResult = leftType->binaryOperatorResult(_operation.getOperator(), rightType); TypeResult builtinResult = leftType->binaryOperatorResult(_operation.getOperator(), rightType);
std::set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = leftType->operatorDefinitions( set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = leftType->operatorDefinitions(
_operation.getOperator(), _operation.getOperator(),
*currentDefinitionScope(), *currentDefinitionScope(),
false // _unary false // _unary
@ -1827,7 +1828,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
} }
else else
{ {
std::string description = fmt::format( string description = fmt::format(
"Built-in binary operator {} cannot be applied to types {} and {}.", "Built-in binary operator {} cannot be applied to types {} and {}.",
TokenTraits::friendlyName(_operation.getOperator()), TokenTraits::friendlyName(_operation.getOperator()),
leftType->humanReadableName(), leftType->humanReadableName(),
@ -1892,7 +1893,7 @@ void TypeChecker::endVisit(BinaryOperation const& _operation)
if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL) if (_operation.getOperator() == Token::Exp || _operation.getOperator() == Token::SHL)
{ {
std::string operation = _operation.getOperator() == Token::Exp ? "exponentiation" : "shift"; string operation = _operation.getOperator() == Token::Exp ? "exponentiation" : "shift";
if ( if (
leftType->category() == Type::Category::RationalNumber && leftType->category() == Type::Category::RationalNumber &&
rightType->category() != Type::Category::RationalNumber rightType->category() != Type::Category::RationalNumber
@ -1932,7 +1933,7 @@ Type const* TypeChecker::typeCheckTypeConversionAndRetrieveReturnType(
solAssert(*_functionCall.annotation().kind == FunctionCallKind::TypeConversion, ""); solAssert(*_functionCall.annotation().kind == FunctionCallKind::TypeConversion, "");
Type const* expressionType = type(_functionCall.expression()); Type const* expressionType = type(_functionCall.expression());
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
bool const isPositionalCall = _functionCall.names().empty(); bool const isPositionalCall = _functionCall.names().empty();
Type const* resultType = dynamic_cast<TypeType const&>(*expressionType).actualType(); Type const* resultType = dynamic_cast<TypeType const&>(*expressionType).actualType();
@ -2214,7 +2215,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
} }
// Check additional arguments for variadic functions // Check additional arguments for variadic functions
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
for (size_t i = 0; i < arguments.size(); ++i) for (size_t i = 0; i < arguments.size(); ++i)
{ {
auto const& argType = type(*arguments[i]); auto const& argType = type(*arguments[i]);
@ -2273,7 +2274,7 @@ void TypeChecker::typeCheckABIEncodeFunctions(
void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall) void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCall)
{ {
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
// Expecting first argument to be the function pointer and second to be a tuple. // Expecting first argument to be the function pointer and second to be a tuple.
if (arguments.size() != 2) if (arguments.size() != 2)
@ -2310,7 +2311,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
externalFunctionType->kind() != FunctionType::Kind::Declaration externalFunctionType->kind() != FunctionType::Kind::Declaration
) )
{ {
std::string msg = "Expected regular external function type, or external view on public function."; string msg = "Expected regular external function type, or external view on public function.";
switch (externalFunctionType->kind()) switch (externalFunctionType->kind())
{ {
@ -2359,7 +2360,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
} }
solAssert(!externalFunctionType->takesArbitraryParameters(), "Function must have fixed parameters."); solAssert(!externalFunctionType->takesArbitraryParameters(), "Function must have fixed parameters.");
// Tuples with only one component become that component // Tuples with only one component become that component
std::vector<ASTPointer<Expression const>> callArguments; vector<ASTPointer<Expression const>> callArguments;
auto const* tupleType = dynamic_cast<TupleType const*>(type(*arguments[1])); auto const* tupleType = dynamic_cast<TupleType const*>(type(*arguments[1]));
if (tupleType) if (tupleType)
@ -2386,9 +2387,9 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
7788_error, 7788_error,
_functionCall.location(), _functionCall.location(),
"Expected " + "Expected " +
std::to_string(externalFunctionType->parameterTypes().size()) + to_string(externalFunctionType->parameterTypes().size()) +
" instead of " + " instead of " +
std::to_string(callArguments.size()) + to_string(callArguments.size()) +
" components for the tuple parameter." " components for the tuple parameter."
); );
else else
@ -2396,13 +2397,13 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
7515_error, 7515_error,
_functionCall.location(), _functionCall.location(),
"Expected a tuple with " + "Expected a tuple with " +
std::to_string(externalFunctionType->parameterTypes().size()) + to_string(externalFunctionType->parameterTypes().size()) +
" components instead of a single non-tuple parameter." " components instead of a single non-tuple parameter."
); );
} }
// Use min() to check as much as we can before failing fatally // Use min() to check as much as we can before failing fatally
size_t const numParameters = std::min(callArguments.size(), externalFunctionType->parameterTypes().size()); size_t const numParameters = min(callArguments.size(), externalFunctionType->parameterTypes().size());
for (size_t i = 0; i < numParameters; i++) for (size_t i = 0; i < numParameters; i++)
{ {
@ -2413,7 +2414,7 @@ void TypeChecker::typeCheckABIEncodeCallFunction(FunctionCall const& _functionCa
5407_error, 5407_error,
callArguments[i]->location(), callArguments[i]->location(),
"Cannot implicitly convert component at position " + "Cannot implicitly convert component at position " +
std::to_string(i) + to_string(i) +
" from \"" + " from \"" +
argType.humanReadableName() + argType.humanReadableName() +
"\" to \"" + "\" to \"" +
@ -2436,7 +2437,7 @@ void TypeChecker::typeCheckStringConcatFunction(
typeCheckFunctionGeneralChecks(_functionCall, _functionType); typeCheckFunctionGeneralChecks(_functionCall, _functionType);
for (std::shared_ptr<Expression const> const& argument: _functionCall.arguments()) for (shared_ptr<Expression const> const& argument: _functionCall.arguments())
{ {
Type const* argumentType = type(*argument); Type const* argumentType = type(*argument);
bool notConvertibleToString = !argumentType->isImplicitlyConvertibleTo(*TypeProvider::stringMemory()); bool notConvertibleToString = !argumentType->isImplicitlyConvertibleTo(*TypeProvider::stringMemory());
@ -2463,7 +2464,7 @@ void TypeChecker::typeCheckBytesConcatFunction(
typeCheckFunctionGeneralChecks(_functionCall, _functionType); typeCheckFunctionGeneralChecks(_functionCall, _functionType);
for (std::shared_ptr<Expression const> const& argument: _functionCall.arguments()) for (shared_ptr<Expression const> const& argument: _functionCall.arguments())
{ {
Type const* argumentType = type(*argument); Type const* argumentType = type(*argument);
bool notConvertibleToBytes = bool notConvertibleToBytes =
@ -2503,8 +2504,8 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
); );
TypePointers const& parameterTypes = _functionType->parameterTypes(); TypePointers const& parameterTypes = _functionType->parameterTypes();
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
std::vector<ASTPointer<ASTString>> const& argumentNames = _functionCall.names(); vector<ASTPointer<ASTString>> const& argumentNames = _functionCall.names();
// Check number of passed in arguments // Check number of passed in arguments
if ( if (
@ -2515,22 +2516,22 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
bool const isStructConstructorCall = bool const isStructConstructorCall =
functionCallKind == FunctionCallKind::StructConstructorCall; functionCallKind == FunctionCallKind::StructConstructorCall;
auto [errorId, description] = [&]() -> std::tuple<ErrorId, std::string> { auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
std::string msg = isVariadic ? string msg = isVariadic ?
"Need at least " + "Need at least " +
toString(parameterTypes.size()) + toString(parameterTypes.size()) +
" arguments for " + " arguments for " +
std::string(isStructConstructorCall ? "struct constructor" : "function call") + string(isStructConstructorCall ? "struct constructor" : "function call") +
", but provided only " + ", but provided only " +
toString(arguments.size()) + toString(arguments.size()) +
"." "."
: :
"Wrong argument count for " + "Wrong argument count for " +
std::string(isStructConstructorCall ? "struct constructor" : "function call") + string(isStructConstructorCall ? "struct constructor" : "function call") +
": " + ": " +
toString(arguments.size()) + toString(arguments.size()) +
" arguments given but " + " arguments given but " +
std::string(isVariadic ? "need at least " : "expected ") + string(isVariadic ? "need at least " : "expected ") +
toString(parameterTypes.size()) + toString(parameterTypes.size()) +
"."; ".";
@ -2658,8 +2659,8 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
BoolResult result = type(*paramArgMap[i])->isImplicitlyConvertibleTo(*parameterTypes[i]); BoolResult result = type(*paramArgMap[i])->isImplicitlyConvertibleTo(*parameterTypes[i]);
if (!result) if (!result)
{ {
auto [errorId, description] = [&]() -> std::tuple<ErrorId, std::string> { auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
std::string msg = string msg =
"Invalid type for argument in function call. " "Invalid type for argument in function call. "
"Invalid implicit conversion from " + "Invalid implicit conversion from " +
type(*paramArgMap[i])->humanReadableName() + type(*paramArgMap[i])->humanReadableName() +
@ -2750,7 +2751,7 @@ void TypeChecker::typeCheckFunctionGeneralChecks(
bool TypeChecker::visit(FunctionCall const& _functionCall) bool TypeChecker::visit(FunctionCall const& _functionCall)
{ {
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.arguments();
bool argumentsArePure = true; bool argumentsArePure = true;
// We need to check arguments' type first as they will be needed for overload resolution. // We need to check arguments' type first as they will be needed for overload resolution.
@ -2990,7 +2991,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
"{...}-option." "{...}-option."
); );
auto setCheckOption = [&](bool& _option, std::string const& _name) auto setCheckOption = [&](bool& _option, string const& _name)
{ {
if (_option) if (_option)
m_errorReporter.typeError( m_errorReporter.typeError(
@ -3004,7 +3005,7 @@ bool TypeChecker::visit(FunctionCallOptions const& _functionCallOptions)
for (size_t i = 0; i < _functionCallOptions.names().size(); ++i) for (size_t i = 0; i < _functionCallOptions.names().size(); ++i)
{ {
std::string const& name = *(_functionCallOptions.names()[i]); string const& name = *(_functionCallOptions.names()[i]);
if (name == "salt") if (name == "salt")
{ {
if (kind == FunctionType::Kind::Creation) if (kind == FunctionType::Kind::Creation)
@ -3184,8 +3185,8 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
); );
} }
auto [errorId, description] = [&]() -> std::tuple<ErrorId, std::string> { auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
std::string errorMsg = "Member \"" + memberName + "\" not found or not visible " string errorMsg = "Member \"" + memberName + "\" not found or not visible "
"after argument-dependent lookup in " + exprType->humanReadableName() + "."; "after argument-dependent lookup in " + exprType->humanReadableName() + ".";
if (auto const* funType = dynamic_cast<FunctionType const*>(exprType)) if (auto const* funType = dynamic_cast<FunctionType const*>(exprType))
@ -3221,7 +3222,7 @@ bool TypeChecker::visit(MemberAccess const& _memberAccess)
if (addressMember.name == memberName) if (addressMember.name == memberName)
{ {
auto const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression()); auto const* var = dynamic_cast<Identifier const*>(&_memberAccess.expression());
std::string varName = var ? var->name() : "..."; string varName = var ? var->name() : "...";
errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member."; errorMsg += " Use \"address(" + varName + ")." + memberName + "\" to access this address member.";
return { 3125_error, errorMsg }; return { 3125_error, errorMsg };
} }
@ -3605,13 +3606,13 @@ bool TypeChecker::visit(IndexRangeAccess const& _access)
return false; return false;
} }
std::vector<Declaration const*> TypeChecker::cleanOverloadedDeclarations( vector<Declaration const*> TypeChecker::cleanOverloadedDeclarations(
Identifier const& _identifier, Identifier const& _identifier,
std::vector<Declaration const*> const& _candidates vector<Declaration const*> const& _candidates
) )
{ {
solAssert(_candidates.size() > 1, ""); solAssert(_candidates.size() > 1, "");
std::vector<Declaration const*> uniqueDeclarations; vector<Declaration const*> uniqueDeclarations;
for (Declaration const* declaration: _candidates) for (Declaration const* declaration: _candidates)
{ {
@ -3664,7 +3665,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
else if (!annotation.arguments) else if (!annotation.arguments)
{ {
// The identifier should be a public state variable shadowing other functions // The identifier should be a public state variable shadowing other functions
std::vector<Declaration const*> candidates; vector<Declaration const*> candidates;
for (Declaration const* declaration: annotation.overloadedDeclarations) for (Declaration const* declaration: annotation.overloadedDeclarations)
{ {
@ -3680,7 +3681,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
} }
else else
{ {
std::vector<Declaration const*> candidates; vector<Declaration const*> candidates;
for (Declaration const* declaration: annotation.overloadedDeclarations) for (Declaration const* declaration: annotation.overloadedDeclarations)
{ {
@ -3699,7 +3700,7 @@ bool TypeChecker::visit(Identifier const& _identifier)
if (!declaration->location().isValid()) if (!declaration->location().isValid())
{ {
// Try to re-construct function definition // Try to re-construct function definition
std::string description; string description;
for (auto const& param: declaration->functionType(true)->parameterTypes()) for (auto const& param: declaration->functionType(true)->parameterTypes())
description += (description.empty() ? "" : ", ") + param->humanReadableName(); description += (description.empty() ? "" : ", ") + param->humanReadableName();
description = "function " + _identifier.name() + "(" + description + ")"; description = "function " + _identifier.name() + "(" + description + ")";
@ -3815,12 +3816,12 @@ void TypeChecker::endVisit(Literal const& _literal)
// Assign type here if it even looks like an address. This prevents double errors for invalid addresses // Assign type here if it even looks like an address. This prevents double errors for invalid addresses
_literal.annotation().type = TypeProvider::address(); _literal.annotation().type = TypeProvider::address();
std::string msg; string msg;
if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits if (_literal.valueWithoutUnderscores().length() != 42) // "0x" + 40 hex digits
// looksLikeAddress enforces that it is a hex literal starting with "0x" // looksLikeAddress enforces that it is a hex literal starting with "0x"
msg = msg =
"This looks like an address but is not exactly 40 hex digits. It is " + "This looks like an address but is not exactly 40 hex digits. It is " +
std::to_string(_literal.valueWithoutUnderscores().length() - 2) + to_string(_literal.valueWithoutUnderscores().length() - 2) +
" hex digits."; " hex digits.";
else if (!_literal.passesAddressChecksum()) else if (!_literal.passesAddressChecksum())
{ {
@ -4033,7 +4034,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
bool isBinaryOnlyOperator = (TokenTraits::isBinaryOp(operator_.value()) && !TokenTraits::isUnaryOp(operator_.value())); bool isBinaryOnlyOperator = (TokenTraits::isBinaryOp(operator_.value()) && !TokenTraits::isUnaryOp(operator_.value()));
bool firstParameterMatchesUsingFor = parameterCount == 0 || *usingForType == *parameterTypes.front(); bool firstParameterMatchesUsingFor = parameterCount == 0 || *usingForType == *parameterTypes.front();
std::optional<std::string> wrongParametersMessage; optional<string> wrongParametersMessage;
if (isBinaryOnlyOperator && (parameterCount != 2 || !identicalFirstTwoParameters)) if (isBinaryOnlyOperator && (parameterCount != 2 || !identicalFirstTwoParameters))
wrongParametersMessage = fmt::format("two parameters of type {} and the same data location", usingForType->canonicalName()); wrongParametersMessage = fmt::format("two parameters of type {} and the same data location", usingForType->canonicalName());
else if (isUnaryOnlyOperator && (parameterCount != 1 || !firstParameterMatchesUsingFor)) else if (isUnaryOnlyOperator && (parameterCount != 1 || !firstParameterMatchesUsingFor))
@ -4064,7 +4065,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
TypePointers const& returnParameterTypes = functionType->returnParameterTypes(); TypePointers const& returnParameterTypes = functionType->returnParameterTypes();
size_t const returnParameterCount = returnParameterTypes.size(); size_t const returnParameterCount = returnParameterTypes.size();
std::optional<std::string> wrongReturnParametersMessage; optional<string> wrongReturnParametersMessage;
if (!TokenTraits::isCompareOp(operator_.value()) && operator_.value() != Token::Not) if (!TokenTraits::isCompareOp(operator_.value()) && operator_.value() != Token::Not)
{ {
if (returnParameterCount != 1 || *usingForType != *returnParameterTypes.front()) if (returnParameterCount != 1 || *usingForType != *returnParameterTypes.front())
@ -4099,7 +4100,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
{ {
// TODO: This is pretty inefficient. For every operator binding we find, we're // TODO: This is pretty inefficient. For every operator binding we find, we're
// traversing all bindings in all `using for` directives in the current scope. // traversing all bindings in all `using for` directives in the current scope.
std::set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = usingForType->operatorDefinitions( set<FunctionDefinition const*, ASTNode::CompareByID> matchingDefinitions = usingForType->operatorDefinitions(
operator_.value(), operator_.value(),
*currentDefinitionScope(), *currentDefinitionScope(),
parameterCount == 1 // _unary parameterCount == 1 // _unary
@ -4132,7 +4133,7 @@ void TypeChecker::endVisit(UsingForDirective const& _usingFor)
void TypeChecker::checkErrorAndEventParameters(CallableDeclaration const& _callable) void TypeChecker::checkErrorAndEventParameters(CallableDeclaration const& _callable)
{ {
std::string kind = dynamic_cast<EventDefinition const*>(&_callable) ? "event" : "error"; string kind = dynamic_cast<EventDefinition const*>(&_callable) ? "event" : "error";
for (ASTPointer<VariableDeclaration> const& var: _callable.parameters()) for (ASTPointer<VariableDeclaration> const& var: _callable.parameters())
{ {
if (type(*var)->containsNestedMapping()) if (type(*var)->containsNestedMapping())
@ -4222,7 +4223,7 @@ void TypeChecker::requireLValue(Expression const& _expression, bool _ordinaryAss
if (*_expression.annotation().isLValue) if (*_expression.annotation().isLValue)
return; return;
auto [errorId, description] = [&]() -> std::tuple<ErrorId, std::string> { auto [errorId, description] = [&]() -> tuple<ErrorId, string> {
if (*_expression.annotation().isConstant) if (*_expression.annotation().isConstant)
return { 6520_error, "Cannot assign to a constant variable." }; return { 6520_error, "Cannot assign to a constant variable." };

View File

@ -27,6 +27,7 @@
#include <utility> #include <utility>
#include <variant> #include <variant>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -311,13 +312,13 @@ ViewPureChecker::MutabilityAndLocation const& ViewPureChecker::modifierMutabilit
{ {
MutabilityAndLocation bestMutabilityAndLocation{}; MutabilityAndLocation bestMutabilityAndLocation{};
FunctionDefinition const* currentFunction = nullptr; FunctionDefinition const* currentFunction = nullptr;
std::swap(bestMutabilityAndLocation, m_bestMutabilityAndLocation); swap(bestMutabilityAndLocation, m_bestMutabilityAndLocation);
std::swap(currentFunction, m_currentFunction); swap(currentFunction, m_currentFunction);
_modifier.accept(*this); _modifier.accept(*this);
std::swap(bestMutabilityAndLocation, m_bestMutabilityAndLocation); swap(bestMutabilityAndLocation, m_bestMutabilityAndLocation);
std::swap(currentFunction, m_currentFunction); swap(currentFunction, m_currentFunction);
} }
return m_inferredMutability.at(&_modifier); return m_inferredMutability.at(&_modifier);
} }
@ -383,8 +384,8 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
break; break;
case Type::Category::Magic: case Type::Category::Magic:
{ {
using MagicMember = std::pair<MagicType::Kind, std::string>; using MagicMember = pair<MagicType::Kind, string>;
std::set<MagicMember> static const pureMembers{ set<MagicMember> static const pureMembers{
{MagicType::Kind::ABI, "decode"}, {MagicType::Kind::ABI, "decode"},
{MagicType::Kind::ABI, "encode"}, {MagicType::Kind::ABI, "encode"},
{MagicType::Kind::ABI, "encodePacked"}, {MagicType::Kind::ABI, "encodePacked"},
@ -400,7 +401,7 @@ void ViewPureChecker::endVisit(MemberAccess const& _memberAccess)
{MagicType::Kind::MetaType, "min"}, {MagicType::Kind::MetaType, "min"},
{MagicType::Kind::MetaType, "max"}, {MagicType::Kind::MetaType, "max"},
}; };
std::set<MagicMember> static const payableMembers{ set<MagicMember> static const payableMembers{
{MagicType::Kind::Message, "value"} {MagicType::Kind::Message, "value"}
}; };

View File

@ -39,12 +39,13 @@
#include <functional> #include <functional>
#include <utility> #include <utility>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
namespace namespace
{ {
TryCatchClause const* findClause(std::vector<ASTPointer<TryCatchClause>> const& _clauses, std::optional<std::string> _errorName = {}) TryCatchClause const* findClause(vector<ASTPointer<TryCatchClause>> const& _clauses, optional<string> _errorName = {})
{ {
for (auto const& clause: ranges::views::tail(_clauses)) for (auto const& clause: ranges::views::tail(_clauses))
if (_errorName.has_value() ? clause->errorName() == _errorName : clause->errorName().empty()) if (_errorName.has_value() ? clause->errorName() == _errorName : clause->errorName().empty())
@ -118,7 +119,7 @@ FunctionDefinition const* ASTNode::resolveFunctionCall(FunctionCall const& _func
ASTAnnotation& ASTNode::annotation() const ASTAnnotation& ASTNode::annotation() const
{ {
if (!m_annotation) if (!m_annotation)
m_annotation = std::make_unique<ASTAnnotation>(); m_annotation = make_unique<ASTAnnotation>();
return *m_annotation; return *m_annotation;
} }
@ -127,9 +128,9 @@ SourceUnitAnnotation& SourceUnit::annotation() const
return initAnnotation<SourceUnitAnnotation>(); return initAnnotation<SourceUnitAnnotation>();
} }
std::set<SourceUnit const*> SourceUnit::referencedSourceUnits(bool _recurse, std::set<SourceUnit const*> _skipList) const set<SourceUnit const*> SourceUnit::referencedSourceUnits(bool _recurse, set<SourceUnit const*> _skipList) const
{ {
std::set<SourceUnit const*> sourceUnits; set<SourceUnit const*> sourceUnits;
for (ImportDirective const* importDirective: filteredNodes<ImportDirective>(nodes())) for (ImportDirective const* importDirective: filteredNodes<ImportDirective>(nodes()))
{ {
auto const& sourceUnit = importDirective->annotation().sourceUnit; auto const& sourceUnit = importDirective->annotation().sourceUnit;
@ -160,11 +161,11 @@ bool ContractDefinition::derivesFrom(ContractDefinition const& _base) const
return util::contains(annotation().linearizedBaseContracts, &_base); return util::contains(annotation().linearizedBaseContracts, &_base);
} }
std::map<util::FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions(bool _includeInheritedFunctions) const map<util::FixedHash<4>, FunctionTypePointer> ContractDefinition::interfaceFunctions(bool _includeInheritedFunctions) const
{ {
auto exportedFunctionList = interfaceFunctionList(_includeInheritedFunctions); auto exportedFunctionList = interfaceFunctionList(_includeInheritedFunctions);
std::map<util::FixedHash<4>, FunctionTypePointer> exportedFunctions; map<util::FixedHash<4>, FunctionTypePointer> exportedFunctions;
for (auto const& it: exportedFunctionList) for (auto const& it: exportedFunctionList)
exportedFunctions.insert(it); exportedFunctions.insert(it);
@ -207,11 +208,11 @@ FunctionDefinition const* ContractDefinition::receiveFunction() const
return nullptr; return nullptr;
} }
std::vector<EventDefinition const*> const& ContractDefinition::definedInterfaceEvents() const vector<EventDefinition const*> const& ContractDefinition::definedInterfaceEvents() const
{ {
return m_interfaceEvents.init([&]{ return m_interfaceEvents.init([&]{
std::set<std::string> eventsSeen; set<string> eventsSeen;
std::vector<EventDefinition const*> interfaceEvents; vector<EventDefinition const*> interfaceEvents;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts) for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
for (EventDefinition const* e: contract->events()) for (EventDefinition const* e: contract->events())
@ -221,7 +222,7 @@ std::vector<EventDefinition const*> const& ContractDefinition::definedInterfaceE
/// and not to function encoding (jump vs. call) /// and not to function encoding (jump vs. call)
FunctionType const* functionType = e->functionType(true); FunctionType const* functionType = e->functionType(true);
solAssert(functionType, ""); solAssert(functionType, "");
std::string eventSignature = functionType->externalSignature(); string eventSignature = functionType->externalSignature();
if (eventsSeen.count(eventSignature) == 0) if (eventsSeen.count(eventSignature) == 0)
{ {
eventsSeen.insert(eventSignature); eventsSeen.insert(eventSignature);
@ -232,7 +233,7 @@ std::vector<EventDefinition const*> const& ContractDefinition::definedInterfaceE
}); });
} }
std::vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvents() const vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvents() const
{ {
solAssert(annotation().creationCallGraph.set(), ""); solAssert(annotation().creationCallGraph.set(), "");
@ -242,9 +243,9 @@ std::vector<EventDefinition const*> const ContractDefinition::usedInterfaceEvent
); );
} }
std::vector<EventDefinition const*> ContractDefinition::interfaceEvents(bool _requireCallGraph) const vector<EventDefinition const*> ContractDefinition::interfaceEvents(bool _requireCallGraph) const
{ {
std::set<EventDefinition const*, CompareByID> result; set<EventDefinition const*, CompareByID> result;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts) for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
result += contract->events(); result += contract->events();
solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set()); solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set());
@ -254,12 +255,12 @@ std::vector<EventDefinition const*> ContractDefinition::interfaceEvents(bool _re
result += usedInterfaceEvents(); result += usedInterfaceEvents();
// We could filter out all events that do not have an external interface // We could filter out all events that do not have an external interface
// if _requireCallGraph is false. // if _requireCallGraph is false.
return util::convertContainer<std::vector<EventDefinition const*>>(std::move(result)); return util::convertContainer<vector<EventDefinition const*>>(std::move(result));
} }
std::vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _requireCallGraph) const
{ {
std::set<ErrorDefinition const*, CompareByID> result; set<ErrorDefinition const*, CompareByID> result;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts) for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
result += filteredNodes<ErrorDefinition>(contract->m_subNodes); result += filteredNodes<ErrorDefinition>(contract->m_subNodes);
solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set(), ""); solAssert(annotation().creationCallGraph.set() == annotation().deployedCallGraph.set(), "");
@ -269,20 +270,20 @@ std::vector<ErrorDefinition const*> ContractDefinition::interfaceErrors(bool _re
result += result +=
(*annotation().creationCallGraph)->usedErrors + (*annotation().creationCallGraph)->usedErrors +
(*annotation().deployedCallGraph)->usedErrors; (*annotation().deployedCallGraph)->usedErrors;
return util::convertContainer<std::vector<ErrorDefinition const*>>(std::move(result)); return util::convertContainer<vector<ErrorDefinition const*>>(std::move(result));
} }
std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const vector<pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::interfaceFunctionList(bool _includeInheritedFunctions) const
{ {
return m_interfaceFunctionList[_includeInheritedFunctions].init([&]{ return m_interfaceFunctionList[_includeInheritedFunctions].init([&]{
std::set<std::string> signaturesSeen; set<string> signaturesSeen;
std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>> interfaceFunctionList; vector<pair<util::FixedHash<4>, FunctionTypePointer>> interfaceFunctionList;
for (ContractDefinition const* contract: annotation().linearizedBaseContracts) for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
{ {
if (_includeInheritedFunctions == false && contract != this) if (_includeInheritedFunctions == false && contract != this)
continue; continue;
std::vector<FunctionTypePointer> functions; vector<FunctionTypePointer> functions;
for (FunctionDefinition const* f: contract->definedFunctions()) for (FunctionDefinition const* f: contract->definedFunctions())
if (f->isPartOfExternalInterface()) if (f->isPartOfExternalInterface())
functions.push_back(TypeProvider::function(*f, FunctionType::Kind::External)); functions.push_back(TypeProvider::function(*f, FunctionType::Kind::External));
@ -294,7 +295,7 @@ std::vector<std::pair<util::FixedHash<4>, FunctionTypePointer>> const& ContractD
if (!fun->interfaceFunctionType()) if (!fun->interfaceFunctionType())
// Fails hopefully because we already registered the error // Fails hopefully because we already registered the error
continue; continue;
std::string functionSignature = fun->externalSignature(); string functionSignature = fun->externalSignature();
if (signaturesSeen.count(functionSignature) == 0) if (signaturesSeen.count(functionSignature) == 0)
{ {
signaturesSeen.insert(functionSignature); signaturesSeen.insert(functionSignature);
@ -356,7 +357,7 @@ FunctionDefinition const* ContractDefinition::nextConstructor(ContractDefinition
return nullptr; return nullptr;
} }
std::multimap<std::string, FunctionDefinition const*> const& ContractDefinition::definedFunctionsByName() const multimap<std::string, FunctionDefinition const*> const& ContractDefinition::definedFunctionsByName() const
{ {
return m_definedFunctionsByName.init([&]{ return m_definedFunctionsByName.init([&]{
std::multimap<std::string, FunctionDefinition const*> result; std::multimap<std::string, FunctionDefinition const*> result;
@ -385,7 +386,7 @@ TypeDeclarationAnnotation& UserDefinedValueTypeDefinition::annotation() const
std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> UsingForDirective::functionsAndOperators() const std::vector<std::pair<ASTPointer<IdentifierPath>, std::optional<Token>>> UsingForDirective::functionsAndOperators() const
{ {
return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<std::vector>; return ranges::zip_view(m_functionsOrLibrary, m_operators) | ranges::to<vector>;
} }
Type const* StructDefinition::type() const Type const* StructDefinition::type() const
@ -483,12 +484,12 @@ Type const* FunctionDefinition::typeViaContractName() const
return TypeProvider::function(*this, FunctionType::Kind::Declaration); return TypeProvider::function(*this, FunctionType::Kind::Declaration);
} }
std::string FunctionDefinition::externalSignature() const string FunctionDefinition::externalSignature() const
{ {
return TypeProvider::function(*this)->externalSignature(); return TypeProvider::function(*this)->externalSignature();
} }
std::string FunctionDefinition::externalIdentifierHex() const string FunctionDefinition::externalIdentifierHex() const
{ {
return TypeProvider::function(*this)->externalIdentifierHex(); return TypeProvider::function(*this)->externalIdentifierHex();
} }
@ -638,7 +639,7 @@ CallableDeclaration const* Scopable::functionOrModifierDefinition() const
return nullptr; return nullptr;
} }
std::string Scopable::sourceUnitName() const string Scopable::sourceUnitName() const
{ {
return *sourceUnit().annotation().path; return *sourceUnit().annotation().path;
} }
@ -700,7 +701,7 @@ bool VariableDeclaration::isCallableOrCatchParameter() const
if (isReturnParameter() || isTryCatchParameter()) if (isReturnParameter() || isTryCatchParameter())
return true; return true;
std::vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr; vector<ASTPointer<VariableDeclaration>> const* parameters = nullptr;
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope())) if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
parameters = &funTypeName->parameterTypes(); parameters = &funTypeName->parameterTypes();
@ -721,7 +722,7 @@ bool VariableDeclaration::isLocalOrReturn() const
bool VariableDeclaration::isReturnParameter() const bool VariableDeclaration::isReturnParameter() const
{ {
std::vector<ASTPointer<VariableDeclaration>> const* returnParameters = nullptr; vector<ASTPointer<VariableDeclaration>> const* returnParameters = nullptr;
if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope())) if (auto const* funTypeName = dynamic_cast<FunctionTypeName const*>(scope()))
returnParameters = &funTypeName->returnParameterTypes(); returnParameters = &funTypeName->returnParameterTypes();
@ -812,15 +813,15 @@ bool VariableDeclaration::isFileLevelVariable() const
return dynamic_cast<SourceUnit const*>(scope()); return dynamic_cast<SourceUnit const*>(scope());
} }
std::set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocations() const
{ {
using Location = VariableDeclaration::Location; using Location = VariableDeclaration::Location;
if (!hasReferenceOrMappingType() || isStateVariable() || isEventOrErrorParameter()) if (!hasReferenceOrMappingType() || isStateVariable() || isEventOrErrorParameter())
return std::set<Location>{ Location::Unspecified }; return set<Location>{ Location::Unspecified };
else if (isCallableOrCatchParameter()) else if (isCallableOrCatchParameter())
{ {
std::set<Location> locations{ Location::Memory }; set<Location> locations{ Location::Memory };
if ( if (
isConstructorParameter() || isConstructorParameter() ||
isInternalCallableParameter() || isInternalCallableParameter() ||
@ -834,13 +835,13 @@ std::set<VariableDeclaration::Location> VariableDeclaration::allowedDataLocation
} }
else if (isLocalVariable()) else if (isLocalVariable())
// Further restrictions will be imposed later on. // Further restrictions will be imposed later on.
return std::set<Location>{ Location::Memory, Location::Storage, Location::CallData }; return set<Location>{ Location::Memory, Location::Storage, Location::CallData };
else else
// Struct members etc. // Struct members etc.
return std::set<Location>{ Location::Unspecified }; return set<Location>{ Location::Unspecified };
} }
std::string VariableDeclaration::externalIdentifierHex() const string VariableDeclaration::externalIdentifierHex() const
{ {
solAssert(isStateVariable() && isPublic(), "Can only be called for public state variables"); solAssert(isStateVariable() && isPublic(), "Can only be called for public state variables");
return TypeProvider::function(*this)->externalIdentifierHex(); return TypeProvider::function(*this)->externalIdentifierHex();
@ -957,7 +958,7 @@ FunctionCallAnnotation& FunctionCall::annotation() const
return initAnnotation<FunctionCallAnnotation>(); return initAnnotation<FunctionCallAnnotation>();
} }
std::vector<ASTPointer<Expression const>> FunctionCall::sortedArguments() const vector<ASTPointer<Expression const>> FunctionCall::sortedArguments() const
{ {
// normal arguments // normal arguments
if (m_names.empty()) if (m_names.empty())
@ -974,7 +975,7 @@ std::vector<ASTPointer<Expression const>> FunctionCall::sortedArguments() const
else else
functionType = dynamic_cast<FunctionType const*>(m_expression->annotation().type); functionType = dynamic_cast<FunctionType const*>(m_expression->annotation().type);
std::vector<ASTPointer<Expression const>> sorted; vector<ASTPointer<Expression const>> sorted;
for (auto const& parameterName: functionType->parameterNames()) for (auto const& parameterName: functionType->parameterNames())
{ {
bool found = false; bool found = false;
@ -1029,13 +1030,13 @@ bool Literal::passesAddressChecksum() const
return util::passesAddressChecksum(valueWithoutUnderscores(), true); return util::passesAddressChecksum(valueWithoutUnderscores(), true);
} }
std::string Literal::getChecksummedAddress() const string Literal::getChecksummedAddress() const
{ {
solAssert(isHexNumber(), "Expected hex number"); solAssert(isHexNumber(), "Expected hex number");
/// Pad literal to be a proper hex address. /// Pad literal to be a proper hex address.
std::string address = valueWithoutUnderscores().substr(2); string address = valueWithoutUnderscores().substr(2);
if (address.length() > 40) if (address.length() > 40)
return std::string(); return string();
address.insert(address.begin(), 40 - address.size(), '0'); address.insert(address.begin(), 40 - address.size(), '0');
return util::getChecksummedAddress(address); return util::getChecksummedAddress(address);
} }

View File

@ -87,20 +87,16 @@ public:
static void listAccept(std::vector<T> const& _list, ASTVisitor& _visitor) static void listAccept(std::vector<T> const& _list, ASTVisitor& _visitor)
{ {
for (T const& element: _list) for (T const& element: _list)
{ if (element)
solAssert(element);
element->accept(_visitor); element->accept(_visitor);
} }
}
template <class T> template <class T>
static void listAccept(std::vector<T> const& _list, ASTConstVisitor& _visitor) static void listAccept(std::vector<T> const& _list, ASTConstVisitor& _visitor)
{ {
for (T const& element: _list) for (T const& element: _list)
{ if (element)
solAssert(element);
element->accept(_visitor); element->accept(_visitor);
} }
}
/// @returns a copy of the vector containing only the nodes which derive from T. /// @returns a copy of the vector containing only the nodes which derive from T.
template <class T> template <class T>

View File

@ -23,6 +23,7 @@
#include <libsolidity/ast/ASTAnnotations.h> #include <libsolidity/ast/ASTAnnotations.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;

View File

@ -44,6 +44,7 @@
#include <type_traits> #include <type_traits>
#include <range/v3/view/map.hpp> #include <range/v3/view/map.hpp>
using namespace std;
using namespace std::string_literals; using namespace std::string_literals;
using namespace solidity::langutil; using namespace solidity::langutil;
@ -51,14 +52,14 @@ namespace
{ {
template<typename V, template<typename> typename C> template<typename V, template<typename> typename C>
void addIfSet(std::vector<std::pair<std::string, Json::Value>>& _attributes, std::string const& _name, C<V> const& _value) void addIfSet(std::vector<pair<string, Json::Value>>& _attributes, string const& _name, C<V> const& _value)
{ {
if constexpr (std::is_same_v<C<V>, solidity::util::SetOnce<V>>) if constexpr (std::is_same_v<C<V>, solidity::util::SetOnce<V>>)
{ {
if (!_value.set()) if (!_value.set())
return; return;
} }
else if constexpr (std::is_same_v<C<V>, std::optional<V>>) else if constexpr (std::is_same_v<C<V>, optional<V>>)
{ {
if (!_value.has_value()) if (!_value.has_value())
return; return;
@ -72,7 +73,7 @@ void addIfSet(std::vector<std::pair<std::string, Json::Value>>& _attributes, std
namespace solidity::frontend namespace solidity::frontend
{ {
ASTJsonExporter::ASTJsonExporter(CompilerStack::State _stackState, std::map<std::string, unsigned> _sourceIndices): ASTJsonExporter::ASTJsonExporter(CompilerStack::State _stackState, map<string, unsigned> _sourceIndices):
m_stackState(_stackState), m_stackState(_stackState),
m_sourceIndices(std::move(_sourceIndices)) m_sourceIndices(std::move(_sourceIndices))
{ {
@ -81,21 +82,21 @@ ASTJsonExporter::ASTJsonExporter(CompilerStack::State _stackState, std::map<std:
void ASTJsonExporter::setJsonNode( void ASTJsonExporter::setJsonNode(
ASTNode const& _node, ASTNode const& _node,
std::string const& _nodeName, string const& _nodeName,
std::initializer_list<std::pair<std::string, Json::Value>>&& _attributes initializer_list<pair<string, Json::Value>>&& _attributes
) )
{ {
ASTJsonExporter::setJsonNode( ASTJsonExporter::setJsonNode(
_node, _node,
_nodeName, _nodeName,
std::vector<std::pair<std::string, Json::Value>>(std::move(_attributes)) std::vector<pair<string, Json::Value>>(std::move(_attributes))
); );
} }
void ASTJsonExporter::setJsonNode( void ASTJsonExporter::setJsonNode(
ASTNode const& _node, ASTNode const& _node,
std::string const& _nodeType, string const& _nodeType,
std::vector<std::pair<std::string, Json::Value>>&& _attributes std::vector<pair<string, Json::Value>>&& _attributes
) )
{ {
m_currentValue = Json::objectValue; m_currentValue = Json::objectValue;
@ -109,24 +110,24 @@ void ASTJsonExporter::setJsonNode(
m_currentValue[e.first] = std::move(e.second); m_currentValue[e.first] = std::move(e.second);
} }
std::optional<size_t> ASTJsonExporter::sourceIndexFromLocation(SourceLocation const& _location) const optional<size_t> ASTJsonExporter::sourceIndexFromLocation(SourceLocation const& _location) const
{ {
if (_location.sourceName && m_sourceIndices.count(*_location.sourceName)) if (_location.sourceName && m_sourceIndices.count(*_location.sourceName))
return m_sourceIndices.at(*_location.sourceName); return m_sourceIndices.at(*_location.sourceName);
else else
return std::nullopt; return nullopt;
} }
std::string ASTJsonExporter::sourceLocationToString(SourceLocation const& _location) const string ASTJsonExporter::sourceLocationToString(SourceLocation const& _location) const
{ {
std::optional<size_t> sourceIndexOpt = sourceIndexFromLocation(_location); optional<size_t> sourceIndexOpt = sourceIndexFromLocation(_location);
int length = -1; int length = -1;
if (_location.start >= 0 && _location.end >= 0) if (_location.start >= 0 && _location.end >= 0)
length = _location.end - _location.start; length = _location.end - _location.start;
return std::to_string(_location.start) + ":" + std::to_string(length) + ":" + (sourceIndexOpt.has_value() ? std::to_string(sourceIndexOpt.value()) : "-1"); return to_string(_location.start) + ":" + to_string(length) + ":" + (sourceIndexOpt.has_value() ? to_string(sourceIndexOpt.value()) : "-1");
} }
Json::Value ASTJsonExporter::sourceLocationsToJson(std::vector<SourceLocation> const& _sourceLocations) const Json::Value ASTJsonExporter::sourceLocationsToJson(vector<SourceLocation> const& _sourceLocations) const
{ {
Json::Value locations = Json::arrayValue; Json::Value locations = Json::arrayValue;
@ -136,7 +137,7 @@ Json::Value ASTJsonExporter::sourceLocationsToJson(std::vector<SourceLocation> c
return locations; return locations;
} }
std::string ASTJsonExporter::namePathToString(std::vector<ASTString> const& _namePath) string ASTJsonExporter::namePathToString(std::vector<ASTString> const& _namePath)
{ {
return boost::algorithm::join(_namePath, "."s); return boost::algorithm::join(_namePath, "."s);
} }
@ -163,13 +164,13 @@ Json::Value ASTJsonExporter::typePointerToJson(std::optional<FuncCallArguments>
} }
void ASTJsonExporter::appendExpressionAttributes( void ASTJsonExporter::appendExpressionAttributes(
std::vector<std::pair<std::string, Json::Value>>& _attributes, std::vector<pair<string, Json::Value>>& _attributes,
ExpressionAnnotation const& _annotation ExpressionAnnotation const& _annotation
) )
{ {
std::vector<std::pair<std::string, Json::Value>> exprAttributes = { std::vector<pair<string, Json::Value>> exprAttributes = {
std::make_pair("typeDescriptions", typePointerToJson(_annotation.type)), make_pair("typeDescriptions", typePointerToJson(_annotation.type)),
std::make_pair("argumentTypes", typePointerToJson(_annotation.arguments)) make_pair("argumentTypes", typePointerToJson(_annotation.arguments))
}; };
addIfSet(exprAttributes, "isLValue", _annotation.isLValue); addIfSet(exprAttributes, "isLValue", _annotation.isLValue);
@ -182,7 +183,7 @@ void ASTJsonExporter::appendExpressionAttributes(
_attributes += exprAttributes; _attributes += exprAttributes;
} }
Json::Value ASTJsonExporter::inlineAssemblyIdentifierToJson(std::pair<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const Json::Value ASTJsonExporter::inlineAssemblyIdentifierToJson(pair<yul::Identifier const*, InlineAssemblyAnnotation::ExternalIdentifierInfo> _info) const
{ {
Json::Value tuple(Json::objectValue); Json::Value tuple(Json::objectValue);
tuple["src"] = sourceLocationToString(nativeLocationOf(*_info.first)); tuple["src"] = sourceLocationToString(nativeLocationOf(*_info.first));
@ -198,7 +199,7 @@ Json::Value ASTJsonExporter::inlineAssemblyIdentifierToJson(std::pair<yul::Ident
return tuple; return tuple;
} }
void ASTJsonExporter::print(std::ostream& _stream, ASTNode const& _node, util::JsonFormat const& _format) void ASTJsonExporter::print(ostream& _stream, ASTNode const& _node, util::JsonFormat const& _format)
{ {
_stream << util::jsonPrint(toJson(_node), _format); _stream << util::jsonPrint(toJson(_node), _format);
} }
@ -211,9 +212,9 @@ Json::Value ASTJsonExporter::toJson(ASTNode const& _node)
bool ASTJsonExporter::visit(SourceUnit const& _node) bool ASTJsonExporter::visit(SourceUnit const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue), make_pair("license", _node.licenseString() ? Json::Value(*_node.licenseString()) : Json::nullValue),
std::make_pair("nodes", toJson(_node.nodes())), make_pair("nodes", toJson(_node.nodes())),
}; };
if (_node.experimentalSolidity()) if (_node.experimentalSolidity())
@ -245,17 +246,17 @@ bool ASTJsonExporter::visit(PragmaDirective const& _node)
for (auto const& literal: _node.literals()) for (auto const& literal: _node.literals())
literals.append(literal); literals.append(literal);
setJsonNode(_node, "PragmaDirective", { setJsonNode(_node, "PragmaDirective", {
std::make_pair("literals", std::move(literals)) make_pair("literals", std::move(literals))
}); });
return false; return false;
} }
bool ASTJsonExporter::visit(ImportDirective const& _node) bool ASTJsonExporter::visit(ImportDirective const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("file", _node.path()), make_pair("file", _node.path()),
std::make_pair("sourceUnit", idOrNull(_node.annotation().sourceUnit)), make_pair("sourceUnit", idOrNull(_node.annotation().sourceUnit)),
std::make_pair("scope", idOrNull(_node.scope())) make_pair("scope", idOrNull(_node.scope()))
}; };
addIfSet(attributes, "absolutePath", _node.annotation().absolutePath); addIfSet(attributes, "absolutePath", _node.annotation().absolutePath);
@ -280,19 +281,19 @@ bool ASTJsonExporter::visit(ImportDirective const& _node)
bool ASTJsonExporter::visit(ContractDefinition const& _node) bool ASTJsonExporter::visit(ContractDefinition const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
std::make_pair("contractKind", contractKind(_node.contractKind())), make_pair("contractKind", contractKind(_node.contractKind())),
std::make_pair("abstract", _node.abstract()), make_pair("abstract", _node.abstract()),
std::make_pair("baseContracts", toJson(_node.baseContracts())), make_pair("baseContracts", toJson(_node.baseContracts())),
std::make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies | ranges::views::keys)), make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies | ranges::views::keys)),
// Do not require call graph because the AST is also created for incorrect sources. // Do not require call graph because the AST is also created for incorrect sources.
std::make_pair("usedEvents", getContainerIds(_node.interfaceEvents(false))), make_pair("usedEvents", getContainerIds(_node.interfaceEvents(false))),
std::make_pair("usedErrors", getContainerIds(_node.interfaceErrors(false))), make_pair("usedErrors", getContainerIds(_node.interfaceErrors(false))),
std::make_pair("nodes", toJson(_node.subNodes())), make_pair("nodes", toJson(_node.subNodes())),
std::make_pair("scope", idOrNull(_node.scope())) make_pair("scope", idOrNull(_node.scope()))
}; };
addIfSet(attributes, "canonicalName", _node.annotation().canonicalName); addIfSet(attributes, "canonicalName", _node.annotation().canonicalName);
@ -305,7 +306,7 @@ bool ASTJsonExporter::visit(ContractDefinition const& _node)
{ {
Json::Value internalFunctionIDs(Json::objectValue); Json::Value internalFunctionIDs(Json::objectValue);
for (auto const& [functionDefinition, internalFunctionID]: _node.annotation().internalFunctionIDs) for (auto const& [functionDefinition, internalFunctionID]: _node.annotation().internalFunctionIDs)
internalFunctionIDs[std::to_string(functionDefinition->id())] = internalFunctionID; internalFunctionIDs[to_string(functionDefinition->id())] = internalFunctionID;
attributes.emplace_back("internalFunctionIDs", std::move(internalFunctionIDs)); attributes.emplace_back("internalFunctionIDs", std::move(internalFunctionIDs));
} }
@ -321,9 +322,9 @@ bool ASTJsonExporter::visit(IdentifierPath const& _node)
nameLocations.append(sourceLocationToString(location)); nameLocations.append(sourceLocationToString(location));
setJsonNode(_node, "IdentifierPath", { setJsonNode(_node, "IdentifierPath", {
std::make_pair("name", namePathToString(_node.path())), make_pair("name", namePathToString(_node.path())),
std::make_pair("nameLocations", nameLocations), make_pair("nameLocations", nameLocations),
std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)) make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration))
}); });
return false; return false;
} }
@ -331,16 +332,16 @@ bool ASTJsonExporter::visit(IdentifierPath const& _node)
bool ASTJsonExporter::visit(InheritanceSpecifier const& _node) bool ASTJsonExporter::visit(InheritanceSpecifier const& _node)
{ {
setJsonNode(_node, "InheritanceSpecifier", { setJsonNode(_node, "InheritanceSpecifier", {
std::make_pair("baseName", toJson(_node.name())), make_pair("baseName", toJson(_node.name())),
std::make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json::nullValue) make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json::nullValue)
}); });
return false; return false;
} }
bool ASTJsonExporter::visit(UsingForDirective const& _node) bool ASTJsonExporter::visit(UsingForDirective const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { vector<pair<string, Json::Value>> attributes = {
std::make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue) make_pair("typeName", _node.typeName() ? toJson(*_node.typeName()) : Json::nullValue)
}; };
if (_node.usesBraces()) if (_node.usesBraces())
@ -354,7 +355,7 @@ bool ASTJsonExporter::visit(UsingForDirective const& _node)
else else
{ {
functionNode["definition"] = toJson(*function); functionNode["definition"] = toJson(*function);
functionNode["operator"] = std::string(TokenTraits::toString(*op)); functionNode["operator"] = string(TokenTraits::toString(*op));
} }
functionList.append(std::move(functionNode)); functionList.append(std::move(functionNode));
} }
@ -376,13 +377,13 @@ bool ASTJsonExporter::visit(UsingForDirective const& _node)
bool ASTJsonExporter::visit(StructDefinition const& _node) bool ASTJsonExporter::visit(StructDefinition const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
std::make_pair("members", toJson(_node.members())), make_pair("members", toJson(_node.members())),
std::make_pair("scope", idOrNull(_node.scope())) make_pair("scope", idOrNull(_node.scope()))
}; };
addIfSet(attributes,"canonicalName", _node.annotation().canonicalName); addIfSet(attributes,"canonicalName", _node.annotation().canonicalName);
@ -394,11 +395,11 @@ bool ASTJsonExporter::visit(StructDefinition const& _node)
bool ASTJsonExporter::visit(EnumDefinition const& _node) bool ASTJsonExporter::visit(EnumDefinition const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
std::make_pair("members", toJson(_node.members())) make_pair("members", toJson(_node.members()))
}; };
addIfSet(attributes,"canonicalName", _node.annotation().canonicalName); addIfSet(attributes,"canonicalName", _node.annotation().canonicalName);
@ -411,8 +412,8 @@ bool ASTJsonExporter::visit(EnumDefinition const& _node)
bool ASTJsonExporter::visit(EnumValue const& _node) bool ASTJsonExporter::visit(EnumValue const& _node)
{ {
setJsonNode(_node, "EnumValue", { setJsonNode(_node, "EnumValue", {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
}); });
return false; return false;
} }
@ -420,10 +421,10 @@ bool ASTJsonExporter::visit(EnumValue const& _node)
bool ASTJsonExporter::visit(UserDefinedValueTypeDefinition const& _node) bool ASTJsonExporter::visit(UserDefinedValueTypeDefinition const& _node)
{ {
solAssert(_node.underlyingType(), ""); solAssert(_node.underlyingType(), "");
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("underlyingType", toJson(*_node.underlyingType())) make_pair("underlyingType", toJson(*_node.underlyingType()))
}; };
addIfSet(attributes, "canonicalName", _node.annotation().canonicalName); addIfSet(attributes, "canonicalName", _node.annotation().canonicalName);
@ -435,7 +436,7 @@ bool ASTJsonExporter::visit(UserDefinedValueTypeDefinition const& _node)
bool ASTJsonExporter::visit(ParameterList const& _node) bool ASTJsonExporter::visit(ParameterList const& _node)
{ {
setJsonNode(_node, "ParameterList", { setJsonNode(_node, "ParameterList", {
std::make_pair("parameters", toJson(_node.parameters())) make_pair("parameters", toJson(_node.parameters()))
}); });
return false; return false;
} }
@ -443,30 +444,30 @@ bool ASTJsonExporter::visit(ParameterList const& _node)
bool ASTJsonExporter::visit(OverrideSpecifier const& _node) bool ASTJsonExporter::visit(OverrideSpecifier const& _node)
{ {
setJsonNode(_node, "OverrideSpecifier", { setJsonNode(_node, "OverrideSpecifier", {
std::make_pair("overrides", toJson(_node.overrides())) make_pair("overrides", toJson(_node.overrides()))
}); });
return false; return false;
} }
bool ASTJsonExporter::visit(FunctionDefinition const& _node) bool ASTJsonExporter::visit(FunctionDefinition const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
std::make_pair("kind", _node.isFree() ? "freeFunction" : TokenTraits::toString(_node.kind())), make_pair("kind", _node.isFree() ? "freeFunction" : TokenTraits::toString(_node.kind())),
std::make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
std::make_pair("virtual", _node.markedVirtual()), make_pair("virtual", _node.markedVirtual()),
std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue), make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
std::make_pair("parameters", toJson(_node.parameterList())), make_pair("parameters", toJson(_node.parameterList())),
std::make_pair("returnParameters", toJson(*_node.returnParameterList())), make_pair("returnParameters", toJson(*_node.returnParameterList())),
std::make_pair("modifiers", toJson(_node.modifiers())), make_pair("modifiers", toJson(_node.modifiers())),
std::make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue), make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue),
std::make_pair("implemented", _node.isImplemented()), make_pair("implemented", _node.isImplemented()),
std::make_pair("scope", idOrNull(_node.scope())) make_pair("scope", idOrNull(_node.scope()))
}; };
std::optional<Visibility> visibility; optional<Visibility> visibility;
if (_node.isConstructor()) if (_node.isConstructor())
{ {
if (_node.annotation().contract) if (_node.annotation().contract)
@ -481,7 +482,7 @@ bool ASTJsonExporter::visit(FunctionDefinition const& _node)
if (_node.isPartOfExternalInterface() && m_stackState > CompilerStack::State::ParsedAndImported) if (_node.isPartOfExternalInterface() && m_stackState > CompilerStack::State::ParsedAndImported)
attributes.emplace_back("functionSelector", _node.externalIdentifierHex()); attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
if (!_node.annotation().baseFunctions.empty()) if (!_node.annotation().baseFunctions.empty())
attributes.emplace_back(std::make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true))); attributes.emplace_back(make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true)));
setJsonNode(_node, "FunctionDefinition", std::move(attributes)); setJsonNode(_node, "FunctionDefinition", std::move(attributes));
return false; return false;
@ -489,19 +490,19 @@ bool ASTJsonExporter::visit(FunctionDefinition const& _node)
bool ASTJsonExporter::visit(VariableDeclaration const& _node) bool ASTJsonExporter::visit(VariableDeclaration const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("typeName", toJson(_node.typeName())), make_pair("typeName", toJson(_node.typeName())),
std::make_pair("constant", _node.isConstant()), make_pair("constant", _node.isConstant()),
std::make_pair("mutability", VariableDeclaration::mutabilityToString(_node.mutability())), make_pair("mutability", VariableDeclaration::mutabilityToString(_node.mutability())),
std::make_pair("stateVariable", _node.isStateVariable()), make_pair("stateVariable", _node.isStateVariable()),
std::make_pair("storageLocation", location(_node.referenceLocation())), make_pair("storageLocation", location(_node.referenceLocation())),
std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue), make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
std::make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue),
std::make_pair("scope", idOrNull(_node.scope())), make_pair("scope", idOrNull(_node.scope())),
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
}; };
if (_node.isStateVariable() && _node.isPublic()) if (_node.isStateVariable() && _node.isPublic())
attributes.emplace_back("functionSelector", _node.externalIdentifierHex()); attributes.emplace_back("functionSelector", _node.externalIdentifierHex());
@ -510,34 +511,34 @@ bool ASTJsonExporter::visit(VariableDeclaration const& _node)
if (m_inEvent) if (m_inEvent)
attributes.emplace_back("indexed", _node.isIndexed()); attributes.emplace_back("indexed", _node.isIndexed());
if (!_node.annotation().baseFunctions.empty()) if (!_node.annotation().baseFunctions.empty())
attributes.emplace_back(std::make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true))); attributes.emplace_back(make_pair("baseFunctions", getContainerIds(_node.annotation().baseFunctions, true)));
setJsonNode(_node, "VariableDeclaration", std::move(attributes)); setJsonNode(_node, "VariableDeclaration", std::move(attributes));
return false; return false;
} }
bool ASTJsonExporter::visit(ModifierDefinition const& _node) bool ASTJsonExporter::visit(ModifierDefinition const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
std::make_pair("parameters", toJson(_node.parameterList())), make_pair("parameters", toJson(_node.parameterList())),
std::make_pair("virtual", _node.markedVirtual()), make_pair("virtual", _node.markedVirtual()),
std::make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue), make_pair("overrides", _node.overrides() ? toJson(*_node.overrides()) : Json::nullValue),
std::make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue) make_pair("body", _node.isImplemented() ? toJson(_node.body()) : Json::nullValue)
}; };
if (!_node.annotation().baseFunctions.empty()) if (!_node.annotation().baseFunctions.empty())
attributes.emplace_back(std::make_pair("baseModifiers", getContainerIds(_node.annotation().baseFunctions, true))); attributes.emplace_back(make_pair("baseModifiers", getContainerIds(_node.annotation().baseFunctions, true)));
setJsonNode(_node, "ModifierDefinition", std::move(attributes)); setJsonNode(_node, "ModifierDefinition", std::move(attributes));
return false; return false;
} }
bool ASTJsonExporter::visit(ModifierInvocation const& _node) bool ASTJsonExporter::visit(ModifierInvocation const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes{ std::vector<pair<string, Json::Value>> attributes{
std::make_pair("modifierName", toJson(_node.name())), make_pair("modifierName", toJson(_node.name())),
std::make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json::nullValue) make_pair("arguments", _node.arguments() ? toJson(*_node.arguments()) : Json::nullValue)
}; };
if (Declaration const* declaration = _node.name().annotation().referencedDeclaration) if (Declaration const* declaration = _node.name().annotation().referencedDeclaration)
{ {
@ -553,16 +554,16 @@ bool ASTJsonExporter::visit(ModifierInvocation const& _node)
bool ASTJsonExporter::visit(EventDefinition const& _node) bool ASTJsonExporter::visit(EventDefinition const& _node)
{ {
m_inEvent = true; m_inEvent = true;
std::vector<std::pair<std::string, Json::Value>> _attributes = { std::vector<pair<string, Json::Value>> _attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
std::make_pair("parameters", toJson(_node.parameterList())), make_pair("parameters", toJson(_node.parameterList())),
std::make_pair("anonymous", _node.isAnonymous()) make_pair("anonymous", _node.isAnonymous())
}; };
if (m_stackState >= CompilerStack::State::AnalysisSuccessful) if (m_stackState >= CompilerStack::State::AnalysisPerformed)
_attributes.emplace_back( _attributes.emplace_back(
std::make_pair( make_pair(
"eventSelector", "eventSelector",
toHex(u256(util::h256::Arith(util::keccak256(_node.functionType(true)->externalSignature())))) toHex(u256(util::h256::Arith(util::keccak256(_node.functionType(true)->externalSignature()))))
)); ));
@ -573,14 +574,14 @@ bool ASTJsonExporter::visit(EventDefinition const& _node)
bool ASTJsonExporter::visit(ErrorDefinition const& _node) bool ASTJsonExporter::visit(ErrorDefinition const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> _attributes = { std::vector<pair<string, Json::Value>> _attributes = {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("nameLocation", sourceLocationToString(_node.nameLocation())), make_pair("nameLocation", sourceLocationToString(_node.nameLocation())),
std::make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue), make_pair("documentation", _node.documentation() ? toJson(*_node.documentation()) : Json::nullValue),
std::make_pair("parameters", toJson(_node.parameterList())) make_pair("parameters", toJson(_node.parameterList()))
}; };
if (m_stackState >= CompilerStack::State::AnalysisSuccessful) if (m_stackState >= CompilerStack::State::AnalysisPerformed)
_attributes.emplace_back(std::make_pair("errorSelector", _node.functionType(true)->externalIdentifierHex())); _attributes.emplace_back(make_pair("errorSelector", _node.functionType(true)->externalIdentifierHex()));
setJsonNode(_node, "ErrorDefinition", std::move(_attributes)); setJsonNode(_node, "ErrorDefinition", std::move(_attributes));
return false; return false;
@ -588,13 +589,13 @@ bool ASTJsonExporter::visit(ErrorDefinition const& _node)
bool ASTJsonExporter::visit(ElementaryTypeName const& _node) bool ASTJsonExporter::visit(ElementaryTypeName const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("name", _node.typeName().toString()), make_pair("name", _node.typeName().toString()),
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
}; };
if (_node.stateMutability()) if (_node.stateMutability())
attributes.emplace_back(std::make_pair("stateMutability", stateMutabilityToString(*_node.stateMutability()))); attributes.emplace_back(make_pair("stateMutability", stateMutabilityToString(*_node.stateMutability())));
setJsonNode(_node, "ElementaryTypeName", std::move(attributes)); setJsonNode(_node, "ElementaryTypeName", std::move(attributes));
return false; return false;
@ -603,9 +604,9 @@ bool ASTJsonExporter::visit(ElementaryTypeName const& _node)
bool ASTJsonExporter::visit(UserDefinedTypeName const& _node) bool ASTJsonExporter::visit(UserDefinedTypeName const& _node)
{ {
setJsonNode(_node, "UserDefinedTypeName", { setJsonNode(_node, "UserDefinedTypeName", {
std::make_pair("pathNode", toJson(_node.pathNode())), make_pair("pathNode", toJson(_node.pathNode())),
std::make_pair("referencedDeclaration", idOrNull(_node.pathNode().annotation().referencedDeclaration)), make_pair("referencedDeclaration", idOrNull(_node.pathNode().annotation().referencedDeclaration)),
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
}); });
return false; return false;
} }
@ -613,11 +614,11 @@ bool ASTJsonExporter::visit(UserDefinedTypeName const& _node)
bool ASTJsonExporter::visit(FunctionTypeName const& _node) bool ASTJsonExporter::visit(FunctionTypeName const& _node)
{ {
setJsonNode(_node, "FunctionTypeName", { setJsonNode(_node, "FunctionTypeName", {
std::make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
std::make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())),
std::make_pair("parameterTypes", toJson(*_node.parameterTypeList())), make_pair("parameterTypes", toJson(*_node.parameterTypeList())),
std::make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())), make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())),
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
}); });
return false; return false;
} }
@ -625,13 +626,13 @@ bool ASTJsonExporter::visit(FunctionTypeName const& _node)
bool ASTJsonExporter::visit(Mapping const& _node) bool ASTJsonExporter::visit(Mapping const& _node)
{ {
setJsonNode(_node, "Mapping", { setJsonNode(_node, "Mapping", {
std::make_pair("keyType", toJson(_node.keyType())), make_pair("keyType", toJson(_node.keyType())),
std::make_pair("keyName", _node.keyName()), make_pair("keyName", _node.keyName()),
std::make_pair("keyNameLocation", sourceLocationToString(_node.keyNameLocation())), make_pair("keyNameLocation", sourceLocationToString(_node.keyNameLocation())),
std::make_pair("valueType", toJson(_node.valueType())), make_pair("valueType", toJson(_node.valueType())),
std::make_pair("valueName", _node.valueName()), make_pair("valueName", _node.valueName()),
std::make_pair("valueNameLocation", sourceLocationToString(_node.valueNameLocation())), make_pair("valueNameLocation", sourceLocationToString(_node.valueNameLocation())),
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
}); });
return false; return false;
} }
@ -639,20 +640,20 @@ bool ASTJsonExporter::visit(Mapping const& _node)
bool ASTJsonExporter::visit(ArrayTypeName const& _node) bool ASTJsonExporter::visit(ArrayTypeName const& _node)
{ {
setJsonNode(_node, "ArrayTypeName", { setJsonNode(_node, "ArrayTypeName", {
std::make_pair("baseType", toJson(_node.baseType())), make_pair("baseType", toJson(_node.baseType())),
std::make_pair("length", toJsonOrNull(_node.length())), make_pair("length", toJsonOrNull(_node.length())),
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true)) make_pair("typeDescriptions", typePointerToJson(_node.annotation().type, true))
}); });
return false; return false;
} }
bool ASTJsonExporter::visit(InlineAssembly const& _node) bool ASTJsonExporter::visit(InlineAssembly const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> externalReferences; vector<pair<string, Json::Value>> externalReferences;
for (auto const& it: _node.annotation().externalReferences) for (auto const& it: _node.annotation().externalReferences)
if (it.first) if (it.first)
externalReferences.emplace_back(std::make_pair( externalReferences.emplace_back(make_pair(
it.first->name.str(), it.first->name.str(),
inlineAssemblyIdentifierToJson(it) inlineAssemblyIdentifierToJson(it)
)); ));
@ -663,10 +664,10 @@ bool ASTJsonExporter::visit(InlineAssembly const& _node)
for (Json::Value& it: externalReferences | ranges::views::values) for (Json::Value& it: externalReferences | ranges::views::values)
externalReferencesJson.append(std::move(it)); externalReferencesJson.append(std::move(it));
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("AST", Json::Value(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))), make_pair("AST", Json::Value(yul::AsmJsonConverter(sourceIndexFromLocation(_node.location()))(_node.operations()))),
std::make_pair("externalReferences", std::move(externalReferencesJson)), make_pair("externalReferences", std::move(externalReferencesJson)),
std::make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name()) make_pair("evmVersion", dynamic_cast<solidity::yul::EVMDialect const&>(_node.dialect()).evmVersion().name())
}; };
if (_node.flags()) if (_node.flags())
@ -677,7 +678,7 @@ bool ASTJsonExporter::visit(InlineAssembly const& _node)
flags.append(*flag); flags.append(*flag);
else else
flags.append(Json::nullValue); flags.append(Json::nullValue);
attributes.emplace_back(std::make_pair("flags", std::move(flags))); attributes.emplace_back(make_pair("flags", std::move(flags)));
} }
setJsonNode(_node, "InlineAssembly", std::move(attributes)); setJsonNode(_node, "InlineAssembly", std::move(attributes));
@ -687,7 +688,7 @@ bool ASTJsonExporter::visit(InlineAssembly const& _node)
bool ASTJsonExporter::visit(Block const& _node) bool ASTJsonExporter::visit(Block const& _node)
{ {
setJsonNode(_node, _node.unchecked() ? "UncheckedBlock" : "Block", { setJsonNode(_node, _node.unchecked() ? "UncheckedBlock" : "Block", {
std::make_pair("statements", toJson(_node.statements())) make_pair("statements", toJson(_node.statements()))
}); });
return false; return false;
} }
@ -701,9 +702,9 @@ bool ASTJsonExporter::visit(PlaceholderStatement const& _node)
bool ASTJsonExporter::visit(IfStatement const& _node) bool ASTJsonExporter::visit(IfStatement const& _node)
{ {
setJsonNode(_node, "IfStatement", { setJsonNode(_node, "IfStatement", {
std::make_pair("condition", toJson(_node.condition())), make_pair("condition", toJson(_node.condition())),
std::make_pair("trueBody", toJson(_node.trueStatement())), make_pair("trueBody", toJson(_node.trueStatement())),
std::make_pair("falseBody", toJsonOrNull(_node.falseStatement())) make_pair("falseBody", toJsonOrNull(_node.falseStatement()))
}); });
return false; return false;
} }
@ -711,9 +712,9 @@ bool ASTJsonExporter::visit(IfStatement const& _node)
bool ASTJsonExporter::visit(TryCatchClause const& _node) bool ASTJsonExporter::visit(TryCatchClause const& _node)
{ {
setJsonNode(_node, "TryCatchClause", { setJsonNode(_node, "TryCatchClause", {
std::make_pair("errorName", _node.errorName()), make_pair("errorName", _node.errorName()),
std::make_pair("parameters", toJsonOrNull(_node.parameters())), make_pair("parameters", toJsonOrNull(_node.parameters())),
std::make_pair("block", toJson(_node.block())) make_pair("block", toJson(_node.block()))
}); });
return false; return false;
} }
@ -721,8 +722,8 @@ bool ASTJsonExporter::visit(TryCatchClause const& _node)
bool ASTJsonExporter::visit(TryStatement const& _node) bool ASTJsonExporter::visit(TryStatement const& _node)
{ {
setJsonNode(_node, "TryStatement", { setJsonNode(_node, "TryStatement", {
std::make_pair("externalCall", toJson(_node.externalCall())), make_pair("externalCall", toJson(_node.externalCall())),
std::make_pair("clauses", toJson(_node.clauses())) make_pair("clauses", toJson(_node.clauses()))
}); });
return false; return false;
} }
@ -733,8 +734,8 @@ bool ASTJsonExporter::visit(WhileStatement const& _node)
_node, _node,
_node.isDoWhile() ? "DoWhileStatement" : "WhileStatement", _node.isDoWhile() ? "DoWhileStatement" : "WhileStatement",
{ {
std::make_pair("condition", toJson(_node.condition())), make_pair("condition", toJson(_node.condition())),
std::make_pair("body", toJson(_node.body())) make_pair("body", toJson(_node.body()))
} }
); );
return false; return false;
@ -743,10 +744,10 @@ bool ASTJsonExporter::visit(WhileStatement const& _node)
bool ASTJsonExporter::visit(ForStatement const& _node) bool ASTJsonExporter::visit(ForStatement const& _node)
{ {
setJsonNode(_node, "ForStatement", { setJsonNode(_node, "ForStatement", {
std::make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())), make_pair("initializationExpression", toJsonOrNull(_node.initializationExpression())),
std::make_pair("condition", toJsonOrNull(_node.condition())), make_pair("condition", toJsonOrNull(_node.condition())),
std::make_pair("loopExpression", toJsonOrNull(_node.loopExpression())), make_pair("loopExpression", toJsonOrNull(_node.loopExpression())),
std::make_pair("body", toJson(_node.body())) make_pair("body", toJson(_node.body()))
}); });
return false; return false;
} }
@ -766,8 +767,8 @@ bool ASTJsonExporter::visit(Break const& _node)
bool ASTJsonExporter::visit(Return const& _node) bool ASTJsonExporter::visit(Return const& _node)
{ {
setJsonNode(_node, "Return", { setJsonNode(_node, "Return", {
std::make_pair("expression", toJsonOrNull(_node.expression())), make_pair("expression", toJsonOrNull(_node.expression())),
std::make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters)) make_pair("functionReturnParameters", idOrNull(_node.annotation().functionReturnParameters))
}); });
return false; return false;
} }
@ -781,7 +782,7 @@ bool ASTJsonExporter::visit(Throw const& _node)
bool ASTJsonExporter::visit(EmitStatement const& _node) bool ASTJsonExporter::visit(EmitStatement const& _node)
{ {
setJsonNode(_node, "EmitStatement", { setJsonNode(_node, "EmitStatement", {
std::make_pair("eventCall", toJson(_node.eventCall())) make_pair("eventCall", toJson(_node.eventCall()))
}); });
return false; return false;
} }
@ -789,7 +790,7 @@ bool ASTJsonExporter::visit(EmitStatement const& _node)
bool ASTJsonExporter::visit(RevertStatement const& _node) bool ASTJsonExporter::visit(RevertStatement const& _node)
{ {
setJsonNode(_node, "RevertStatement", { setJsonNode(_node, "RevertStatement", {
std::make_pair("errorCall", toJson(_node.errorCall())) make_pair("errorCall", toJson(_node.errorCall()))
}); });
return false; return false;
} }
@ -800,9 +801,9 @@ bool ASTJsonExporter::visit(VariableDeclarationStatement const& _node)
for (auto const& v: _node.declarations()) for (auto const& v: _node.declarations())
appendMove(varDecs, idOrNull(v.get())); appendMove(varDecs, idOrNull(v.get()));
setJsonNode(_node, "VariableDeclarationStatement", { setJsonNode(_node, "VariableDeclarationStatement", {
std::make_pair("assignments", std::move(varDecs)), make_pair("assignments", std::move(varDecs)),
std::make_pair("declarations", toJson(_node.declarations())), make_pair("declarations", toJson(_node.declarations())),
std::make_pair("initialValue", toJsonOrNull(_node.initialValue())) make_pair("initialValue", toJsonOrNull(_node.initialValue()))
}); });
return false; return false;
} }
@ -810,17 +811,17 @@ bool ASTJsonExporter::visit(VariableDeclarationStatement const& _node)
bool ASTJsonExporter::visit(ExpressionStatement const& _node) bool ASTJsonExporter::visit(ExpressionStatement const& _node)
{ {
setJsonNode(_node, "ExpressionStatement", { setJsonNode(_node, "ExpressionStatement", {
std::make_pair("expression", toJson(_node.expression())) make_pair("expression", toJson(_node.expression()))
}); });
return false; return false;
} }
bool ASTJsonExporter::visit(Conditional const& _node) bool ASTJsonExporter::visit(Conditional const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("condition", toJson(_node.condition())), make_pair("condition", toJson(_node.condition())),
std::make_pair("trueExpression", toJson(_node.trueExpression())), make_pair("trueExpression", toJson(_node.trueExpression())),
std::make_pair("falseExpression", toJson(_node.falseExpression())) make_pair("falseExpression", toJson(_node.falseExpression()))
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "Conditional", std::move(attributes)); setJsonNode(_node, "Conditional", std::move(attributes));
@ -829,10 +830,10 @@ bool ASTJsonExporter::visit(Conditional const& _node)
bool ASTJsonExporter::visit(Assignment const& _node) bool ASTJsonExporter::visit(Assignment const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("operator", TokenTraits::toString(_node.assignmentOperator())), make_pair("operator", TokenTraits::toString(_node.assignmentOperator())),
std::make_pair("leftHandSide", toJson(_node.leftHandSide())), make_pair("leftHandSide", toJson(_node.leftHandSide())),
std::make_pair("rightHandSide", toJson(_node.rightHandSide())) make_pair("rightHandSide", toJson(_node.rightHandSide()))
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "Assignment", std::move(attributes)); setJsonNode(_node, "Assignment", std::move(attributes));
@ -841,9 +842,9 @@ bool ASTJsonExporter::visit(Assignment const& _node)
bool ASTJsonExporter::visit(TupleExpression const& _node) bool ASTJsonExporter::visit(TupleExpression const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("isInlineArray", Json::Value(_node.isInlineArray())), make_pair("isInlineArray", Json::Value(_node.isInlineArray())),
std::make_pair("components", toJson(_node.components())), make_pair("components", toJson(_node.components())),
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "TupleExpression", std::move(attributes)); setJsonNode(_node, "TupleExpression", std::move(attributes));
@ -852,10 +853,10 @@ bool ASTJsonExporter::visit(TupleExpression const& _node)
bool ASTJsonExporter::visit(UnaryOperation const& _node) bool ASTJsonExporter::visit(UnaryOperation const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("prefix", _node.isPrefixOperation()), make_pair("prefix", _node.isPrefixOperation()),
std::make_pair("operator", TokenTraits::toString(_node.getOperator())), make_pair("operator", TokenTraits::toString(_node.getOperator())),
std::make_pair("subExpression", toJson(_node.subExpression())) make_pair("subExpression", toJson(_node.subExpression()))
}; };
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage. // NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr) if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
@ -867,11 +868,11 @@ bool ASTJsonExporter::visit(UnaryOperation const& _node)
bool ASTJsonExporter::visit(BinaryOperation const& _node) bool ASTJsonExporter::visit(BinaryOperation const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("operator", TokenTraits::toString(_node.getOperator())), make_pair("operator", TokenTraits::toString(_node.getOperator())),
std::make_pair("leftExpression", toJson(_node.leftExpression())), make_pair("leftExpression", toJson(_node.leftExpression())),
std::make_pair("rightExpression", toJson(_node.rightExpression())), make_pair("rightExpression", toJson(_node.rightExpression())),
std::make_pair("commonType", typePointerToJson(_node.annotation().commonType)), make_pair("commonType", typePointerToJson(_node.annotation().commonType)),
}; };
// NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage. // NOTE: This annotation is guaranteed to be set but only if we didn't stop at the parsing stage.
if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr) if (_node.annotation().userDefinedFunction.set() && *_node.annotation().userDefinedFunction != nullptr)
@ -886,12 +887,12 @@ bool ASTJsonExporter::visit(FunctionCall const& _node)
Json::Value names(Json::arrayValue); Json::Value names(Json::arrayValue);
for (auto const& name: _node.names()) for (auto const& name: _node.names())
names.append(Json::Value(*name)); names.append(Json::Value(*name));
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("expression", toJson(_node.expression())), make_pair("expression", toJson(_node.expression())),
std::make_pair("names", std::move(names)), make_pair("names", std::move(names)),
std::make_pair("nameLocations", sourceLocationsToJson(_node.nameLocations())), make_pair("nameLocations", sourceLocationsToJson(_node.nameLocations())),
std::make_pair("arguments", toJson(_node.arguments())), make_pair("arguments", toJson(_node.arguments())),
std::make_pair("tryCall", _node.annotation().tryCall) make_pair("tryCall", _node.annotation().tryCall)
}; };
if (_node.annotation().kind.set()) if (_node.annotation().kind.set())
@ -911,10 +912,10 @@ bool ASTJsonExporter::visit(FunctionCallOptions const& _node)
for (auto const& name: _node.names()) for (auto const& name: _node.names())
names.append(Json::Value(*name)); names.append(Json::Value(*name));
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("expression", toJson(_node.expression())), make_pair("expression", toJson(_node.expression())),
std::make_pair("names", std::move(names)), make_pair("names", std::move(names)),
std::make_pair("options", toJson(_node.options())), make_pair("options", toJson(_node.options())),
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
@ -924,8 +925,8 @@ bool ASTJsonExporter::visit(FunctionCallOptions const& _node)
bool ASTJsonExporter::visit(NewExpression const& _node) bool ASTJsonExporter::visit(NewExpression const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("typeName", toJson(_node.typeName())) make_pair("typeName", toJson(_node.typeName()))
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "NewExpression", std::move(attributes)); setJsonNode(_node, "NewExpression", std::move(attributes));
@ -934,11 +935,11 @@ bool ASTJsonExporter::visit(NewExpression const& _node)
bool ASTJsonExporter::visit(MemberAccess const& _node) bool ASTJsonExporter::visit(MemberAccess const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("memberName", _node.memberName()), make_pair("memberName", _node.memberName()),
std::make_pair("memberLocation", Json::Value(sourceLocationToString(_node.memberLocation()))), make_pair("memberLocation", Json::Value(sourceLocationToString(_node.memberLocation()))),
std::make_pair("expression", toJson(_node.expression())), make_pair("expression", toJson(_node.expression())),
std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)),
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "MemberAccess", std::move(attributes)); setJsonNode(_node, "MemberAccess", std::move(attributes));
@ -947,9 +948,9 @@ bool ASTJsonExporter::visit(MemberAccess const& _node)
bool ASTJsonExporter::visit(IndexAccess const& _node) bool ASTJsonExporter::visit(IndexAccess const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("baseExpression", toJson(_node.baseExpression())), make_pair("baseExpression", toJson(_node.baseExpression())),
std::make_pair("indexExpression", toJsonOrNull(_node.indexExpression())), make_pair("indexExpression", toJsonOrNull(_node.indexExpression())),
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "IndexAccess", std::move(attributes)); setJsonNode(_node, "IndexAccess", std::move(attributes));
@ -958,10 +959,10 @@ bool ASTJsonExporter::visit(IndexAccess const& _node)
bool ASTJsonExporter::visit(IndexRangeAccess const& _node) bool ASTJsonExporter::visit(IndexRangeAccess const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("baseExpression", toJson(_node.baseExpression())), make_pair("baseExpression", toJson(_node.baseExpression())),
std::make_pair("startExpression", toJsonOrNull(_node.startExpression())), make_pair("startExpression", toJsonOrNull(_node.startExpression())),
std::make_pair("endExpression", toJsonOrNull(_node.endExpression())), make_pair("endExpression", toJsonOrNull(_node.endExpression())),
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "IndexRangeAccess", std::move(attributes)); setJsonNode(_node, "IndexRangeAccess", std::move(attributes));
@ -974,19 +975,19 @@ bool ASTJsonExporter::visit(Identifier const& _node)
for (auto const& dec: _node.annotation().overloadedDeclarations) for (auto const& dec: _node.annotation().overloadedDeclarations)
overloads.append(nodeId(*dec)); overloads.append(nodeId(*dec));
setJsonNode(_node, "Identifier", { setJsonNode(_node, "Identifier", {
std::make_pair("name", _node.name()), make_pair("name", _node.name()),
std::make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)), make_pair("referencedDeclaration", idOrNull(_node.annotation().referencedDeclaration)),
std::make_pair("overloadedDeclarations", overloads), make_pair("overloadedDeclarations", overloads),
std::make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)), make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)),
std::make_pair("argumentTypes", typePointerToJson(_node.annotation().arguments)) make_pair("argumentTypes", typePointerToJson(_node.annotation().arguments))
}); });
return false; return false;
} }
bool ASTJsonExporter::visit(ElementaryTypeNameExpression const& _node) bool ASTJsonExporter::visit(ElementaryTypeNameExpression const& _node)
{ {
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("typeName", toJson(_node.type())) make_pair("typeName", toJson(_node.type()))
}; };
appendExpressionAttributes(attributes, _node.annotation()); appendExpressionAttributes(attributes, _node.annotation());
setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes)); setJsonNode(_node, "ElementaryTypeNameExpression", std::move(attributes));
@ -999,11 +1000,11 @@ bool ASTJsonExporter::visit(Literal const& _node)
if (!util::validateUTF8(_node.value())) if (!util::validateUTF8(_node.value()))
value = Json::nullValue; value = Json::nullValue;
Token subdenomination = Token(_node.subDenomination()); Token subdenomination = Token(_node.subDenomination());
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("kind", literalTokenKind(_node.token())), make_pair("kind", literalTokenKind(_node.token())),
std::make_pair("value", value), make_pair("value", value),
std::make_pair("hexValue", util::toHex(util::asBytes(_node.value()))), make_pair("hexValue", util::toHex(util::asBytes(_node.value()))),
std::make_pair( make_pair(
"subdenomination", "subdenomination",
subdenomination == Token::Illegal ? subdenomination == Token::Illegal ?
Json::nullValue : Json::nullValue :
@ -1018,8 +1019,8 @@ bool ASTJsonExporter::visit(Literal const& _node)
bool ASTJsonExporter::visit(StructuredDocumentation const& _node) bool ASTJsonExporter::visit(StructuredDocumentation const& _node)
{ {
Json::Value text{*_node.text()}; Json::Value text{*_node.text()};
std::vector<std::pair<std::string, Json::Value>> attributes = { std::vector<pair<string, Json::Value>> attributes = {
std::make_pair("text", text) make_pair("text", text)
}; };
setJsonNode(_node, "StructuredDocumentation", std::move(attributes)); setJsonNode(_node, "StructuredDocumentation", std::move(attributes));
return false; return false;
@ -1032,7 +1033,7 @@ void ASTJsonExporter::endVisit(EventDefinition const&)
m_inEvent = false; m_inEvent = false;
} }
std::string ASTJsonExporter::location(VariableDeclaration::Location _location) string ASTJsonExporter::location(VariableDeclaration::Location _location)
{ {
switch (_location) switch (_location)
{ {
@ -1049,7 +1050,7 @@ std::string ASTJsonExporter::location(VariableDeclaration::Location _location)
return {}; return {};
} }
std::string ASTJsonExporter::contractKind(ContractKind _kind) string ASTJsonExporter::contractKind(ContractKind _kind)
{ {
switch (_kind) switch (_kind)
{ {
@ -1065,7 +1066,7 @@ std::string ASTJsonExporter::contractKind(ContractKind _kind)
return {}; return {};
} }
std::string ASTJsonExporter::functionCallKind(FunctionCallKind _kind) string ASTJsonExporter::functionCallKind(FunctionCallKind _kind)
{ {
switch (_kind) switch (_kind)
{ {
@ -1080,7 +1081,7 @@ std::string ASTJsonExporter::functionCallKind(FunctionCallKind _kind)
} }
} }
std::string ASTJsonExporter::literalTokenKind(Token _token) string ASTJsonExporter::literalTokenKind(Token _token)
{ {
switch (_token) switch (_token)
{ {
@ -1100,12 +1101,12 @@ std::string ASTJsonExporter::literalTokenKind(Token _token)
} }
} }
std::string ASTJsonExporter::type(Expression const& _expression) string ASTJsonExporter::type(Expression const& _expression)
{ {
return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown"; return _expression.annotation().type ? _expression.annotation().type->toString() : "Unknown";
} }
std::string ASTJsonExporter::type(VariableDeclaration const& _varDecl) string ASTJsonExporter::type(VariableDeclaration const& _varDecl)
{ {
return _varDecl.annotation().type ? _varDecl.annotation().type->toString() : "Unknown"; return _varDecl.annotation().type ? _varDecl.annotation().type->toString() : "Unknown";
} }

View File

@ -37,6 +37,8 @@
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
using namespace std;
namespace solidity::frontend namespace solidity::frontend
{ {
@ -48,16 +50,16 @@ ASTPointer<T> ASTJsonImporter::nullOrCast(Json::Value const& _json)
if (_json.isNull()) if (_json.isNull())
return nullptr; return nullptr;
else else
return std::dynamic_pointer_cast<T>(convertJsonToASTNode(_json)); return dynamic_pointer_cast<T>(convertJsonToASTNode(_json));
} }
// ============ public =========================== // ============ public ===========================
std::map<std::string, ASTPointer<SourceUnit>> ASTJsonImporter::jsonToSourceUnit(std::map<std::string, Json::Value> const& _sourceList) map<string, ASTPointer<SourceUnit>> ASTJsonImporter::jsonToSourceUnit(map<string, Json::Value> const& _sourceList)
{ {
for (auto const& src: _sourceList) for (auto const& src: _sourceList)
m_sourceNames.emplace_back(std::make_shared<std::string const>(src.first)); m_sourceNames.emplace_back(make_shared<string const>(src.first));
for (auto const& srcPair: _sourceList) for (auto const& srcPair: _sourceList)
{ {
astAssert(!srcPair.second.isNull()); astAssert(!srcPair.second.isNull());
@ -79,7 +81,7 @@ ASTPointer<T> ASTJsonImporter::createASTNode(Json::Value const& _node, Args&&...
astAssert(m_usedIDs.insert(id).second, "Found duplicate node ID!"); astAssert(m_usedIDs.insert(id).second, "Found duplicate node ID!");
auto n = std::make_shared<T>( auto n = make_shared<T>(
id, id,
createSourceLocation(_node), createSourceLocation(_node),
std::forward<Args>(_args)... std::forward<Args>(_args)...
@ -94,9 +96,9 @@ SourceLocation const ASTJsonImporter::createSourceLocation(Json::Value const& _n
return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceNames); return solidity::langutil::parseSourceLocation(_node["src"].asString(), m_sourceNames);
} }
std::optional<std::vector<SourceLocation>> ASTJsonImporter::createSourceLocations(Json::Value const& _node) const optional<vector<SourceLocation>> ASTJsonImporter::createSourceLocations(Json::Value const& _node) const
{ {
std::vector<SourceLocation> locations; vector<SourceLocation> locations;
if (_node.isMember("nameLocations") && _node["nameLocations"].isArray()) if (_node.isMember("nameLocations") && _node["nameLocations"].isArray())
{ {
@ -105,7 +107,7 @@ std::optional<std::vector<SourceLocation>> ASTJsonImporter::createSourceLocation
return locations; return locations;
} }
return std::nullopt; return nullopt;
} }
SourceLocation ASTJsonImporter::createNameSourceLocation(Json::Value const& _node) SourceLocation ASTJsonImporter::createNameSourceLocation(Json::Value const& _node)
@ -132,7 +134,7 @@ SourceLocation ASTJsonImporter::createValueNameSourceLocation(Json::Value const&
template<class T> template<class T>
ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node) ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node)
{ {
ASTPointer<T> ret = std::dynamic_pointer_cast<T>(convertJsonToASTNode(_node)); ASTPointer<T> ret = dynamic_pointer_cast<T>(convertJsonToASTNode(_node));
astAssert(ret, "cast of converted json-node must not be nullptr"); astAssert(ret, "cast of converted json-node must not be nullptr");
return ret; return ret;
} }
@ -141,7 +143,7 @@ ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node)
ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _json) ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _json)
{ {
astAssert(_json["nodeType"].isString() && _json.isMember("id"), "JSON-Node needs to have 'nodeType' and 'id' fields."); astAssert(_json["nodeType"].isString() && _json.isMember("id"), "JSON-Node needs to have 'nodeType' and 'id' fields.");
std::string nodeType = _json["nodeType"].asString(); string nodeType = _json["nodeType"].asString();
if (nodeType == "PragmaDirective") if (nodeType == "PragmaDirective")
return createPragmaDirective(_json); return createPragmaDirective(_json);
if (nodeType == "ImportDirective") if (nodeType == "ImportDirective")
@ -263,9 +265,9 @@ ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _js
// ============ functions to instantiate the AST-Nodes from Json-Nodes ============== // ============ functions to instantiate the AST-Nodes from Json-Nodes ==============
ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _node, std::string const& _srcName) ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _node, string const& _srcName)
{ {
std::optional<std::string> license; optional<string> license;
if (_node.isMember("license") && !_node["license"].isNull()) if (_node.isMember("license") && !_node["license"].isNull())
license = _node["license"].asString(); license = _node["license"].asString();
@ -273,7 +275,7 @@ ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _nod
if (_node.isMember("experimentalSolidity") && !_node["experimentalSolidity"].isNull()) if (_node.isMember("experimentalSolidity") && !_node["experimentalSolidity"].isNull())
experimentalSolidity = _node["experimentalSolidity"].asBool(); experimentalSolidity = _node["experimentalSolidity"].asBool();
std::vector<ASTPointer<ASTNode>> nodes; vector<ASTPointer<ASTNode>> nodes;
for (auto& child: member(_node, "nodes")) for (auto& child: member(_node, "nodes"))
nodes.emplace_back(convertJsonToASTNode(child)); nodes.emplace_back(convertJsonToASTNode(child));
@ -284,11 +286,11 @@ ASTPointer<SourceUnit> ASTJsonImporter::createSourceUnit(Json::Value const& _nod
ASTPointer<PragmaDirective> ASTJsonImporter::createPragmaDirective(Json::Value const& _node) ASTPointer<PragmaDirective> ASTJsonImporter::createPragmaDirective(Json::Value const& _node)
{ {
std::vector<Token> tokens; vector<Token> tokens;
std::vector<ASTString> literals; vector<ASTString> literals;
for (auto const& lit: member(_node, "literals")) for (auto const& lit: member(_node, "literals"))
{ {
std::string l = lit.asString(); string l = lit.asString();
literals.push_back(l); literals.push_back(l);
tokens.push_back(scanSingleToken(l)); tokens.push_back(scanSingleToken(l));
} }
@ -307,7 +309,7 @@ ASTPointer<ImportDirective> ASTJsonImporter::createImportDirective(Json::Value c
symbolAliases.push_back({ symbolAliases.push_back({
createIdentifier(tuple["foreign"]), createIdentifier(tuple["foreign"]),
tuple["local"].isNull() ? nullptr : std::make_shared<ASTString>(tuple["local"].asString()), tuple["local"].isNull() ? nullptr : make_shared<ASTString>(tuple["local"].asString()),
createSourceLocation(tuple["foreign"])} createSourceLocation(tuple["foreign"])}
); );
} }
@ -341,7 +343,7 @@ ASTPointer<ContractDefinition> ASTJsonImporter::createContractDefinition(Json::V
return createASTNode<ContractDefinition>( return createASTNode<ContractDefinition>(
_node, _node,
std::make_shared<ASTString>(_node["name"].asString()), make_shared<ASTString>(_node["name"].asString()),
createNameSourceLocation(_node), createNameSourceLocation(_node),
_node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")), _node["documentation"].isNull() ? nullptr : createDocumentation(member(_node, "documentation")),
baseContracts, baseContracts,
@ -355,13 +357,13 @@ ASTPointer<IdentifierPath> ASTJsonImporter::createIdentifierPath(Json::Value con
{ {
astAssert(_node["name"].isString(), "Expected 'name' to be a string!"); astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
std::vector<ASTString> namePath; vector<ASTString> namePath;
std::vector<SourceLocation> namePathLocations; vector<SourceLocation> namePathLocations;
std::vector<std::string> strs; vector<string> strs;
std::string nameString = member(_node, "name").asString(); string nameString = member(_node, "name").asString();
boost::algorithm::split(strs, nameString, boost::is_any_of(".")); boost::algorithm::split(strs, nameString, boost::is_any_of("."));
astAssert(!strs.empty(), "Expected at least one element in IdentifierPath."); astAssert(!strs.empty(), "Expected at least one element in IdentifierPath.");
for (std::string s: strs) for (string s: strs)
{ {
astAssert(!s.empty(), "Expected non-empty string for IdentifierPath element."); astAssert(!s.empty(), "Expected non-empty string for IdentifierPath element.");
namePath.emplace_back(s); namePath.emplace_back(s);
@ -393,20 +395,20 @@ ASTPointer<InheritanceSpecifier> ASTJsonImporter::createInheritanceSpecifier(Jso
return createASTNode<InheritanceSpecifier>( return createASTNode<InheritanceSpecifier>(
_node, _node,
createIdentifierPath(member(_node, "baseName")), createIdentifierPath(member(_node, "baseName")),
member(_node, "arguments").isNull() ? nullptr : std::make_unique<std::vector<ASTPointer<Expression>>>(arguments) member(_node, "arguments").isNull() ? nullptr : make_unique<std::vector<ASTPointer<Expression>>>(arguments)
); );
} }
ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node) ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Value const& _node)
{ {
std::vector<ASTPointer<IdentifierPath>> functions; vector<ASTPointer<IdentifierPath>> functions;
std::vector<std::optional<Token>> operators; vector<optional<Token>> operators;
if (_node.isMember("libraryName")) if (_node.isMember("libraryName"))
{ {
astAssert(!_node["libraryName"].isArray()); astAssert(!_node["libraryName"].isArray());
astAssert(!_node["libraryName"]["operator"]); astAssert(!_node["libraryName"]["operator"]);
functions.emplace_back(createIdentifierPath(_node["libraryName"])); functions.emplace_back(createIdentifierPath(_node["libraryName"]));
operators.emplace_back(std::nullopt); operators.emplace_back(nullopt);
} }
else if (_node.isMember("functionList")) else if (_node.isMember("functionList"))
for (Json::Value const& function: _node["functionList"]) for (Json::Value const& function: _node["functionList"])
@ -417,7 +419,7 @@ ASTPointer<UsingForDirective> ASTJsonImporter::createUsingForDirective(Json::Val
astAssert(!function.isMember("definition")); astAssert(!function.isMember("definition"));
functions.emplace_back(createIdentifierPath(function["function"])); functions.emplace_back(createIdentifierPath(function["function"]));
operators.emplace_back(std::nullopt); operators.emplace_back(nullopt);
} }
else else
{ {
@ -518,7 +520,7 @@ ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(Json::V
Token kind; Token kind;
bool freeFunction = false; bool freeFunction = false;
std::string kindStr = member(_node, "kind").asString(); string kindStr = member(_node, "kind").asString();
if (kindStr == "constructor") if (kindStr == "constructor")
kind = Token::Constructor; kind = Token::Constructor;
@ -570,7 +572,7 @@ ASTPointer<VariableDeclaration> ASTJsonImporter::createVariableDeclaration(Json:
VariableDeclaration::Mutability mutability{}; VariableDeclaration::Mutability mutability{};
astAssert(member(_node, "mutability").isString(), "'mutability' expected to be string."); astAssert(member(_node, "mutability").isString(), "'mutability' expected to be string.");
std::string const mutabilityStr = member(_node, "mutability").asString(); string const mutabilityStr = member(_node, "mutability").asString();
if (mutabilityStr == "constant") if (mutabilityStr == "constant")
{ {
mutability = VariableDeclaration::Mutability::Constant; mutability = VariableDeclaration::Mutability::Constant;
@ -590,7 +592,7 @@ ASTPointer<VariableDeclaration> ASTJsonImporter::createVariableDeclaration(Json:
return createASTNode<VariableDeclaration>( return createASTNode<VariableDeclaration>(
_node, _node,
nullOrCast<TypeName>(member(_node, "typeName")), nullOrCast<TypeName>(member(_node, "typeName")),
std::make_shared<ASTString>(member(_node, "name").asString()), make_shared<ASTString>(member(_node, "name").asString()),
createNameSourceLocation(_node), createNameSourceLocation(_node),
nullOrCast<Expression>(member(_node, "value")), nullOrCast<Expression>(member(_node, "value")),
visibility(_node), visibility(_node),
@ -624,7 +626,7 @@ ASTPointer<ModifierInvocation> ASTJsonImporter::createModifierInvocation(Json::V
return createASTNode<ModifierInvocation>( return createASTNode<ModifierInvocation>(
_node, _node,
createIdentifierPath(member(_node, "modifierName")), createIdentifierPath(member(_node, "modifierName")),
member(_node, "arguments").isNull() ? nullptr : std::make_unique<std::vector<ASTPointer<Expression>>>(arguments) member(_node, "arguments").isNull() ? nullptr : make_unique<std::vector<ASTPointer<Expression>>>(arguments)
); );
} }
@ -658,9 +660,9 @@ ASTPointer<ElementaryTypeName> ASTJsonImporter::createElementaryTypeName(Json::V
astAssert(_node["name"].isString(), "Expected 'name' to be a string!"); astAssert(_node["name"].isString(), "Expected 'name' to be a string!");
std::string name = member(_node, "name").asString(); string name = member(_node, "name").asString();
Token token; Token token;
std::tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(name); tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(name);
ElementaryTypeNameToken elem(token, firstNum, secondNum); ElementaryTypeNameToken elem(token, firstNum, secondNum);
std::optional<StateMutability> mutability = {}; std::optional<StateMutability> mutability = {};
@ -719,19 +721,19 @@ ASTPointer<InlineAssembly> ASTJsonImporter::createInlineAssembly(Json::Value con
astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!"); astAssert(m_evmVersion == evmVersion, "Imported tree evm version differs from configured evm version!");
yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value()); yul::Dialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(evmVersion.value());
ASTPointer<std::vector<ASTPointer<ASTString>>> flags; ASTPointer<vector<ASTPointer<ASTString>>> flags;
if (_node.isMember("flags")) if (_node.isMember("flags"))
{ {
flags = std::make_shared<std::vector<ASTPointer<ASTString>>>(); flags = make_shared<vector<ASTPointer<ASTString>>>();
Json::Value const& flagsNode = _node["flags"]; Json::Value const& flagsNode = _node["flags"];
astAssert(flagsNode.isArray(), "Assembly flags must be an array."); astAssert(flagsNode.isArray(), "Assembly flags must be an array.");
for (Json::ArrayIndex i = 0; i < flagsNode.size(); ++i) for (Json::ArrayIndex i = 0; i < flagsNode.size(); ++i)
{ {
astAssert(flagsNode[i].isString(), "Assembly flag must be a string."); astAssert(flagsNode[i].isString(), "Assembly flag must be a string.");
flags->emplace_back(std::make_shared<ASTString>(flagsNode[i].asString())); flags->emplace_back(make_shared<ASTString>(flagsNode[i].asString()));
} }
} }
std::shared_ptr<yul::Block> operations = std::make_shared<yul::Block>(yul::AsmJsonImporter(m_sourceNames).createBlock(member(_node, "AST"))); shared_ptr<yul::Block> operations = make_shared<yul::Block>(yul::AsmJsonImporter(m_sourceNames).createBlock(member(_node, "AST")));
return createASTNode<InlineAssembly>( return createASTNode<InlineAssembly>(
_node, _node,
nullOrASTString(_node, "documentation"), nullOrASTString(_node, "documentation"),
@ -785,7 +787,7 @@ ASTPointer<TryCatchClause> ASTJsonImporter::createTryCatchClause(Json::Value con
ASTPointer<TryStatement> ASTJsonImporter::createTryStatement(Json::Value const& _node) ASTPointer<TryStatement> ASTJsonImporter::createTryStatement(Json::Value const& _node)
{ {
std::vector<ASTPointer<TryCatchClause>> clauses; vector<ASTPointer<TryCatchClause>> clauses;
for (auto& param: _node["clauses"]) for (auto& param: _node["clauses"])
clauses.emplace_back(createTryCatchClause(param)); clauses.emplace_back(createTryCatchClause(param));
@ -955,10 +957,10 @@ ASTPointer<FunctionCall> ASTJsonImporter::createFunctionCall(Json::Value const&
for (auto& name: member(_node, "names")) for (auto& name: member(_node, "names"))
{ {
astAssert(name.isString(), "Expected 'names' members to be strings!"); astAssert(name.isString(), "Expected 'names' members to be strings!");
names.push_back(std::make_shared<ASTString>(name.asString())); names.push_back(make_shared<ASTString>(name.asString()));
} }
std::optional<std::vector<SourceLocation>> sourceLocations = createSourceLocations(_node); optional<vector<SourceLocation>> sourceLocations = createSourceLocations(_node);
return createASTNode<FunctionCall>( return createASTNode<FunctionCall>(
_node, _node,
@ -967,7 +969,7 @@ ASTPointer<FunctionCall> ASTJsonImporter::createFunctionCall(Json::Value const&
names, names,
sourceLocations ? sourceLocations ?
*sourceLocations : *sourceLocations :
std::vector<SourceLocation>(names.size()) vector<SourceLocation>(names.size())
); );
} }
@ -980,7 +982,7 @@ ASTPointer<FunctionCallOptions> ASTJsonImporter::createFunctionCallOptions(Json:
for (auto& name: member(_node, "names")) for (auto& name: member(_node, "names"))
{ {
astAssert(name.isString(), "Expected 'names' members to be strings!"); astAssert(name.isString(), "Expected 'names' members to be strings!");
names.push_back(std::make_shared<ASTString>(name.asString())); names.push_back(make_shared<ASTString>(name.asString()));
} }
return createASTNode<FunctionCallOptions>( return createASTNode<FunctionCallOptions>(
@ -1047,14 +1049,14 @@ ASTPointer<ElementaryTypeNameExpression> ASTJsonImporter::createElementaryTypeNa
ASTPointer<ASTNode> ASTJsonImporter::createLiteral(Json::Value const& _node) ASTPointer<ASTNode> ASTJsonImporter::createLiteral(Json::Value const& _node)
{ {
static std::string const valStr = "value"; static string const valStr = "value";
static std::string const hexValStr = "hexValue"; static string const hexValStr = "hexValue";
astAssert(member(_node, valStr).isString() || member(_node, hexValStr).isString(), "Literal-value is unset."); astAssert(member(_node, valStr).isString() || member(_node, hexValStr).isString(), "Literal-value is unset.");
ASTPointer<ASTString> value = _node.isMember(hexValStr) ? ASTPointer<ASTString> value = _node.isMember(hexValStr) ?
std::make_shared<ASTString>(util::asString(util::fromHex(_node[hexValStr].asString()))) : make_shared<ASTString>(util::asString(util::fromHex(_node[hexValStr].asString()))) :
std::make_shared<ASTString>(_node[valStr].asString()); make_shared<ASTString>(_node[valStr].asString());
return createASTNode<Literal>( return createASTNode<Literal>(
_node, _node,
@ -1066,19 +1068,19 @@ ASTPointer<ASTNode> ASTJsonImporter::createLiteral(Json::Value const& _node)
ASTPointer<StructuredDocumentation> ASTJsonImporter::createDocumentation(Json::Value const& _node) ASTPointer<StructuredDocumentation> ASTJsonImporter::createDocumentation(Json::Value const& _node)
{ {
static std::string const textString = "text"; static string const textString = "text";
astAssert(member(_node, textString).isString(), "'text' must be a string"); astAssert(member(_node, textString).isString(), "'text' must be a string");
return createASTNode<StructuredDocumentation>( return createASTNode<StructuredDocumentation>(
_node, _node,
std::make_shared<ASTString>(_node[textString].asString()) make_shared<ASTString>(_node[textString].asString())
); );
} }
// ===== helper functions ========== // ===== helper functions ==========
Json::Value ASTJsonImporter::member(Json::Value const& _node, std::string const& _name) Json::Value ASTJsonImporter::member(Json::Value const& _node, string const& _name)
{ {
if (!_node.isMember(_name)) if (!_node.isMember(_name))
return Json::nullValue; return Json::nullValue;
@ -1093,19 +1095,19 @@ Token ASTJsonImporter::scanSingleToken(Json::Value const& _node)
return scanner.currentToken(); return scanner.currentToken();
} }
ASTPointer<ASTString> ASTJsonImporter::nullOrASTString(Json::Value const& _json, std::string const& _name) ASTPointer<ASTString> ASTJsonImporter::nullOrASTString(Json::Value const& _json, string const& _name)
{ {
return _json[_name].isString() ? memberAsASTString(_json, _name) : nullptr; return _json[_name].isString() ? memberAsASTString(_json, _name) : nullptr;
} }
ASTPointer<ASTString> ASTJsonImporter::memberAsASTString(Json::Value const& _node, std::string const& _name) ASTPointer<ASTString> ASTJsonImporter::memberAsASTString(Json::Value const& _node, string const& _name)
{ {
Json::Value value = member(_node, _name); Json::Value value = member(_node, _name);
astAssert(value.isString(), "field " + _name + " must be of type string."); astAssert(value.isString(), "field " + _name + " must be of type string.");
return std::make_shared<ASTString>(_node[_name].asString()); return make_shared<ASTString>(_node[_name].asString());
} }
bool ASTJsonImporter::memberAsBool(Json::Value const& _node, std::string const& _name) bool ASTJsonImporter::memberAsBool(Json::Value const& _node, string const& _name)
{ {
Json::Value value = member(_node, _name); Json::Value value = member(_node, _name);
astAssert(value.isBool(), "field " + _name + " must be of type boolean."); astAssert(value.isBool(), "field " + _name + " must be of type boolean.");
@ -1154,7 +1156,7 @@ Visibility ASTJsonImporter::visibility(Json::Value const& _node)
Json::Value visibility = member(_node, "visibility"); Json::Value visibility = member(_node, "visibility");
astAssert(visibility.isString(), "'visibility' expected to be a string."); astAssert(visibility.isString(), "'visibility' expected to be a string.");
std::string const visibilityStr = visibility.asString(); string const visibilityStr = visibility.asString();
if (visibilityStr == "default") if (visibilityStr == "default")
return Visibility::Default; return Visibility::Default;
@ -1178,7 +1180,7 @@ VariableDeclaration::Location ASTJsonImporter::location(Json::Value const& _node
Json::Value storageLoc = member(_node, "storageLocation"); Json::Value storageLoc = member(_node, "storageLocation");
astAssert(storageLoc.isString(), "'storageLocation' expected to be a string."); astAssert(storageLoc.isString(), "'storageLocation' expected to be a string.");
std::string const storageLocStr = storageLoc.asString(); string const storageLocStr = storageLoc.asString();
if (storageLocStr == "default") if (storageLocStr == "default")
return VariableDeclaration::Location::Unspecified; return VariableDeclaration::Location::Unspecified;
@ -1204,7 +1206,7 @@ Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _no
astAssert(subDen.isString(), "'subDenomination' expected to be string."); astAssert(subDen.isString(), "'subDenomination' expected to be string.");
std::string const subDenStr = subDen.asString(); string const subDenStr = subDen.asString();
if (subDenStr == "wei") if (subDenStr == "wei")
return Literal::SubDenomination::Wei; return Literal::SubDenomination::Wei;
@ -1234,7 +1236,7 @@ Literal::SubDenomination ASTJsonImporter::subdenomination(Json::Value const& _no
StateMutability ASTJsonImporter::stateMutability(Json::Value const& _node) StateMutability ASTJsonImporter::stateMutability(Json::Value const& _node)
{ {
astAssert(member(_node, "stateMutability").isString(), "StateMutability' expected to be string."); astAssert(member(_node, "stateMutability").isString(), "StateMutability' expected to be string.");
std::string const mutabilityStr = member(_node, "stateMutability").asString(); string const mutabilityStr = member(_node, "stateMutability").asString();
if (mutabilityStr == "pure") if (mutabilityStr == "pure")
return StateMutability::Pure; return StateMutability::Pure;

View File

@ -18,6 +18,7 @@
#include <libsolidity/ast/CallGraph.h> #include <libsolidity/ast/CallGraph.h>
using namespace std;
using namespace solidity::frontend; using namespace solidity::frontend;
bool CallGraph::CompareByID::operator()(Node const& _lhs, Node const& _rhs) const bool CallGraph::CompareByID::operator()(Node const& _lhs, Node const& _rhs) const
@ -25,21 +26,21 @@ bool CallGraph::CompareByID::operator()(Node const& _lhs, Node const& _rhs) cons
if (_lhs.index() != _rhs.index()) if (_lhs.index() != _rhs.index())
return _lhs.index() < _rhs.index(); return _lhs.index() < _rhs.index();
if (std::holds_alternative<SpecialNode>(_lhs)) if (holds_alternative<SpecialNode>(_lhs))
return std::get<SpecialNode>(_lhs) < std::get<SpecialNode>(_rhs); return get<SpecialNode>(_lhs) < get<SpecialNode>(_rhs);
return std::get<CallableDeclaration const*>(_lhs)->id() < std::get<CallableDeclaration const*>(_rhs)->id(); return get<CallableDeclaration const*>(_lhs)->id() < get<CallableDeclaration const*>(_rhs)->id();
} }
bool CallGraph::CompareByID::operator()(Node const& _lhs, int64_t _rhs) const bool CallGraph::CompareByID::operator()(Node const& _lhs, int64_t _rhs) const
{ {
solAssert(!std::holds_alternative<SpecialNode>(_lhs), ""); solAssert(!holds_alternative<SpecialNode>(_lhs), "");
return std::get<CallableDeclaration const*>(_lhs)->id() < _rhs; return get<CallableDeclaration const*>(_lhs)->id() < _rhs;
} }
bool CallGraph::CompareByID::operator()(int64_t _lhs, Node const& _rhs) const bool CallGraph::CompareByID::operator()(int64_t _lhs, Node const& _rhs) const
{ {
solAssert(!std::holds_alternative<SpecialNode>(_rhs), ""); solAssert(!holds_alternative<SpecialNode>(_rhs), "");
return _lhs < std::get<CallableDeclaration const*>(_rhs)->id(); return _lhs < get<CallableDeclaration const*>(_rhs)->id();
} }

View File

@ -21,6 +21,7 @@
#include <boost/algorithm/string.hpp> #include <boost/algorithm/string.hpp>
#include <boost/algorithm/string/split.hpp> #include <boost/algorithm/string/split.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::util; using namespace solidity::util;
@ -30,126 +31,126 @@ InaccessibleDynamicType const TypeProvider::m_inaccessibleDynamic{};
/// The string and bytes unique_ptrs are initialized when they are first used because /// The string and bytes unique_ptrs are initialized when they are first used because
/// they rely on `byte` being available which we cannot guarantee in the static init context. /// they rely on `byte` being available which we cannot guarantee in the static init context.
std::unique_ptr<ArrayType> TypeProvider::m_bytesStorage; unique_ptr<ArrayType> TypeProvider::m_bytesStorage;
std::unique_ptr<ArrayType> TypeProvider::m_bytesMemory; unique_ptr<ArrayType> TypeProvider::m_bytesMemory;
std::unique_ptr<ArrayType> TypeProvider::m_bytesCalldata; unique_ptr<ArrayType> TypeProvider::m_bytesCalldata;
std::unique_ptr<ArrayType> TypeProvider::m_stringStorage; unique_ptr<ArrayType> TypeProvider::m_stringStorage;
std::unique_ptr<ArrayType> TypeProvider::m_stringMemory; unique_ptr<ArrayType> TypeProvider::m_stringMemory;
TupleType const TypeProvider::m_emptyTuple{}; TupleType const TypeProvider::m_emptyTuple{};
AddressType const TypeProvider::m_payableAddress{StateMutability::Payable}; AddressType const TypeProvider::m_payableAddress{StateMutability::Payable};
AddressType const TypeProvider::m_address{StateMutability::NonPayable}; AddressType const TypeProvider::m_address{StateMutability::NonPayable};
std::array<std::unique_ptr<IntegerType>, 32> const TypeProvider::m_intM{{ array<unique_ptr<IntegerType>, 32> const TypeProvider::m_intM{{
{std::make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Signed)}, {make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Signed)},
{std::make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Signed)} {make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Signed)}
}}; }};
std::array<std::unique_ptr<IntegerType>, 32> const TypeProvider::m_uintM{{ array<unique_ptr<IntegerType>, 32> const TypeProvider::m_uintM{{
{std::make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 1, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 2, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 3, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 4, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 5, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 6, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 7, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 8, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 9, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 10, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 11, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 12, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 13, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 14, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 15, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 16, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 17, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 18, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 19, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 20, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 21, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 22, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 23, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 24, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 25, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 26, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 27, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 28, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 29, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 30, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Unsigned)}, {make_unique<IntegerType>(8 * 31, IntegerType::Modifier::Unsigned)},
{std::make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Unsigned)} {make_unique<IntegerType>(8 * 32, IntegerType::Modifier::Unsigned)}
}}; }};
std::array<std::unique_ptr<FixedBytesType>, 32> const TypeProvider::m_bytesM{{ array<unique_ptr<FixedBytesType>, 32> const TypeProvider::m_bytesM{{
{std::make_unique<FixedBytesType>(1)}, {make_unique<FixedBytesType>(1)},
{std::make_unique<FixedBytesType>(2)}, {make_unique<FixedBytesType>(2)},
{std::make_unique<FixedBytesType>(3)}, {make_unique<FixedBytesType>(3)},
{std::make_unique<FixedBytesType>(4)}, {make_unique<FixedBytesType>(4)},
{std::make_unique<FixedBytesType>(5)}, {make_unique<FixedBytesType>(5)},
{std::make_unique<FixedBytesType>(6)}, {make_unique<FixedBytesType>(6)},
{std::make_unique<FixedBytesType>(7)}, {make_unique<FixedBytesType>(7)},
{std::make_unique<FixedBytesType>(8)}, {make_unique<FixedBytesType>(8)},
{std::make_unique<FixedBytesType>(9)}, {make_unique<FixedBytesType>(9)},
{std::make_unique<FixedBytesType>(10)}, {make_unique<FixedBytesType>(10)},
{std::make_unique<FixedBytesType>(11)}, {make_unique<FixedBytesType>(11)},
{std::make_unique<FixedBytesType>(12)}, {make_unique<FixedBytesType>(12)},
{std::make_unique<FixedBytesType>(13)}, {make_unique<FixedBytesType>(13)},
{std::make_unique<FixedBytesType>(14)}, {make_unique<FixedBytesType>(14)},
{std::make_unique<FixedBytesType>(15)}, {make_unique<FixedBytesType>(15)},
{std::make_unique<FixedBytesType>(16)}, {make_unique<FixedBytesType>(16)},
{std::make_unique<FixedBytesType>(17)}, {make_unique<FixedBytesType>(17)},
{std::make_unique<FixedBytesType>(18)}, {make_unique<FixedBytesType>(18)},
{std::make_unique<FixedBytesType>(19)}, {make_unique<FixedBytesType>(19)},
{std::make_unique<FixedBytesType>(20)}, {make_unique<FixedBytesType>(20)},
{std::make_unique<FixedBytesType>(21)}, {make_unique<FixedBytesType>(21)},
{std::make_unique<FixedBytesType>(22)}, {make_unique<FixedBytesType>(22)},
{std::make_unique<FixedBytesType>(23)}, {make_unique<FixedBytesType>(23)},
{std::make_unique<FixedBytesType>(24)}, {make_unique<FixedBytesType>(24)},
{std::make_unique<FixedBytesType>(25)}, {make_unique<FixedBytesType>(25)},
{std::make_unique<FixedBytesType>(26)}, {make_unique<FixedBytesType>(26)},
{std::make_unique<FixedBytesType>(27)}, {make_unique<FixedBytesType>(27)},
{std::make_unique<FixedBytesType>(28)}, {make_unique<FixedBytesType>(28)},
{std::make_unique<FixedBytesType>(29)}, {make_unique<FixedBytesType>(29)},
{std::make_unique<FixedBytesType>(30)}, {make_unique<FixedBytesType>(30)},
{std::make_unique<FixedBytesType>(31)}, {make_unique<FixedBytesType>(31)},
{std::make_unique<FixedBytesType>(32)} {make_unique<FixedBytesType>(32)}
}}; }};
std::array<std::unique_ptr<MagicType>, 4> const TypeProvider::m_magics{{ array<unique_ptr<MagicType>, 4> const TypeProvider::m_magics{{
{std::make_unique<MagicType>(MagicType::Kind::Block)}, {make_unique<MagicType>(MagicType::Kind::Block)},
{std::make_unique<MagicType>(MagicType::Kind::Message)}, {make_unique<MagicType>(MagicType::Kind::Message)},
{std::make_unique<MagicType>(MagicType::Kind::Transaction)}, {make_unique<MagicType>(MagicType::Kind::Transaction)},
{std::make_unique<MagicType>(MagicType::Kind::ABI)} {make_unique<MagicType>(MagicType::Kind::ABI)}
// MetaType is stored separately // MetaType is stored separately
}}; }};
@ -159,7 +160,7 @@ inline void clearCache(Type const& type)
} }
template <typename T> template <typename T>
inline void clearCache(std::unique_ptr<T> const& type) inline void clearCache(unique_ptr<T> const& type)
{ {
// Some lazy-initialized types might not exist yet. // Some lazy-initialized types might not exist yet.
if (type) if (type)
@ -199,7 +200,7 @@ void TypeProvider::reset()
template <typename T, typename... Args> template <typename T, typename... Args>
inline T const* TypeProvider::createAndGet(Args&& ... _args) inline T const* TypeProvider::createAndGet(Args&& ... _args)
{ {
instance().m_generalTypes.emplace_back(std::make_unique<T>(std::forward<Args>(_args)...)); instance().m_generalTypes.emplace_back(make_unique<T>(std::forward<Args>(_args)...));
return static_cast<T const*>(instance().m_generalTypes.back().get()); return static_cast<T const*>(instance().m_generalTypes.back().get());
} }
@ -258,15 +259,15 @@ Type const* TypeProvider::fromElementaryTypeName(ElementaryTypeNameToken const&
} }
} }
Type const* TypeProvider::fromElementaryTypeName(std::string const& _name) Type const* TypeProvider::fromElementaryTypeName(string const& _name)
{ {
std::vector<std::string> nameParts; vector<string> nameParts;
boost::split(nameParts, _name, boost::is_any_of(" ")); boost::split(nameParts, _name, boost::is_any_of(" "));
solAssert(nameParts.size() == 1 || nameParts.size() == 2, "Cannot parse elementary type: " + _name); solAssert(nameParts.size() == 1 || nameParts.size() == 2, "Cannot parse elementary type: " + _name);
Token token; Token token;
unsigned short firstNum, secondNum; unsigned short firstNum, secondNum;
std::tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(nameParts[0]); tie(token, firstNum, secondNum) = TokenTraits::fromIdentifierOrKeyword(nameParts[0]);
auto t = fromElementaryTypeName(ElementaryTypeNameToken(token, firstNum, secondNum)); auto t = fromElementaryTypeName(ElementaryTypeNameToken(token, firstNum, secondNum));
if (auto* ref = dynamic_cast<ReferenceType const*>(t)) if (auto* ref = dynamic_cast<ReferenceType const*>(t))
@ -306,35 +307,35 @@ Type const* TypeProvider::fromElementaryTypeName(std::string const& _name)
ArrayType const* TypeProvider::bytesStorage() ArrayType const* TypeProvider::bytesStorage()
{ {
if (!m_bytesStorage) if (!m_bytesStorage)
m_bytesStorage = std::make_unique<ArrayType>(DataLocation::Storage, false); m_bytesStorage = make_unique<ArrayType>(DataLocation::Storage, false);
return m_bytesStorage.get(); return m_bytesStorage.get();
} }
ArrayType const* TypeProvider::bytesMemory() ArrayType const* TypeProvider::bytesMemory()
{ {
if (!m_bytesMemory) if (!m_bytesMemory)
m_bytesMemory = std::make_unique<ArrayType>(DataLocation::Memory, false); m_bytesMemory = make_unique<ArrayType>(DataLocation::Memory, false);
return m_bytesMemory.get(); return m_bytesMemory.get();
} }
ArrayType const* TypeProvider::bytesCalldata() ArrayType const* TypeProvider::bytesCalldata()
{ {
if (!m_bytesCalldata) if (!m_bytesCalldata)
m_bytesCalldata = std::make_unique<ArrayType>(DataLocation::CallData, false); m_bytesCalldata = make_unique<ArrayType>(DataLocation::CallData, false);
return m_bytesCalldata.get(); return m_bytesCalldata.get();
} }
ArrayType const* TypeProvider::stringStorage() ArrayType const* TypeProvider::stringStorage()
{ {
if (!m_stringStorage) if (!m_stringStorage)
m_stringStorage = std::make_unique<ArrayType>(DataLocation::Storage, true); m_stringStorage = make_unique<ArrayType>(DataLocation::Storage, true);
return m_stringStorage.get(); return m_stringStorage.get();
} }
ArrayType const* TypeProvider::stringMemory() ArrayType const* TypeProvider::stringMemory()
{ {
if (!m_stringMemory) if (!m_stringMemory)
m_stringMemory = std::make_unique<ArrayType>(DataLocation::Memory, true); m_stringMemory = make_unique<ArrayType>(DataLocation::Memory, true);
return m_stringMemory.get(); return m_stringMemory.get();
} }
@ -375,30 +376,30 @@ RationalNumberType const* TypeProvider::rationalNumber(Literal const& _literal)
return nullptr; return nullptr;
} }
StringLiteralType const* TypeProvider::stringLiteral(std::string const& literal) StringLiteralType const* TypeProvider::stringLiteral(string const& literal)
{ {
auto i = instance().m_stringLiteralTypes.find(literal); auto i = instance().m_stringLiteralTypes.find(literal);
if (i != instance().m_stringLiteralTypes.end()) if (i != instance().m_stringLiteralTypes.end())
return i->second.get(); return i->second.get();
else else
return instance().m_stringLiteralTypes.emplace(literal, std::make_unique<StringLiteralType>(literal)).first->second.get(); return instance().m_stringLiteralTypes.emplace(literal, make_unique<StringLiteralType>(literal)).first->second.get();
} }
FixedPointType const* TypeProvider::fixedPoint(unsigned m, unsigned n, FixedPointType::Modifier _modifier) FixedPointType const* TypeProvider::fixedPoint(unsigned m, unsigned n, FixedPointType::Modifier _modifier)
{ {
auto& map = _modifier == FixedPointType::Modifier::Unsigned ? instance().m_ufixedMxN : instance().m_fixedMxN; auto& map = _modifier == FixedPointType::Modifier::Unsigned ? instance().m_ufixedMxN : instance().m_fixedMxN;
auto i = map.find(std::make_pair(m, n)); auto i = map.find(make_pair(m, n));
if (i != map.end()) if (i != map.end())
return i->second.get(); return i->second.get();
return map.emplace( return map.emplace(
std::make_pair(m, n), make_pair(m, n),
std::make_unique<FixedPointType>(m, n, _modifier) make_unique<FixedPointType>(m, n, _modifier)
).first->second.get(); ).first->second.get();
} }
TupleType const* TypeProvider::tuple(std::vector<Type const*> members) TupleType const* TypeProvider::tuple(vector<Type const*> members)
{ {
if (members.empty()) if (members.empty())
return &m_emptyTuple; return &m_emptyTuple;

File diff suppressed because it is too large Load Diff

View File

@ -30,11 +30,12 @@
#include <boost/algorithm/string/join.hpp> #include <boost/algorithm/string/join.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::frontend; using namespace solidity::frontend;
std::string ABIFunctions::tupleEncoder( string ABIFunctions::tupleEncoder(
TypePointers const& _givenTypes, TypePointers const& _givenTypes,
TypePointers _targetTypes, TypePointers _targetTypes,
bool _encodeAsLibraryTypes, bool _encodeAsLibraryTypes,
@ -55,7 +56,7 @@ std::string ABIFunctions::tupleEncoder(
solAssert(t, ""); solAssert(t, "");
} }
std::string functionName = std::string("abi_encode_tuple_"); string functionName = string("abi_encode_tuple_");
for (auto const& t: _givenTypes) for (auto const& t: _givenTypes)
functionName += t->identifier() + "_"; functionName += t->identifier() + "_";
functionName += "_to_"; functionName += "_to_";
@ -75,8 +76,8 @@ std::string ABIFunctions::tupleEncoder(
)"); )");
templ("functionName", functionName); templ("functionName", functionName);
size_t const headSize_ = headSize(_targetTypes); size_t const headSize_ = headSize(_targetTypes);
templ("headSize", std::to_string(headSize_)); templ("headSize", to_string(headSize_));
std::string encodeElements; string encodeElements;
size_t headPos = 0; size_t headPos = 0;
size_t stackPos = 0; size_t stackPos = 0;
for (size_t i = 0; i < _givenTypes.size(); ++i) for (size_t i = 0; i < _givenTypes.size(); ++i)
@ -87,24 +88,24 @@ std::string ABIFunctions::tupleEncoder(
bool dynamic = _targetTypes[i]->isDynamicallyEncoded(); bool dynamic = _targetTypes[i]->isDynamicallyEncoded();
Whiskers elementTempl( Whiskers elementTempl(
dynamic ? dynamic ?
std::string(R"( string(R"(
mstore(add(headStart, <pos>), sub(tail, headStart)) mstore(add(headStart, <pos>), sub(tail, headStart))
tail := <abiEncode>(<values> tail) tail := <abiEncode>(<values> tail)
)") : )") :
std::string(R"( string(R"(
<abiEncode>(<values> add(headStart, <pos>)) <abiEncode>(<values> add(headStart, <pos>))
)") )")
); );
std::string values = suffixedVariableNameList("value", stackPos, stackPos + sizeOnStack); string values = suffixedVariableNameList("value", stackPos, stackPos + sizeOnStack);
elementTempl("values", values.empty() ? "" : values + ", "); elementTempl("values", values.empty() ? "" : values + ", ");
elementTempl("pos", std::to_string(headPos)); elementTempl("pos", to_string(headPos));
elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options)); elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options));
encodeElements += elementTempl.render(); encodeElements += elementTempl.render();
headPos += _targetTypes[i]->calldataHeadSize(); headPos += _targetTypes[i]->calldataHeadSize();
stackPos += sizeOnStack; stackPos += sizeOnStack;
} }
solAssert(headPos == headSize_, ""); solAssert(headPos == headSize_, "");
std::string valueParams = string valueParams =
_reversed ? _reversed ?
suffixedVariableNameList("value", stackPos, 0) : suffixedVariableNameList("value", stackPos, 0) :
suffixedVariableNameList("value", 0, stackPos); suffixedVariableNameList("value", 0, stackPos);
@ -115,7 +116,7 @@ std::string ABIFunctions::tupleEncoder(
}); });
} }
std::string ABIFunctions::tupleEncoderPacked( string ABIFunctions::tupleEncoderPacked(
TypePointers const& _givenTypes, TypePointers const& _givenTypes,
TypePointers _targetTypes, TypePointers _targetTypes,
bool _reversed bool _reversed
@ -134,7 +135,7 @@ std::string ABIFunctions::tupleEncoderPacked(
solAssert(t, ""); solAssert(t, "");
} }
std::string functionName = std::string("abi_encode_tuple_packed_"); string functionName = string("abi_encode_tuple_packed_");
for (auto const& t: _givenTypes) for (auto const& t: _givenTypes)
functionName += t->identifier() + "_"; functionName += t->identifier() + "_";
functionName += "_to_"; functionName += "_to_";
@ -153,7 +154,7 @@ std::string ABIFunctions::tupleEncoderPacked(
} }
)"); )");
templ("functionName", functionName); templ("functionName", functionName);
std::string encodeElements; string encodeElements;
size_t stackPos = 0; size_t stackPos = 0;
for (size_t i = 0; i < _givenTypes.size(); ++i) for (size_t i = 0; i < _givenTypes.size(); ++i)
{ {
@ -163,23 +164,23 @@ std::string ABIFunctions::tupleEncoderPacked(
bool dynamic = _targetTypes[i]->isDynamicallyEncoded(); bool dynamic = _targetTypes[i]->isDynamicallyEncoded();
Whiskers elementTempl( Whiskers elementTempl(
dynamic ? dynamic ?
std::string(R"( string(R"(
pos := <abiEncode>(<values> pos) pos := <abiEncode>(<values> pos)
)") : )") :
std::string(R"( string(R"(
<abiEncode>(<values> pos) <abiEncode>(<values> pos)
pos := add(pos, <calldataEncodedSize>) pos := add(pos, <calldataEncodedSize>)
)") )")
); );
std::string values = suffixedVariableNameList("value", stackPos, stackPos + sizeOnStack); string values = suffixedVariableNameList("value", stackPos, stackPos + sizeOnStack);
elementTempl("values", values.empty() ? "" : values + ", "); elementTempl("values", values.empty() ? "" : values + ", ");
if (!dynamic) if (!dynamic)
elementTempl("calldataEncodedSize", std::to_string(_targetTypes[i]->calldataEncodedSize(false))); elementTempl("calldataEncodedSize", to_string(_targetTypes[i]->calldataEncodedSize(false)));
elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options)); elementTempl("abiEncode", abiEncodingFunction(*_givenTypes[i], *_targetTypes[i], options));
encodeElements += elementTempl.render(); encodeElements += elementTempl.render();
stackPos += sizeOnStack; stackPos += sizeOnStack;
} }
std::string valueParams = string valueParams =
_reversed ? _reversed ?
suffixedVariableNameList("value", stackPos, 0) : suffixedVariableNameList("value", stackPos, 0) :
suffixedVariableNameList("value", 0, stackPos); suffixedVariableNameList("value", 0, stackPos);
@ -189,9 +190,9 @@ std::string ABIFunctions::tupleEncoderPacked(
return templ.render(); return templ.render();
}); });
} }
std::string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory) string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMemory)
{ {
std::string functionName = std::string("abi_decode_tuple_"); string functionName = string("abi_decode_tuple_");
for (auto const& t: _types) for (auto const& t: _types)
functionName += t->identifier(); functionName += t->identifier();
if (_fromMemory) if (_fromMemory)
@ -210,10 +211,10 @@ std::string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMem
)"); )");
templ("functionName", functionName); templ("functionName", functionName);
templ("revertString", revertReasonIfDebugFunction("ABI decoding: tuple data too short")); templ("revertString", revertReasonIfDebugFunction("ABI decoding: tuple data too short"));
templ("minimumSize", std::to_string(headSize(decodingTypes))); templ("minimumSize", to_string(headSize(decodingTypes)));
std::string decodeElements; string decodeElements;
std::vector<std::string> valueReturnParams; vector<string> valueReturnParams;
size_t headPos = 0; size_t headPos = 0;
size_t stackPos = 0; size_t stackPos = 0;
for (size_t i = 0; i < _types.size(); ++i) for (size_t i = 0; i < _types.size(); ++i)
@ -223,11 +224,11 @@ std::string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMem
size_t sizeOnStack = _types[i]->sizeOnStack(); size_t sizeOnStack = _types[i]->sizeOnStack();
solAssert(sizeOnStack == decodingTypes[i]->sizeOnStack(), ""); solAssert(sizeOnStack == decodingTypes[i]->sizeOnStack(), "");
solAssert(sizeOnStack > 0, ""); solAssert(sizeOnStack > 0, "");
std::vector<std::string> valueNamesLocal; vector<string> valueNamesLocal;
for (size_t j = 0; j < sizeOnStack; j++) for (size_t j = 0; j < sizeOnStack; j++)
{ {
valueNamesLocal.emplace_back("value" + std::to_string(stackPos)); valueNamesLocal.emplace_back("value" + to_string(stackPos));
valueReturnParams.emplace_back("value" + std::to_string(stackPos)); valueReturnParams.emplace_back("value" + to_string(stackPos));
stackPos++; stackPos++;
} }
Whiskers elementTempl(R"( Whiskers elementTempl(R"(
@ -246,7 +247,7 @@ std::string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMem
elementTempl("revertString", revertReasonIfDebugFunction("ABI decoding: invalid tuple offset")); elementTempl("revertString", revertReasonIfDebugFunction("ABI decoding: invalid tuple offset"));
elementTempl("load", _fromMemory ? "mload" : "calldataload"); elementTempl("load", _fromMemory ? "mload" : "calldataload");
elementTempl("values", boost::algorithm::join(valueNamesLocal, ", ")); elementTempl("values", boost::algorithm::join(valueNamesLocal, ", "));
elementTempl("pos", std::to_string(headPos)); elementTempl("pos", to_string(headPos));
elementTempl("abiDecode", abiDecodingFunction(*_types[i], _fromMemory, true)); elementTempl("abiDecode", abiDecodingFunction(*_types[i], _fromMemory, true));
decodeElements += elementTempl.render(); decodeElements += elementTempl.render();
headPos += decodingTypes[i]->calldataHeadSize(); headPos += decodingTypes[i]->calldataHeadSize();
@ -259,9 +260,9 @@ std::string ABIFunctions::tupleDecoder(TypePointers const& _types, bool _fromMem
}); });
} }
std::string ABIFunctions::EncodingOptions::toFunctionNameSuffix() const string ABIFunctions::EncodingOptions::toFunctionNameSuffix() const
{ {
std::string suffix; string suffix;
if (!padded) if (!padded)
suffix += "_nonPadded"; suffix += "_nonPadded";
if (dynamicInplace) if (dynamicInplace)
@ -273,7 +274,7 @@ std::string ABIFunctions::EncodingOptions::toFunctionNameSuffix() const
return suffix; return suffix;
} }
std::string ABIFunctions::abiEncodingFunction( string ABIFunctions::abiEncodingFunction(
Type const& _from, Type const& _from,
Type const& _to, Type const& _to,
EncodingOptions const& _options EncodingOptions const& _options
@ -348,7 +349,7 @@ std::string ABIFunctions::abiEncodingFunction(
solAssert(_from.sizeOnStack() == 1, ""); solAssert(_from.sizeOnStack() == 1, "");
solAssert(to.isValueType(), ""); solAssert(to.isValueType(), "");
solAssert(to.calldataEncodedSize() == 32, ""); solAssert(to.calldataEncodedSize() == 32, "");
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -375,7 +376,7 @@ std::string ABIFunctions::abiEncodingFunction(
} }
else else
{ {
std::string cleanupConvert; string cleanupConvert;
if (_from == to) if (_from == to)
cleanupConvert = m_utils.cleanupFunction(_from) + "(value)"; cleanupConvert = m_utils.cleanupFunction(_from) + "(value)";
else else
@ -388,21 +389,21 @@ std::string ABIFunctions::abiEncodingFunction(
}); });
} }
std::string ABIFunctions::abiEncodeAndReturnUpdatedPosFunction( string ABIFunctions::abiEncodeAndReturnUpdatedPosFunction(
Type const& _givenType, Type const& _givenType,
Type const& _targetType, Type const& _targetType,
ABIFunctions::EncodingOptions const& _options ABIFunctions::EncodingOptions const& _options
) )
{ {
std::string functionName = string functionName =
"abi_encodeUpdatedPos_" + "abi_encodeUpdatedPos_" +
_givenType.identifier() + _givenType.identifier() +
"_to_" + "_to_" +
_targetType.identifier() + _targetType.identifier() +
_options.toFunctionNameSuffix(); _options.toFunctionNameSuffix();
return createFunction(functionName, [&]() { return createFunction(functionName, [&]() {
std::string values = suffixedVariableNameList("value", 0, numVariablesForType(_givenType, _options)); string values = suffixedVariableNameList("value", 0, numVariablesForType(_givenType, _options));
std::string encoder = abiEncodingFunction(_givenType, _targetType, _options); string encoder = abiEncodingFunction(_givenType, _targetType, _options);
Type const* targetEncoding = _targetType.fullEncodingType(_options.encodeAsLibraryTypes, true, false); Type const* targetEncoding = _targetType.fullEncodingType(_options.encodeAsLibraryTypes, true, false);
solAssert(targetEncoding, ""); solAssert(targetEncoding, "");
if (targetEncoding->isDynamicallyEncoded()) if (targetEncoding->isDynamicallyEncoded())
@ -434,7 +435,7 @@ std::string ABIFunctions::abiEncodeAndReturnUpdatedPosFunction(
}); });
} }
std::string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup( string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
Type const& _from, Type const& _from,
Type const& _to, Type const& _to,
EncodingOptions const& _options EncodingOptions const& _options
@ -460,7 +461,7 @@ std::string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
"" ""
); );
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -521,13 +522,13 @@ std::string ABIFunctions::abiEncodingFunctionCalldataArrayWithoutCleanup(
}); });
} }
std::string ABIFunctions::abiEncodingFunctionSimpleArray( string ABIFunctions::abiEncodingFunctionSimpleArray(
ArrayType const& _from, ArrayType const& _from,
ArrayType const& _to, ArrayType const& _to,
EncodingOptions const& _options EncodingOptions const& _options
) )
{ {
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -547,7 +548,7 @@ std::string ABIFunctions::abiEncodingFunctionSimpleArray(
EncodingOptions subOptions(_options); EncodingOptions subOptions(_options);
subOptions.encodeFunctionFromStack = false; subOptions.encodeFunctionFromStack = false;
subOptions.padded = true; subOptions.padded = true;
std::string elementValues = suffixedVariableNameList("elementValue", 0, numVariablesForType(*_from.baseType(), subOptions)); string elementValues = suffixedVariableNameList("elementValue", 0, numVariablesForType(*_from.baseType(), subOptions));
Whiskers templ( Whiskers templ(
usesTail ? usesTail ?
R"( R"(
@ -631,13 +632,13 @@ std::string ABIFunctions::abiEncodingFunctionSimpleArray(
}); });
} }
std::string ABIFunctions::abiEncodingFunctionMemoryByteArray( string ABIFunctions::abiEncodingFunctionMemoryByteArray(
ArrayType const& _from, ArrayType const& _from,
ArrayType const& _to, ArrayType const& _to,
EncodingOptions const& _options EncodingOptions const& _options
) )
{ {
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -668,13 +669,13 @@ std::string ABIFunctions::abiEncodingFunctionMemoryByteArray(
}); });
} }
std::string ABIFunctions::abiEncodingFunctionCompactStorageArray( string ABIFunctions::abiEncodingFunctionCompactStorageArray(
ArrayType const& _from, ArrayType const& _from,
ArrayType const& _to, ArrayType const& _to,
EncodingOptions const& _options EncodingOptions const& _options
) )
{ {
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -790,13 +791,13 @@ std::string ABIFunctions::abiEncodingFunctionCompactStorageArray(
templ("useSpill", "1"); templ("useSpill", "1");
else else
templ("useSpill", "0"); templ("useSpill", "0");
templ("itemsPerSlot", std::to_string(itemsPerSlot)); templ("itemsPerSlot", to_string(itemsPerSlot));
templ("stride", toCompactHexWithPrefix(_to.calldataStride())); templ("stride", toCompactHexWithPrefix(_to.calldataStride()));
EncodingOptions subOptions(_options); EncodingOptions subOptions(_options);
subOptions.encodeFunctionFromStack = false; subOptions.encodeFunctionFromStack = false;
subOptions.padded = true; subOptions.padded = true;
std::string encodeToMemoryFun = abiEncodingFunction( string encodeToMemoryFun = abiEncodingFunction(
*_from.baseType(), *_from.baseType(),
*_to.baseType(), *_to.baseType(),
subOptions subOptions
@ -819,13 +820,13 @@ std::string ABIFunctions::abiEncodingFunctionCompactStorageArray(
}); });
} }
std::string ABIFunctions::abiEncodingFunctionStruct( string ABIFunctions::abiEncodingFunctionStruct(
StructType const& _from, StructType const& _from,
StructType const& _to, StructType const& _to,
EncodingOptions const& _options EncodingOptions const& _options
) )
{ {
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -866,7 +867,7 @@ std::string ABIFunctions::abiEncodingFunctionStruct(
templ("init", _from.dataStoredIn(DataLocation::Storage) ? "let slotValue := 0" : ""); templ("init", _from.dataStoredIn(DataLocation::Storage) ? "let slotValue := 0" : "");
u256 previousSlotOffset(-1); u256 previousSlotOffset(-1);
u256 encodingOffset = 0; u256 encodingOffset = 0;
std::vector<std::map<std::string, std::string>> members; vector<map<string, string>> members;
for (auto const& member: _to.members(nullptr)) for (auto const& member: _to.members(nullptr))
{ {
solAssert(member.type, ""); solAssert(member.type, "");
@ -889,7 +890,7 @@ std::string ABIFunctions::abiEncodingFunctionStruct(
solAssert(memberTypeFrom->isValueType() == memberTypeTo->isValueType(), ""); solAssert(memberTypeFrom->isValueType() == memberTypeTo->isValueType(), "");
u256 storageSlotOffset; u256 storageSlotOffset;
size_t intraSlotOffset; size_t intraSlotOffset;
std::tie(storageSlotOffset, intraSlotOffset) = _from.storageOffsetsOfMember(member.name); tie(storageSlotOffset, intraSlotOffset) = _from.storageOffsetsOfMember(member.name);
if (memberTypeFrom->isValueType()) if (memberTypeFrom->isValueType())
{ {
if (storageSlotOffset != previousSlotOffset) if (storageSlotOffset != previousSlotOffset)
@ -909,13 +910,13 @@ std::string ABIFunctions::abiEncodingFunctionStruct(
} }
case DataLocation::Memory: case DataLocation::Memory:
{ {
std::string sourceOffset = toCompactHexWithPrefix(_from.memoryOffsetOfMember(member.name)); string sourceOffset = toCompactHexWithPrefix(_from.memoryOffsetOfMember(member.name));
members.back()["retrieveValue"] = "mload(add(value, " + sourceOffset + "))"; members.back()["retrieveValue"] = "mload(add(value, " + sourceOffset + "))";
break; break;
} }
case DataLocation::CallData: case DataLocation::CallData:
{ {
std::string sourceOffset = toCompactHexWithPrefix(_from.calldataOffsetOfMember(member.name)); string sourceOffset = toCompactHexWithPrefix(_from.calldataOffsetOfMember(member.name));
members.back()["retrieveValue"] = calldataAccessFunction(*memberTypeFrom) + "(value, add(value, " + sourceOffset + "))"; members.back()["retrieveValue"] = calldataAccessFunction(*memberTypeFrom) + "(value, add(value, " + sourceOffset + "))";
break; break;
} }
@ -928,10 +929,10 @@ std::string ABIFunctions::abiEncodingFunctionStruct(
// Like with arrays, struct members are always padded. // Like with arrays, struct members are always padded.
subOptions.padded = true; subOptions.padded = true;
std::string memberValues = suffixedVariableNameList("memberValue", 0, numVariablesForType(*memberTypeFrom, subOptions)); string memberValues = suffixedVariableNameList("memberValue", 0, numVariablesForType(*memberTypeFrom, subOptions));
members.back()["memberValues"] = memberValues; members.back()["memberValues"] = memberValues;
std::string encode; string encode;
if (_options.dynamicInplace) if (_options.dynamicInplace)
encode = Whiskers{"pos := <encode>(<memberValues>, pos)"} encode = Whiskers{"pos := <encode>(<memberValues>, pos)"}
("encode", abiEncodeAndReturnUpdatedPosFunction(*memberTypeFrom, *memberTypeTo, subOptions)) ("encode", abiEncodeAndReturnUpdatedPosFunction(*memberTypeFrom, *memberTypeTo, subOptions))
@ -941,7 +942,7 @@ std::string ABIFunctions::abiEncodingFunctionStruct(
{ {
Whiskers encodeTempl( Whiskers encodeTempl(
dynamicMember ? dynamicMember ?
std::string(R"( string(R"(
mstore(add(pos, <encodingOffset>), sub(tail, pos)) mstore(add(pos, <encodingOffset>), sub(tail, pos))
tail := <abiEncode>(<memberValues>, tail) tail := <abiEncode>(<memberValues>, tail)
)") : )") :
@ -965,7 +966,7 @@ std::string ABIFunctions::abiEncodingFunctionStruct(
}); });
} }
std::string ABIFunctions::abiEncodingFunctionStringLiteral( string ABIFunctions::abiEncodingFunctionStringLiteral(
Type const& _from, Type const& _from,
Type const& _to, Type const& _to,
EncodingOptions const& _options EncodingOptions const& _options
@ -973,7 +974,7 @@ std::string ABIFunctions::abiEncodingFunctionStringLiteral(
{ {
solAssert(_from.category() == Type::Category::StringLiteral, ""); solAssert(_from.category() == Type::Category::StringLiteral, "");
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -981,7 +982,7 @@ std::string ABIFunctions::abiEncodingFunctionStringLiteral(
_options.toFunctionNameSuffix(); _options.toFunctionNameSuffix();
return createFunction(functionName, [&]() { return createFunction(functionName, [&]() {
auto const& strType = dynamic_cast<StringLiteralType const&>(_from); auto const& strType = dynamic_cast<StringLiteralType const&>(_from);
std::string const& value = strType.value(); string const& value = strType.value();
solAssert(_from.sizeOnStack() == 0, ""); solAssert(_from.sizeOnStack() == 0, "");
if (_to.isDynamicallySized()) if (_to.isDynamicallySized())
@ -997,12 +998,12 @@ std::string ABIFunctions::abiEncodingFunctionStringLiteral(
templ("functionName", functionName); templ("functionName", functionName);
// TODO this can make use of CODECOPY for large strings once we have that in Yul // TODO this can make use of CODECOPY for large strings once we have that in Yul
templ("length", std::to_string(value.size())); templ("length", to_string(value.size()));
templ("storeLength", arrayStoreLengthForEncodingFunction(dynamic_cast<ArrayType const&>(_to), _options)); templ("storeLength", arrayStoreLengthForEncodingFunction(dynamic_cast<ArrayType const&>(_to), _options));
if (_options.padded) if (_options.padded)
templ("overallSize", std::to_string(((value.size() + 31) / 32) * 32)); templ("overallSize", to_string(((value.size() + 31) / 32) * 32));
else else
templ("overallSize", std::to_string(value.size())); templ("overallSize", to_string(value.size()));
templ("storeLiteralInMemory", m_utils.storeLiteralInMemoryFunction(value)); templ("storeLiteralInMemory", m_utils.storeLiteralInMemoryFunction(value));
return templ.render(); return templ.render();
} }
@ -1022,7 +1023,7 @@ std::string ABIFunctions::abiEncodingFunctionStringLiteral(
}); });
} }
std::string ABIFunctions::abiEncodingFunctionFunctionType( string ABIFunctions::abiEncodingFunctionFunctionType(
FunctionType const& _from, FunctionType const& _from,
Type const& _to, Type const& _to,
EncodingOptions const& _options EncodingOptions const& _options
@ -1035,7 +1036,7 @@ std::string ABIFunctions::abiEncodingFunctionFunctionType(
"Invalid function type conversion requested" "Invalid function type conversion requested"
); );
std::string functionName = string functionName =
"abi_encode_" + "abi_encode_" +
_from.identifier() + _from.identifier() +
"_to_" + "_to_" +
@ -1068,7 +1069,7 @@ std::string ABIFunctions::abiEncodingFunctionFunctionType(
}); });
} }
std::string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bool _forUseOnStack) string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemory, bool _forUseOnStack)
{ {
// The decoding function has to perform bounds checks unless it decodes a value type. // The decoding function has to perform bounds checks unless it decodes a value type.
// Conversely, bounds checks have to be performed before the decoding function // Conversely, bounds checks have to be performed before the decoding function
@ -1103,7 +1104,7 @@ std::string ABIFunctions::abiDecodingFunction(Type const& _type, bool _fromMemor
return abiDecodingFunctionValueType(_type, _fromMemory); return abiDecodingFunctionValueType(_type, _fromMemory);
} }
std::string ABIFunctions::abiDecodingFunctionValueType(Type const& _type, bool _fromMemory) string ABIFunctions::abiDecodingFunctionValueType(Type const& _type, bool _fromMemory)
{ {
Type const* decodingType = _type.decodingType(); Type const* decodingType = _type.decodingType();
solAssert(decodingType, ""); solAssert(decodingType, "");
@ -1112,7 +1113,7 @@ std::string ABIFunctions::abiDecodingFunctionValueType(Type const& _type, bool _
solAssert(!decodingType->isDynamicallyEncoded(), ""); solAssert(!decodingType->isDynamicallyEncoded(), "");
solAssert(decodingType->calldataEncodedSize() == 32, ""); solAssert(decodingType->calldataEncodedSize() == 32, "");
std::string functionName = string functionName =
"abi_decode_" + "abi_decode_" +
_type.identifier() + _type.identifier() +
(_fromMemory ? "_fromMemory" : ""); (_fromMemory ? "_fromMemory" : "");
@ -1133,17 +1134,17 @@ std::string ABIFunctions::abiDecodingFunctionValueType(Type const& _type, bool _
} }
std::string ABIFunctions::abiDecodingFunctionArray(ArrayType const& _type, bool _fromMemory) string ABIFunctions::abiDecodingFunctionArray(ArrayType const& _type, bool _fromMemory)
{ {
solAssert(_type.dataStoredIn(DataLocation::Memory), ""); solAssert(_type.dataStoredIn(DataLocation::Memory), "");
std::string functionName = string functionName =
"abi_decode_" + "abi_decode_" +
_type.identifier() + _type.identifier() +
(_fromMemory ? "_fromMemory" : ""); (_fromMemory ? "_fromMemory" : "");
return createFunction(functionName, [&]() { return createFunction(functionName, [&]() {
std::string load = _fromMemory ? "mload" : "calldataload"; string load = _fromMemory ? "mload" : "calldataload";
Whiskers templ( Whiskers templ(
R"( R"(
// <readableTypeName> // <readableTypeName>
@ -1165,14 +1166,14 @@ std::string ABIFunctions::abiDecodingFunctionArray(ArrayType const& _type, bool
}); });
} }
std::string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory) string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType const& _type, bool _fromMemory)
{ {
solAssert(_type.dataStoredIn(DataLocation::Memory), ""); solAssert(_type.dataStoredIn(DataLocation::Memory), "");
if (_type.isByteArrayOrString()) if (_type.isByteArrayOrString())
return abiDecodingFunctionByteArrayAvailableLength(_type, _fromMemory); return abiDecodingFunctionByteArrayAvailableLength(_type, _fromMemory);
solAssert(_type.calldataStride() > 0, ""); solAssert(_type.calldataStride() > 0, "");
std::string functionName = string functionName =
"abi_decode_available_length_" + "abi_decode_available_length_" +
_type.identifier() + _type.identifier() +
(_fromMemory ? "_fromMemory" : ""); (_fromMemory ? "_fromMemory" : "");
@ -1223,7 +1224,7 @@ std::string ABIFunctions::abiDecodingFunctionArrayAvailableLength(ArrayType cons
}); });
} }
std::string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _type) string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _type)
{ {
solAssert(_type.dataStoredIn(DataLocation::CallData), ""); solAssert(_type.dataStoredIn(DataLocation::CallData), "");
if (!_type.isDynamicallySized()) if (!_type.isDynamicallySized())
@ -1231,7 +1232,7 @@ std::string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _typ
solAssert(_type.calldataStride() > 0, ""); solAssert(_type.calldataStride() > 0, "");
solAssert(_type.calldataStride() < u256("0xffffffffffffffff"), ""); solAssert(_type.calldataStride() < u256("0xffffffffffffffff"), "");
std::string functionName = string functionName =
"abi_decode_" + "abi_decode_" +
_type.identifier(); _type.identifier();
return createFunction(functionName, [&]() { return createFunction(functionName, [&]() {
@ -1272,12 +1273,12 @@ std::string ABIFunctions::abiDecodingFunctionCalldataArray(ArrayType const& _typ
}); });
} }
std::string ABIFunctions::abiDecodingFunctionByteArrayAvailableLength(ArrayType const& _type, bool _fromMemory) string ABIFunctions::abiDecodingFunctionByteArrayAvailableLength(ArrayType const& _type, bool _fromMemory)
{ {
solAssert(_type.dataStoredIn(DataLocation::Memory), ""); solAssert(_type.dataStoredIn(DataLocation::Memory), "");
solAssert(_type.isByteArrayOrString(), ""); solAssert(_type.isByteArrayOrString(), "");
std::string functionName = string functionName =
"abi_decode_available_length_" + "abi_decode_available_length_" +
_type.identifier() + _type.identifier() +
(_fromMemory ? "_fromMemory" : ""); (_fromMemory ? "_fromMemory" : "");
@ -1301,10 +1302,10 @@ std::string ABIFunctions::abiDecodingFunctionByteArrayAvailableLength(ArrayType
}); });
} }
std::string ABIFunctions::abiDecodingFunctionCalldataStruct(StructType const& _type) string ABIFunctions::abiDecodingFunctionCalldataStruct(StructType const& _type)
{ {
solAssert(_type.dataStoredIn(DataLocation::CallData), ""); solAssert(_type.dataStoredIn(DataLocation::CallData), "");
std::string functionName = string functionName =
"abi_decode_" + "abi_decode_" +
_type.identifier(); _type.identifier();
@ -1320,15 +1321,15 @@ std::string ABIFunctions::abiDecodingFunctionCalldataStruct(StructType const& _t
w("revertString", revertReasonIfDebugFunction("ABI decoding: struct calldata too short")); w("revertString", revertReasonIfDebugFunction("ABI decoding: struct calldata too short"));
w("functionName", functionName); w("functionName", functionName);
w("readableTypeName", _type.toString(true)); w("readableTypeName", _type.toString(true));
w("minimumSize", std::to_string(_type.isDynamicallyEncoded() ? _type.calldataEncodedTailSize() : _type.calldataEncodedSize(true))); w("minimumSize", to_string(_type.isDynamicallyEncoded() ? _type.calldataEncodedTailSize() : _type.calldataEncodedSize(true)));
return w.render(); return w.render();
}); });
} }
std::string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, bool _fromMemory) string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, bool _fromMemory)
{ {
solAssert(!_type.dataStoredIn(DataLocation::CallData), ""); solAssert(!_type.dataStoredIn(DataLocation::CallData), "");
std::string functionName = string functionName =
"abi_decode_" + "abi_decode_" +
_type.identifier() + _type.identifier() +
(_fromMemory ? "_fromMemory" : ""); (_fromMemory ? "_fromMemory" : "");
@ -1355,7 +1356,7 @@ std::string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, boo
solAssert(_type.memoryDataSize() < u256("0xffffffffffffffff"), ""); solAssert(_type.memoryDataSize() < u256("0xffffffffffffffff"), "");
templ("memorySize", toCompactHexWithPrefix(_type.memoryDataSize())); templ("memorySize", toCompactHexWithPrefix(_type.memoryDataSize()));
size_t headPos = 0; size_t headPos = 0;
std::vector<std::map<std::string, std::string>> members; vector<map<string, string>> members;
for (auto const& member: _type.members(nullptr)) for (auto const& member: _type.members(nullptr))
{ {
solAssert(member.type, ""); solAssert(member.type, "");
@ -1375,7 +1376,7 @@ std::string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, boo
// TODO add test // TODO add test
memberTempl("revertString", revertReasonIfDebugFunction("ABI decoding: invalid struct offset")); memberTempl("revertString", revertReasonIfDebugFunction("ABI decoding: invalid struct offset"));
memberTempl("load", _fromMemory ? "mload" : "calldataload"); memberTempl("load", _fromMemory ? "mload" : "calldataload");
memberTempl("pos", std::to_string(headPos)); memberTempl("pos", to_string(headPos));
memberTempl("memoryOffset", toCompactHexWithPrefix(_type.memoryOffsetOfMember(member.name))); memberTempl("memoryOffset", toCompactHexWithPrefix(_type.memoryOffsetOfMember(member.name)));
memberTempl("abiDecode", abiDecodingFunction(*member.type, _fromMemory, false)); memberTempl("abiDecode", abiDecodingFunction(*member.type, _fromMemory, false));
@ -1390,11 +1391,11 @@ std::string ABIFunctions::abiDecodingFunctionStruct(StructType const& _type, boo
}); });
} }
std::string ABIFunctions::abiDecodingFunctionFunctionType(FunctionType const& _type, bool _fromMemory, bool _forUseOnStack) string ABIFunctions::abiDecodingFunctionFunctionType(FunctionType const& _type, bool _fromMemory, bool _forUseOnStack)
{ {
solAssert(_type.kind() == FunctionType::Kind::External, ""); solAssert(_type.kind() == FunctionType::Kind::External, "");
std::string functionName = string functionName =
"abi_decode_" + "abi_decode_" +
_type.identifier() + _type.identifier() +
(_fromMemory ? "_fromMemory" : "") + (_fromMemory ? "_fromMemory" : "") +
@ -1429,10 +1430,10 @@ std::string ABIFunctions::abiDecodingFunctionFunctionType(FunctionType const& _t
}); });
} }
std::string ABIFunctions::calldataAccessFunction(Type const& _type) string ABIFunctions::calldataAccessFunction(Type const& _type)
{ {
solAssert(_type.isValueType() || _type.dataStoredIn(DataLocation::CallData), ""); solAssert(_type.isValueType() || _type.dataStoredIn(DataLocation::CallData), "");
std::string functionName = "calldata_access_" + _type.identifier(); string functionName = "calldata_access_" + _type.identifier();
return createFunction(functionName, [&]() { return createFunction(functionName, [&]() {
if (_type.isDynamicallyEncoded()) if (_type.isDynamicallyEncoded())
{ {
@ -1476,7 +1477,7 @@ std::string ABIFunctions::calldataAccessFunction(Type const& _type)
} }
else if (_type.isValueType()) else if (_type.isValueType())
{ {
std::string decodingFunction; string decodingFunction;
if (auto const* functionType = dynamic_cast<FunctionType const*>(&_type)) if (auto const* functionType = dynamic_cast<FunctionType const*>(&_type))
decodingFunction = abiDecodingFunctionFunctionType(*functionType, false, false); decodingFunction = abiDecodingFunctionFunctionType(*functionType, false, false);
else else
@ -1509,9 +1510,9 @@ std::string ABIFunctions::calldataAccessFunction(Type const& _type)
}); });
} }
std::string ABIFunctions::arrayStoreLengthForEncodingFunction(ArrayType const& _type, EncodingOptions const& _options) string ABIFunctions::arrayStoreLengthForEncodingFunction(ArrayType const& _type, EncodingOptions const& _options)
{ {
std::string functionName = "array_storeLengthForEncoding_" + _type.identifier() + _options.toFunctionNameSuffix(); string functionName = "array_storeLengthForEncoding_" + _type.identifier() + _options.toFunctionNameSuffix();
return createFunction(functionName, [&]() { return createFunction(functionName, [&]() {
if (_type.isDynamicallySized() && !_options.dynamicInplace) if (_type.isDynamicallySized() && !_options.dynamicInplace)
return Whiskers(R"( return Whiskers(R"(
@ -1533,7 +1534,7 @@ std::string ABIFunctions::arrayStoreLengthForEncodingFunction(ArrayType const& _
}); });
} }
std::string ABIFunctions::createFunction(std::string const& _name, std::function<std::string ()> const& _creator) string ABIFunctions::createFunction(string const& _name, function<string ()> const& _creator)
{ {
return m_functionCollector.createFunction(_name, _creator); return m_functionCollector.createFunction(_name, _creator);
} }

View File

@ -36,6 +36,7 @@
#include <libevmasm/Instruction.h> #include <libevmasm/Instruction.h>
#include <liblangutil/Exceptions.h> #include <liblangutil/Exceptions.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::evmasm; using namespace solidity::evmasm;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -313,7 +314,7 @@ void ArrayUtils::copyArrayToMemory(ArrayType const& _sourceType, bool _padToWord
if (!_sourceType.isByteArrayOrString()) if (!_sourceType.isByteArrayOrString())
convertLengthToSize(_sourceType); convertLengthToSize(_sourceType);
std::string routine = "calldatacopy(target, source, len)\n"; string routine = "calldatacopy(target, source, len)\n";
if (_padToWordBoundaries) if (_padToWordBoundaries)
routine += R"( routine += R"(
// Set padding suffix to zero // Set padding suffix to zero
@ -889,7 +890,7 @@ void ArrayUtils::popStorageArrayElement(ArrayType const& _type) const
sstore(ref, slot_value) sstore(ref, slot_value)
})"); })");
code("panicSelector", util::selectorFromSignatureU256("Panic(uint256)").str()); code("panicSelector", util::selectorFromSignatureU256("Panic(uint256)").str());
code("emptyArrayPop", std::to_string(unsigned(util::PanicCode::EmptyArrayPop))); code("emptyArrayPop", to_string(unsigned(util::PanicCode::EmptyArrayPop)));
m_context.appendInlineAssembly(code.render(), {"ref", "slot_value", "length"}); m_context.appendInlineAssembly(code.render(), {"ref", "slot_value", "length"});
m_context << Instruction::POP << Instruction::POP << Instruction::POP; m_context << Instruction::POP << Instruction::POP << Instruction::POP;
} }

View File

@ -26,12 +26,13 @@
#include <libsolidity/codegen/ContractCompiler.h> #include <libsolidity/codegen/ContractCompiler.h>
#include <libevmasm/Assembly.h> #include <libevmasm/Assembly.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
void Compiler::compileContract( void Compiler::compileContract(
ContractDefinition const& _contract, ContractDefinition const& _contract,
std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers, std::map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers,
bytes const& _metadata bytes const& _metadata
) )
{ {

View File

@ -55,6 +55,7 @@
#undef SOL_OUTPUT_ASM #undef SOL_OUTPUT_ASM
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::evmasm; using namespace solidity::evmasm;
@ -67,7 +68,7 @@ void CompilerContext::addStateVariable(
unsigned _byteOffset unsigned _byteOffset
) )
{ {
m_stateVariables[&_declaration] = std::make_pair(_storageOffset, _byteOffset); m_stateVariables[&_declaration] = make_pair(_storageOffset, _byteOffset);
} }
void CompilerContext::addImmutable(VariableDeclaration const& _variable) void CompilerContext::addImmutable(VariableDeclaration const& _variable)
@ -87,14 +88,14 @@ size_t CompilerContext::immutableMemoryOffset(VariableDeclaration const& _variab
return m_immutableVariables.at(&_variable); return m_immutableVariables.at(&_variable);
} }
std::vector<std::string> CompilerContext::immutableVariableSlotNames(VariableDeclaration const& _variable) vector<string> CompilerContext::immutableVariableSlotNames(VariableDeclaration const& _variable)
{ {
std::string baseName = std::to_string(_variable.id()); string baseName = to_string(_variable.id());
solAssert(_variable.annotation().type->sizeOnStack() > 0, ""); solAssert(_variable.annotation().type->sizeOnStack() > 0, "");
if (_variable.annotation().type->sizeOnStack() == 1) if (_variable.annotation().type->sizeOnStack() == 1)
return {baseName}; return {baseName};
std::vector<std::string> names; vector<string> names;
auto collectSlotNames = [&](std::string const& _baseName, Type const* type, auto const& _recurse) -> void { auto collectSlotNames = [&](string const& _baseName, Type const* type, auto const& _recurse) -> void {
for (auto const& [slot, type]: type->stackItems()) for (auto const& [slot, type]: type->stackItems())
if (type) if (type)
_recurse(_baseName + " " + slot, type, _recurse); _recurse(_baseName + " " + slot, type, _recurse);
@ -120,10 +121,10 @@ void CompilerContext::startFunction(Declaration const& _function)
} }
void CompilerContext::callLowLevelFunction( void CompilerContext::callLowLevelFunction(
std::string const& _name, string const& _name,
unsigned _inArgs, unsigned _inArgs,
unsigned _outArgs, unsigned _outArgs,
std::function<void(CompilerContext&)> const& _generator function<void(CompilerContext&)> const& _generator
) )
{ {
evmasm::AssemblyItem retTag = pushNewTag(); evmasm::AssemblyItem retTag = pushNewTag();
@ -137,7 +138,7 @@ void CompilerContext::callLowLevelFunction(
} }
void CompilerContext::callYulFunction( void CompilerContext::callYulFunction(
std::string const& _name, string const& _name,
unsigned _inArgs, unsigned _inArgs,
unsigned _outArgs unsigned _outArgs
) )
@ -151,10 +152,10 @@ void CompilerContext::callYulFunction(
} }
evmasm::AssemblyItem CompilerContext::lowLevelFunctionTag( evmasm::AssemblyItem CompilerContext::lowLevelFunctionTag(
std::string const& _name, string const& _name,
unsigned _inArgs, unsigned _inArgs,
unsigned _outArgs, unsigned _outArgs,
std::function<void(CompilerContext&)> const& _generator function<void(CompilerContext&)> const& _generator
) )
{ {
auto it = m_lowLevelFunctions.find(_name); auto it = m_lowLevelFunctions.find(_name);
@ -173,10 +174,10 @@ void CompilerContext::appendMissingLowLevelFunctions()
{ {
while (!m_lowLevelFunctionGenerationQueue.empty()) while (!m_lowLevelFunctionGenerationQueue.empty())
{ {
std::string name; string name;
unsigned inArgs; unsigned inArgs;
unsigned outArgs; unsigned outArgs;
std::function<void(CompilerContext&)> generator; function<void(CompilerContext&)> generator;
tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front(); tie(name, inArgs, outArgs, generator) = m_lowLevelFunctionGenerationQueue.front();
m_lowLevelFunctionGenerationQueue.pop(); m_lowLevelFunctionGenerationQueue.pop();
@ -194,7 +195,7 @@ void CompilerContext::appendYulUtilityFunctions(OptimiserSettings const& _optimi
solAssert(!m_appendYulUtilityFunctionsRan, "requestedYulFunctions called more than once."); solAssert(!m_appendYulUtilityFunctionsRan, "requestedYulFunctions called more than once.");
m_appendYulUtilityFunctionsRan = true; m_appendYulUtilityFunctionsRan = true;
std::string code = m_yulFunctionCollector.requestedFunctions(); string code = m_yulFunctionCollector.requestedFunctions();
if (!code.empty()) if (!code.empty())
{ {
appendInlineAssembly( appendInlineAssembly(
@ -232,7 +233,7 @@ void CompilerContext::removeVariable(Declaration const& _declaration)
void CompilerContext::removeVariablesAboveStackHeight(unsigned _stackHeight) void CompilerContext::removeVariablesAboveStackHeight(unsigned _stackHeight)
{ {
std::vector<Declaration const*> toRemove; vector<Declaration const*> toRemove;
for (auto _var: m_localVariables) for (auto _var: m_localVariables)
{ {
solAssert(!_var.second.empty(), ""); solAssert(!_var.second.empty(), "");
@ -249,14 +250,14 @@ unsigned CompilerContext::numberOfLocalVariables() const
return static_cast<unsigned>(m_localVariables.size()); return static_cast<unsigned>(m_localVariables.size());
} }
std::shared_ptr<evmasm::Assembly> CompilerContext::compiledContract(ContractDefinition const& _contract) const shared_ptr<evmasm::Assembly> CompilerContext::compiledContract(ContractDefinition const& _contract) const
{ {
auto ret = m_otherCompilers.find(&_contract); auto ret = m_otherCompilers.find(&_contract);
solAssert(ret != m_otherCompilers.end(), "Compiled contract not found."); solAssert(ret != m_otherCompilers.end(), "Compiled contract not found.");
return ret->second->assemblyPtr(); return ret->second->assemblyPtr();
} }
std::shared_ptr<evmasm::Assembly> CompilerContext::compiledContractRuntime(ContractDefinition const& _contract) const shared_ptr<evmasm::Assembly> CompilerContext::compiledContractRuntime(ContractDefinition const& _contract) const
{ {
auto ret = m_otherCompilers.find(&_contract); auto ret = m_otherCompilers.find(&_contract);
solAssert(ret != m_otherCompilers.end(), "Compiled contract not found."); solAssert(ret != m_otherCompilers.end(), "Compiled contract not found.");
@ -319,7 +320,7 @@ unsigned CompilerContext::currentToBaseStackOffset(unsigned _offset) const
return static_cast<unsigned>(m_asm->deposit()) - _offset - 1; return static_cast<unsigned>(m_asm->deposit()) - _offset - 1;
} }
std::pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const pair<u256, unsigned> CompilerContext::storageLocationOfVariable(Declaration const& _declaration) const
{ {
auto it = m_stateVariables.find(&_declaration); auto it = m_stateVariables.find(&_declaration);
solAssert(it != m_stateVariables.end(), "Variable not found in storage."); solAssert(it != m_stateVariables.end(), "Variable not found in storage.");
@ -348,13 +349,13 @@ CompilerContext& CompilerContext::appendConditionalPanic(util::PanicCode _code)
return *this; return *this;
} }
CompilerContext& CompilerContext::appendRevert(std::string const& _message) CompilerContext& CompilerContext::appendRevert(string const& _message)
{ {
appendInlineAssembly("{ " + revertReasonIfDebug(_message) + " }"); appendInlineAssembly("{ " + revertReasonIfDebug(_message) + " }");
return *this; return *this;
} }
CompilerContext& CompilerContext::appendConditionalRevert(bool _forwardReturnData, std::string const& _message) CompilerContext& CompilerContext::appendConditionalRevert(bool _forwardReturnData, string const& _message)
{ {
if (_forwardReturnData && m_evmVersion.supportsReturndata()) if (_forwardReturnData && m_evmVersion.supportsReturndata())
appendInlineAssembly(R"({ appendInlineAssembly(R"({
@ -371,24 +372,24 @@ CompilerContext& CompilerContext::appendConditionalRevert(bool _forwardReturnDat
void CompilerContext::resetVisitedNodes(ASTNode const* _node) void CompilerContext::resetVisitedNodes(ASTNode const* _node)
{ {
std::stack<ASTNode const*> newStack; stack<ASTNode const*> newStack;
newStack.push(_node); newStack.push(_node);
std::swap(m_visitedNodes, newStack); std::swap(m_visitedNodes, newStack);
updateSourceLocation(); updateSourceLocation();
} }
void CompilerContext::appendInlineAssembly( void CompilerContext::appendInlineAssembly(
std::string const& _assembly, string const& _assembly,
std::vector<std::string> const& _localVariables, vector<string> const& _localVariables,
std::set<std::string> const& _externallyUsedFunctions, set<string> const& _externallyUsedFunctions,
bool _system, bool _system,
OptimiserSettings const& _optimiserSettings, OptimiserSettings const& _optimiserSettings,
std::string _sourceName string _sourceName
) )
{ {
unsigned startStackHeight = stackHeight(); unsigned startStackHeight = stackHeight();
std::set<yul::YulString> externallyUsedIdentifiers; set<yul::YulString> externallyUsedIdentifiers;
for (auto const& fun: _externallyUsedFunctions) for (auto const& fun: _externallyUsedFunctions)
externallyUsedIdentifiers.insert(yul::YulString(fun)); externallyUsedIdentifiers.insert(yul::YulString(fun));
for (auto const& var: _localVariables) for (auto const& var: _localVariables)
@ -437,19 +438,19 @@ void CompilerContext::appendInlineAssembly(
ErrorReporter errorReporter(errors); ErrorReporter errorReporter(errors);
langutil::CharStream charStream(_assembly, _sourceName); langutil::CharStream charStream(_assembly, _sourceName);
yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion); yul::EVMDialect const& dialect = yul::EVMDialect::strictAssemblyForEVM(m_evmVersion);
std::optional<langutil::SourceLocation> locationOverride; optional<langutil::SourceLocation> locationOverride;
if (!_system) if (!_system)
locationOverride = m_asm->currentSourceLocation(); locationOverride = m_asm->currentSourceLocation();
std::shared_ptr<yul::Block> parserResult = shared_ptr<yul::Block> parserResult =
yul::Parser(errorReporter, dialect, std::move(locationOverride)) yul::Parser(errorReporter, dialect, std::move(locationOverride))
.parse(charStream); .parse(charStream);
#ifdef SOL_OUTPUT_ASM #ifdef SOL_OUTPUT_ASM
cout << yul::AsmPrinter(&dialect)(*parserResult) << endl; cout << yul::AsmPrinter(&dialect)(*parserResult) << endl;
#endif #endif
auto reportError = [&](std::string const& _context) auto reportError = [&](string const& _context)
{ {
std::string message = string message =
"Error parsing/analyzing inline assembly block:\n" + "Error parsing/analyzing inline assembly block:\n" +
_context + "\n" _context + "\n"
"------------------ Input: -----------------\n" + "------------------ Input: -----------------\n" +
@ -482,7 +483,7 @@ void CompilerContext::appendInlineAssembly(
{ {
yul::Object obj; yul::Object obj;
obj.code = parserResult; obj.code = parserResult;
obj.analysisInfo = std::make_shared<yul::AsmAnalysisInfo>(analysisInfo); obj.analysisInfo = make_shared<yul::AsmAnalysisInfo>(analysisInfo);
solAssert(!dialect.providesObjectAccess()); solAssert(!dialect.providesObjectAccess());
optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers); optimizeYul(obj, dialect, _optimiserSettings, externallyUsedIdentifiers);
@ -492,7 +493,7 @@ void CompilerContext::appendInlineAssembly(
// Store as generated sources, but first re-parse to update the source references. // Store as generated sources, but first re-parse to update the source references.
solAssert(m_generatedYulUtilityCode.empty(), ""); solAssert(m_generatedYulUtilityCode.empty(), "");
m_generatedYulUtilityCode = yul::AsmPrinter(dialect)(*obj.code); m_generatedYulUtilityCode = yul::AsmPrinter(dialect)(*obj.code);
std::string code = yul::AsmPrinter{dialect}(*obj.code); string code = yul::AsmPrinter{dialect}(*obj.code);
langutil::CharStream charStream(m_generatedYulUtilityCode, _sourceName); langutil::CharStream charStream(m_generatedYulUtilityCode, _sourceName);
obj.code = yul::Parser(errorReporter, dialect).parse(charStream); obj.code = yul::Parser(errorReporter, dialect).parse(charStream);
*obj.analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(dialect, obj); *obj.analysisInfo = yul::AsmAnalyzer::analyzeStrictAssertCorrect(dialect, obj);
@ -547,7 +548,7 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _
_optimiserSettings.optimizeStackAllocation, _optimiserSettings.optimizeStackAllocation,
_optimiserSettings.yulOptimiserSteps, _optimiserSettings.yulOptimiserSteps,
_optimiserSettings.yulOptimiserCleanupSteps, _optimiserSettings.yulOptimiserCleanupSteps,
isCreation? std::nullopt : std::make_optional(_optimiserSettings.expectedExecutionsPerDeployment), isCreation? nullopt : make_optional(_optimiserSettings.expectedExecutionsPerDeployment),
_externalIdentifiers _externalIdentifiers
); );
@ -557,11 +558,11 @@ void CompilerContext::optimizeYul(yul::Object& _object, yul::EVMDialect const& _
#endif #endif
} }
std::string CompilerContext::revertReasonIfDebug(std::string const& _message) string CompilerContext::revertReasonIfDebug(string const& _message)
{ {
return YulUtilFunctions::revertReasonIfDebugBody( return YulUtilFunctions::revertReasonIfDebugBody(
m_revertStrings, m_revertStrings,
"mload(" + std::to_string(CompilerUtils::freeMemoryPointer) + ")", "mload(" + to_string(CompilerUtils::freeMemoryPointer) + ")",
_message _message
); );
} }
@ -589,14 +590,14 @@ evmasm::AssemblyItem CompilerContext::FunctionCompilationQueue::entryLabel(
} }
// some name that cannot clash with yul function names. // some name that cannot clash with yul function names.
std::string labelName = "@" + _declaration.name() + "_" + std::to_string(_declaration.id()); string labelName = "@" + _declaration.name() + "_" + to_string(_declaration.id());
evmasm::AssemblyItem tag = _context.namedTag( evmasm::AssemblyItem tag = _context.namedTag(
labelName, labelName,
params, params,
returns, returns,
_declaration.id() _declaration.id()
); );
m_entryLabels.insert(std::make_pair(&_declaration, tag)); m_entryLabels.insert(make_pair(&_declaration, tag));
m_functionsToCompile.push(&_declaration); m_functionsToCompile.push(&_declaration);
return tag.tag(); return tag.tag();
} }

View File

@ -33,6 +33,7 @@
#include <libsolutil/Whiskers.h> #include <libsolutil/Whiskers.h>
#include <libsolutil/StackTooDeepString.h> #include <libsolutil/StackTooDeepString.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::evmasm; using namespace solidity::evmasm;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -104,9 +105,9 @@ void CompilerUtils::revertWithStringData(Type const& _argumentType)
} }
void CompilerUtils::revertWithError( void CompilerUtils::revertWithError(
std::string const& _signature, string const& _signature,
std::vector<Type const*> const& _parameterTypes, vector<Type const*> const& _parameterTypes,
std::vector<Type const*> const& _argumentTypes vector<Type const*> const& _argumentTypes
) )
{ {
fetchFreeMemoryPointer(); fetchFreeMemoryPointer();
@ -214,7 +215,7 @@ void CompilerUtils::storeInMemoryDynamic(Type const& _type, bool _padToWordBound
m_context << Instruction::DUP1; m_context << Instruction::DUP1;
storeStringData(bytesConstRef(str->value())); storeStringData(bytesConstRef(str->value()));
if (_padToWordBoundaries) if (_padToWordBoundaries)
m_context << u256(std::max<size_t>(32, ((str->value().size() + 31) / 32) * 32)); m_context << u256(max<size_t>(32, ((str->value().size() + 31) / 32) * 32));
else else
m_context << u256(str->value().size()); m_context << u256(str->value().size());
m_context << Instruction::ADD; m_context << Instruction::ADD;
@ -263,7 +264,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
Whiskers templ(R"({ Whiskers templ(R"({
if lt(len, <encodedSize>) { <revertString> } if lt(len, <encodedSize>) { <revertString> }
})"); })");
templ("encodedSize", std::to_string(encodedSize)); templ("encodedSize", to_string(encodedSize));
templ("revertString", m_context.revertReasonIfDebug("Calldata too short")); templ("revertString", m_context.revertReasonIfDebug("Calldata too short"));
m_context.appendInlineAssembly(templ.render(), {"len"}); m_context.appendInlineAssembly(templ.render(), {"len"});
@ -319,7 +320,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
mstore(dst, array_length) mstore(dst, array_length)
dst := add(dst, 0x20) dst := add(dst, 0x20)
})"); })");
templ("item_size", std::to_string(arrayType.calldataStride())); templ("item_size", to_string(arrayType.calldataStride()));
// TODO add test // TODO add test
templ("revertStringPointer", m_context.revertReasonIfDebug("ABI memory decoding: invalid data pointer")); templ("revertStringPointer", m_context.revertReasonIfDebug("ABI memory decoding: invalid data pointer"));
templ("revertStringStart", m_context.revertReasonIfDebug("ABI memory decoding: invalid data start")); templ("revertStringStart", m_context.revertReasonIfDebug("ABI memory decoding: invalid data start"));
@ -373,7 +374,7 @@ void CompilerUtils::abiDecode(TypePointers const& _typeParameters, bool _fromMem
m_context.appendInlineAssembly(Whiskers(R"({ m_context.appendInlineAssembly(Whiskers(R"({
if or( if or(
gt(array_length, 0x100000000), gt(array_length, 0x100000000),
gt(add(data_ptr, mul(array_length, )" + std::to_string(arrayType.calldataStride()) + R"()), input_end) gt(add(data_ptr, mul(array_length, )" + to_string(arrayType.calldataStride()) + R"()), input_end)
) { <revertString> } ) { <revertString> }
})") })")
("revertString", m_context.revertReasonIfDebug("ABI calldata decoding: invalid data pointer")) ("revertString", m_context.revertReasonIfDebug("ABI calldata decoding: invalid data pointer"))
@ -617,7 +618,7 @@ void CompilerUtils::abiEncodeV2(
// stack: <$value0> <$value1> ... <$value(n-1)> <$headStart> // stack: <$value0> <$value1> ... <$value(n-1)> <$headStart>
std::string encoderName = string encoderName =
_padToWordBoundaries ? _padToWordBoundaries ?
m_context.abiFunctions().tupleEncoderReversed(_givenTypes, _targetTypes, _encodeAsLibraryTypes) : m_context.abiFunctions().tupleEncoderReversed(_givenTypes, _targetTypes, _encodeAsLibraryTypes) :
m_context.abiFunctions().tupleEncoderPackedReversed(_givenTypes, _targetTypes); m_context.abiFunctions().tupleEncoderPackedReversed(_givenTypes, _targetTypes);
@ -630,7 +631,7 @@ void CompilerUtils::abiDecodeV2(TypePointers const& _parameterTypes, bool _fromM
m_context << Instruction::DUP2 << Instruction::ADD; m_context << Instruction::DUP2 << Instruction::ADD;
m_context << Instruction::SWAP1; m_context << Instruction::SWAP1;
// stack: <end> <start> // stack: <end> <start>
std::string decoderName = m_context.abiFunctions().tupleDecoder(_parameterTypes, _fromMemory); string decoderName = m_context.abiFunctions().tupleDecoder(_parameterTypes, _fromMemory);
m_context.callYulFunction(decoderName, 2, sizeOnStack(_parameterTypes)); m_context.callYulFunction(decoderName, 2, sizeOnStack(_parameterTypes));
} }
@ -645,7 +646,7 @@ void CompilerUtils::zeroInitialiseMemoryArray(ArrayType const& _type)
calldatacopy(memptr, calldatasize(), size) calldatacopy(memptr, calldatasize(), size)
memptr := add(memptr, size) memptr := add(memptr, size)
})"); })");
templ("element_size", std::to_string(_type.memoryStride())); templ("element_size", to_string(_type.memoryStride()));
m_context.appendInlineAssembly(templ.render(), {"length", "memptr"}); m_context.appendInlineAssembly(templ.render(), {"length", "memptr"});
} }
else else
@ -841,7 +842,7 @@ void CompilerUtils::convertType(
m_context << Instruction::POP << u256(0); m_context << Instruction::POP << u256(0);
else if (targetType.numBytes() > typeOnStack.numBytes() || _cleanupNeeded) else if (targetType.numBytes() > typeOnStack.numBytes() || _cleanupNeeded)
{ {
unsigned bytes = std::min(typeOnStack.numBytes(), targetType.numBytes()); unsigned bytes = min(typeOnStack.numBytes(), targetType.numBytes());
m_context << ((u256(1) << (256 - bytes * 8)) - 1); m_context << ((u256(1) << (256 - bytes * 8)) - 1);
m_context << Instruction::NOT << Instruction::AND; m_context << Instruction::NOT << Instruction::AND;
} }
@ -959,7 +960,7 @@ void CompilerUtils::convertType(
case Type::Category::StringLiteral: case Type::Category::StringLiteral:
{ {
auto const& literalType = dynamic_cast<StringLiteralType const&>(_typeOnStack); auto const& literalType = dynamic_cast<StringLiteralType const&>(_typeOnStack);
std::string const& value = literalType.value(); string const& value = literalType.value();
bytesConstRef data(value); bytesConstRef data(value);
if (targetTypeCategory == Type::Category::FixedBytes) if (targetTypeCategory == Type::Category::FixedBytes)
{ {
@ -1185,7 +1186,7 @@ void CompilerUtils::convertType(
for (auto const& member: typeOnStack->members(nullptr)) for (auto const& member: typeOnStack->members(nullptr))
{ {
solAssert(!member.type->containsNestedMapping()); solAssert(!member.type->containsNestedMapping());
std::pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = typeOnStack->storageOffsetsOfMember(member.name);
_context << offsets.first << Instruction::DUP3 << Instruction::ADD; _context << offsets.first << Instruction::DUP3 << Instruction::ADD;
_context << u256(offsets.second); _context << u256(offsets.second);
StorageItem(_context, *member.type).retrieveValue(SourceLocation(), true); StorageItem(_context, *member.type).retrieveValue(SourceLocation(), true);
@ -1267,7 +1268,7 @@ void CompilerUtils::convertType(
if (sourceSize > 0 || targetSize > 0) if (sourceSize > 0 || targetSize > 0)
{ {
// Move it back into its place. // Move it back into its place.
for (unsigned j = 0; j < std::min(sourceSize, targetSize); ++j) for (unsigned j = 0; j < min(sourceSize, targetSize); ++j)
m_context << m_context <<
swapInstruction(depth + targetSize - sourceSize) << swapInstruction(depth + targetSize - sourceSize) <<
Instruction::POP; Instruction::POP;
@ -1374,7 +1375,7 @@ void CompilerUtils::pushZeroValue(Type const& _type)
[type](CompilerContext& _context) { [type](CompilerContext& _context) {
CompilerUtils utils(_context); CompilerUtils utils(_context);
utils.allocateMemory(std::max<u256>(32u, type->memoryDataSize())); utils.allocateMemory(max<u256>(32u, type->memoryDataSize()));
_context << Instruction::DUP1; _context << Instruction::DUP1;
if (auto structType = dynamic_cast<StructType const*>(type)) if (auto structType = dynamic_cast<StructType const*>(type))
@ -1492,7 +1493,7 @@ void CompilerUtils::popAndJump(unsigned _toHeight, evmasm::AssemblyItem const& _
m_context.adjustStackOffset(static_cast<int>(amount)); m_context.adjustStackOffset(static_cast<int>(amount));
} }
unsigned CompilerUtils::sizeOnStack(std::vector<Type const*> const& _variableTypes) unsigned CompilerUtils::sizeOnStack(vector<Type const*> const& _variableTypes)
{ {
unsigned size = 0; unsigned size = 0;
for (Type const* type: _variableTypes) for (Type const* type: _variableTypes)
@ -1508,7 +1509,7 @@ void CompilerUtils::computeHashStatic()
void CompilerUtils::copyContractCodeToMemory(ContractDefinition const& contract, bool _creation) void CompilerUtils::copyContractCodeToMemory(ContractDefinition const& contract, bool _creation)
{ {
std::string which = _creation ? "Creation" : "Runtime"; string which = _creation ? "Creation" : "Runtime";
m_context.callLowLevelFunction( m_context.callLowLevelFunction(
"$copyContract" + which + "CodeToMemory_" + contract.type()->identifier(), "$copyContract" + which + "CodeToMemory_" + contract.type()->identifier(),
1, 1,
@ -1516,7 +1517,7 @@ void CompilerUtils::copyContractCodeToMemory(ContractDefinition const& contract,
[&contract, _creation](CompilerContext& _context) [&contract, _creation](CompilerContext& _context)
{ {
// copy the contract's code into memory // copy the contract's code into memory
std::shared_ptr<evmasm::Assembly> assembly = shared_ptr<evmasm::Assembly> assembly =
_creation ? _creation ?
_context.compiledContract(contract) : _context.compiledContract(contract) :
_context.compiledContractRuntime(contract); _context.compiledContractRuntime(contract);

View File

@ -55,6 +55,7 @@
#include <algorithm> #include <algorithm>
#include <limits> #include <limits>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::evmasm; using namespace solidity::evmasm;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -79,7 +80,7 @@ public:
{ {
solAssert( solAssert(
m_context.stackHeight() == stackHeight, m_context.stackHeight() == stackHeight,
std::string("I sense a disturbance in the stack: ") + std::to_string(m_context.stackHeight()) + " vs " + std::to_string(stackHeight) std::string("I sense a disturbance in the stack: ") + to_string(m_context.stackHeight()) + " vs " + to_string(stackHeight)
); );
} }
private: private:
@ -91,7 +92,7 @@ private:
void ContractCompiler::compileContract( void ContractCompiler::compileContract(
ContractDefinition const& _contract, ContractDefinition const& _contract,
std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers
) )
{ {
CompilerContext::LocationSetter locationSetter(m_context, _contract); CompilerContext::LocationSetter locationSetter(m_context, _contract);
@ -110,7 +111,7 @@ void ContractCompiler::compileContract(
size_t ContractCompiler::compileConstructor( size_t ContractCompiler::compileConstructor(
ContractDefinition const& _contract, ContractDefinition const& _contract,
std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers std::map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers
) )
{ {
CompilerContext::LocationSetter locationSetter(m_context, _contract); CompilerContext::LocationSetter locationSetter(m_context, _contract);
@ -125,7 +126,7 @@ size_t ContractCompiler::compileConstructor(
void ContractCompiler::initializeContext( void ContractCompiler::initializeContext(
ContractDefinition const& _contract, ContractDefinition const& _contract,
std::map<ContractDefinition const*, std::shared_ptr<Compiler const>> const& _otherCompilers map<ContractDefinition const*, shared_ptr<Compiler const>> const& _otherCompilers
) )
{ {
m_context.setUseABICoderV2(*_contract.sourceUnit().annotation().useABICoderV2); m_context.setUseABICoderV2(*_contract.sourceUnit().annotation().useABICoderV2);
@ -186,7 +187,7 @@ size_t ContractCompiler::packIntoContractCreator(ContractDefinition const& _cont
CompilerContext::LocationSetter locationSetter(m_context, _contract); CompilerContext::LocationSetter locationSetter(m_context, _contract);
m_context << deployRoutine; m_context << deployRoutine;
solAssert(m_context.runtimeSub() != std::numeric_limits<size_t>::max(), "Runtime sub not registered"); solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
ContractType contractType(_contract); ContractType contractType(_contract);
auto const& immutables = contractType.immutableVariables(); auto const& immutables = contractType.immutableVariables();
@ -230,7 +231,7 @@ size_t ContractCompiler::deployLibrary(ContractDefinition const& _contract)
CompilerContext::LocationSetter locationSetter(m_context, _contract); CompilerContext::LocationSetter locationSetter(m_context, _contract);
solAssert(m_context.runtimeSub() != std::numeric_limits<size_t>::max(), "Runtime sub not registered"); solAssert(m_context.runtimeSub() != numeric_limits<size_t>::max(), "Runtime sub not registered");
m_context.pushSubroutineSize(m_context.runtimeSub()); m_context.pushSubroutineSize(m_context.runtimeSub());
m_context.pushSubroutineOffset(m_context.runtimeSub()); m_context.pushSubroutineOffset(m_context.runtimeSub());
// This code replaces the address added by appendDeployTimeAddress(). // This code replaces the address added by appendDeployTimeAddress().
@ -323,8 +324,8 @@ void ContractCompiler::appendDelegatecallCheck()
} }
void ContractCompiler::appendInternalSelector( void ContractCompiler::appendInternalSelector(
std::map<FixedHash<4>, evmasm::AssemblyItem const> const& _entryPoints, map<FixedHash<4>, evmasm::AssemblyItem const> const& _entryPoints,
std::vector<FixedHash<4>> const& _ids, vector<FixedHash<4>> const& _ids,
evmasm::AssemblyItem const& _notFoundTag, evmasm::AssemblyItem const& _notFoundTag,
size_t _runs size_t _runs
) )
@ -368,11 +369,11 @@ void ContractCompiler::appendInternalSelector(
m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT; m_context << dupInstruction(1) << u256(FixedHash<4>::Arith(pivot)) << Instruction::GT;
evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()}; evmasm::AssemblyItem lessTag{m_context.appendConditionalJump()};
// Here, we have funid >= pivot // Here, we have funid >= pivot
std::vector<FixedHash<4>> larger{_ids.begin() + static_cast<ptrdiff_t>(pivotIndex), _ids.end()}; vector<FixedHash<4>> larger{_ids.begin() + static_cast<ptrdiff_t>(pivotIndex), _ids.end()};
appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs); appendInternalSelector(_entryPoints, larger, _notFoundTag, _runs);
m_context << lessTag; m_context << lessTag;
// Here, we have funid < pivot // Here, we have funid < pivot
std::vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + static_cast<ptrdiff_t>(pivotIndex)}; vector<FixedHash<4>> smaller{_ids.begin(), _ids.begin() + static_cast<ptrdiff_t>(pivotIndex)};
appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs); appendInternalSelector(_entryPoints, smaller, _notFoundTag, _runs);
} }
else else
@ -410,8 +411,8 @@ bool hasPayableFunctions(ContractDefinition const& _contract)
void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contract) void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contract)
{ {
std::map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.interfaceFunctions(); map<FixedHash<4>, FunctionTypePointer> interfaceFunctions = _contract.interfaceFunctions();
std::map<FixedHash<4>, evmasm::AssemblyItem const> callDataUnpackerEntryPoints; map<FixedHash<4>, evmasm::AssemblyItem const> callDataUnpackerEntryPoints;
if (_contract.isLibrary()) if (_contract.isLibrary())
{ {
@ -447,7 +448,7 @@ void ContractCompiler::appendFunctionSelector(ContractDefinition const& _contrac
CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true, false); CompilerUtils(m_context).loadFromMemory(0, IntegerType(CompilerUtils::dataStartOffset * 8), true, false);
// stack now is: <can-call-non-view-functions>? <funhash> // stack now is: <can-call-non-view-functions>? <funhash>
std::vector<FixedHash<4>> sortedIDs; vector<FixedHash<4>> sortedIDs;
for (auto const& it: interfaceFunctions) for (auto const& it: interfaceFunctions)
{ {
callDataUnpackerEntryPoints.emplace(it.first, m_context.newTag()); callDataUnpackerEntryPoints.emplace(it.first, m_context.newTag());
@ -571,7 +572,7 @@ void ContractCompiler::appendReturnValuePacker(TypePointers const& _typeParamete
void ContractCompiler::registerStateVariables(ContractDefinition const& _contract) void ContractCompiler::registerStateVariables(ContractDefinition const& _contract)
{ {
for (auto const& var: ContractType(_contract).stateVariables()) for (auto const& var: ContractType(_contract).stateVariables())
m_context.addStateVariable(*std::get<0>(var), std::get<1>(var), std::get<2>(var)); m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var));
} }
void ContractCompiler::registerImmutableVariables(ContractDefinition const& _contract) void ContractCompiler::registerImmutableVariables(ContractDefinition const& _contract)
@ -644,7 +645,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
m_breakTags.clear(); m_breakTags.clear();
m_continueTags.clear(); m_continueTags.clear();
m_currentFunction = &_function; m_currentFunction = &_function;
m_modifierDepth = std::numeric_limits<unsigned>::max(); m_modifierDepth = numeric_limits<unsigned>::max();
m_scopeStackHeight.clear(); m_scopeStackHeight.clear();
m_context.setModifierDepth(0); m_context.setModifierDepth(0);
@ -661,10 +662,10 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
unsigned const c_argumentsSize = CompilerUtils::sizeOnStack(_function.parameters()); unsigned const c_argumentsSize = CompilerUtils::sizeOnStack(_function.parameters());
unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters()); unsigned const c_returnValuesSize = CompilerUtils::sizeOnStack(_function.returnParameters());
std::vector<int> stackLayout; vector<int> stackLayout;
if (!_function.isConstructor() && !_function.isFallback()) if (!_function.isConstructor() && !_function.isFallback())
stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address stackLayout.push_back(static_cast<int>(c_returnValuesSize)); // target of return address
stackLayout += std::vector<int>(c_argumentsSize, -1); // discard all arguments stackLayout += vector<int>(c_argumentsSize, -1); // discard all arguments
for (size_t i = 0; i < c_returnValuesSize; ++i) for (size_t i = 0; i < c_returnValuesSize; ++i)
stackLayout.push_back(static_cast<int>(i)); stackLayout.push_back(static_cast<int>(i));
@ -683,7 +684,7 @@ bool ContractCompiler::visit(FunctionDefinition const& _function)
else else
{ {
m_context << swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u); m_context << swapInstruction(static_cast<unsigned>(stackLayout.size()) - static_cast<unsigned>(stackLayout.back()) - 1u);
std::swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back()); swap(stackLayout[static_cast<size_t>(stackLayout.back())], stackLayout.back());
} }
for (size_t i = 0; i < stackLayout.size(); ++i) for (size_t i = 0; i < stackLayout.size(); ++i)
if (stackLayout[i] != static_cast<int>(i)) if (stackLayout[i] != static_cast<int>(i))
@ -789,7 +790,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable); unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable);
if (!ref->second.suffix.empty()) if (!ref->second.suffix.empty())
{ {
std::string const& suffix = ref->second.suffix; string const& suffix = ref->second.suffix;
if (variable->type()->dataStoredIn(DataLocation::Storage)) if (variable->type()->dataStoredIn(DataLocation::Storage))
{ {
solAssert(suffix == "offset" || suffix == "slot", ""); solAssert(suffix == "offset" || suffix == "slot", "");
@ -864,7 +865,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
// lvalue context // lvalue context
auto variable = dynamic_cast<VariableDeclaration const*>(decl); auto variable = dynamic_cast<VariableDeclaration const*>(decl);
unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1; unsigned stackDiff = static_cast<unsigned>(_assembly.stackHeight()) - m_context.baseStackOffsetOfVariable(*variable) - 1;
std::string const& suffix = ref->second.suffix; string const& suffix = ref->second.suffix;
if (variable->type()->dataStoredIn(DataLocation::Storage)) if (variable->type()->dataStoredIn(DataLocation::Storage))
{ {
solAssert( solAssert(
@ -927,7 +928,7 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
yul::AsmAnalysisInfo* analysisInfo = _inlineAssembly.annotation().analysisInfo.get(); yul::AsmAnalysisInfo* analysisInfo = _inlineAssembly.annotation().analysisInfo.get();
// Only used in the scope below, but required to live outside to keep the // Only used in the scope below, but required to live outside to keep the
// std::shared_ptr's alive // shared_ptr's alive
yul::Object object = {}; yul::Object object = {};
// The optimiser cannot handle external references // The optimiser cannot handle external references
@ -940,8 +941,8 @@ bool ContractCompiler::visit(InlineAssembly const& _inlineAssembly)
solAssert(dialect, ""); solAssert(dialect, "");
// Create a modifiable copy of the code and analysis // Create a modifiable copy of the code and analysis
object.code = std::make_shared<yul::Block>(yul::ASTCopier().translate(*code)); object.code = make_shared<yul::Block>(yul::ASTCopier().translate(*code));
object.analysisInfo = std::make_shared<yul::AsmAnalysisInfo>(yul::AsmAnalyzer::analyzeStrictAssertCorrect(*dialect, object)); object.analysisInfo = make_shared<yul::AsmAnalysisInfo>(yul::AsmAnalyzer::analyzeStrictAssertCorrect(*dialect, object));
m_context.optimizeYul(object, *dialect, m_optimiserSettings); m_context.optimizeYul(object, *dialect, m_optimiserSettings);
@ -988,10 +989,10 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement)
TryCatchClause const& successClause = *_tryStatement.clauses().front(); TryCatchClause const& successClause = *_tryStatement.clauses().front();
if (successClause.parameters()) if (successClause.parameters())
{ {
std::vector<Type const*> exprTypes{_tryStatement.externalCall().annotation().type}; vector<Type const*> exprTypes{_tryStatement.externalCall().annotation().type};
if (auto tupleType = dynamic_cast<TupleType const*>(exprTypes.front())) if (auto tupleType = dynamic_cast<TupleType const*>(exprTypes.front()))
exprTypes = tupleType->components(); exprTypes = tupleType->components();
std::vector<ASTPointer<VariableDeclaration>> const& params = successClause.parameters()->parameters(); vector<ASTPointer<VariableDeclaration>> const& params = successClause.parameters()->parameters();
solAssert(exprTypes.size() == params.size(), ""); solAssert(exprTypes.size() == params.size(), "");
for (size_t i = 0; i < exprTypes.size(); ++i) for (size_t i = 0; i < exprTypes.size(); ++i)
solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], ""); solAssert(params[i] && exprTypes[i] && *params[i]->annotation().type == *exprTypes[i], "");
@ -1007,7 +1008,7 @@ bool ContractCompiler::visit(TryStatement const& _tryStatement)
return false; return false;
} }
void ContractCompiler::handleCatch(std::vector<ASTPointer<TryCatchClause>> const& _catchClauses) void ContractCompiler::handleCatch(vector<ASTPointer<TryCatchClause>> const& _catchClauses)
{ {
// Stack is empty. // Stack is empty.
ASTPointer<TryCatchClause> error{}; ASTPointer<TryCatchClause> error{};
@ -1284,7 +1285,7 @@ bool ContractCompiler::visit(Return const& _return)
if (Expression const* expression = _return.expression()) if (Expression const* expression = _return.expression())
{ {
solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer."); solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer.");
std::vector<ASTPointer<VariableDeclaration>> const& returnParameters = vector<ASTPointer<VariableDeclaration>> const& returnParameters =
_return.annotation().functionReturnParameters->parameters(); _return.annotation().functionReturnParameters->parameters();
TypePointers types; TypePointers types;
for (auto const& retVariable: returnParameters) for (auto const& retVariable: returnParameters)
@ -1431,7 +1432,7 @@ void ContractCompiler::appendModifierOrFunctionCode()
solAssert(m_currentFunction, ""); solAssert(m_currentFunction, "");
unsigned stackSurplus = 0; unsigned stackSurplus = 0;
Block const* codeBlock = nullptr; Block const* codeBlock = nullptr;
std::vector<VariableDeclaration const*> addedVariables; vector<VariableDeclaration const*> addedVariables;
m_modifierDepth++; m_modifierDepth++;
m_context.setModifierDepth(m_modifierDepth); m_context.setModifierDepth(m_modifierDepth);

View File

@ -43,6 +43,7 @@
#include <numeric> #include <numeric>
#include <utility> #include <utility>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::evmasm; using namespace solidity::evmasm;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -241,7 +242,7 @@ void ExpressionCompiler::appendStateVariableAccessor(VariableDeclaration const&
if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i])) if (auto arrayType = dynamic_cast<ArrayType const*>(returnTypes[i]))
if (!arrayType->isByteArrayOrString()) if (!arrayType->isByteArrayOrString())
continue; continue;
std::pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]); pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second); m_context << Instruction::DUP1 << u256(offsets.first) << Instruction::ADD << u256(offsets.second);
Type const* memberType = structType->memberType(names[i]); Type const* memberType = structType->memberType(names[i]);
StorageItem(m_context, *memberType).retrieveValue(SourceLocation(), true); StorageItem(m_context, *memberType).retrieveValue(SourceLocation(), true);
@ -369,7 +370,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type); ArrayType const& arrayType = dynamic_cast<ArrayType const&>(*_tuple.annotation().type);
solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array."); solAssert(!arrayType.isDynamicallySized(), "Cannot create dynamically sized inline array.");
utils().allocateMemory(std::max(u256(32u), arrayType.memoryDataSize())); utils().allocateMemory(max(u256(32u), arrayType.memoryDataSize()));
m_context << Instruction::DUP1; m_context << Instruction::DUP1;
for (auto const& component: _tuple.components()) for (auto const& component: _tuple.components())
@ -382,7 +383,7 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
} }
else else
{ {
std::vector<std::unique_ptr<LValue>> lvalues; vector<unique_ptr<LValue>> lvalues;
for (auto const& component: _tuple.components()) for (auto const& component: _tuple.components())
if (component) if (component)
{ {
@ -394,13 +395,13 @@ bool ExpressionCompiler::visit(TupleExpression const& _tuple)
} }
} }
else if (_tuple.annotation().willBeWrittenTo) else if (_tuple.annotation().willBeWrittenTo)
lvalues.push_back(std::unique_ptr<LValue>()); lvalues.push_back(unique_ptr<LValue>());
if (_tuple.annotation().willBeWrittenTo) if (_tuple.annotation().willBeWrittenTo)
{ {
if (_tuple.components().size() == 1) if (_tuple.components().size() == 1)
m_currentLValue = std::move(lvalues[0]); m_currentLValue = std::move(lvalues[0]);
else else
m_currentLValue = std::make_unique<TupleObject>(m_context, std::move(lvalues)); m_currentLValue = make_unique<TupleObject>(m_context, std::move(lvalues));
} }
} }
return false; return false;
@ -523,7 +524,7 @@ bool ExpressionCompiler::visit(UnaryOperation const& _unaryOperation)
m_context << u256(0) << Instruction::SUB; m_context << u256(0) << Instruction::SUB;
break; break;
default: default:
solAssert(false, "Invalid unary operator: " + std::string(TokenTraits::toString(_unaryOperation.getOperator()))); solAssert(false, "Invalid unary operator: " + string(TokenTraits::toString(_unaryOperation.getOperator())));
} }
return false; return false;
} }
@ -658,14 +659,14 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
TypePointers parameterTypes = functionType->parameterTypes(); TypePointers parameterTypes = functionType->parameterTypes();
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.sortedArguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.sortedArguments();
if (functionCallKind == FunctionCallKind::StructConstructorCall) if (functionCallKind == FunctionCallKind::StructConstructorCall)
{ {
TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type); TypeType const& type = dynamic_cast<TypeType const&>(*_functionCall.expression().annotation().type);
auto const& structType = dynamic_cast<StructType const&>(*type.actualType()); auto const& structType = dynamic_cast<StructType const&>(*type.actualType());
utils().allocateMemory(std::max(u256(32u), structType.memoryDataSize())); utils().allocateMemory(max(u256(32u), structType.memoryDataSize()));
m_context << Instruction::DUP1; m_context << Instruction::DUP1;
for (unsigned i = 0; i < arguments.size(); ++i) for (unsigned i = 0; i < arguments.size(); ++i)
@ -991,7 +992,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::Error: case FunctionType::Kind::Error:
{ {
_functionCall.expression().accept(*this); _functionCall.expression().accept(*this);
std::vector<Type const*> argumentTypes; vector<Type const*> argumentTypes;
for (ASTPointer<Expression const> const& arg: _functionCall.sortedArguments()) for (ASTPointer<Expression const> const& arg: _functionCall.sortedArguments())
{ {
arg->accept(*this); arg->accept(*this);
@ -1059,7 +1060,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::RIPEMD160: case FunctionType::Kind::RIPEMD160:
{ {
_functionCall.expression().accept(*this); _functionCall.expression().accept(*this);
static std::map<FunctionType::Kind, u256> const contractAddresses{ static map<FunctionType::Kind, u256> const contractAddresses{
{FunctionType::Kind::ECRecover, 1}, {FunctionType::Kind::ECRecover, 1},
{FunctionType::Kind::SHA256, 2}, {FunctionType::Kind::SHA256, 2},
{FunctionType::Kind::RIPEMD160, 3} {FunctionType::Kind::RIPEMD160, 3}
@ -1150,8 +1151,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
case FunctionType::Kind::BytesConcat: case FunctionType::Kind::BytesConcat:
{ {
_functionCall.expression().accept(*this); _functionCall.expression().accept(*this);
std::vector<Type const*> argumentTypes; vector<Type const*> argumentTypes;
std::vector<Type const*> targetTypes; vector<Type const*> targetTypes;
for (auto const& argument: arguments) for (auto const& argument: arguments)
{ {
argument->accept(*this); argument->accept(*this);
@ -1415,7 +1416,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
// stack: <memory pointer> <selector> // stack: <memory pointer> <selector>
// load current memory, mask and combine the selector // load current memory, mask and combine the selector
std::string mask = formatNumber((u256(-1) >> 32)); string mask = formatNumber((u256(-1) >> 32));
m_context.appendInlineAssembly(R"({ m_context.appendInlineAssembly(R"({
let data_start := add(mem_ptr, 0x20) let data_start := add(mem_ptr, 0x20)
let data := mload(data_start) let data := mload(data_start)
@ -1475,7 +1476,7 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions)
// Desired Stack: [salt], [gas], [value] // Desired Stack: [salt], [gas], [value]
enum Option { Salt, Gas, Value }; enum Option { Salt, Gas, Value };
std::vector<Option> presentOptions; vector<Option> presentOptions;
FunctionType const& funType = dynamic_cast<FunctionType const&>( FunctionType const& funType = dynamic_cast<FunctionType const&>(
*_functionCallOptions.expression().annotation().type *_functionCallOptions.expression().annotation().type
); );
@ -1485,7 +1486,7 @@ bool ExpressionCompiler::visit(FunctionCallOptions const& _functionCallOptions)
for (size_t i = 0; i < _functionCallOptions.options().size(); ++i) for (size_t i = 0; i < _functionCallOptions.options().size(); ++i)
{ {
std::string const& name = *_functionCallOptions.names()[i]; string const& name = *_functionCallOptions.names()[i];
Type const* requiredType = TypeProvider::uint256(); Type const* requiredType = TypeProvider::uint256();
Option newOption; Option newOption;
if (name == "salt") if (name == "salt")
@ -1817,7 +1818,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
); );
m_context << Instruction::EXTCODEHASH; m_context << Instruction::EXTCODEHASH;
} }
else if ((std::set<std::string>{"send", "transfer"}).count(member)) else if ((set<string>{"send", "transfer"}).count(member))
{ {
solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, ""); solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable, "");
utils().convertType( utils().convertType(
@ -1826,7 +1827,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
true true
); );
} }
else if ((std::set<std::string>{"call", "callcode", "delegatecall", "staticcall"}).count(member)) else if ((set<string>{"call", "callcode", "delegatecall", "staticcall"}).count(member))
utils().convertType( utils().convertType(
*_memberAccess.expression().annotation().type, *_memberAccess.expression().annotation().type,
*TypeProvider::address(), *TypeProvider::address(),
@ -1909,7 +1910,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
Whiskers(R"({ Whiskers(R"({
mstore(start, sub(end, add(start, 0x20))) mstore(start, sub(end, add(start, 0x20)))
mstore(<free>, and(add(end, 31), not(31))) mstore(<free>, and(add(end, 31), not(31)))
})")("free", std::to_string(CompilerUtils::freeMemoryPointer)).render(), })")("free", to_string(CompilerUtils::freeMemoryPointer)).render(),
{"start", "end"} {"start", "end"}
); );
m_context << Instruction::POP; m_context << Instruction::POP;
@ -1945,7 +1946,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
solAssert(false, "min/max not available for the given type."); solAssert(false, "min/max not available for the given type.");
} }
else if ((std::set<std::string>{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}).count(member)) else if ((set<string>{"encode", "encodePacked", "encodeWithSelector", "encodeWithSignature", "decode"}).count(member))
{ {
// no-op // no-op
} }
@ -1960,7 +1961,7 @@ bool ExpressionCompiler::visit(MemberAccess const& _memberAccess)
{ {
case DataLocation::Storage: case DataLocation::Storage:
{ {
std::pair<u256, unsigned> const& offsets = type.storageOffsetsOfMember(member); pair<u256, unsigned> const& offsets = type.storageOffsetsOfMember(member);
m_context << offsets.first << Instruction::ADD << u256(offsets.second); m_context << offsets.first << Instruction::ADD << u256(offsets.second);
setLValueToStorageItem(_memberAccess); setLValueToStorageItem(_memberAccess);
break; break;
@ -2453,7 +2454,7 @@ void ExpressionCompiler::appendArithmeticOperatorCode(Token _operator, Type cons
IntegerType const& type = dynamic_cast<IntegerType const&>(_type); IntegerType const& type = dynamic_cast<IntegerType const&>(_type);
if (m_context.arithmetic() == Arithmetic::Checked) if (m_context.arithmetic() == Arithmetic::Checked)
{ {
std::string functionName; string functionName;
switch (_operator) switch (_operator)
{ {
case Token::Add: case Token::Add:
@ -2619,7 +2620,7 @@ void ExpressionCompiler::appendExpOperatorCode(Type const& _valueType, Type cons
void ExpressionCompiler::appendExternalFunctionCall( void ExpressionCompiler::appendExternalFunctionCall(
FunctionType const& _functionType, FunctionType const& _functionType,
std::vector<ASTPointer<Expression const>> const& _arguments, vector<ASTPointer<Expression const>> const& _arguments,
bool _tryCall bool _tryCall
) )
{ {

View File

@ -30,6 +30,7 @@
#include <libsolutil/StackTooDeepString.h> #include <libsolutil/StackTooDeepString.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::evmasm; using namespace solidity::evmasm;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -409,7 +410,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
if (sourceType.location() == DataLocation::Storage) if (sourceType.location() == DataLocation::Storage)
{ {
// stack layout: source_ref target_ref // stack layout: source_ref target_ref
std::pair<u256, unsigned> const& offsets = sourceType.storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = sourceType.storageOffsetsOfMember(member.name);
m_context << offsets.first << Instruction::DUP3 << Instruction::ADD; m_context << offsets.first << Instruction::DUP3 << Instruction::ADD;
m_context << u256(offsets.second); m_context << u256(offsets.second);
// stack: source_ref target_ref source_member_ref source_member_off // stack: source_ref target_ref source_member_ref source_member_off
@ -426,7 +427,7 @@ void StorageItem::storeValue(Type const& _sourceType, SourceLocation const& _loc
// stack layout: source_ref target_ref source_value... // stack layout: source_ref target_ref source_value...
} }
unsigned stackSize = sourceMemberType->sizeOnStack(); unsigned stackSize = sourceMemberType->sizeOnStack();
std::pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
m_context << dupInstruction(1 + stackSize) << offsets.first << Instruction::ADD; m_context << dupInstruction(1 + stackSize) << offsets.first << Instruction::ADD;
m_context << u256(offsets.second); m_context << u256(offsets.second);
// stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off // stack: source_ref target_ref target_off source_value... target_member_ref target_member_byte_off
@ -468,7 +469,7 @@ void StorageItem::setToZero(SourceLocation const&, bool _removeReference) const
Type const* memberType = member.type; Type const* memberType = member.type;
if (memberType->category() == Type::Category::Mapping) if (memberType->category() == Type::Category::Mapping)
continue; continue;
std::pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name); pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member.name);
m_context m_context
<< offsets.first << Instruction::DUP3 << Instruction::ADD << offsets.first << Instruction::DUP3 << Instruction::ADD
<< u256(offsets.second); << u256(offsets.second);
@ -591,7 +592,7 @@ void TupleObject::storeValue(Type const& _sourceType, SourceLocation const& _loc
// We will assign from right to left to optimize stack layout. // We will assign from right to left to optimize stack layout.
for (size_t i = 0; i < m_lvalues.size(); ++i) for (size_t i = 0; i < m_lvalues.size(); ++i)
{ {
std::unique_ptr<LValue> const& lvalue = m_lvalues[m_lvalues.size() - i - 1]; unique_ptr<LValue> const& lvalue = m_lvalues[m_lvalues.size() - i - 1];
Type const* valType = valueTypes[valueTypes.size() - i - 1]; Type const* valType = valueTypes[valueTypes.size() - i - 1];
unsigned stackHeight = m_context.stackHeight(); unsigned stackHeight = m_context.stackHeight();
solAssert(!valType == !lvalue, ""); solAssert(!valType == !lvalue, "");

View File

@ -26,43 +26,44 @@
#include <libsolutil/Whiskers.h> #include <libsolutil/Whiskers.h>
#include <libsolutil/StringUtils.h> #include <libsolutil/StringUtils.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::util; using namespace solidity::util;
std::string MultiUseYulFunctionCollector::requestedFunctions() string MultiUseYulFunctionCollector::requestedFunctions()
{ {
std::string result = std::move(m_code); string result = std::move(m_code);
m_code.clear(); m_code.clear();
m_requestedFunctions.clear(); m_requestedFunctions.clear();
return result; return result;
} }
std::string MultiUseYulFunctionCollector::createFunction(std::string const& _name, std::function<std::string()> const& _creator) string MultiUseYulFunctionCollector::createFunction(string const& _name, function<string ()> const& _creator)
{ {
if (!m_requestedFunctions.count(_name)) if (!m_requestedFunctions.count(_name))
{ {
m_requestedFunctions.insert(_name); m_requestedFunctions.insert(_name);
std::string fun = _creator(); string fun = _creator();
solAssert(!fun.empty(), ""); solAssert(!fun.empty(), "");
solAssert(fun.find("function " + _name + "(") != std::string::npos, "Function not properly named."); solAssert(fun.find("function " + _name + "(") != string::npos, "Function not properly named.");
m_code += std::move(fun); m_code += std::move(fun);
} }
return _name; return _name;
} }
std::string MultiUseYulFunctionCollector::createFunction( string MultiUseYulFunctionCollector::createFunction(
std::string const& _name, string const& _name,
std::function<std::string(std::vector<std::string>&, std::vector<std::string>&)> const& _creator function<string(vector<string>&, vector<string>&)> const& _creator
) )
{ {
solAssert(!_name.empty(), ""); solAssert(!_name.empty(), "");
if (!m_requestedFunctions.count(_name)) if (!m_requestedFunctions.count(_name))
{ {
m_requestedFunctions.insert(_name); m_requestedFunctions.insert(_name);
std::vector<std::string> arguments; vector<string> arguments;
std::vector<std::string> returnParameters; vector<string> returnParameters;
std::string body = _creator(arguments, returnParameters); string body = _creator(arguments, returnParameters);
solAssert(!body.empty(), ""); solAssert(!body.empty(), "");
m_code += Whiskers(R"( m_code += Whiskers(R"(

File diff suppressed because it is too large Load Diff

View File

@ -24,6 +24,7 @@
#include <libyul/AsmPrinter.h> #include <libyul/AsmPrinter.h>
using namespace std;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::util; using namespace solidity::util;
@ -40,110 +41,110 @@ YulArity YulArity::fromType(FunctionType const& _functionType)
}; };
} }
std::string IRNames::externalFunctionABIWrapper(Declaration const& _functionOrVarDecl) string IRNames::externalFunctionABIWrapper(Declaration const& _functionOrVarDecl)
{ {
if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_functionOrVarDecl)) if (auto const* function = dynamic_cast<FunctionDefinition const*>(&_functionOrVarDecl))
solAssert(!function->isConstructor()); solAssert(!function->isConstructor());
return "external_fun_" + _functionOrVarDecl.name() + "_" + std::to_string(_functionOrVarDecl.id()); return "external_fun_" + _functionOrVarDecl.name() + "_" + to_string(_functionOrVarDecl.id());
} }
std::string IRNames::function(FunctionDefinition const& _function) string IRNames::function(FunctionDefinition const& _function)
{ {
if (_function.isConstructor()) if (_function.isConstructor())
return constructor(*_function.annotation().contract); return constructor(*_function.annotation().contract);
return "fun_" + _function.name() + "_" + std::to_string(_function.id()); return "fun_" + _function.name() + "_" + to_string(_function.id());
} }
std::string IRNames::function(VariableDeclaration const& _varDecl) string IRNames::function(VariableDeclaration const& _varDecl)
{ {
return "getter_fun_" + _varDecl.name() + "_" + std::to_string(_varDecl.id()); return "getter_fun_" + _varDecl.name() + "_" + to_string(_varDecl.id());
} }
std::string IRNames::modifierInvocation(ModifierInvocation const& _modifierInvocation) string IRNames::modifierInvocation(ModifierInvocation const& _modifierInvocation)
{ {
// This uses the ID of the modifier invocation because it has to be unique // This uses the ID of the modifier invocation because it has to be unique
// for each invocation. // for each invocation.
solAssert(!_modifierInvocation.name().path().empty(), ""); solAssert(!_modifierInvocation.name().path().empty(), "");
std::string const& modifierName = _modifierInvocation.name().path().back(); string const& modifierName = _modifierInvocation.name().path().back();
solAssert(!modifierName.empty(), ""); solAssert(!modifierName.empty(), "");
return "modifier_" + modifierName + "_" + std::to_string(_modifierInvocation.id()); return "modifier_" + modifierName + "_" + to_string(_modifierInvocation.id());
} }
std::string IRNames::functionWithModifierInner(FunctionDefinition const& _function) string IRNames::functionWithModifierInner(FunctionDefinition const& _function)
{ {
return "fun_" + _function.name() + "_" + std::to_string(_function.id()) + "_inner"; return "fun_" + _function.name() + "_" + to_string(_function.id()) + "_inner";
} }
std::string IRNames::creationObject(ContractDefinition const& _contract) string IRNames::creationObject(ContractDefinition const& _contract)
{ {
return _contract.name() + "_" + toString(_contract.id()); return _contract.name() + "_" + toString(_contract.id());
} }
std::string IRNames::deployedObject(ContractDefinition const& _contract) string IRNames::deployedObject(ContractDefinition const& _contract)
{ {
return _contract.name() + "_" + toString(_contract.id()) + "_deployed"; return _contract.name() + "_" + toString(_contract.id()) + "_deployed";
} }
std::string IRNames::internalDispatch(YulArity const& _arity) string IRNames::internalDispatch(YulArity const& _arity)
{ {
return "dispatch_internal" return "dispatch_internal"
"_in_" + std::to_string(_arity.in) + "_in_" + to_string(_arity.in) +
"_out_" + std::to_string(_arity.out); "_out_" + to_string(_arity.out);
} }
std::string IRNames::constructor(ContractDefinition const& _contract) string IRNames::constructor(ContractDefinition const& _contract)
{ {
return "constructor_" + _contract.name() + "_" + std::to_string(_contract.id()); return "constructor_" + _contract.name() + "_" + to_string(_contract.id());
} }
std::string IRNames::libraryAddressImmutable() string IRNames::libraryAddressImmutable()
{ {
return "library_deploy_address"; return "library_deploy_address";
} }
std::string IRNames::constantValueFunction(VariableDeclaration const& _constant) string IRNames::constantValueFunction(VariableDeclaration const& _constant)
{ {
solAssert(_constant.isConstant(), ""); solAssert(_constant.isConstant(), "");
return "constant_" + _constant.name() + "_" + std::to_string(_constant.id()); return "constant_" + _constant.name() + "_" + to_string(_constant.id());
} }
std::string IRNames::localVariable(VariableDeclaration const& _declaration) string IRNames::localVariable(VariableDeclaration const& _declaration)
{ {
return "var_" + _declaration.name() + '_' + std::to_string(_declaration.id()); return "var_" + _declaration.name() + '_' + std::to_string(_declaration.id());
} }
std::string IRNames::localVariable(Expression const& _expression) string IRNames::localVariable(Expression const& _expression)
{ {
return "expr_" + std::to_string(_expression.id()); return "expr_" + to_string(_expression.id());
} }
std::string IRNames::trySuccessConditionVariable(Expression const& _expression) string IRNames::trySuccessConditionVariable(Expression const& _expression)
{ {
auto annotation = dynamic_cast<FunctionCallAnnotation const*>(&_expression.annotation()); auto annotation = dynamic_cast<FunctionCallAnnotation const*>(&_expression.annotation());
solAssert(annotation, ""); solAssert(annotation, "");
solAssert(annotation->tryCall, "Parameter must be a FunctionCall with tryCall-annotation set."); solAssert(annotation->tryCall, "Parameter must be a FunctionCall with tryCall-annotation set.");
return "trySuccessCondition_" + std::to_string(_expression.id()); return "trySuccessCondition_" + to_string(_expression.id());
} }
std::string IRNames::tupleComponent(size_t _i) string IRNames::tupleComponent(size_t _i)
{ {
return "component_" + std::to_string(_i + 1); return "component_" + to_string(_i + 1);
} }
std::string IRNames::zeroValue(Type const& _type, std::string const& _variableName) string IRNames::zeroValue(Type const& _type, string const& _variableName)
{ {
return "zero_" + _type.identifier() + _variableName; return "zero_" + _type.identifier() + _variableName;
} }
std::string dispenseLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context) string dispenseLocationComment(langutil::SourceLocation const& _location, IRGenerationContext& _context)
{ {
solAssert(_location.sourceName, ""); solAssert(_location.sourceName, "");
_context.markSourceUsed(*_location.sourceName); _context.markSourceUsed(*_location.sourceName);
std::string debugInfo = AsmPrinter::formatSourceLocation( string debugInfo = AsmPrinter::formatSourceLocation(
_location, _location,
_context.sourceIndices(), _context.sourceIndices(),
_context.debugInfoSelection(), _context.debugInfoSelection(),
@ -153,7 +154,7 @@ std::string dispenseLocationComment(langutil::SourceLocation const& _location, I
return debugInfo.empty() ? "" : "/// " + debugInfo; return debugInfo.empty() ? "" : "/// " + debugInfo;
} }
std::string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context) string dispenseLocationComment(ASTNode const& _node, IRGenerationContext& _context)
{ {
return dispenseLocationComment(_node.location(), _context); return dispenseLocationComment(_node.location(), _context);
} }

View File

@ -31,18 +31,18 @@
#include <libsolutil/StringUtils.h> #include <libsolutil/StringUtils.h>
#include <range/v3/view/map.hpp> #include <range/v3/view/map.hpp>
#include <range/v3/algorithm/find.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::frontend; using namespace solidity::frontend;
std::string IRGenerationContext::enqueueFunctionForCodeGeneration(FunctionDefinition const& _function) string IRGenerationContext::enqueueFunctionForCodeGeneration(FunctionDefinition const& _function)
{ {
std::string name = IRNames::function(_function); string name = IRNames::function(_function);
if (!m_functions.contains(name)) if (!m_functions.contains(name))
m_functionGenerationQueue.push_back(&_function); m_functionGenerationQueue.insert(&_function);
return name; return name;
} }
@ -51,8 +51,8 @@ FunctionDefinition const* IRGenerationContext::dequeueFunctionForCodeGeneration(
{ {
solAssert(!m_functionGenerationQueue.empty(), ""); solAssert(!m_functionGenerationQueue.empty(), "");
FunctionDefinition const* result = m_functionGenerationQueue.front(); FunctionDefinition const* result = *m_functionGenerationQueue.begin();
m_functionGenerationQueue.pop_front(); m_functionGenerationQueue.erase(m_functionGenerationQueue.begin());
return result; return result;
} }
@ -121,19 +121,19 @@ void IRGenerationContext::addStateVariable(
unsigned _byteOffset unsigned _byteOffset
) )
{ {
m_stateVariables[&_declaration] = std::make_pair(std::move(_storageOffset), _byteOffset); m_stateVariables[&_declaration] = make_pair(std::move(_storageOffset), _byteOffset);
} }
std::string IRGenerationContext::newYulVariable() string IRGenerationContext::newYulVariable()
{ {
return "_" + std::to_string(++m_varCounter); return "_" + to_string(++m_varCounter);
} }
void IRGenerationContext::initializeInternalDispatch(InternalDispatchMap _internalDispatch) void IRGenerationContext::initializeInternalDispatch(InternalDispatchMap _internalDispatch)
{ {
solAssert(internalDispatchClean(), ""); solAssert(internalDispatchClean(), "");
for (DispatchQueue const& functions: _internalDispatch | ranges::views::values) for (DispatchSet const& functions: _internalDispatch | ranges::views::values)
for (auto function: functions) for (auto function: functions)
enqueueFunctionForCodeGeneration(*function); enqueueFunctionForCodeGeneration(*function);
@ -150,15 +150,16 @@ InternalDispatchMap IRGenerationContext::consumeInternalDispatchMap()
void IRGenerationContext::addToInternalDispatch(FunctionDefinition const& _function) void IRGenerationContext::addToInternalDispatch(FunctionDefinition const& _function)
{ {
FunctionType const* functionType = TypeProvider::function(_function, FunctionType::Kind::Internal); FunctionType const* functionType = TypeProvider::function(_function, FunctionType::Kind::Internal);
solAssert(functionType); solAssert(functionType, "");
YulArity arity = YulArity::fromType(*functionType); YulArity arity = YulArity::fromType(*functionType);
DispatchQueue& dispatchQueue = m_internalDispatchMap[arity];
if (ranges::find(dispatchQueue, &_function) == ranges::end(dispatchQueue)) if (m_internalDispatchMap.count(arity) != 0 && m_internalDispatchMap[arity].count(&_function) != 0)
{ // Note that m_internalDispatchMap[arity] is a set with a custom comparator, which looks at function IDs not definitions
dispatchQueue.push_back(&_function); solAssert(*m_internalDispatchMap[arity].find(&_function) == &_function, "Different definitions with the same function ID");
m_internalDispatchMap[arity].insert(&_function);
enqueueFunctionForCodeGeneration(_function); enqueueFunctionForCodeGeneration(_function);
}
} }

View File

@ -37,6 +37,7 @@
#include <set> #include <set>
#include <string> #include <string>
#include <memory> #include <memory>
#include <vector>
namespace solidity::frontend namespace solidity::frontend
{ {
@ -44,8 +45,20 @@ namespace solidity::frontend
class YulUtilFunctions; class YulUtilFunctions;
class ABIFunctions; class ABIFunctions;
using DispatchQueue = std::deque<FunctionDefinition const*>; struct AscendingFunctionIDCompare
using InternalDispatchMap = std::map<YulArity, DispatchQueue>; {
bool operator()(FunctionDefinition const* _f1, FunctionDefinition const* _f2) const
{
// NULLs always first.
if (_f1 != nullptr && _f2 != nullptr)
return _f1->id() < _f2->id();
else
return _f1 == nullptr;
}
};
using DispatchSet = std::set<FunctionDefinition const*, AscendingFunctionIDCompare>;
using InternalDispatchMap = std::map<YulArity, DispatchSet>;
/** /**
* Class that contains contextual information during IR generation. * Class that contains contextual information during IR generation.
@ -184,9 +197,10 @@ private:
/// were discovered by the IR generator during AST traversal. /// were discovered by the IR generator during AST traversal.
/// Note that the queue gets filled in a lazy way - new definitions can be added while the /// Note that the queue gets filled in a lazy way - new definitions can be added while the
/// collected ones get removed and traversed. /// collected ones get removed and traversed.
/// The order and duplicates are relevant here /// The order and duplicates are irrelevant here (hence std::set rather than std::queue) as
/// (see: IRGenerationContext::[enqueue|dequeue]FunctionForCodeGeneration) /// long as the order of Yul functions in the generated code is deterministic and the same on
DispatchQueue m_functionGenerationQueue; /// all platforms - which is a property guaranteed by MultiUseYulFunctionCollector.
DispatchSet m_functionGenerationQueue;
/// Collection of functions that need to be callable via internal dispatch. /// Collection of functions that need to be callable via internal dispatch.
/// Note that having a key with an empty set of functions is a valid situation. It means that /// Note that having a key with an empty set of functions is a valid situation. It means that

View File

@ -38,23 +38,25 @@
#include <libsolutil/StringUtils.h> #include <libsolutil/StringUtils.h>
#include <libsolutil/Whiskers.h> #include <libsolutil/Whiskers.h>
#include <liblangutil/SourceReferenceFormatter.h>
#include <json/json.h> #include <json/json.h>
#include <sstream> #include <sstream>
#include <variant> #include <variant>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::langutil; using namespace solidity::langutil;
using namespace solidity::util; using namespace solidity::util;
using namespace std::string_literals;
namespace namespace
{ {
void verifyCallGraph( void verifyCallGraph(
std::set<CallableDeclaration const*, ASTNode::CompareByID> const& _expectedCallables, set<CallableDeclaration const*, ASTNode::CompareByID> const& _expectedCallables,
std::set<FunctionDefinition const*> _generatedFunctions set<FunctionDefinition const*> _generatedFunctions
) )
{ {
for (auto const& expectedCallable: _expectedCallables) for (auto const& expectedCallable: _expectedCallables)
@ -73,47 +75,47 @@ void verifyCallGraph(
); );
} }
std::set<CallableDeclaration const*, ASTNode::CompareByID> collectReachableCallables( set<CallableDeclaration const*, ASTNode::CompareByID> collectReachableCallables(
CallGraph const& _graph CallGraph const& _graph
) )
{ {
std::set<CallableDeclaration const*, ASTNode::CompareByID> reachableCallables; set<CallableDeclaration const*, ASTNode::CompareByID> reachableCallables;
for (CallGraph::Node const& reachableNode: _graph.edges | ranges::views::keys) for (CallGraph::Node const& reachableNode: _graph.edges | ranges::views::keys)
if (std::holds_alternative<CallableDeclaration const*>(reachableNode)) if (holds_alternative<CallableDeclaration const*>(reachableNode))
reachableCallables.emplace(std::get<CallableDeclaration const*>(reachableNode)); reachableCallables.emplace(get<CallableDeclaration const*>(reachableNode));
return reachableCallables; return reachableCallables;
} }
} }
std::string IRGenerator::run( string IRGenerator::run(
ContractDefinition const& _contract, ContractDefinition const& _contract,
bytes const& _cborMetadata, bytes const& _cborMetadata,
std::map<ContractDefinition const*, std::string_view const> const& _otherYulSources map<ContractDefinition const*, string_view const> const& _otherYulSources
) )
{ {
return yul::reindent(generate(_contract, _cborMetadata, _otherYulSources)); return yul::reindent(generate(_contract, _cborMetadata, _otherYulSources));
} }
std::string IRGenerator::generate( string IRGenerator::generate(
ContractDefinition const& _contract, ContractDefinition const& _contract,
bytes const& _cborMetadata, bytes const& _cborMetadata,
std::map<ContractDefinition const*, std::string_view const> const& _otherYulSources map<ContractDefinition const*, string_view const> const& _otherYulSources
) )
{ {
auto subObjectSources = [&_otherYulSources](std::set<ContractDefinition const*, ASTNode::CompareByID> const& subObjects) -> std::string auto subObjectSources = [&_otherYulSources](std::set<ContractDefinition const*, ASTNode::CompareByID> const& subObjects) -> string
{ {
std::string subObjectsSources; std::string subObjectsSources;
for (ContractDefinition const* subObject: subObjects) for (ContractDefinition const* subObject: subObjects)
subObjectsSources += _otherYulSources.at(subObject); subObjectsSources += _otherYulSources.at(subObject);
return subObjectsSources; return subObjectsSources;
}; };
auto formatUseSrcMap = [](IRGenerationContext const& _context) -> std::string auto formatUseSrcMap = [](IRGenerationContext const& _context) -> string
{ {
return joinHumanReadable( return joinHumanReadable(
ranges::views::transform(_context.usedSourceNames(), [_context](std::string const& _sourceName) { ranges::views::transform(_context.usedSourceNames(), [_context](string const& _sourceName) {
return std::to_string(_context.sourceIndices().at(_sourceName)) + ":" + escapeAndQuoteString(_sourceName); return to_string(_context.sourceIndices().at(_sourceName)) + ":" + escapeAndQuoteString(_sourceName);
}), }),
", " ", "
); );
@ -162,7 +164,7 @@ std::string IRGenerator::generate(
FunctionDefinition const* constructor = _contract.constructor(); FunctionDefinition const* constructor = _contract.constructor();
t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : ""); t("callValueCheck", !constructor || !constructor->isPayable() ? callValueCheck() : "");
std::vector<std::string> constructorParams; vector<string> constructorParams;
if (constructor && !constructor->parameters().empty()) if (constructor && !constructor->parameters().empty())
{ {
for (size_t i = 0; i < CompilerUtils::sizeOnStack(constructor->parameters()); ++i) for (size_t i = 0; i < CompilerUtils::sizeOnStack(constructor->parameters()); ++i)
@ -178,7 +180,7 @@ std::string IRGenerator::generate(
t("deploy", deployCode(_contract)); t("deploy", deployCode(_contract));
generateConstructors(_contract); generateConstructors(_contract);
std::set<FunctionDefinition const*> creationFunctionList = generateQueuedFunctions(); set<FunctionDefinition const*> creationFunctionList = generateQueuedFunctions();
InternalDispatchMap internalDispatchMap = generateInternalDispatchFunctions(_contract); InternalDispatchMap internalDispatchMap = generateInternalDispatchFunctions(_contract);
t("functions", m_context.functionCollector().requestedFunctions()); t("functions", m_context.functionCollector().requestedFunctions());
@ -201,7 +203,7 @@ std::string IRGenerator::generate(
t("sourceLocationCommentDeployed", dispenseLocationComment(_contract)); t("sourceLocationCommentDeployed", dispenseLocationComment(_contract));
t("library_address", IRNames::libraryAddressImmutable()); t("library_address", IRNames::libraryAddressImmutable());
t("dispatch", dispatchRoutine(_contract)); t("dispatch", dispatchRoutine(_contract));
std::set<FunctionDefinition const*> deployedFunctionList = generateQueuedFunctions(); set<FunctionDefinition const*> deployedFunctionList = generateQueuedFunctions();
generateInternalDispatchFunctions(_contract); generateInternalDispatchFunctions(_contract);
t("deployedFunctions", m_context.functionCollector().requestedFunctions()); t("deployedFunctions", m_context.functionCollector().requestedFunctions());
t("deployedSubObjects", subObjectSources(m_context.subObjectsCreated())); t("deployedSubObjects", subObjectSources(m_context.subObjectsCreated()));
@ -222,16 +224,16 @@ std::string IRGenerator::generate(
return t.render(); return t.render();
} }
std::string IRGenerator::generate(Block const& _block) string IRGenerator::generate(Block const& _block)
{ {
IRGeneratorForStatements generator(m_context, m_utils); IRGeneratorForStatements generator(m_context, m_utils);
generator.generate(_block); generator.generate(_block);
return generator.code(); return generator.code();
} }
std::set<FunctionDefinition const*> IRGenerator::generateQueuedFunctions() set<FunctionDefinition const*> IRGenerator::generateQueuedFunctions()
{ {
std::set<FunctionDefinition const*> functions; set<FunctionDefinition const*> functions;
while (!m_context.functionGenerationQueueEmpty()) while (!m_context.functionGenerationQueueEmpty())
{ {
@ -256,7 +258,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin
InternalDispatchMap internalDispatchMap = m_context.consumeInternalDispatchMap(); InternalDispatchMap internalDispatchMap = m_context.consumeInternalDispatchMap();
for (YulArity const& arity: internalDispatchMap | ranges::views::keys) for (YulArity const& arity: internalDispatchMap | ranges::views::keys)
{ {
std::string funName = IRNames::internalDispatch(arity); string funName = IRNames::internalDispatch(arity);
m_context.functionCollector().createFunction(funName, [&]() { m_context.functionCollector().createFunction(funName, [&]() {
Whiskers templ(R"( Whiskers templ(R"(
<sourceLocationComment> <sourceLocationComment>
@ -278,8 +280,7 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin
templ("in", suffixedVariableNameList("in_", 0, arity.in)); templ("in", suffixedVariableNameList("in_", 0, arity.in));
templ("out", suffixedVariableNameList("out_", 0, arity.out)); templ("out", suffixedVariableNameList("out_", 0, arity.out));
std::vector<std::map<std::string, std::string>> cases; vector<map<string, string>> cases;
std::set<int64_t> caseValues;
for (FunctionDefinition const* function: internalDispatchMap.at(arity)) for (FunctionDefinition const* function: internalDispatchMap.at(arity))
{ {
solAssert(function, ""); solAssert(function, "");
@ -290,14 +291,12 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin
solAssert(!function->isConstructor(), ""); solAssert(!function->isConstructor(), "");
// 0 is reserved for uninitialized function pointers // 0 is reserved for uninitialized function pointers
solAssert(function->id() != 0, "Unexpected function ID: 0"); solAssert(function->id() != 0, "Unexpected function ID: 0");
solAssert(caseValues.count(function->id()) == 0, "Duplicate function ID");
solAssert(m_context.functionCollector().contains(IRNames::function(*function)), ""); solAssert(m_context.functionCollector().contains(IRNames::function(*function)), "");
cases.emplace_back(std::map<std::string, std::string>{ cases.emplace_back(map<string, string>{
{"funID", std::to_string(m_context.mostDerivedContract().annotation().internalFunctionIDs.at(function))}, {"funID", to_string(m_context.mostDerivedContract().annotation().internalFunctionIDs.at(function))},
{"name", IRNames::function(*function)} {"name", IRNames::function(*function)}
}); });
caseValues.insert(function->id());
} }
templ("cases", std::move(cases)); templ("cases", std::move(cases));
@ -314,9 +313,9 @@ InternalDispatchMap IRGenerator::generateInternalDispatchFunctions(ContractDefin
return internalDispatchMap; return internalDispatchMap;
} }
std::string IRGenerator::generateFunction(FunctionDefinition const& _function) string IRGenerator::generateFunction(FunctionDefinition const& _function)
{ {
std::string functionName = IRNames::function(_function); string functionName = IRNames::function(_function);
return m_context.functionCollector().createFunction(functionName, [&]() { return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables(); m_context.resetLocalVariables();
Whiskers t(R"( Whiskers t(R"(
@ -329,7 +328,7 @@ std::string IRGenerator::generateFunction(FunctionDefinition const& _function)
)"); )");
if (m_context.debugInfoSelection().astID) if (m_context.debugInfoSelection().astID)
t("astIDComment", "/// @ast-id " + std::to_string(_function.id()) + "\n"); t("astIDComment", "/// @ast-id " + to_string(_function.id()) + "\n");
else else
t("astIDComment", ""); t("astIDComment", "");
t("sourceLocationComment", dispenseLocationComment(_function)); t("sourceLocationComment", dispenseLocationComment(_function));
@ -339,12 +338,12 @@ std::string IRGenerator::generateFunction(FunctionDefinition const& _function)
); );
t("functionName", functionName); t("functionName", functionName);
std::vector<std::string> params; vector<string> params;
for (auto const& varDecl: _function.parameters()) for (auto const& varDecl: _function.parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots(); params += m_context.addLocalVariable(*varDecl).stackSlots();
t("params", joinHumanReadable(params)); t("params", joinHumanReadable(params));
std::vector<std::string> retParams; vector<string> retParams;
std::string retInit; string retInit;
for (auto const& varDecl: _function.returnParameters()) for (auto const& varDecl: _function.returnParameters())
{ {
retParams += m_context.addLocalVariable(*varDecl).stackSlots(); retParams += m_context.addLocalVariable(*varDecl).stackSlots();
@ -361,14 +360,14 @@ std::string IRGenerator::generateFunction(FunctionDefinition const& _function)
for (size_t i = 0; i < _function.modifiers().size(); ++i) for (size_t i = 0; i < _function.modifiers().size(); ++i)
{ {
ModifierInvocation const& modifier = *_function.modifiers().at(i); ModifierInvocation const& modifier = *_function.modifiers().at(i);
std::string next = string next =
i + 1 < _function.modifiers().size() ? i + 1 < _function.modifiers().size() ?
IRNames::modifierInvocation(*_function.modifiers().at(i + 1)) : IRNames::modifierInvocation(*_function.modifiers().at(i + 1)) :
IRNames::functionWithModifierInner(_function); IRNames::functionWithModifierInner(_function);
generateModifier(modifier, _function, next); generateModifier(modifier, _function, next);
} }
t("body", t("body",
(retParams.empty() ? std::string{} : joinHumanReadable(retParams) + " := ") + (retParams.empty() ? string{} : joinHumanReadable(retParams) + " := ") +
IRNames::modifierInvocation(*_function.modifiers().at(0)) + IRNames::modifierInvocation(*_function.modifiers().at(0)) +
"(" + "(" +
joinHumanReadable(retParams + params) + joinHumanReadable(retParams + params) +
@ -381,13 +380,13 @@ std::string IRGenerator::generateFunction(FunctionDefinition const& _function)
}); });
} }
std::string IRGenerator::generateModifier( string IRGenerator::generateModifier(
ModifierInvocation const& _modifierInvocation, ModifierInvocation const& _modifierInvocation,
FunctionDefinition const& _function, FunctionDefinition const& _function,
std::string const& _nextFunction string const& _nextFunction
) )
{ {
std::string functionName = IRNames::modifierInvocation(_modifierInvocation); string functionName = IRNames::modifierInvocation(_modifierInvocation);
return m_context.functionCollector().createFunction(functionName, [&]() { return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables(); m_context.resetLocalVariables();
Whiskers t(R"( Whiskers t(R"(
@ -401,15 +400,15 @@ std::string IRGenerator::generateModifier(
)"); )");
t("functionName", functionName); t("functionName", functionName);
std::vector<std::string> retParamsIn; vector<string> retParamsIn;
for (auto const& varDecl: _function.returnParameters()) for (auto const& varDecl: _function.returnParameters())
retParamsIn += m_context.addLocalVariable(*varDecl).stackSlots(); retParamsIn += m_context.addLocalVariable(*varDecl).stackSlots();
std::vector<std::string> params = retParamsIn; vector<string> params = retParamsIn;
for (auto const& varDecl: _function.parameters()) for (auto const& varDecl: _function.parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots(); params += m_context.addLocalVariable(*varDecl).stackSlots();
t("params", joinHumanReadable(params)); t("params", joinHumanReadable(params));
std::vector<std::string> retParams; vector<string> retParams;
std::string assignRetParams; string assignRetParams;
for (size_t i = 0; i < retParamsIn.size(); ++i) for (size_t i = 0; i < retParamsIn.size(); ++i)
{ {
retParams.emplace_back(m_context.newYulVariable()); retParams.emplace_back(m_context.newYulVariable());
@ -424,7 +423,7 @@ std::string IRGenerator::generateModifier(
solAssert(modifier, ""); solAssert(modifier, "");
if (m_context.debugInfoSelection().astID) if (m_context.debugInfoSelection().astID)
t("astIDComment", "/// @ast-id " + std::to_string(modifier->id()) + "\n"); t("astIDComment", "/// @ast-id " + to_string(modifier->id()) + "\n");
else else
t("astIDComment", ""); t("astIDComment", "");
t("sourceLocationComment", dispenseLocationComment(*modifier)); t("sourceLocationComment", dispenseLocationComment(*modifier));
@ -466,7 +465,7 @@ std::string IRGenerator::generateModifier(
t("evalArgs", expressionEvaluator.code()); t("evalArgs", expressionEvaluator.code());
IRGeneratorForStatements generator(m_context, m_utils, [&]() { IRGeneratorForStatements generator(m_context, m_utils, [&]() {
std::string ret = joinHumanReadable(retParams); string ret = joinHumanReadable(retParams);
return return
(ret.empty() ? "" : ret + " := ") + (ret.empty() ? "" : ret + " := ") +
_nextFunction + "(" + joinHumanReadable(params) + ")\n"; _nextFunction + "(" + joinHumanReadable(params) + ")\n";
@ -477,9 +476,9 @@ std::string IRGenerator::generateModifier(
}); });
} }
std::string IRGenerator::generateFunctionWithModifierInner(FunctionDefinition const& _function) string IRGenerator::generateFunctionWithModifierInner(FunctionDefinition const& _function)
{ {
std::string functionName = IRNames::functionWithModifierInner(_function); string functionName = IRNames::functionWithModifierInner(_function);
return m_context.functionCollector().createFunction(functionName, [&]() { return m_context.functionCollector().createFunction(functionName, [&]() {
m_context.resetLocalVariables(); m_context.resetLocalVariables();
Whiskers t(R"( Whiskers t(R"(
@ -496,17 +495,17 @@ std::string IRGenerator::generateFunctionWithModifierInner(FunctionDefinition co
dispenseLocationComment(m_context.mostDerivedContract()) dispenseLocationComment(m_context.mostDerivedContract())
); );
t("functionName", functionName); t("functionName", functionName);
std::vector<std::string> retParams; vector<string> retParams;
std::vector<std::string> retParamsIn; vector<string> retParamsIn;
for (auto const& varDecl: _function.returnParameters()) for (auto const& varDecl: _function.returnParameters())
retParams += m_context.addLocalVariable(*varDecl).stackSlots(); retParams += m_context.addLocalVariable(*varDecl).stackSlots();
std::string assignRetParams; string assignRetParams;
for (size_t i = 0; i < retParams.size(); ++i) for (size_t i = 0; i < retParams.size(); ++i)
{ {
retParamsIn.emplace_back(m_context.newYulVariable()); retParamsIn.emplace_back(m_context.newYulVariable());
assignRetParams += retParams.at(i) + " := " + retParamsIn.at(i) + "\n"; assignRetParams += retParams.at(i) + " := " + retParamsIn.at(i) + "\n";
} }
std::vector<std::string> params = retParamsIn; vector<string> params = retParamsIn;
for (auto const& varDecl: _function.parameters()) for (auto const& varDecl: _function.parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots(); params += m_context.addLocalVariable(*varDecl).stackSlots();
t("params", joinHumanReadable(params)); t("params", joinHumanReadable(params));
@ -517,9 +516,9 @@ std::string IRGenerator::generateFunctionWithModifierInner(FunctionDefinition co
}); });
} }
std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl) string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
{ {
std::string functionName = IRNames::function(_varDecl); string functionName = IRNames::function(_varDecl);
return m_context.functionCollector().createFunction(functionName, [&]() { return m_context.functionCollector().createFunction(functionName, [&]() {
Type const* type = _varDecl.annotation().type; Type const* type = _varDecl.annotation().type;
@ -541,7 +540,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
( (
"astIDComment", "astIDComment",
m_context.debugInfoSelection().astID ? m_context.debugInfoSelection().astID ?
"/// @ast-id " + std::to_string(_varDecl.id()) + "\n" : "/// @ast-id " + to_string(_varDecl.id()) + "\n" :
"" ""
) )
("sourceLocationComment", dispenseLocationComment(_varDecl)) ("sourceLocationComment", dispenseLocationComment(_varDecl))
@ -550,7 +549,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
dispenseLocationComment(m_context.mostDerivedContract()) dispenseLocationComment(m_context.mostDerivedContract())
) )
("functionName", functionName) ("functionName", functionName)
("id", std::to_string(_varDecl.id())) ("id", to_string(_varDecl.id()))
.render(); .render();
} }
else if (_varDecl.isConstant()) else if (_varDecl.isConstant())
@ -566,7 +565,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
( (
"astIDComment", "astIDComment",
m_context.debugInfoSelection().astID ? m_context.debugInfoSelection().astID ?
"/// @ast-id " + std::to_string(_varDecl.id()) + "\n" : "/// @ast-id " + to_string(_varDecl.id()) + "\n" :
"" ""
) )
("sourceLocationComment", dispenseLocationComment(_varDecl)) ("sourceLocationComment", dispenseLocationComment(_varDecl))
@ -580,7 +579,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
.render(); .render();
} }
std::string code; string code;
auto const& location = m_context.storageLocationOfStateVariable(_varDecl); auto const& location = m_context.storageLocationOfStateVariable(_varDecl);
code += Whiskers(R"( code += Whiskers(R"(
@ -588,7 +587,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
let offset := <offset> let offset := <offset>
)") )")
("slot", location.first.str()) ("slot", location.first.str())
("offset", std::to_string(location.second)) ("offset", to_string(location.second))
.render(); .render();
if (!paramTypes.empty()) if (!paramTypes.empty())
@ -604,8 +603,8 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
// The initial value of @a currentType is only used if we skip the loop completely. // The initial value of @a currentType is only used if we skip the loop completely.
Type const* currentType = _varDecl.annotation().type; Type const* currentType = _varDecl.annotation().type;
std::vector<std::string> parameters; vector<string> parameters;
std::vector<std::string> returnVariables; vector<string> returnVariables;
for (size_t i = 0; i < paramTypes.size(); ++i) for (size_t i = 0; i < paramTypes.size(); ++i)
{ {
@ -613,7 +612,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
ArrayType const* arrayType = dynamic_cast<ArrayType const*>(currentType); ArrayType const* arrayType = dynamic_cast<ArrayType const*>(currentType);
solAssert(mappingType || arrayType, ""); solAssert(mappingType || arrayType, "");
std::vector<std::string> keys = IRVariable("key_" + std::to_string(i), vector<string> keys = IRVariable("key_" + to_string(i),
mappingType ? *mappingType->keyType() : *TypeProvider::uint256() mappingType ? *mappingType->keyType() : *TypeProvider::uint256()
).stackSlots(); ).stackSlots();
parameters += keys; parameters += keys;
@ -656,8 +655,8 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
) )
continue; continue;
std::pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]); pair<u256, unsigned> const& offsets = structType->storageOffsetsOfMember(names[i]);
std::vector<std::string> retVars = IRVariable("ret_" + std::to_string(returnVariables.size()), *returnTypes[i]).stackSlots(); vector<string> retVars = IRVariable("ret_" + to_string(returnVariables.size()), *returnTypes[i]).stackSlots();
returnVariables += retVars; returnVariables += retVars;
code += Whiskers(R"( code += Whiskers(R"(
<ret> := <readStorage>(add(slot, <slotOffset>)) <ret> := <readStorage>(add(slot, <slotOffset>))
@ -674,7 +673,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes.front()); auto const* arrayType = dynamic_cast<ArrayType const*>(returnTypes.front());
if (arrayType) if (arrayType)
solAssert(arrayType->isByteArrayOrString(), ""); solAssert(arrayType->isByteArrayOrString(), "");
std::vector<std::string> retVars = IRVariable("ret", *returnTypes.front()).stackSlots(); vector<string> retVars = IRVariable("ret", *returnTypes.front()).stackSlots();
returnVariables += retVars; returnVariables += retVars;
code += Whiskers(R"( code += Whiskers(R"(
<ret> := <readStorage>(slot, offset) <ret> := <readStorage>(slot, offset)
@ -698,7 +697,7 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
( (
"astIDComment", "astIDComment",
m_context.debugInfoSelection().astID ? m_context.debugInfoSelection().astID ?
"/// @ast-id " + std::to_string(_varDecl.id()) + "\n" : "/// @ast-id " + to_string(_varDecl.id()) + "\n" :
"" ""
) )
("sourceLocationComment", dispenseLocationComment(_varDecl)) ("sourceLocationComment", dispenseLocationComment(_varDecl))
@ -710,10 +709,10 @@ std::string IRGenerator::generateGetter(VariableDeclaration const& _varDecl)
}); });
} }
std::string IRGenerator::generateExternalFunction(ContractDefinition const& _contract, FunctionType const& _functionType) string IRGenerator::generateExternalFunction(ContractDefinition const& _contract, FunctionType const& _functionType)
{ {
std::string functionName = IRNames::externalFunctionABIWrapper(_functionType.declaration()); string functionName = IRNames::externalFunctionABIWrapper(_functionType.declaration());
return m_context.functionCollector().createFunction(functionName, [&](std::vector<std::string>&, std::vector<std::string>&) -> std::string { return m_context.functionCollector().createFunction(functionName, [&](vector<string>&, vector<string>&) -> string {
Whiskers t(R"X( Whiskers t(R"X(
<callValueCheck> <callValueCheck>
<?+params>let <params> := </+params> <abiDecode>(4, calldatasize()) <?+params>let <params> := </+params> <abiDecode>(4, calldatasize())
@ -724,8 +723,8 @@ std::string IRGenerator::generateExternalFunction(ContractDefinition const& _con
)X"); )X");
t("callValueCheck", (_functionType.isPayable() || _contract.isLibrary()) ? "" : callValueCheck()); t("callValueCheck", (_functionType.isPayable() || _contract.isLibrary()) ? "" : callValueCheck());
unsigned paramVars = std::make_shared<TupleType>(_functionType.parameterTypes())->sizeOnStack(); unsigned paramVars = make_shared<TupleType>(_functionType.parameterTypes())->sizeOnStack();
unsigned retVars = std::make_shared<TupleType>(_functionType.returnParameterTypes())->sizeOnStack(); unsigned retVars = make_shared<TupleType>(_functionType.returnParameterTypes())->sizeOnStack();
ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector()); ABIFunctions abiFunctions(m_evmVersion, m_context.revertStrings(), m_context.functionCollector());
t("abiDecode", abiFunctions.tupleDecoder(_functionType.parameterTypes())); t("abiDecode", abiFunctions.tupleDecoder(_functionType.parameterTypes()));
@ -748,14 +747,14 @@ std::string IRGenerator::generateExternalFunction(ContractDefinition const& _con
}); });
} }
std::string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl) string IRGenerator::generateInitialAssignment(VariableDeclaration const& _varDecl)
{ {
IRGeneratorForStatements generator(m_context, m_utils); IRGeneratorForStatements generator(m_context, m_utils);
generator.initializeLocalVar(_varDecl); generator.initializeLocalVar(_varDecl);
return generator.code(); return generator.code();
} }
std::pair<std::string, std::map<ContractDefinition const*, std::vector<std::string>>> IRGenerator::evaluateConstructorArguments( pair<string, map<ContractDefinition const*, vector<string>>> IRGenerator::evaluateConstructorArguments(
ContractDefinition const& _contract ContractDefinition const& _contract
) )
{ {
@ -768,12 +767,12 @@ std::pair<std::string, std::map<ContractDefinition const*, std::vector<std::stri
auto it2 = find(linearizedBaseContracts.begin(), linearizedBaseContracts.end(), _c2); auto it2 = find(linearizedBaseContracts.begin(), linearizedBaseContracts.end(), _c2);
return it1 < it2; return it1 < it2;
} }
std::vector<ContractDefinition const*> const& linearizedBaseContracts; vector<ContractDefinition const*> const& linearizedBaseContracts;
} inheritanceOrder{_contract.annotation().linearizedBaseContracts}; } inheritanceOrder{_contract.annotation().linearizedBaseContracts};
std::map<ContractDefinition const*, std::vector<std::string>> constructorParams; map<ContractDefinition const*, vector<string>> constructorParams;
std::map<ContractDefinition const*, std::vector<ASTPointer<Expression>>const *, InheritanceOrder> map<ContractDefinition const*, std::vector<ASTPointer<Expression>>const *, InheritanceOrder>
baseConstructorArguments(inheritanceOrder); baseConstructorArguments(inheritanceOrder);
for (ASTPointer<InheritanceSpecifier> const& base: _contract.baseContracts()) for (ASTPointer<InheritanceSpecifier> const& base: _contract.baseContracts())
@ -805,7 +804,7 @@ std::pair<std::string, std::map<ContractDefinition const*, std::vector<std::stri
solAssert(baseContract && arguments, ""); solAssert(baseContract && arguments, "");
if (baseContract->constructor() && !arguments->empty()) if (baseContract->constructor() && !arguments->empty())
{ {
std::vector<std::string> params; vector<string> params;
for (size_t i = 0; i < arguments->size(); ++i) for (size_t i = 0; i < arguments->size(); ++i)
params += generator.evaluateExpression( params += generator.evaluateExpression(
*(arguments->at(i)), *(arguments->at(i)),
@ -818,7 +817,7 @@ std::pair<std::string, std::map<ContractDefinition const*, std::vector<std::stri
return {generator.code(), constructorParams}; return {generator.code(), constructorParams};
} }
std::string IRGenerator::initStateVariables(ContractDefinition const& _contract) string IRGenerator::initStateVariables(ContractDefinition const& _contract)
{ {
IRGeneratorForStatements generator{m_context, m_utils}; IRGeneratorForStatements generator{m_context, m_utils};
for (VariableDeclaration const* variable: _contract.stateVariables()) for (VariableDeclaration const* variable: _contract.stateVariables())
@ -832,16 +831,16 @@ std::string IRGenerator::initStateVariables(ContractDefinition const& _contract)
void IRGenerator::generateConstructors(ContractDefinition const& _contract) void IRGenerator::generateConstructors(ContractDefinition const& _contract)
{ {
auto listAllParams = auto listAllParams =
[&](std::map<ContractDefinition const*, std::vector<std::string>> const& baseParams) -> std::vector<std::string> [&](map<ContractDefinition const*, vector<string>> const& baseParams) -> vector<string>
{ {
std::vector<std::string> params; vector<string> params;
for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts) for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
if (baseParams.count(contract)) if (baseParams.count(contract))
params += baseParams.at(contract); params += baseParams.at(contract);
return params; return params;
}; };
std::map<ContractDefinition const*, std::vector<std::string>> baseConstructorParams; map<ContractDefinition const*, vector<string>> baseConstructorParams;
for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i) for (size_t i = 0; i < _contract.annotation().linearizedBaseContracts.size(); ++i)
{ {
ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i]; ContractDefinition const* contract = _contract.annotation().linearizedBaseContracts[i];
@ -860,13 +859,13 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract)
} }
<contractSourceLocationComment> <contractSourceLocationComment>
)"); )");
std::vector<std::string> params; vector<string> params;
if (contract->constructor()) if (contract->constructor())
for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters()) for (ASTPointer<VariableDeclaration> const& varDecl: contract->constructor()->parameters())
params += m_context.addLocalVariable(*varDecl).stackSlots(); params += m_context.addLocalVariable(*varDecl).stackSlots();
if (m_context.debugInfoSelection().astID && contract->constructor()) if (m_context.debugInfoSelection().astID && contract->constructor())
t("astIDComment", "/// @ast-id " + std::to_string(contract->constructor()->id()) + "\n"); t("astIDComment", "/// @ast-id " + to_string(contract->constructor()->id()) + "\n");
else else
t("astIDComment", ""); t("astIDComment", "");
t("sourceLocationComment", dispenseLocationComment( t("sourceLocationComment", dispenseLocationComment(
@ -880,11 +879,11 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract)
); );
t("params", joinHumanReadable(params)); t("params", joinHumanReadable(params));
std::vector<std::string> baseParams = listAllParams(baseConstructorParams); vector<string> baseParams = listAllParams(baseConstructorParams);
t("baseParams", joinHumanReadable(baseParams)); t("baseParams", joinHumanReadable(baseParams));
t("comma", !params.empty() && !baseParams.empty() ? ", " : ""); t("comma", !params.empty() && !baseParams.empty() ? ", " : "");
t("functionName", IRNames::constructor(*contract)); t("functionName", IRNames::constructor(*contract));
std::pair<std::string, std::map<ContractDefinition const*, std::vector<std::string>>> evaluatedArgs = evaluateConstructorArguments(*contract); pair<string, map<ContractDefinition const*, vector<string>>> evaluatedArgs = evaluateConstructorArguments(*contract);
baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end()); baseConstructorParams.insert(evaluatedArgs.second.begin(), evaluatedArgs.second.end());
t("evalBaseArguments", evaluatedArgs.first); t("evalBaseArguments", evaluatedArgs.first);
if (i < _contract.annotation().linearizedBaseContracts.size() - 1) if (i < _contract.annotation().linearizedBaseContracts.size() - 1)
@ -897,10 +896,10 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract)
else else
t("hasNextConstructor", false); t("hasNextConstructor", false);
t("initStateVariables", initStateVariables(*contract)); t("initStateVariables", initStateVariables(*contract));
std::string body; string body;
if (FunctionDefinition const* constructor = contract->constructor()) if (FunctionDefinition const* constructor = contract->constructor())
{ {
std::vector<ModifierInvocation*> realModifiers; vector<ModifierInvocation*> realModifiers;
for (auto const& modifierInvocation: constructor->modifiers()) for (auto const& modifierInvocation: constructor->modifiers())
// Filter out the base constructor calls // Filter out the base constructor calls
if (dynamic_cast<ModifierDefinition const*>(modifierInvocation->name().annotation().referencedDeclaration)) if (dynamic_cast<ModifierDefinition const*>(modifierInvocation->name().annotation().referencedDeclaration))
@ -912,7 +911,7 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract)
for (size_t i = 0; i < realModifiers.size(); ++i) for (size_t i = 0; i < realModifiers.size(); ++i)
{ {
ModifierInvocation const& modifier = *realModifiers.at(i); ModifierInvocation const& modifier = *realModifiers.at(i);
std::string next = string next =
i + 1 < realModifiers.size() ? i + 1 < realModifiers.size() ?
IRNames::modifierInvocation(*realModifiers.at(i + 1)) : IRNames::modifierInvocation(*realModifiers.at(i + 1)) :
IRNames::functionWithModifierInner(*constructor); IRNames::functionWithModifierInner(*constructor);
@ -934,7 +933,7 @@ void IRGenerator::generateConstructors(ContractDefinition const& _contract)
} }
} }
std::string IRGenerator::deployCode(ContractDefinition const& _contract) string IRGenerator::deployCode(ContractDefinition const& _contract)
{ {
Whiskers t(R"X( Whiskers t(R"X(
let <codeOffset> := <allocateUnbounded>() let <codeOffset> := <allocateUnbounded>()
@ -948,11 +947,11 @@ std::string IRGenerator::deployCode(ContractDefinition const& _contract)
t("codeOffset", m_context.newYulVariable()); t("codeOffset", m_context.newYulVariable());
t("object", IRNames::deployedObject(_contract)); t("object", IRNames::deployedObject(_contract));
std::vector<std::map<std::string, std::string>> immutables; vector<map<string, string>> immutables;
if (_contract.isLibrary()) if (_contract.isLibrary())
{ {
solAssert(ContractType(_contract).immutableVariables().empty(), ""); solAssert(ContractType(_contract).immutableVariables().empty(), "");
immutables.emplace_back(std::map<std::string, std::string>{ immutables.emplace_back(map<string, string>{
{"immutableName"s, IRNames::libraryAddressImmutable()}, {"immutableName"s, IRNames::libraryAddressImmutable()},
{"value"s, "address()"} {"value"s, "address()"}
}); });
@ -963,21 +962,21 @@ std::string IRGenerator::deployCode(ContractDefinition const& _contract)
{ {
solUnimplementedAssert(immutable->type()->isValueType()); solUnimplementedAssert(immutable->type()->isValueType());
solUnimplementedAssert(immutable->type()->sizeOnStack() == 1); solUnimplementedAssert(immutable->type()->sizeOnStack() == 1);
immutables.emplace_back(std::map<std::string, std::string>{ immutables.emplace_back(map<string, string>{
{"immutableName"s, std::to_string(immutable->id())}, {"immutableName"s, to_string(immutable->id())},
{"value"s, "mload(" + std::to_string(m_context.immutableMemoryOffset(*immutable)) + ")"} {"value"s, "mload(" + to_string(m_context.immutableMemoryOffset(*immutable)) + ")"}
}); });
} }
t("immutables", std::move(immutables)); t("immutables", std::move(immutables));
return t.render(); return t.render();
} }
std::string IRGenerator::callValueCheck() string IRGenerator::callValueCheck()
{ {
return "if callvalue() { " + m_utils.revertReasonIfDebugFunction("Ether sent to non-payable function") + "() }"; return "if callvalue() { " + m_utils.revertReasonIfDebugFunction("Ether sent to non-payable function") + "() }";
} }
std::string IRGenerator::dispatchRoutine(ContractDefinition const& _contract) string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
{ {
Whiskers t(R"X( Whiskers t(R"X(
<?+cases>if iszero(lt(calldatasize(), 4)) <?+cases>if iszero(lt(calldatasize(), 4))
@ -998,15 +997,15 @@ std::string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
<fallback> <fallback>
)X"); )X");
t("shr224", m_utils.shiftRightFunction(224)); t("shr224", m_utils.shiftRightFunction(224));
std::vector<std::map<std::string, std::string>> functions; vector<map<string, string>> functions;
for (auto const& function: _contract.interfaceFunctions()) for (auto const& function: _contract.interfaceFunctions())
{ {
functions.emplace_back(); functions.emplace_back();
std::map<std::string, std::string>& templ = functions.back(); map<string, string>& templ = functions.back();
templ["functionSelector"] = "0x" + function.first.hex(); templ["functionSelector"] = "0x" + function.first.hex();
FunctionTypePointer const& type = function.second; FunctionTypePointer const& type = function.second;
templ["functionName"] = type->externalSignature(); templ["functionName"] = type->externalSignature();
std::string delegatecallCheck; string delegatecallCheck;
if (_contract.isLibrary()) if (_contract.isLibrary())
{ {
solAssert(!type->isPayable(), ""); solAssert(!type->isPayable(), "");
@ -1034,7 +1033,7 @@ std::string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
if (FunctionDefinition const* fallback = _contract.fallbackFunction()) if (FunctionDefinition const* fallback = _contract.fallbackFunction())
{ {
solAssert(!_contract.isLibrary(), ""); solAssert(!_contract.isLibrary(), "");
std::string fallbackCode; string fallbackCode;
if (!fallback->isPayable()) if (!fallback->isPayable())
fallbackCode += callValueCheck() + "\n"; fallbackCode += callValueCheck() + "\n";
if (fallback->parameters().empty()) if (fallback->parameters().empty())
@ -1058,7 +1057,7 @@ std::string IRGenerator::dispatchRoutine(ContractDefinition const& _contract)
return t.render(); return t.render();
} }
std::string IRGenerator::memoryInit(bool _useMemoryGuard) string IRGenerator::memoryInit(bool _useMemoryGuard)
{ {
// This function should be called at the beginning of the EVM call frame // This function should be called at the beginning of the EVM call frame
// and thus can assume all memory to be zero, including the contents of // and thus can assume all memory to be zero, including the contents of
@ -1069,10 +1068,10 @@ std::string IRGenerator::memoryInit(bool _useMemoryGuard)
"mstore(<memPtr>, memoryguard(<freeMemoryStart>))" : "mstore(<memPtr>, memoryguard(<freeMemoryStart>))" :
"mstore(<memPtr>, <freeMemoryStart>)" "mstore(<memPtr>, <freeMemoryStart>)"
} }
("memPtr", std::to_string(CompilerUtils::freeMemoryPointer)) ("memPtr", to_string(CompilerUtils::freeMemoryPointer))
( (
"freeMemoryStart", "freeMemoryStart",
std::to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory()) to_string(CompilerUtils::generalPurposeMemoryStart + m_context.reservedMemory())
).render(); ).render();
} }
@ -1102,10 +1101,10 @@ void IRGenerator::resetContext(ContractDefinition const& _contract, ExecutionCon
m_context.setMostDerivedContract(_contract); m_context.setMostDerivedContract(_contract);
for (auto const& var: ContractType(_contract).stateVariables()) for (auto const& var: ContractType(_contract).stateVariables())
m_context.addStateVariable(*std::get<0>(var), std::get<1>(var), std::get<2>(var)); m_context.addStateVariable(*get<0>(var), get<1>(var), get<2>(var));
} }
std::string IRGenerator::dispenseLocationComment(ASTNode const& _node) string IRGenerator::dispenseLocationComment(ASTNode const& _node)
{ {
return ::dispenseLocationComment(_node, m_context); return ::dispenseLocationComment(_node, m_context);
} }

View File

@ -49,6 +49,7 @@
#include <range/v3/view/transform.hpp> #include <range/v3/view/transform.hpp>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::frontend; using namespace solidity::frontend;
@ -94,8 +95,8 @@ struct CopyTranslate: public yul::ASTCopier
return ASTCopier::translate(_identifier); return ASTCopier::translate(_identifier);
yul::Expression translated = translateReference(_identifier); yul::Expression translated = translateReference(_identifier);
solAssert(std::holds_alternative<yul::Identifier>(translated)); solAssert(holds_alternative<yul::Identifier>(translated));
return std::get<yul::Identifier>(std::move(translated)); return get<yul::Identifier>(std::move(translated));
} }
private: private:
@ -108,9 +109,9 @@ private:
auto const& reference = m_references.at(&_identifier); auto const& reference = m_references.at(&_identifier);
auto const varDecl = dynamic_cast<VariableDeclaration const*>(reference.declaration); auto const varDecl = dynamic_cast<VariableDeclaration const*>(reference.declaration);
solUnimplementedAssert(varDecl); solUnimplementedAssert(varDecl);
std::string const& suffix = reference.suffix; string const& suffix = reference.suffix;
std::string value; string value;
if (suffix.empty() && varDecl->isLocalVariable()) if (suffix.empty() && varDecl->isLocalVariable())
{ {
auto const& var = m_context.localVariable(*varDecl); auto const& var = m_context.localVariable(*varDecl);
@ -164,7 +165,7 @@ private:
if (suffix == "slot") if (suffix == "slot")
value = m_context.storageLocationOfStateVariable(*varDecl).first.str(); value = m_context.storageLocationOfStateVariable(*varDecl).first.str();
else if (suffix == "offset") else if (suffix == "offset")
value = std::to_string(m_context.storageLocationOfStateVariable(*varDecl).second); value = to_string(m_context.storageLocationOfStateVariable(*varDecl).second);
else else
solAssert(false); solAssert(false);
} }
@ -215,7 +216,7 @@ private:
} }
std::string IRGeneratorForStatementsBase::code() const string IRGeneratorForStatementsBase::code() const
{ {
return m_code.str(); return m_code.str();
} }
@ -239,7 +240,7 @@ void IRGeneratorForStatementsBase::setLocation(ASTNode const& _node)
m_currentLocation = _node.location(); m_currentLocation = _node.location();
} }
std::string IRGeneratorForStatements::code() const string IRGeneratorForStatements::code() const
{ {
solAssert(!m_currentLValue, "LValue not reset!"); solAssert(!m_currentLValue, "LValue not reset!");
return IRGeneratorForStatementsBase::code(); return IRGeneratorForStatementsBase::code();
@ -337,11 +338,11 @@ IRVariable IRGeneratorForStatements::evaluateExpression(Expression const& _expre
} }
} }
std::string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant) string IRGeneratorForStatements::constantValueFunction(VariableDeclaration const& _constant)
{ {
try try
{ {
std::string functionName = IRNames::constantValueFunction(_constant); string functionName = IRNames::constantValueFunction(_constant);
return m_context.functionCollector().createFunction(functionName, [&] { return m_context.functionCollector().createFunction(functionName, [&] {
Whiskers templ(R"( Whiskers templ(R"(
<sourceLocationComment> <sourceLocationComment>
@ -409,7 +410,7 @@ bool IRGeneratorForStatements::visit(Conditional const& _conditional)
setLocation(_conditional); setLocation(_conditional);
std::string condition = expressionAsType(_conditional.condition(), *TypeProvider::boolean()); string condition = expressionAsType(_conditional.condition(), *TypeProvider::boolean());
declare(_conditional); declare(_conditional);
appendCode() << "switch " << condition << "\n" "case 0 {\n"; appendCode() << "switch " << condition << "\n" "case 0 {\n";
@ -500,7 +501,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
_tuple.components().size() << _tuple.components().size() <<
")\n"; ")\n";
std::string mpos = IRVariable(_tuple).part("mpos").name(); string mpos = IRVariable(_tuple).part("mpos").name();
Type const& baseType = *arrayType.baseType(); Type const& baseType = *arrayType.baseType();
for (size_t i = 0; i < _tuple.components().size(); i++) for (size_t i = 0; i < _tuple.components().size(); i++)
{ {
@ -511,7 +512,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
appendCode() << appendCode() <<
m_utils.writeToMemoryFunction(baseType) << m_utils.writeToMemoryFunction(baseType) <<
"(" << "(" <<
("add(" + mpos + ", " + std::to_string(i * arrayType.memoryStride()) + ")") << ("add(" + mpos + ", " + to_string(i * arrayType.memoryStride()) + ")") <<
", " << ", " <<
converted.commaSeparatedList() << converted.commaSeparatedList() <<
")\n"; ")\n";
@ -534,7 +535,7 @@ bool IRGeneratorForStatements::visit(TupleExpression const& _tuple)
} }
else else
{ {
std::vector<std::optional<IRLValue>> lvalues; vector<optional<IRLValue>> lvalues;
for (size_t i = 0; i < _tuple.components().size(); ++i) for (size_t i = 0; i < _tuple.components().size(); ++i)
if (auto const& component = _tuple.components()[i]) if (auto const& component = _tuple.components()[i])
{ {
@ -585,7 +586,7 @@ bool IRGeneratorForStatements::visit(IfStatement const& _ifStatement)
{ {
_ifStatement.condition().accept(*this); _ifStatement.condition().accept(*this);
setLocation(_ifStatement); setLocation(_ifStatement);
std::string condition = expressionAsType(_ifStatement.condition(), *TypeProvider::boolean()); string condition = expressionAsType(_ifStatement.condition(), *TypeProvider::boolean());
if (_ifStatement.falseStatement()) if (_ifStatement.falseStatement())
{ {
@ -657,7 +658,7 @@ void IRGeneratorForStatements::endVisit(Return const& _return)
if (Expression const* value = _return.expression()) if (Expression const* value = _return.expression())
{ {
solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer."); solAssert(_return.annotation().functionReturnParameters, "Invalid return parameters pointer.");
std::vector<ASTPointer<VariableDeclaration>> const& returnParameters = vector<ASTPointer<VariableDeclaration>> const& returnParameters =
_return.annotation().functionReturnParameters->parameters(); _return.annotation().functionReturnParameters->parameters();
if (returnParameters.size() > 1) if (returnParameters.size() > 1)
for (size_t i = 0; i < returnParameters.size(); ++i) for (size_t i = 0; i < returnParameters.size(); ++i)
@ -684,7 +685,7 @@ bool IRGeneratorForStatements::visit(UnaryOperation const& _unaryOperation)
solAssert(function->returnParameters().size() == 1); solAssert(function->returnParameters().size() == 1);
solAssert(*function->returnParameters()[0]->type() == *_unaryOperation.annotation().type); solAssert(*function->returnParameters()[0]->type() == *_unaryOperation.annotation().type);
std::string argument = expressionAsType(_unaryOperation.subExpression(), *function->parameters()[0]->type()); string argument = expressionAsType(_unaryOperation.subExpression(), *function->parameters()[0]->type());
solAssert(!argument.empty()); solAssert(!argument.empty());
solAssert(_unaryOperation.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal); solAssert(_unaryOperation.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal);
@ -811,8 +812,8 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
solAssert(function->returnParameters().size() == 1); solAssert(function->returnParameters().size() == 1);
solAssert(*function->returnParameters()[0]->type() == *_binOp.annotation().type); solAssert(*function->returnParameters()[0]->type() == *_binOp.annotation().type);
std::string left = expressionAsType(_binOp.leftExpression(), *function->parameters()[0]->type()); string left = expressionAsType(_binOp.leftExpression(), *function->parameters()[0]->type());
std::string right = expressionAsType(_binOp.rightExpression(), *function->parameters()[1]->type()); string right = expressionAsType(_binOp.rightExpression(), *function->parameters()[1]->type());
solAssert(!left.empty() && !right.empty()); solAssert(!left.empty() && !right.empty());
solAssert(_binOp.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal); solAssert(_binOp.userDefinedFunctionType()->kind() == FunctionType::Kind::Internal);
@ -852,13 +853,13 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
if (auto type = dynamic_cast<IntegerType const*>(commonType)) if (auto type = dynamic_cast<IntegerType const*>(commonType))
isSigned = type->isSigned(); isSigned = type->isSigned();
std::string args = expressionAsCleanedType(_binOp.leftExpression(), *commonType); string args = expressionAsCleanedType(_binOp.leftExpression(), *commonType);
args += ", " + expressionAsCleanedType(_binOp.rightExpression(), *commonType); args += ", " + expressionAsCleanedType(_binOp.rightExpression(), *commonType);
auto functionType = dynamic_cast<FunctionType const*>(commonType); auto functionType = dynamic_cast<FunctionType const*>(commonType);
solAssert(functionType ? (op == Token::Equal || op == Token::NotEqual) : true, "Invalid function pointer comparison!"); solAssert(functionType ? (op == Token::Equal || op == Token::NotEqual) : true, "Invalid function pointer comparison!");
std::string expr; string expr;
if (functionType && functionType->kind() == FunctionType::Kind::External) if (functionType && functionType->kind() == FunctionType::Kind::External)
{ {
@ -878,9 +879,9 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
else if (op == Token::NotEqual) else if (op == Token::NotEqual)
expr = "iszero(eq(" + std::move(args) + "))"; expr = "iszero(eq(" + std::move(args) + "))";
else if (op == Token::GreaterThanOrEqual) else if (op == Token::GreaterThanOrEqual)
expr = "iszero(" + std::string(isSigned ? "slt(" : "lt(") + std::move(args) + "))"; expr = "iszero(" + string(isSigned ? "slt(" : "lt(") + std::move(args) + "))";
else if (op == Token::LessThanOrEqual) else if (op == Token::LessThanOrEqual)
expr = "iszero(" + std::string(isSigned ? "sgt(" : "gt(") + std::move(args) + "))"; expr = "iszero(" + string(isSigned ? "sgt(" : "gt(") + std::move(args) + "))";
else if (op == Token::GreaterThan) else if (op == Token::GreaterThan)
expr = (isSigned ? "sgt(" : "gt(") + std::move(args) + ")"; expr = (isSigned ? "sgt(" : "gt(") + std::move(args) + ")";
else if (op == Token::LessThan) else if (op == Token::LessThan)
@ -924,8 +925,8 @@ bool IRGeneratorForStatements::visit(BinaryOperation const& _binOp)
} }
else else
{ {
std::string left = expressionAsType(_binOp.leftExpression(), *commonType); string left = expressionAsType(_binOp.leftExpression(), *commonType);
std::string right = expressionAsType(_binOp.rightExpression(), *commonType); string right = expressionAsType(_binOp.rightExpression(), *commonType);
define(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right) << "\n"; define(_binOp) << binaryOperation(_binOp.getOperator(), *commonType, left, right) << "\n";
} }
return false; return false;
@ -959,7 +960,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
TypePointers parameterTypes = functionType->parameterTypes(); TypePointers parameterTypes = functionType->parameterTypes();
std::vector<ASTPointer<Expression const>> const& arguments = _functionCall.sortedArguments(); vector<ASTPointer<Expression const>> const& arguments = _functionCall.sortedArguments();
if (functionCallKind == FunctionCallKind::StructConstructorCall) if (functionCallKind == FunctionCallKind::StructConstructorCall)
{ {
@ -1000,7 +1001,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
solAssert(!functionType->takesArbitraryParameters()); solAssert(!functionType->takesArbitraryParameters());
std::vector<std::string> args; vector<string> args;
if (functionType->hasBoundFirstArgument()) if (functionType->hasBoundFirstArgument())
args += IRVariable(_functionCall.expression()).part("self").stackSlots(); args += IRVariable(_functionCall.expression()).part("self").stackSlots();
@ -1048,8 +1049,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
TypePointers paramTypes = functionType->parameterTypes(); TypePointers paramTypes = functionType->parameterTypes();
ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector()); ABIFunctions abi(m_context.evmVersion(), m_context.revertStrings(), m_context.functionCollector());
std::vector<IRVariable> indexedArgs; vector<IRVariable> indexedArgs;
std::vector<std::string> nonIndexedArgs; vector<string> nonIndexedArgs;
TypePointers nonIndexedArgTypes; TypePointers nonIndexedArgTypes;
TypePointers nonIndexedParamTypes; TypePointers nonIndexedParamTypes;
if (!event.isAnonymous()) if (!event.isAnonymous())
@ -1060,7 +1061,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
Expression const& arg = *arguments[i]; Expression const& arg = *arguments[i];
if (event.parameters()[i]->isIndexed()) if (event.parameters()[i]->isIndexed())
{ {
std::string value; string value;
if (auto const& referenceType = dynamic_cast<ReferenceType const*>(paramTypes[i])) if (auto const& referenceType = dynamic_cast<ReferenceType const*>(paramTypes[i]))
define(indexedArgs.emplace_back(m_context.newYulVariable(), *TypeProvider::uint256())) << define(indexedArgs.emplace_back(m_context.newYulVariable(), *TypeProvider::uint256())) <<
m_utils.packedHashFunction({arg.annotation().type}, {referenceType}) << m_utils.packedHashFunction({arg.annotation().type}, {referenceType}) <<
@ -1105,7 +1106,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
templ("allocateUnbounded", m_utils.allocateUnboundedFunction()); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes)); templ("encode", abi.tupleEncoder(nonIndexedArgTypes, nonIndexedParamTypes));
templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs)); templ("nonIndexedArgs", joinHumanReadablePrefixed(nonIndexedArgs));
templ("log", "log" + std::to_string(indexedArgs.size())); templ("log", "log" + to_string(indexedArgs.size()));
templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | ranges::views::transform([&](auto const& _arg) { templ("indexedArgs", joinHumanReadablePrefixed(indexedArgs | ranges::views::transform([&](auto const& _arg) {
return _arg.commaSeparatedList(); return _arg.commaSeparatedList();
}))); })));
@ -1151,7 +1152,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
arguments.size() > 1 && m_context.revertStrings() != RevertStrings::Strip ? arguments.size() > 1 && m_context.revertStrings() != RevertStrings::Strip ?
arguments[1]->annotation().type : arguments[1]->annotation().type :
nullptr; nullptr;
std::string requireOrAssertFunction = m_utils.requireOrAssertFunction( string requireOrAssertFunction = m_utils.requireOrAssertFunction(
functionType->kind() == FunctionType::Kind::Assert, functionType->kind() == FunctionType::Kind::Assert,
messageArgumentType messageArgumentType
); );
@ -1178,9 +1179,9 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
TypePointers argumentTypes; TypePointers argumentTypes;
TypePointers targetTypes; TypePointers targetTypes;
std::vector<std::string> argumentVars; vector<string> argumentVars;
std::string selector; string selector;
std::vector<ASTPointer<Expression const>> argumentsOfEncodeFunction; vector<ASTPointer<Expression const>> argumentsOfEncodeFunction;
if (functionType->kind() == FunctionType::Kind::ABIEncodeCall) if (functionType->kind() == FunctionType::Kind::ABIEncodeCall)
{ {
@ -1251,13 +1252,13 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
// TODO This is an abuse of the `allocateUnbounded` function. // TODO This is an abuse of the `allocateUnbounded` function.
// We might want to introduce a new set of memory handling functions here // We might want to introduce a new set of memory handling functions here
// a la "setMemoryCheckPoint" and "freeUntilCheckPoint". // a la "setMemoryCheckPoint" and "freeUntilCheckPoint".
std::string freeMemoryPre = m_context.newYulVariable(); string freeMemoryPre = m_context.newYulVariable();
appendCode() << "let " << freeMemoryPre << " := " << m_utils.allocateUnboundedFunction() << "()\n"; appendCode() << "let " << freeMemoryPre << " := " << m_utils.allocateUnboundedFunction() << "()\n";
IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory()); IRVariable array = convert(*arguments[0], *TypeProvider::bytesMemory());
IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32)); IRVariable hashVariable(m_context.newYulVariable(), *TypeProvider::fixedBytes(32));
std::string dataAreaFunction = m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory()); string dataAreaFunction = m_utils.arrayDataAreaFunction(*TypeProvider::bytesMemory());
std::string arrayLengthFunction = m_utils.arrayLengthFunction(*TypeProvider::bytesMemory()); string arrayLengthFunction = m_utils.arrayLengthFunction(*TypeProvider::bytesMemory());
define(hashVariable) << define(hashVariable) <<
"keccak256(" << "keccak256(" <<
(dataAreaFunction + "(" + array.commaSeparatedList() + ")") << (dataAreaFunction + "(" + array.commaSeparatedList() + ")") <<
@ -1388,8 +1389,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
{ {
auto array = convert(*arguments[0], *arrayType); auto array = convert(*arguments[0], *arrayType);
std::string dataAreaFunction = m_utils.arrayDataAreaFunction(*arrayType); string dataAreaFunction = m_utils.arrayDataAreaFunction(*arrayType);
std::string arrayLengthFunction = m_utils.arrayLengthFunction(*arrayType); string arrayLengthFunction = m_utils.arrayLengthFunction(*arrayType);
define(_functionCall) << define(_functionCall) <<
"keccak256(" << "keccak256(" <<
(dataAreaFunction + "(" + array.commaSeparatedList() + ")") << (dataAreaFunction + "(" + array.commaSeparatedList() + ")") <<
@ -1452,7 +1453,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
case FunctionType::Kind::BytesConcat: case FunctionType::Kind::BytesConcat:
{ {
TypePointers argumentTypes; TypePointers argumentTypes;
std::vector<std::string> argumentVars; vector<string> argumentVars;
for (ASTPointer<Expression const> const& argument: arguments) for (ASTPointer<Expression const> const& argument: arguments)
{ {
argumentTypes.emplace_back(&type(*argument)); argumentTypes.emplace_back(&type(*argument));
@ -1472,7 +1473,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
case FunctionType::Kind::AddMod: case FunctionType::Kind::AddMod:
case FunctionType::Kind::MulMod: case FunctionType::Kind::MulMod:
{ {
static std::map<FunctionType::Kind, std::string> functions = { static map<FunctionType::Kind, string> functions = {
{FunctionType::Kind::AddMod, "addmod"}, {FunctionType::Kind::AddMod, "addmod"},
{FunctionType::Kind::MulMod, "mulmod"}, {FunctionType::Kind::MulMod, "mulmod"},
}; };
@ -1486,7 +1487,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
templ("panic", m_utils.panicFunction(PanicCode::DivisionByZero)); templ("panic", m_utils.panicFunction(PanicCode::DivisionByZero));
appendCode() << templ.render(); appendCode() << templ.render();
std::string args; string args;
for (size_t i = 0; i < 2; ++i) for (size_t i = 0; i < 2; ++i)
args += expressionAsType(*arguments[i], *(parameterTypes[i])) + ", "; args += expressionAsType(*arguments[i], *(parameterTypes[i])) + ", ";
args += modulus.name(); args += modulus.name();
@ -1497,14 +1498,14 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
case FunctionType::Kind::Selfdestruct: case FunctionType::Kind::Selfdestruct:
case FunctionType::Kind::BlockHash: case FunctionType::Kind::BlockHash:
{ {
static std::map<FunctionType::Kind, std::string> functions = { static map<FunctionType::Kind, string> functions = {
{FunctionType::Kind::GasLeft, "gas"}, {FunctionType::Kind::GasLeft, "gas"},
{FunctionType::Kind::Selfdestruct, "selfdestruct"}, {FunctionType::Kind::Selfdestruct, "selfdestruct"},
{FunctionType::Kind::BlockHash, "blockhash"}, {FunctionType::Kind::BlockHash, "blockhash"},
}; };
solAssert(functions.find(functionType->kind()) != functions.end()); solAssert(functions.find(functionType->kind()) != functions.end());
std::string args; string args;
for (size_t i = 0; i < arguments.size(); ++i) for (size_t i = 0; i < arguments.size(); ++i)
args += (args.empty() ? "" : ", ") + expressionAsType(*arguments[i], *(parameterTypes[i])); args += (args.empty() ? "" : ", ") + expressionAsType(*arguments[i], *(parameterTypes[i]));
define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n"; define(_functionCall) << functions[functionType->kind()] << "(" << args << ")\n";
@ -1519,7 +1520,7 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
); );
TypePointers argumentTypes; TypePointers argumentTypes;
std::vector<std::string> constructorParams; vector<string> constructorParams;
for (ASTPointer<Expression const> const& arg: arguments) for (ASTPointer<Expression const> const& arg: arguments)
{ {
argumentTypes.push_back(arg->annotation().type); argumentTypes.push_back(arg->annotation().type);
@ -1574,8 +1575,8 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
case FunctionType::Kind::Transfer: case FunctionType::Kind::Transfer:
{ {
solAssert(arguments.size() == 1 && parameterTypes.size() == 1); solAssert(arguments.size() == 1 && parameterTypes.size() == 1);
std::string address{IRVariable(_functionCall.expression()).part("address").name()}; string address{IRVariable(_functionCall.expression()).part("address").name()};
std::string value{expressionAsType(*arguments[0], *(parameterTypes[0]))}; string value{expressionAsType(*arguments[0], *(parameterTypes[0]))};
Whiskers templ(R"( Whiskers templ(R"(
let <gas> := 0 let <gas> := 0
if iszero(<value>) { <gas> := <callStipend> } if iszero(<value>) { <gas> := <callStipend> }
@ -1607,14 +1608,14 @@ void IRGeneratorForStatements::endVisit(FunctionCall const& _functionCall)
solAssert(!functionType->gasSet()); solAssert(!functionType->gasSet());
solAssert(!functionType->hasBoundFirstArgument()); solAssert(!functionType->hasBoundFirstArgument());
static std::map<FunctionType::Kind, std::tuple<unsigned, size_t>> precompiles = { static map<FunctionType::Kind, std::tuple<unsigned, size_t>> precompiles = {
{FunctionType::Kind::ECRecover, std::make_tuple(1, 0)}, {FunctionType::Kind::ECRecover, std::make_tuple(1, 0)},
{FunctionType::Kind::SHA256, std::make_tuple(2, 0)}, {FunctionType::Kind::SHA256, std::make_tuple(2, 0)},
{FunctionType::Kind::RIPEMD160, std::make_tuple(3, 12)}, {FunctionType::Kind::RIPEMD160, std::make_tuple(3, 12)},
}; };
auto [ address, offset ] = precompiles[functionType->kind()]; auto [ address, offset ] = precompiles[functionType->kind()];
TypePointers argumentTypes; TypePointers argumentTypes;
std::vector<std::string> argumentStrings; vector<string> argumentStrings;
for (auto const& arg: arguments) for (auto const& arg: arguments)
{ {
argumentTypes.emplace_back(&type(*arg)); argumentTypes.emplace_back(&type(*arg));
@ -1675,11 +1676,11 @@ void IRGeneratorForStatements::endVisit(FunctionCallOptions const& _options)
// Copy over existing values. // Copy over existing values.
for (auto const& item: previousType.stackItems()) for (auto const& item: previousType.stackItems())
define(IRVariable(_options).part(std::get<0>(item)), IRVariable(_options.expression()).part(std::get<0>(item))); define(IRVariable(_options).part(get<0>(item)), IRVariable(_options.expression()).part(get<0>(item)));
for (size_t i = 0; i < _options.names().size(); ++i) for (size_t i = 0; i < _options.names().size(); ++i)
{ {
std::string const& name = *_options.names()[i]; string const& name = *_options.names()[i];
solAssert(name == "salt" || name == "gas" || name == "value"); solAssert(name == "salt" || name == "gas" || name == "value");
define(IRVariable(_options).part(name), *_options.options()[i]); define(IRVariable(_options).part(name), *_options.options()[i]);
@ -1784,7 +1785,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
")\n"; ")\n";
else if (member == "code") else if (member == "code")
{ {
std::string externalCodeFunction = m_utils.externalCodeFunction(); string externalCodeFunction = m_utils.externalCodeFunction();
define(_memberAccess) << define(_memberAccess) <<
externalCodeFunction << externalCodeFunction <<
"(" << "(" <<
@ -1796,12 +1797,12 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
"extcodehash(" << "extcodehash(" <<
expressionAsType(_memberAccess.expression(), *TypeProvider::address()) << expressionAsType(_memberAccess.expression(), *TypeProvider::address()) <<
")\n"; ")\n";
else if (std::set<std::string>{"send", "transfer"}.count(member)) else if (set<string>{"send", "transfer"}.count(member))
{ {
solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable); solAssert(dynamic_cast<AddressType const&>(*_memberAccess.expression().annotation().type).stateMutability() == StateMutability::Payable);
define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression()); define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression());
} }
else if (std::set<std::string>{"call", "callcode", "delegatecall", "staticcall"}.count(member)) else if (set<string>{"call", "callcode", "delegatecall", "staticcall"}.count(member))
define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression()); define(IRVariable{_memberAccess}.part("address"), _memberAccess.expression());
else else
solAssert(false, "Invalid member access to address"); solAssert(false, "Invalid member access to address");
@ -1944,7 +1945,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
{ {
MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type); MagicType const* arg = dynamic_cast<MagicType const*>(_memberAccess.expression().annotation().type);
std::string requestedValue; string requestedValue;
if (IntegerType const* integerType = dynamic_cast<IntegerType const*>(arg->typeArgument())) if (IntegerType const* integerType = dynamic_cast<IntegerType const*>(arg->typeArgument()))
{ {
if (member == "min") if (member == "min")
@ -1955,16 +1956,16 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(arg->typeArgument())) else if (EnumType const* enumType = dynamic_cast<EnumType const*>(arg->typeArgument()))
{ {
if (member == "min") if (member == "min")
requestedValue = std::to_string(enumType->minValue()); requestedValue = to_string(enumType->minValue());
else else
requestedValue = std::to_string(enumType->maxValue()); requestedValue = to_string(enumType->maxValue());
} }
else else
solAssert(false, "min/max requested on unexpected type."); solAssert(false, "min/max requested on unexpected type.");
define(_memberAccess) << requestedValue << "\n"; define(_memberAccess) << requestedValue << "\n";
} }
else if (std::set<std::string>{"encode", "encodePacked", "encodeWithSelector", "encodeCall", "encodeWithSignature", "decode"}.count(member)) else if (set<string>{"encode", "encodePacked", "encodeWithSelector", "encodeCall", "encodeWithSignature", "decode"}.count(member))
{ {
// no-op // no-op
} }
@ -1980,8 +1981,8 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
{ {
case DataLocation::Storage: case DataLocation::Storage:
{ {
std::pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member); pair<u256, unsigned> const& offsets = structType.storageOffsetsOfMember(member);
std::string slot = m_context.newYulVariable(); string slot = m_context.newYulVariable();
appendCode() << "let " << slot << " := " << appendCode() << "let " << slot << " := " <<
("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n"); ("add(" + expression.part("slot").name() + ", " + offsets.first.str() + ")\n");
setLValue(_memberAccess, IRLValue{ setLValue(_memberAccess, IRLValue{
@ -1992,7 +1993,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
} }
case DataLocation::Memory: case DataLocation::Memory:
{ {
std::string pos = m_context.newYulVariable(); string pos = m_context.newYulVariable();
appendCode() << "let " << pos << " := " << appendCode() << "let " << pos << " := " <<
("add(" + expression.part("mpos").name() + ", " + structType.memoryOffsetOfMember(member).str() + ")\n"); ("add(" + expression.part("mpos").name() + ", " + structType.memoryOffsetOfMember(member).str() + ")\n");
setLValue(_memberAccess, IRLValue{ setLValue(_memberAccess, IRLValue{
@ -2003,9 +2004,9 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
} }
case DataLocation::CallData: case DataLocation::CallData:
{ {
std::string baseRef = expression.part("offset").name(); string baseRef = expression.part("offset").name();
std::string offset = m_context.newYulVariable(); string offset = m_context.newYulVariable();
appendCode() << "let " << offset << " := " << "add(" << baseRef << ", " << std::to_string(structType.calldataOffsetOfMember(member)) << ")\n"; appendCode() << "let " << offset << " := " << "add(" << baseRef << ", " << to_string(structType.calldataOffsetOfMember(member)) << ")\n";
if (_memberAccess.annotation().type->isDynamicallyEncoded()) if (_memberAccess.annotation().type->isDynamicallyEncoded())
define(_memberAccess) << define(_memberAccess) <<
m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) << m_utils.accessCalldataTailFunction(*_memberAccess.annotation().type) <<
@ -2035,7 +2036,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
case Type::Category::Enum: case Type::Category::Enum:
{ {
EnumType const& type = dynamic_cast<EnumType const&>(*_memberAccess.expression().annotation().type); EnumType const& type = dynamic_cast<EnumType const&>(*_memberAccess.expression().annotation().type);
define(_memberAccess) << std::to_string(type.memberValue(_memberAccess.memberName())) << "\n"; define(_memberAccess) << to_string(type.memberValue(_memberAccess.memberName())) << "\n";
break; break;
} }
case Type::Category::Array: case Type::Category::Array:
@ -2075,7 +2076,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
{ {
auto const& type = dynamic_cast<FixedBytesType const&>(*_memberAccess.expression().annotation().type); auto const& type = dynamic_cast<FixedBytesType const&>(*_memberAccess.expression().annotation().type);
if (member == "length") if (member == "length")
define(_memberAccess) << std::to_string(type.numBytes()) << "\n"; define(_memberAccess) << to_string(type.numBytes()) << "\n";
else else
solAssert(false, "Illegal fixed bytes member."); solAssert(false, "Illegal fixed bytes member.");
break; break;
@ -2161,7 +2162,7 @@ void IRGeneratorForStatements::endVisit(MemberAccess const& _memberAccess)
solAssert(false); solAssert(false);
} }
else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType)) else if (EnumType const* enumType = dynamic_cast<EnumType const*>(&actualType))
define(_memberAccess) << std::to_string(enumType->memberValue(_memberAccess.memberName())) << "\n"; define(_memberAccess) << to_string(enumType->memberValue(_memberAccess.memberName())) << "\n";
else if (dynamic_cast<UserDefinedValueType const*>(&actualType)) else if (dynamic_cast<UserDefinedValueType const*>(&actualType))
solAssert(member == "wrap" || member == "unwrap"); solAssert(member == "wrap" || member == "unwrap");
else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType)) else if (auto const* arrayType = dynamic_cast<ArrayType const*>(&actualType))
@ -2221,7 +2222,7 @@ bool IRGeneratorForStatements::visit(InlineAssembly const& _inlineAsm)
yul::Statement modified = bodyCopier(_inlineAsm.operations()); yul::Statement modified = bodyCopier(_inlineAsm.operations());
solAssert(std::holds_alternative<yul::Block>(modified)); solAssert(holds_alternative<yul::Block>(modified));
// Do not provide dialect so that we get the full type information. // Do not provide dialect so that we get the full type information.
appendCode() << yul::AsmPrinter()(std::get<yul::Block>(modified)) << "\n"; appendCode() << yul::AsmPrinter()(std::get<yul::Block>(modified)) << "\n";
@ -2241,7 +2242,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
MappingType const& mappingType = dynamic_cast<MappingType const&>(baseType); MappingType const& mappingType = dynamic_cast<MappingType const&>(baseType);
Type const& keyType = *_indexAccess.indexExpression()->annotation().type; Type const& keyType = *_indexAccess.indexExpression()->annotation().type;
std::string slot = m_context.newYulVariable(); string slot = m_context.newYulVariable();
Whiskers templ("let <slot> := <indexAccess>(<base><?+key>,<key></+key>)\n"); Whiskers templ("let <slot> := <indexAccess>(<base><?+key>,<key></+key>)\n");
templ("slot", slot); templ("slot", slot);
templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType)); templ("indexAccess", m_utils.mappingIndexAccessFunction(mappingType, keyType));
@ -2272,8 +2273,8 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
{ {
case DataLocation::Storage: case DataLocation::Storage:
{ {
std::string slot = m_context.newYulVariable(); string slot = m_context.newYulVariable();
std::string offset = m_context.newYulVariable(); string offset = m_context.newYulVariable();
appendCode() << Whiskers(R"( appendCode() << Whiskers(R"(
let <slot>, <offset> := <indexFunc>(<array>, <index>) let <slot>, <offset> := <indexFunc>(<array>, <index>)
@ -2294,13 +2295,13 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
} }
case DataLocation::Memory: case DataLocation::Memory:
{ {
std::string const indexAccessFunction = m_utils.memoryArrayIndexAccessFunction(arrayType); string const indexAccessFunction = m_utils.memoryArrayIndexAccessFunction(arrayType);
std::string const baseRef = IRVariable(_indexAccess.baseExpression()).part("mpos").name(); string const baseRef = IRVariable(_indexAccess.baseExpression()).part("mpos").name();
std::string const indexExpression = expressionAsType( string const indexExpression = expressionAsType(
*_indexAccess.indexExpression(), *_indexAccess.indexExpression(),
*TypeProvider::uint256() *TypeProvider::uint256()
); );
std::string const memAddress = indexAccessFunction + "(" + baseRef + ", " + indexExpression + ")"; string const memAddress = indexAccessFunction + "(" + baseRef + ", " + indexExpression + ")";
setLValue(_indexAccess, IRLValue{ setLValue(_indexAccess, IRLValue{
*arrayType.baseType(), *arrayType.baseType(),
@ -2310,13 +2311,13 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
} }
case DataLocation::CallData: case DataLocation::CallData:
{ {
std::string const indexAccessFunction = m_utils.calldataArrayIndexAccessFunction(arrayType); string const indexAccessFunction = m_utils.calldataArrayIndexAccessFunction(arrayType);
std::string const baseRef = IRVariable(_indexAccess.baseExpression()).commaSeparatedList(); string const baseRef = IRVariable(_indexAccess.baseExpression()).commaSeparatedList();
std::string const indexExpression = expressionAsType( string const indexExpression = expressionAsType(
*_indexAccess.indexExpression(), *_indexAccess.indexExpression(),
*TypeProvider::uint256() *TypeProvider::uint256()
); );
std::string const calldataAddress = indexAccessFunction + "(" + baseRef + ", " + indexExpression + ")"; string const calldataAddress = indexAccessFunction + "(" + baseRef + ", " + indexExpression + ")";
if (arrayType.isByteArrayOrString()) if (arrayType.isByteArrayOrString())
define(_indexAccess) << define(_indexAccess) <<
@ -2348,7 +2349,7 @@ void IRGeneratorForStatements::endVisit(IndexAccess const& _indexAccess)
let <result> := <shl248>(byte(<index>, <array>)) let <result> := <shl248>(byte(<index>, <array>))
)") )")
("index", index.name()) ("index", index.name())
("length", std::to_string(fixedBytesType.numBytes())) ("length", to_string(fixedBytesType.numBytes()))
("panic", m_utils.panicFunction(PanicCode::ArrayOutOfBounds)) ("panic", m_utils.panicFunction(PanicCode::ArrayOutOfBounds))
("array", IRVariable(_indexAccess.baseExpression()).name()) ("array", IRVariable(_indexAccess.baseExpression()).name())
("shl248", m_utils.shiftLeftFunction(256 - 8)) ("shl248", m_utils.shiftLeftFunction(256 - 8))
@ -2537,7 +2538,7 @@ void IRGeneratorForStatements::handleVariableReference(
void IRGeneratorForStatements::appendExternalFunctionCall( void IRGeneratorForStatements::appendExternalFunctionCall(
FunctionCall const& _functionCall, FunctionCall const& _functionCall,
std::vector<ASTPointer<Expression const>> const& _arguments vector<ASTPointer<Expression const>> const& _arguments
) )
{ {
FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression())); FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression()));
@ -2558,7 +2559,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
TypePointers parameterTypes = funType.parameterTypes(); TypePointers parameterTypes = funType.parameterTypes();
TypePointers argumentTypes; TypePointers argumentTypes;
std::vector<std::string> argumentStrings; vector<string> argumentStrings;
if (funType.hasBoundFirstArgument()) if (funType.hasBoundFirstArgument())
{ {
parameterTypes.insert(parameterTypes.begin(), funType.selfType()); parameterTypes.insert(parameterTypes.begin(), funType.selfType());
@ -2580,7 +2581,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
// We could also just use MLOAD; POP right before the gas calculation, but the optimizer // We could also just use MLOAD; POP right before the gas calculation, but the optimizer
// would remove that, so we use MSTORE here. // would remove that, so we use MSTORE here.
if (!funType.gasSet() && returnInfo.estimatedReturnSize > 0) if (!funType.gasSet() && returnInfo.estimatedReturnSize > 0)
appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << std::to_string(returnInfo.estimatedReturnSize) << "), 0)\n"; appendCode() << "mstore(add(" << m_utils.allocateUnboundedFunction() << "() , " << to_string(returnInfo.estimatedReturnSize) << "), 0)\n";
} }
// NOTE: When the expected size of returndata is static, we pass that in to the call opcode and it gets copied automatically. // NOTE: When the expected size of returndata is static, we pass that in to the call opcode and it gets copied automatically.
@ -2648,10 +2649,10 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
if (returnInfo.dynamicReturnSize) if (returnInfo.dynamicReturnSize)
solAssert(m_context.evmVersion().supportsReturndata()); solAssert(m_context.evmVersion().supportsReturndata());
templ("returnDataSizeVar", m_context.newYulVariable()); templ("returnDataSizeVar", m_context.newYulVariable());
templ("staticReturndataSize", std::to_string(returnInfo.estimatedReturnSize)); templ("staticReturndataSize", to_string(returnInfo.estimatedReturnSize));
templ("supportsReturnData", m_context.evmVersion().supportsReturndata()); templ("supportsReturnData", m_context.evmVersion().supportsReturndata());
std::string const retVars = IRVariable(_functionCall).commaSeparatedList(); string const retVars = IRVariable(_functionCall).commaSeparatedList();
templ("retVars", retVars); templ("retVars", retVars);
solAssert(retVars.empty() == returnInfo.returnTypes.empty()); solAssert(retVars.empty() == returnInfo.returnTypes.empty());
@ -2703,7 +2704,7 @@ void IRGeneratorForStatements::appendExternalFunctionCall(
void IRGeneratorForStatements::appendBareCall( void IRGeneratorForStatements::appendBareCall(
FunctionCall const& _functionCall, FunctionCall const& _functionCall,
std::vector<ASTPointer<Expression const>> const& _arguments vector<ASTPointer<Expression const>> const& _arguments
) )
{ {
FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression())); FunctionType const& funType = dynamic_cast<FunctionType const&>(type(_functionCall.expression()));
@ -2806,7 +2807,7 @@ void IRGeneratorForStatements::assignInternalFunctionIDIfNotCalledDirectly(
return; return;
define(IRVariable(_expression).part("functionIdentifier")) << define(IRVariable(_expression).part("functionIdentifier")) <<
std::to_string(m_context.mostDerivedContract().annotation().internalFunctionIDs.at(&_referencedFunction)) << to_string(m_context.mostDerivedContract().annotation().internalFunctionIDs.at(&_referencedFunction)) <<
"\n"; "\n";
m_context.addToInternalDispatch(_referencedFunction); m_context.addToInternalDispatch(_referencedFunction);
} }
@ -2863,7 +2864,7 @@ void IRGeneratorForStatements::declare(IRVariable const& _var)
void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare, bool _forceCleanup) void IRGeneratorForStatements::declareAssign(IRVariable const& _lhs, IRVariable const& _rhs, bool _declare, bool _forceCleanup)
{ {
std::string output; string output;
if (_lhs.type() == _rhs.type() && !_forceCleanup) if (_lhs.type() == _rhs.type() && !_forceCleanup)
for (auto const& [stackItemName, stackItemType]: _lhs.type().stackItems()) for (auto const& [stackItemName, stackItemType]: _lhs.type().stackItems())
if (stackItemType) if (stackItemType)
@ -2893,7 +2894,7 @@ IRVariable IRGeneratorForStatements::zeroValue(Type const& _type, bool _splitFun
void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr) void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const& _operation, Expression const& _expr)
{ {
std::string func; string func;
if (_operation.getOperator() == Token::Not) if (_operation.getOperator() == Token::Not)
func = "iszero"; func = "iszero";
@ -2912,18 +2913,18 @@ void IRGeneratorForStatements::appendSimpleUnaryOperation(UnaryOperation const&
")\n"; ")\n";
} }
std::string IRGeneratorForStatements::binaryOperation( string IRGeneratorForStatements::binaryOperation(
langutil::Token _operator, langutil::Token _operator,
Type const& _type, Type const& _type,
std::string const& _left, string const& _left,
std::string const& _right string const& _right
) )
{ {
solAssert( solAssert(
!TokenTraits::isShiftOp(_operator), !TokenTraits::isShiftOp(_operator),
"Have to use specific shift operation function for shifts." "Have to use specific shift operation function for shifts."
); );
std::string fun; string fun;
if (TokenTraits::isBitOp(_operator)) if (TokenTraits::isBitOp(_operator))
{ {
solAssert( solAssert(
@ -3029,12 +3030,12 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
std::visit( std::visit(
util::GenericVisitor{ util::GenericVisitor{
[&](IRLValue::Storage const& _storage) { [&](IRLValue::Storage const& _storage) {
std::string offsetArgument; string offsetArgument;
std::optional<unsigned> offsetStatic; optional<unsigned> offsetStatic;
std::visit(GenericVisitor{ std::visit(GenericVisitor{
[&](unsigned _offset) { offsetStatic = _offset; }, [&](unsigned _offset) { offsetStatic = _offset; },
[&](std::string const& _offset) { offsetArgument = ", " + _offset; } [&](string const& _offset) { offsetArgument = ", " + _offset; }
}, _storage.offset); }, _storage.offset);
appendCode() << appendCode() <<
@ -3067,7 +3068,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
} }
else if (auto const* literalType = dynamic_cast<StringLiteralType const*>(&_value.type())) else if (auto const* literalType = dynamic_cast<StringLiteralType const*>(&_value.type()))
{ {
std::string writeUInt = m_utils.writeToMemoryFunction(*TypeProvider::uint256()); string writeUInt = m_utils.writeToMemoryFunction(*TypeProvider::uint256());
appendCode() << appendCode() <<
writeUInt << writeUInt <<
"(" << "(" <<
@ -3098,7 +3099,7 @@ void IRGeneratorForStatements::writeToLValue(IRLValue const& _lvalue, IRVariable
IRVariable prepared(m_context.newYulVariable(), _lvalue.type); IRVariable prepared(m_context.newYulVariable(), _lvalue.type);
define(prepared, _value); define(prepared, _value);
appendCode() << "mstore(" << std::to_string(memOffset) << ", " << prepared.commaSeparatedList() << ")\n"; appendCode() << "mstore(" << to_string(memOffset) << ", " << prepared.commaSeparatedList() << ")\n";
}, },
[&](IRLValue::Tuple const& _tuple) { [&](IRLValue::Tuple const& _tuple) {
auto components = std::move(_tuple.components); auto components = std::move(_tuple.components);
@ -3121,13 +3122,13 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue)
[&](IRLValue::Storage const& _storage) { [&](IRLValue::Storage const& _storage) {
if (!_lvalue.type.isValueType()) if (!_lvalue.type.isValueType())
define(result) << _storage.slot << "\n"; define(result) << _storage.slot << "\n";
else if (std::holds_alternative<std::string>(_storage.offset)) else if (std::holds_alternative<string>(_storage.offset))
define(result) << define(result) <<
m_utils.readFromStorageDynamic(_lvalue.type, true) << m_utils.readFromStorageDynamic(_lvalue.type, true) <<
"(" << "(" <<
_storage.slot << _storage.slot <<
", " << ", " <<
std::get<std::string>(_storage.offset) << std::get<string>(_storage.offset) <<
")\n"; ")\n";
else else
define(result) << define(result) <<
@ -3155,15 +3156,15 @@ IRVariable IRGeneratorForStatements::readFromLValue(IRLValue const& _lvalue)
solAssert(_lvalue.type == *_immutable.variable->type()); solAssert(_lvalue.type == *_immutable.variable->type());
if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation) if (m_context.executionContext() == IRGenerationContext::ExecutionContext::Creation)
{ {
std::string readFunction = m_utils.readFromMemory(*_immutable.variable->type()); string readFunction = m_utils.readFromMemory(*_immutable.variable->type());
define(result) << define(result) <<
readFunction << readFunction <<
"(" << "(" <<
std::to_string(m_context.immutableMemoryOffset(*_immutable.variable)) << to_string(m_context.immutableMemoryOffset(*_immutable.variable)) <<
")\n"; ")\n";
} }
else else
define(result) << "loadimmutable(\"" << std::to_string(_immutable.variable->id()) << "\")\n"; define(result) << "loadimmutable(\"" << to_string(_immutable.variable->id()) << "\")\n";
}, },
[&](IRLValue::Tuple const&) { [&](IRLValue::Tuple const&) {
solAssert(false, "Attempted to read from tuple lvalue."); solAssert(false, "Attempted to read from tuple lvalue.");
@ -3180,7 +3181,7 @@ void IRGeneratorForStatements::setLValue(Expression const& _expression, IRLValue
{ {
m_currentLValue.emplace(std::move(_lvalue)); m_currentLValue.emplace(std::move(_lvalue));
if (_lvalue.type.dataStoredIn(DataLocation::CallData)) if (_lvalue.type.dataStoredIn(DataLocation::CallData))
solAssert(std::holds_alternative<IRLValue::Stack>(_lvalue.kind)); solAssert(holds_alternative<IRLValue::Stack>(_lvalue.kind));
} }
else else
// Only define the expression, if it will not be written to. // Only define the expression, if it will not be written to.
@ -3195,7 +3196,7 @@ void IRGeneratorForStatements::generateLoop(
bool _isDoWhile bool _isDoWhile
) )
{ {
std::string firstRun; string firstRun;
if (_isDoWhile) if (_isDoWhile)
{ {
@ -3277,7 +3278,7 @@ bool IRGeneratorForStatements::visit(TryStatement const& _tryStatement)
void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement) void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
{ {
setLocation(_tryStatement); setLocation(_tryStatement);
std::string const runFallback = m_context.newYulVariable(); string const runFallback = m_context.newYulVariable();
appendCode() << "let " << runFallback << " := 1\n"; appendCode() << "let " << runFallback << " := 1\n";
// This function returns zero on "short returndata". We have to add a success flag // This function returns zero on "short returndata". We have to add a success flag
@ -3289,7 +3290,7 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
{ {
appendCode() << "case " << selectorFromSignatureU32("Error(string)") << " {\n"; appendCode() << "case " << selectorFromSignatureU32("Error(string)") << " {\n";
setLocation(*errorClause); setLocation(*errorClause);
std::string const dataVariable = m_context.newYulVariable(); string const dataVariable = m_context.newYulVariable();
appendCode() << "let " << dataVariable << " := " << m_utils.tryDecodeErrorMessageFunction() << "()\n"; appendCode() << "let " << dataVariable << " := " << m_utils.tryDecodeErrorMessageFunction() << "()\n";
appendCode() << "if " << dataVariable << " {\n"; appendCode() << "if " << dataVariable << " {\n";
appendCode() << runFallback << " := 0\n"; appendCode() << runFallback << " := 0\n";
@ -3309,8 +3310,8 @@ void IRGeneratorForStatements::handleCatch(TryStatement const& _tryStatement)
{ {
appendCode() << "case " << selectorFromSignatureU32("Panic(uint256)") << " {\n"; appendCode() << "case " << selectorFromSignatureU32("Panic(uint256)") << " {\n";
setLocation(*panicClause); setLocation(*panicClause);
std::string const success = m_context.newYulVariable(); string const success = m_context.newYulVariable();
std::string const code = m_context.newYulVariable(); string const code = m_context.newYulVariable();
appendCode() << "let " << success << ", " << code << " := " << m_utils.tryDecodePanicDataFunction() << "()\n"; appendCode() << "let " << success << ", " << code << " := " << m_utils.tryDecodePanicDataFunction() << "()\n";
appendCode() << "if " << success << " {\n"; appendCode() << "if " << success << " {\n";
appendCode() << runFallback << " := 0\n"; appendCode() << runFallback << " := 0\n";
@ -3357,9 +3358,9 @@ void IRGeneratorForStatements::handleCatchFallback(TryCatchClause const& _fallba
} }
void IRGeneratorForStatements::revertWithError( void IRGeneratorForStatements::revertWithError(
std::string const& _signature, string const& _signature,
std::vector<Type const*> const& _parameterTypes, vector<Type const*> const& _parameterTypes,
std::vector<ASTPointer<Expression const>> const& _errorArguments vector<ASTPointer<Expression const>> const& _errorArguments
) )
{ {
Whiskers templ(R"({ Whiskers templ(R"({
@ -3373,8 +3374,8 @@ void IRGeneratorForStatements::revertWithError(
templ("hash", util::selectorFromSignatureU256(_signature).str()); templ("hash", util::selectorFromSignatureU256(_signature).str());
templ("allocateUnbounded", m_utils.allocateUnboundedFunction()); templ("allocateUnbounded", m_utils.allocateUnboundedFunction());
std::vector<std::string> errorArgumentVars; vector<string> errorArgumentVars;
std::vector<Type const*> errorArgumentTypes; vector<Type const*> errorArgumentTypes;
for (ASTPointer<Expression const> const& arg: _errorArguments) for (ASTPointer<Expression const> const& arg: _errorArguments)
{ {
errorArgumentVars += IRVariable(*arg).stackSlots(); errorArgumentVars += IRVariable(*arg).stackSlots();
@ -3394,7 +3395,7 @@ bool IRGeneratorForStatements::visit(TryCatchClause const& _clause)
return false; return false;
} }
std::string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const string IRGeneratorForStatements::linkerSymbol(ContractDefinition const& _library) const
{ {
solAssert(_library.isLibrary()); solAssert(_library.isLibrary());
return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")"; return "linkersymbol(" + util::escapeAndQuoteString(_library.fullyQualifiedName()) + ")";

View File

@ -20,6 +20,7 @@
#include <libsolidity/ast/AST.h> #include <libsolidity/ast/AST.h>
#include <libsolutil/StringUtils.h> #include <libsolutil/StringUtils.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::util; using namespace solidity::util;
@ -40,7 +41,7 @@ IRVariable::IRVariable(Expression const& _expression):
{ {
} }
IRVariable IRVariable::part(std::string const& _name) const IRVariable IRVariable::part(string const& _name) const
{ {
for (auto const& [itemName, itemType]: m_type.stackItems()) for (auto const& [itemName, itemType]: m_type.stackItems())
if (itemName == _name) if (itemName == _name)
@ -62,9 +63,9 @@ bool IRVariable::hasPart(std::string const& _name) const
return false; return false;
} }
std::vector<std::string> IRVariable::stackSlots() const vector<string> IRVariable::stackSlots() const
{ {
std::vector<std::string> result; vector<string> result;
for (auto const& [itemName, itemType]: m_type.stackItems()) for (auto const& [itemName, itemType]: m_type.stackItems())
if (itemType) if (itemType)
{ {
@ -80,17 +81,17 @@ std::vector<std::string> IRVariable::stackSlots() const
return result; return result;
} }
std::string IRVariable::commaSeparatedList() const string IRVariable::commaSeparatedList() const
{ {
return joinHumanReadable(stackSlots()); return joinHumanReadable(stackSlots());
} }
std::string IRVariable::commaSeparatedListPrefixed() const string IRVariable::commaSeparatedListPrefixed() const
{ {
return joinHumanReadablePrefixed(stackSlots()); return joinHumanReadablePrefixed(stackSlots());
} }
std::string IRVariable::name() const string IRVariable::name() const
{ {
solAssert(m_type.sizeOnStack() == 1, ""); solAssert(m_type.sizeOnStack() == 1, "");
auto const& [itemName, type] = m_type.stackItems().front(); auto const& [itemName, type] = m_type.stackItems().front();
@ -107,7 +108,7 @@ IRVariable IRVariable::tupleComponent(size_t _i) const
return part(IRNames::tupleComponent(_i)); return part(IRNames::tupleComponent(_i));
} }
std::string IRVariable::suffixedName(std::string const& _suffix) const string IRVariable::suffixedName(string const& _suffix) const
{ {
if (_suffix.empty()) if (_suffix.empty())
return m_baseName; return m_baseName;

View File

@ -1,34 +0,0 @@
/*
This file is part of solidity.
solidity is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
solidity is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with solidity. If not, see <http://www.gnu.org/licenses/>.
*/
// SPDX-License-Identifier: GPL-3.0
#include <libsolidity/experimental/analysis/Analysis.h>
#include <liblangutil/ErrorReporter.h>
using namespace solidity::langutil;
using namespace solidity::frontend::experimental;
bool Analysis::check(std::vector<std::shared_ptr<SourceUnit const>> const&)
{
m_errorReporter.error(
6547_error,
Error::Type::UnimplementedFeatureError,
SourceLocation{},
"Experimental Analysis is not implemented yet."
);
return false;
}

View File

@ -20,17 +20,18 @@
#include <liblangutil/Exceptions.h> #include <liblangutil/Exceptions.h>
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::smtutil; using namespace solidity::smtutil;
using namespace solidity::frontend; using namespace solidity::frontend;
using namespace solidity::frontend::smt; using namespace solidity::frontend::smt;
std::map<std::string, ArraySlicePredicate::SliceData> ArraySlicePredicate::m_slicePredicates; map<string, ArraySlicePredicate::SliceData> ArraySlicePredicate::m_slicePredicates;
std::pair<bool, ArraySlicePredicate::SliceData const&> ArraySlicePredicate::create(SortPointer _sort, EncodingContext& _context) pair<bool, ArraySlicePredicate::SliceData const&> ArraySlicePredicate::create(SortPointer _sort, EncodingContext& _context)
{ {
solAssert(_sort->kind == Kind::Tuple, ""); solAssert(_sort->kind == Kind::Tuple, "");
auto tupleSort = std::dynamic_pointer_cast<TupleSort>(_sort); auto tupleSort = dynamic_pointer_cast<TupleSort>(_sort);
solAssert(tupleSort, ""); solAssert(tupleSort, "");
auto tupleName = tupleSort->name; auto tupleName = tupleSort->name;
@ -46,12 +47,12 @@ std::pair<bool, ArraySlicePredicate::SliceData const&> ArraySlicePredicate::crea
smt::SymbolicIntVariable endVar{TypeProvider::uint256(), TypeProvider::uint256(), "end_" + tupleName, _context }; smt::SymbolicIntVariable endVar{TypeProvider::uint256(), TypeProvider::uint256(), "end_" + tupleName, _context };
smt::SymbolicIntVariable iVar{TypeProvider::uint256(), TypeProvider::uint256(), "i_" + tupleName, _context}; smt::SymbolicIntVariable iVar{TypeProvider::uint256(), TypeProvider::uint256(), "i_" + tupleName, _context};
std::vector<SortPointer> domain{sort, sort, startVar.sort(), endVar.sort()}; vector<SortPointer> domain{sort, sort, startVar.sort(), endVar.sort()};
auto sliceSort = std::make_shared<FunctionSort>(domain, SortProvider::boolSort); auto sliceSort = make_shared<FunctionSort>(domain, SortProvider::boolSort);
Predicate const& slice = *Predicate::create(sliceSort, "array_slice_" + tupleName, PredicateType::Custom, _context); Predicate const& slice = *Predicate::create(sliceSort, "array_slice_" + tupleName, PredicateType::Custom, _context);
domain.emplace_back(iVar.sort()); domain.emplace_back(iVar.sort());
auto predSort = std::make_shared<FunctionSort>(domain, SortProvider::boolSort); auto predSort = make_shared<FunctionSort>(domain, SortProvider::boolSort);
Predicate const& header = *Predicate::create(predSort, "array_slice_header_" + tupleName, PredicateType::Custom, _context); Predicate const& header = *Predicate::create(predSort, "array_slice_header_" + tupleName, PredicateType::Custom, _context);
Predicate const& loop = *Predicate::create(predSort, "array_slice_loop_" + tupleName, PredicateType::Custom, _context); Predicate const& loop = *Predicate::create(predSort, "array_slice_loop_" + tupleName, PredicateType::Custom, _context);

View File

@ -31,6 +31,7 @@
#include <z3_version.h> #include <z3_version.h>
#endif #endif
using namespace std;
using namespace solidity; using namespace solidity;
using namespace solidity::util; using namespace solidity::util;
using namespace solidity::langutil; using namespace solidity::langutil;
@ -40,13 +41,13 @@ BMC::BMC(
smt::EncodingContext& _context, smt::EncodingContext& _context,
UniqueErrorReporter& _errorReporter, UniqueErrorReporter& _errorReporter,
UniqueErrorReporter& _unsupportedErrorReporter, UniqueErrorReporter& _unsupportedErrorReporter,
std::map<h256, std::string> const& _smtlib2Responses, map<h256, string> const& _smtlib2Responses,
ReadCallback::Callback const& _smtCallback, ReadCallback::Callback const& _smtCallback,
ModelCheckerSettings _settings, ModelCheckerSettings _settings,
CharStreamProvider const& _charStreamProvider CharStreamProvider const& _charStreamProvider
): ):
SMTEncoder(_context, _settings, _errorReporter, _unsupportedErrorReporter, _charStreamProvider), SMTEncoder(_context, _settings, _errorReporter, _unsupportedErrorReporter, _charStreamProvider),
m_interface(std::make_unique<smtutil::SMTPortfolio>( m_interface(make_unique<smtutil::SMTPortfolio>(
_smtlib2Responses, _smtCallback, _settings.solvers, _settings.timeout, _settings.printQuery _smtlib2Responses, _smtCallback, _settings.solvers, _settings.timeout, _settings.printQuery
)) ))
{ {
@ -64,7 +65,7 @@ BMC::BMC(
#endif #endif
} }
void BMC::analyze(SourceUnit const& _source, std::map<ASTNode const*, std::set<VerificationTargetType>, smt::EncodingContext::IdCompare> _solvedTargets) void BMC::analyze(SourceUnit const& _source, map<ASTNode const*, set<VerificationTargetType>, smt::EncodingContext::IdCompare> _solvedTargets)
{ {
// At this point every enabled solver is available. // At this point every enabled solver is available.
if (!m_settings.solvers.cvc4 && !m_settings.solvers.smtlib2 && !m_settings.solvers.z3) if (!m_settings.solvers.cvc4 && !m_settings.solvers.smtlib2 && !m_settings.solvers.z3)
@ -96,7 +97,7 @@ void BMC::analyze(SourceUnit const& _source, std::map<ASTNode const*, std::set<V
2788_error, 2788_error,
{}, {},
"BMC: " + "BMC: " +
std::to_string(m_unprovedAmt) + to_string(m_unprovedAmt) +
" verification condition(s) could not be proved." + " verification condition(s) could not be proved." +
" Enable the model checker option \"show unproved\" to see all of them." + " Enable the model checker option \"show unproved\" to see all of them." +
" Consider choosing a specific contract to be verified in order to reduce the solving problems." + " Consider choosing a specific contract to be verified in order to reduce the solving problems." +
@ -107,7 +108,7 @@ void BMC::analyze(SourceUnit const& _source, std::map<ASTNode const*, std::set<V
m_errorReporter.info( m_errorReporter.info(
6002_error, 6002_error,
"BMC: " + "BMC: " +
std::to_string(m_safeTargets.size()) + to_string(m_safeTargets.size()) +
" verification condition(s) proved safe!" + " verification condition(s) proved safe!" +
" Enable the model checker option \"show proved safe\" to see all of them." " Enable the model checker option \"show proved safe\" to see all of them."
); );
@ -137,7 +138,7 @@ void BMC::analyze(SourceUnit const& _source, std::map<ASTNode const*, std::set<V
"BMC analysis was not possible. No SMT solver (Z3 or CVC4) was available." "BMC analysis was not possible. No SMT solver (Z3 or CVC4) was available."
" None of the installed solvers was enabled." " None of the installed solvers was enabled."
#ifdef HAVE_Z3_DLOPEN #ifdef HAVE_Z3_DLOPEN
" Install libz3.so." + std::to_string(Z3_MAJOR_VERSION) + "." + std::to_string(Z3_MINOR_VERSION) + " to enable Z3." " Install libz3.so." + to_string(Z3_MAJOR_VERSION) + "." + to_string(Z3_MINOR_VERSION) + " to enable Z3."
#endif #endif
); );
} }
@ -312,7 +313,7 @@ bool BMC::visit(WhileStatement const& _node)
auto indicesBefore = copyVariableIndices(); auto indicesBefore = copyVariableIndices();
_node.body().accept(*this); _node.body().accept(*this);
auto brokeInCurrentIteration = mergeVariablesFromLoopCheckpoints(); auto [continues, brokeInCurrentIteration] = mergeVariablesFromLoopCheckpoints();
auto indicesBreak = copyVariableIndices(); auto indicesBreak = copyVariableIndices();
_node.condition().accept(*this); _node.condition().accept(*this);
@ -327,15 +328,13 @@ bool BMC::visit(WhileStatement const& _node)
indicesBefore, indicesBefore,
copyVariableIndices() copyVariableIndices()
); );
loopCondition = loopCondition && expr(_node.condition()); loopCondition = expr(_node.condition());
broke = broke || brokeInCurrentIteration; broke = broke || brokeInCurrentIteration;
m_loopCheckpoints.pop(); m_loopCheckpoints.pop();
} }
if (bmcLoopIterations > 0)
m_context.addAssertion(!loopCondition || broke);
} }
else { else {
smtutil::Expression loopConditionOnPreviousIterations(true); smtutil::Expression loopConditionOnPreviousIteration(true);
for (unsigned int i = 0; i < bmcLoopIterations; ++i) for (unsigned int i = 0; i < bmcLoopIterations; ++i)
{ {
m_loopCheckpoints.emplace(); m_loopCheckpoints.emplace();
@ -349,7 +348,7 @@ bool BMC::visit(WhileStatement const& _node)
_node.body().accept(*this); _node.body().accept(*this);
popPathCondition(); popPathCondition();
auto brokeInCurrentIteration = mergeVariablesFromLoopCheckpoints(); auto [continues, brokeInCurrentIteration] = mergeVariablesFromLoopCheckpoints();
// merges indices modified when accepting loop condition that no longer holds // merges indices modified when accepting loop condition that no longer holds
mergeVariables( mergeVariables(
@ -362,29 +361,17 @@ bool BMC::visit(WhileStatement const& _node)
// breaks in current iterations are handled when traversing loop checkpoints // breaks in current iterations are handled when traversing loop checkpoints
// handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop // handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop
mergeVariables( mergeVariables(
broke || !loopConditionOnPreviousIterations, broke || !loopConditionOnPreviousIteration,
indicesBefore, indicesBefore,
copyVariableIndices() copyVariableIndices()
); );
m_loopCheckpoints.pop(); m_loopCheckpoints.pop();
broke = broke || brokeInCurrentIteration; broke = broke || brokeInCurrentIteration;
loopConditionOnPreviousIterations = loopConditionOnPreviousIterations && loopCondition; loopConditionOnPreviousIteration = loopCondition;
}
} }
if (bmcLoopIterations > 0) if (bmcLoopIterations > 0)
{ m_context.addAssertion(not(loopCondition) || broke);
//after loop iterations are done, we check the loop condition last final time
auto indices = copyVariableIndices();
_node.condition().accept(*this);
loopCondition = expr(_node.condition());
// asseert that the loop is complete
m_context.addAssertion(!loopCondition || broke || !loopConditionOnPreviousIterations);
mergeVariables(
broke || !loopConditionOnPreviousIterations,
indices,
copyVariableIndices()
);
}
}
m_loopExecutionHappened = true; m_loopExecutionHappened = true;
return false; return false;
} }
@ -397,7 +384,7 @@ bool BMC::visit(ForStatement const& _node)
smtutil::Expression broke(false); smtutil::Expression broke(false);
smtutil::Expression forCondition(true); smtutil::Expression forCondition(true);
smtutil::Expression forConditionOnPreviousIterations(true); smtutil::Expression forConditionOnPreviousIteration(true);
unsigned int bmcLoopIterations = m_settings.bmcLoopIterations.value_or(1); unsigned int bmcLoopIterations = m_settings.bmcLoopIterations.value_or(1);
for (unsigned int i = 0; i < bmcLoopIterations; ++i) for (unsigned int i = 0; i < bmcLoopIterations; ++i)
{ {
@ -414,7 +401,7 @@ bool BMC::visit(ForStatement const& _node)
pushPathCondition(forCondition); pushPathCondition(forCondition);
_node.body().accept(*this); _node.body().accept(*this);
auto brokeInCurrentIteration = mergeVariablesFromLoopCheckpoints(); auto [continues, brokeInCurrentIteration] = mergeVariablesFromLoopCheckpoints();
// accept loop expression if there was no break // accept loop expression if there was no break
if (_node.loopExpression()) if (_node.loopExpression())
@ -440,38 +427,21 @@ bool BMC::visit(ForStatement const& _node)
// breaks in current iterations are handled when traversing loop checkpoints // breaks in current iterations are handled when traversing loop checkpoints
// handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop // handles case when the loop condition no longer holds but bmc loop iterations still unrolls the loop
mergeVariables( mergeVariables(
broke || !forConditionOnPreviousIterations, broke || !forConditionOnPreviousIteration,
indicesBefore, indicesBefore,
copyVariableIndices() copyVariableIndices()
); );
m_loopCheckpoints.pop(); m_loopCheckpoints.pop();
broke = broke || brokeInCurrentIteration; broke = broke || brokeInCurrentIteration;
forConditionOnPreviousIterations = forConditionOnPreviousIterations && forCondition; forConditionOnPreviousIteration = forCondition;
} }
if (bmcLoopIterations > 0) if (bmcLoopIterations > 0)
{ m_context.addAssertion(not(forCondition) || broke);
//after loop iterations are done, we check the loop condition last final time
auto indices = copyVariableIndices();
if (_node.condition())
{
_node.condition()->accept(*this);
forCondition = expr(*_node.condition());
}
// asseert that the loop is complete
m_context.addAssertion(!forCondition || broke || !forConditionOnPreviousIterations);
mergeVariables(
broke || !forConditionOnPreviousIterations,
indices,
copyVariableIndices()
);
}
m_loopExecutionHappened = true; m_loopExecutionHappened = true;
return false; return false;
} }
// merges variables based on loop control statements std::tuple<smtutil::Expression, smtutil::Expression> BMC::mergeVariablesFromLoopCheckpoints()
// returns expression indicating whether there was a break in current loop unroll iteration
smtutil::Expression BMC::mergeVariablesFromLoopCheckpoints()
{ {
smtutil::Expression continues(false); smtutil::Expression continues(false);
smtutil::Expression brokeInCurrentIteration(false); smtutil::Expression brokeInCurrentIteration(false);
@ -491,7 +461,7 @@ smtutil::Expression BMC::mergeVariablesFromLoopCheckpoints()
else if (loopControl.kind == LoopControlKind::Continue) else if (loopControl.kind == LoopControlKind::Continue)
continues = continues || loopControl.pathConditions; continues = continues || loopControl.pathConditions;
} }
return brokeInCurrentIteration; return std::pair(continues, brokeInCurrentIteration);
} }
bool BMC::visit(TryStatement const& _tryStatement) bool BMC::visit(TryStatement const& _tryStatement)
@ -503,11 +473,11 @@ bool BMC::visit(TryStatement const& _tryStatement)
if (_tryStatement.successClause()->parameters()) if (_tryStatement.successClause()->parameters())
expressionToTupleAssignment(_tryStatement.successClause()->parameters()->parameters(), *externalCall); expressionToTupleAssignment(_tryStatement.successClause()->parameters()->parameters(), *externalCall);
smtutil::Expression clauseId = m_context.newVariable("clause_choice_" + std::to_string(m_context.newUniqueId()), smtutil::SortProvider::uintSort); smtutil::Expression clauseId = m_context.newVariable("clause_choice_" + to_string(m_context.newUniqueId()), smtutil::SortProvider::uintSort);
auto const& clauses = _tryStatement.clauses(); auto const& clauses = _tryStatement.clauses();
m_context.addAssertion(clauseId >= 0 && clauseId < clauses.size()); m_context.addAssertion(clauseId >= 0 && clauseId < clauses.size());
solAssert(clauses[0].get() == _tryStatement.successClause(), "First clause of TryStatement should be the success clause"); solAssert(clauses[0].get() == _tryStatement.successClause(), "First clause of TryStatement should be the success clause");
std::vector<std::pair<VariableIndices, smtutil::Expression>> clausesVisitResults; vector<pair<VariableIndices, smtutil::Expression>> clausesVisitResults;
for (size_t i = 0; i < clauses.size(); ++i) for (size_t i = 0; i < clauses.size(); ++i)
clausesVisitResults.push_back(visitBranch(clauses[i].get())); clausesVisitResults.push_back(visitBranch(clauses[i].get()));
@ -735,7 +705,7 @@ void BMC::internalOrExternalFunctionCall(FunctionCall const& _funCall)
} }
} }
std::pair<smtutil::Expression, smtutil::Expression> BMC::arithmeticOperation( pair<smtutil::Expression, smtutil::Expression> BMC::arithmeticOperation(
Token _op, Token _op,
smtutil::Expression const& _left, smtutil::Expression const& _left,
smtutil::Expression const& _right, smtutil::Expression const& _right,
@ -799,10 +769,10 @@ void BMC::reset()
m_loopExecutionHappened = false; m_loopExecutionHappened = false;
} }
std::pair<std::vector<smtutil::Expression>, std::vector<std::string>> BMC::modelExpressions() pair<vector<smtutil::Expression>, vector<string>> BMC::modelExpressions()
{ {
std::vector<smtutil::Expression> expressionsToEvaluate; vector<smtutil::Expression> expressionsToEvaluate;
std::vector<std::string> expressionNames; vector<string> expressionNames;
for (auto const& var: m_context.variables()) for (auto const& var: m_context.variables())
if (var.first->type()->isValueType()) if (var.first->type()->isValueType())
{ {
@ -825,7 +795,7 @@ std::pair<std::vector<smtutil::Expression>, std::vector<std::string>> BMC::model
if (uf->annotation().type->isValueType()) if (uf->annotation().type->isValueType())
{ {
expressionsToEvaluate.emplace_back(expr(*uf)); expressionsToEvaluate.emplace_back(expr(*uf));
std::string expressionName; string expressionName;
if (uf->location().hasText()) if (uf->location().hasText())
expressionName = m_charStreamProvider.charStream(*uf->location().sourceName).text( expressionName = m_charStreamProvider.charStream(*uf->location().sourceName).text(
uf->location() uf->location()
@ -838,7 +808,7 @@ std::pair<std::vector<smtutil::Expression>, std::vector<std::string>> BMC::model
/// Verification targets. /// Verification targets.
std::string BMC::targetDescription(BMCVerificationTarget const& _target) string BMC::targetDescription(BMCVerificationTarget const& _target)
{ {
if ( if (
_target.type == VerificationTargetType::Underflow || _target.type == VerificationTargetType::Underflow ||
@ -1064,20 +1034,20 @@ void BMC::addVerificationTarget(
void BMC::checkCondition( void BMC::checkCondition(
BMCVerificationTarget const& _target, BMCVerificationTarget const& _target,
smtutil::Expression _condition, smtutil::Expression _condition,
std::vector<SMTEncoder::CallStackEntry> const& _callStack, vector<SMTEncoder::CallStackEntry> const& _callStack,
std::pair<std::vector<smtutil::Expression>, std::vector<std::string>> const& _modelExpressions, pair<vector<smtutil::Expression>, vector<string>> const& _modelExpressions,
SourceLocation const& _location, SourceLocation const& _location,
ErrorId _errorHappens, ErrorId _errorHappens,
ErrorId _errorMightHappen, ErrorId _errorMightHappen,
std::string const& _additionalValueName, string const& _additionalValueName,
smtutil::Expression const* _additionalValue smtutil::Expression const* _additionalValue
) )
{ {
m_interface->push(); m_interface->push();
m_interface->addAssertion(_condition); m_interface->addAssertion(_condition);
std::vector<smtutil::Expression> expressionsToEvaluate; vector<smtutil::Expression> expressionsToEvaluate;
std::vector<std::string> expressionNames; vector<string> expressionNames;
tie(expressionsToEvaluate, expressionNames) = _modelExpressions; tie(expressionsToEvaluate, expressionNames) = _modelExpressions;
if (!_callStack.empty()) if (!_callStack.empty())
if (_additionalValue) if (_additionalValue)
@ -1086,10 +1056,10 @@ void BMC::checkCondition(
expressionNames.push_back(_additionalValueName); expressionNames.push_back(_additionalValueName);
} }
smtutil::CheckResult result; smtutil::CheckResult result;
std::vector<std::string> values; vector<string> values;
tie(result, values) = checkSatisfiableAndGenerateModel(expressionsToEvaluate); tie(result, values) = checkSatisfiableAndGenerateModel(expressionsToEvaluate);
std::string extraComment = SMTEncoder::extraComment(); string extraComment = SMTEncoder::extraComment();
if (m_loopExecutionHappened) if (m_loopExecutionHappened)
extraComment += extraComment +=
"False negatives are possible when unrolling loops.\n" "False negatives are possible when unrolling loops.\n"
@ -1118,7 +1088,7 @@ void BMC::checkCondition(
if (values.size() == expressionNames.size()) if (values.size() == expressionNames.size())
{ {
modelMessage << "Counterexample:\n"; modelMessage << "Counterexample:\n";
std::map<std::string, std::string> sortedModel; map<string, string> sortedModel;
for (size_t i = 0; i < values.size(); ++i) for (size_t i = 0; i < values.size(); ++i)
if (expressionsToEvaluate.at(i).name != values.at(i)) if (expressionsToEvaluate.at(i).name != values.at(i))
sortedModel[expressionNames.at(i)] = values.at(i); sortedModel[expressionNames.at(i)] = values.at(i);
@ -1164,7 +1134,7 @@ void BMC::checkBooleanNotConstant(
Expression const& _condition, Expression const& _condition,
smtutil::Expression const& _constraints, smtutil::Expression const& _constraints,
smtutil::Expression const& _value, smtutil::Expression const& _value,
std::vector<SMTEncoder::CallStackEntry> const& _callStack vector<SMTEncoder::CallStackEntry> const& _callStack
) )
{ {
// Do not check for const-ness if this is a constant. // Do not check for const-ness if this is a constant.
@ -1197,7 +1167,7 @@ void BMC::checkBooleanNotConstant(
m_errorReporter.warning(2512_error, _condition.location(), "BMC: Condition unreachable.", SMTEncoder::callStackMessage(_callStack)); m_errorReporter.warning(2512_error, _condition.location(), "BMC: Condition unreachable.", SMTEncoder::callStackMessage(_callStack));
else else
{ {
std::string description; string description;
if (positiveResult == smtutil::CheckResult::SATISFIABLE) if (positiveResult == smtutil::CheckResult::SATISFIABLE)
{ {
solAssert(negatedResult == smtutil::CheckResult::UNSATISFIABLE, ""); solAssert(negatedResult == smtutil::CheckResult::UNSATISFIABLE, "");
@ -1218,17 +1188,17 @@ void BMC::checkBooleanNotConstant(
} }
} }
std::pair<smtutil::CheckResult, std::vector<std::string>> pair<smtutil::CheckResult, vector<string>>
BMC::checkSatisfiableAndGenerateModel(std::vector<smtutil::Expression> const& _expressionsToEvaluate) BMC::checkSatisfiableAndGenerateModel(vector<smtutil::Expression> const& _expressionsToEvaluate)
{ {
smtutil::CheckResult result; smtutil::CheckResult result;
std::vector<std::string> values; vector<string> values;
try try
{ {
if (m_settings.printQuery) if (m_settings.printQuery)
{ {
auto portfolio = dynamic_cast<smtutil::SMTPortfolio*>(m_interface.get()); auto portfolio = dynamic_cast<smtutil::SMTPortfolio*>(m_interface.get());
std::string smtlibCode = portfolio->dumpQuery(_expressionsToEvaluate); string smtlibCode = portfolio->dumpQuery(_expressionsToEvaluate);
m_errorReporter.info( m_errorReporter.info(
6240_error, 6240_error,
"BMC: Requested query:\n" + smtlibCode "BMC: Requested query:\n" + smtlibCode
@ -1238,14 +1208,14 @@ BMC::checkSatisfiableAndGenerateModel(std::vector<smtutil::Expression> const& _e
} }
catch (smtutil::SolverError const& _e) catch (smtutil::SolverError const& _e)
{ {
std::string description("BMC: Error querying SMT solver"); string description("BMC: Error querying SMT solver");
if (_e.comment()) if (_e.comment())
description += ": " + *_e.comment(); description += ": " + *_e.comment();
m_errorReporter.warning(8140_error, description); m_errorReporter.warning(8140_error, description);
result = smtutil::CheckResult::ERROR; result = smtutil::CheckResult::ERROR;
} }
for (std::string& value: values) for (string& value: values)
{ {
try try
{ {

View File

@ -190,7 +190,7 @@ private:
smtutil::CheckResult checkSatisfiable(); smtutil::CheckResult checkSatisfiable();
//@} //@}
smtutil::Expression mergeVariablesFromLoopCheckpoints(); std::tuple<smtutil::Expression, smtutil::Expression> mergeVariablesFromLoopCheckpoints();
bool isInsideLoop() const; bool isInsideLoop() const;
std::unique_ptr<smtutil::SolverInterface> m_interface; std::unique_ptr<smtutil::SolverInterface> m_interface;

Some files were not shown because too many files have changed in this diff Show More