From b2ce8898eadf105f346a7e7bb94b61078411ad4c Mon Sep 17 00:00:00 2001 From: r0qs Date: Wed, 19 Jul 2023 12:18:26 +0200 Subject: [PATCH 1/5] Update solidity-website links in release checklist --- ReleaseChecklist.md | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/ReleaseChecklist.md b/ReleaseChecklist.md index 889256682..2d94281bb 100644 --- a/ReleaseChecklist.md +++ b/ReleaseChecklist.md @@ -3,7 +3,7 @@ ### Requirements - [ ] 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), - [solidity-blog](https://github.com/ethereum/solidity-blog) and [solidity-portal](https://github.com/ethereum/solidity-portal) repositories. + [solidity-website](https://github.com/ethereum/solidity-website). - [ ] DockerHub account with push rights to the [``solc`` image](https://hub.docker.com/r/ethereum/solc). - [ ] 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). @@ -37,8 +37,8 @@ At least a day before the release: - [ ] Prepare drafts of Twitter, Reddit and Solidity Forum announcements. ### Blog Post - - [ ] 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-blog](https://github.com/ethereum/solidity-blog) in the ``Security Alerts`` category in case of important bug(s). + - [ ] 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-website](https://github.com/ethereum/solidity-website/tree/main/src/posts) in the ``Security Alerts`` category in case of important bug(s). ### Changelog - [ ] 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. 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). - - [ ] Merge the [blog posts](https://github.com/ethereum/solidity-blog/pulls) related to the release. + - [ ] Merge the [blog posts](https://github.com/ethereum/solidity-website/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. - - [ ] Update the release information section [in the source of soliditylang.org](https://github.com/ethereum/solidity-portal/blob/master/index.html). + - [ ] Update the release information section [in the source of soliditylang.org](https://github.com/ethereum/solidity-website/blob/main/src/pages/index.tsx). - [ ] 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. - [ ] Share the announcement on Reddit in [``/r/ethdev``](https://reddit.com/r/ethdev/), cross-posted to [``/r/ethereum``](https://reddit.com/r/ethereum/). From 927eddee84a645807ff59f82567d5fd8e69a80ce Mon Sep 17 00:00:00 2001 From: r0qs Date: Fri, 21 Jul 2023 15:54:59 +0200 Subject: [PATCH 2/5] Add TMP and remove TODO and FIXME from pylint note tags list --- scripts/pylintrc | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/scripts/pylintrc b/scripts/pylintrc index 735810ad5..5ef5a6eff 100644 --- a/scripts/pylintrc +++ b/scripts/pylintrc @@ -63,3 +63,7 @@ expected-line-ending-format=LF # Maximum number of characters on a single line. max-line-length=130 + +[MISCELLANEOUS] + +notes=XXX,TMP From ab4f5f298330da2c25e478d94be0f840df6e9ae1 Mon Sep 17 00:00:00 2001 From: r0qs Date: Fri, 13 Jan 2023 11:43:34 +0100 Subject: [PATCH 3/5] Initial prototype of prb-math external tests using foundry rewritten in python MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kamil Úliwak --- .circleci/config.yml | 6 +- scripts/externalTests/runners/base.py | 172 +++++++++++++++++++++++ scripts/externalTests/runners/foundry.py | 110 +++++++++++++++ scripts/externalTests/test_helpers.py | 151 ++++++++++++++++++++ test/externalTests/prb-math.py | 53 +++++++ test/external_tests.py | 2 +- 6 files changed, 491 insertions(+), 3 deletions(-) create mode 100644 scripts/externalTests/runners/base.py create mode 100644 scripts/externalTests/runners/foundry.py create mode 100644 scripts/externalTests/test_helpers.py create mode 100755 test/externalTests/prb-math.py diff --git a/.circleci/config.yml b/.circleci/config.yml index bb6e562f1..38e9ee47f 100644 --- a/.circleci/config.yml +++ b/.circleci/config.yml @@ -691,7 +691,7 @@ defaults: name: t_native_test_ext_prb_math project: prb-math binary_type: native - image: cimg/node:18.16 + image: cimg/rust:1.70 - job_native_test_ext_elementfi: &job_native_test_ext_elementfi <<: *requires_b_ubu_static @@ -1724,11 +1724,13 @@ workflows: - t_native_test_ext_yield_liquidator - t_native_test_ext_perpetual_pools - t_native_test_ext_uniswap - - t_native_test_ext_prb_math - t_native_test_ext_elementfi - t_native_test_ext_brink # NOTE: We are disabling gp2 tests due to constant failures. #- 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 # depend on a specific version of hardhat which does not support shanghai EVM. #- t_native_test_ext_trident diff --git a/scripts/externalTests/runners/base.py b/scripts/externalTests/runners/base.py new file mode 100644 index 000000000..a79ed5344 --- /dev/null +++ b/scripts/externalTests/runners/base.py @@ -0,0 +1,172 @@ +#!/usr/bin/env python3 + +# ------------------------------------------------------------------------------ +# 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 +# +# (c) 2023 solidity contributors. +# ------------------------------------------------------------------------------ + +import os +import subprocess +from abc import ABCMeta +from abc import abstractmethod +from dataclasses import dataclass +from dataclasses import field +from pathlib import Path +from shutil import rmtree +from tempfile import mkdtemp +from textwrap import dedent +from typing import List +from typing import Set + +from test_helpers import download_project +from test_helpers import get_solc_short_version +from test_helpers import parse_command_line +from test_helpers import parse_custom_presets +from test_helpers import parse_solc_version +from test_helpers import replace_version_pragmas +from test_helpers import settings_from_preset +from test_helpers import SettingsPreset + +CURRENT_EVM_VERSION: str = "shanghai" + +@dataclass +class TestConfig: + name: str + repo_url: str + ref_type: str + ref: str + compile_only_presets: List[SettingsPreset] = field(default_factory=list) + settings_presets: List[SettingsPreset] = field(default_factory=lambda: list(SettingsPreset)) + evm_version: str = field(default=CURRENT_EVM_VERSION) + + def selected_presets(self) -> Set[SettingsPreset]: + return set(self.compile_only_presets + self.settings_presets) + + +class BaseRunner(metaclass=ABCMeta): + config: TestConfig + solc_binary_type: str + solc_binary_path: Path + presets: Set[SettingsPreset] + + def __init__(self, argv, config: TestConfig): + args = parse_command_line(f"{config.name} external tests", argv) + self.config = config + self.solc_binary_type = args.solc_binary_type + self.solc_binary_path = args.solc_binary_path + self.presets = parse_custom_presets(args.selected_presets) if args.selected_presets else config.selected_presets() + self.env = os.environ.copy() + self.tmp_dir = mkdtemp(prefix=f"ext-test-{config.name}-") + self.test_dir = Path(self.tmp_dir) / "ext" + + def setup_solc(self) -> str: + if self.solc_binary_type == "solcjs": + # TODO: add support to solc-js + raise NotImplementedError() + print("Setting up solc...") + solc_version_output = subprocess.check_output( + [self.solc_binary_path, "--version"], + shell=False, + encoding="utf-8" + ).split(":")[1] + return parse_solc_version(solc_version_output) + + @staticmethod + def enter_test_dir(fn): + """Run a function inside the test directory""" + + previous_dir = os.getcwd() + def f(self, *args, **kwargs): + try: + assert self.test_dir is not None + os.chdir(self.test_dir) + return fn(self, *args, **kwargs) + finally: + # Restore the previous directory after execute fn + os.chdir(previous_dir) + return f + + def setup_environment(self): + """Configure the project build environment""" + print("Configuring Runner building environment...") + replace_version_pragmas(self.test_dir) + + @enter_test_dir + def clean(self): + """Clean temporary directories""" + rmtree(self.tmp_dir) + + @enter_test_dir + @abstractmethod + def configure(self): + raise NotImplementedError() + + @enter_test_dir + @abstractmethod + def compile(self, preset: SettingsPreset): + raise NotImplementedError() + + @enter_test_dir + @abstractmethod + def run_test(self): + raise NotImplementedError() + +def run_test(runner: BaseRunner): + print(f"Testing {runner.config.name}...\n===========================") + print(f"Selected settings presets: {' '.join(p.value for p in runner.presets)}") + + # Configure solc compiler + solc_version = runner.setup_solc() + print(f"Using compiler version {solc_version}") + + # Download project + download_project(runner.test_dir, runner.config.repo_url, runner.config.ref_type, runner.config.ref) + + # Configure run environment + runner.setup_environment() + + # Configure TestRunner instance + print(dedent(f"""\ + Configuring runner's profiles with: + ------------------------------------- + Binary type: {runner.solc_binary_type} + Compiler path: {runner.solc_binary_path} + ------------------------------------- + """)) + runner.configure() + for preset in runner.presets: + print("Running compile function...") + settings = settings_from_preset(preset, runner.config.evm_version) + print(dedent(f"""\ + ------------------------------------- + Settings preset: {preset.value} + Settings: {settings} + EVM version: {runner.config.evm_version} + Compiler version: {get_solc_short_version(solc_version)} + Compiler version (full): {solc_version} + ------------------------------------- + """)) + runner.compile(preset) + # TODO: COMPILE_ONLY should be a command-line option + if os.environ.get("COMPILE_ONLY") == "1" or preset in runner.config.compile_only_presets: + print("Skipping test function...") + else: + print("Running test function...") + runner.run_test() + # TODO: store_benchmark_report + runner.clean() + print("Done.") diff --git a/scripts/externalTests/runners/foundry.py b/scripts/externalTests/runners/foundry.py new file mode 100644 index 000000000..0b171250f --- /dev/null +++ b/scripts/externalTests/runners/foundry.py @@ -0,0 +1,110 @@ +#!/usr/bin/env python3 + +# ------------------------------------------------------------------------------ +# 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 +# +# (c) 2023 solidity contributors. +# ------------------------------------------------------------------------------ + +import os +import re +import subprocess +from shutil import which +from textwrap import dedent +from typing import Optional + +from runners.base import BaseRunner +from test_helpers import SettingsPreset +from test_helpers import settings_from_preset + +def run_forge_command(command: str, env: Optional[dict] = None): + subprocess.run( + command.split(), + env=env if env is not None else os.environ.copy(), + check=True + ) + + +class FoundryRunner(BaseRunner): + """Configure and run Foundry-based projects""" + + FOUNDRY_CONFIG_FILE = "foundry.toml" + + def setup_environment(self): + super().setup_environment() + if which("forge") is None: + raise RuntimeError("Forge not found.") + + @staticmethod + def profile_name(preset: SettingsPreset): + """Returns foundry profile name""" + # Replace - or + by underscore to avoid invalid toml syntax + return re.sub(r"(\-|\+)+", "_", preset.value) + + @staticmethod + def profile_section(profile_fields: dict) -> str: + return dedent("""\ + [profile.{name}] + gas_reports = ["*"] + auto_detect_solc = false + solc = "{solc}" + evm_version = "{evm_version}" + optimizer = {optimizer} + via_ir = {via_ir} + + [profile.{name}.optimizer_details] + yul = {yul} + """).format(**profile_fields) + + @BaseRunner.enter_test_dir + def configure(self): + """Configure forge tests profiles""" + + profiles = [] + for preset in self.presets: + settings = settings_from_preset(preset, self.config.evm_version) + profiles.append(self.profile_section({ + "name": self.profile_name(preset), + "solc": self.solc_binary_path, + "evm_version": self.config.evm_version, + "optimizer": str(settings["optimizer"]["enabled"]).lower(), + "via_ir": str(settings["viaIR"]).lower(), + "yul": str(settings["optimizer"]["details"]["yul"]).lower(), + })) + + with open( + file=self.test_dir / self.FOUNDRY_CONFIG_FILE, + mode="a", + encoding="utf-8", + ) as f: + for profile in profiles: + f.write(profile) + + run_forge_command("forge install", self.env) + + @BaseRunner.enter_test_dir + def compile(self, preset: SettingsPreset): + """Compile project""" + + # Set the Foundry profile environment variable + self.env.update({"FOUNDRY_PROFILE": self.profile_name(preset)}) + run_forge_command("forge build", self.env) + + @BaseRunner.enter_test_dir + def run_test(self): + """Run project tests""" + + run_forge_command("forge test --gas-report", self.env) diff --git a/scripts/externalTests/test_helpers.py b/scripts/externalTests/test_helpers.py new file mode 100644 index 000000000..9a573d50a --- /dev/null +++ b/scripts/externalTests/test_helpers.py @@ -0,0 +1,151 @@ +#!/usr/bin/env python3 + +# ------------------------------------------------------------------------------ +# 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 +# +# (c) 2023 solidity contributors. +# ------------------------------------------------------------------------------ + +import os +import re +import subprocess +import sys +from argparse import ArgumentParser +from enum import Enum +from pathlib import Path +from typing import List +from typing import Set + +# Our scripts/ is not a proper Python package so we need to modify PYTHONPATH to import from it +# pragma pylint: disable=import-error,wrong-import-position +PROJECT_ROOT = Path(__file__).parents[2] +sys.path.insert(0, f"{PROJECT_ROOT}/scripts/common") + +from git_helpers import git_commit_hash + +SOLC_FULL_VERSION_REGEX = re.compile(r"^[a-zA-Z: ]*(.*)$") +SOLC_SHORT_VERSION_REGEX = re.compile(r"^([0-9.]+).*\+|\-$") + + +class SettingsPreset(Enum): + LEGACY_NO_OPTIMIZE = 'legacy-no-optimize' + IR_NO_OPTIMIZE = 'ir-no-optimize' + LEGACY_OPTIMIZE_EVM_ONLY = 'legacy-optimize-evm-only' + IR_OPTIMIZE_EVM_ONLY = 'ir-optimize-evm-only' + LEGACY_OPTIMIZE_EVM_YUL = 'legacy-optimize-evm+yul' + IR_OPTIMIZE_EVM_YUL = 'ir-optimize-evm+yul' + + +def compiler_settings(evm_version: str, via_ir: bool = False, optimizer: bool = False, yul: bool = False) -> dict: + return { + "optimizer": {"enabled": optimizer, "details": {"yul": yul}}, + "evmVersion": evm_version, + "viaIR": via_ir, + } + + +def settings_from_preset(preset: SettingsPreset, evm_version: str) -> dict: + return { + SettingsPreset.LEGACY_NO_OPTIMIZE: compiler_settings(evm_version), + SettingsPreset.IR_NO_OPTIMIZE: compiler_settings(evm_version, via_ir=True), + SettingsPreset.LEGACY_OPTIMIZE_EVM_ONLY: compiler_settings(evm_version, optimizer=True), + SettingsPreset.IR_OPTIMIZE_EVM_ONLY: compiler_settings(evm_version, via_ir=True, optimizer=True), + SettingsPreset.LEGACY_OPTIMIZE_EVM_YUL: compiler_settings(evm_version, optimizer=True, yul=True), + SettingsPreset.IR_OPTIMIZE_EVM_YUL: compiler_settings(evm_version, via_ir=True, optimizer=True, yul=True), + }[preset] + + +def parse_custom_presets(presets: List[str]) -> Set[SettingsPreset]: + return {SettingsPreset(p) for p in presets} + +def parse_command_line(description: str, args: List[str]): + arg_parser = ArgumentParser(description) + arg_parser.add_argument( + "solc_binary_type", + metavar="solc-binary-type", + type=str, + default="native", + choices=["native", "solcjs"], + help="""Solidity compiler binary type""", + ) + arg_parser.add_argument( + "solc_binary_path", + metavar="solc-binary-path", + type=Path, + help="""Path to solc binary""", + ) + arg_parser.add_argument( + "selected_presets", + metavar="selected-presets", + help="""List of compiler settings presets""", + nargs='*', + ) + return arg_parser.parse_args(args) + + +def download_project(test_dir: Path, repo_url: str, ref_type: str = "branch", ref: str = "master"): + assert ref_type in ("commit", "branch", "tag") + + print(f"Cloning {ref_type} {ref} of {repo_url}...") + if ref_type == "commit": + os.mkdir(test_dir) + os.chdir(test_dir) + subprocess.run(["git", "init"], check=True) + subprocess.run(["git", "remote", "add", "origin", repo_url], check=True) + subprocess.run(["git", "fetch", "--depth", "1", "origin", ref], check=True) + subprocess.run(["git", "reset", "--hard", "FETCH_HEAD"], check=True) + else: + os.chdir(test_dir.parent) + subprocess.run(["git", "clone", "--no-progress", "--depth", "1", repo_url, "-b", ref, test_dir.resolve()], check=True) + if not test_dir.exists(): + raise RuntimeError("Failed to clone the project.") + os.chdir(test_dir) + + if (test_dir / ".gitmodules").exists(): + subprocess.run(["git", "submodule", "update", "--init"], check=True) + + print(f"Current commit hash: {git_commit_hash()}") + + +def parse_solc_version(solc_version_string: str) -> str: + solc_version_match = re.search(SOLC_FULL_VERSION_REGEX, solc_version_string) + if solc_version_match is None: + raise RuntimeError(f"Solc version could not be found in: {solc_version_string}.") + return solc_version_match.group(1) + + +def get_solc_short_version(solc_full_version: str) -> str: + solc_short_version_match = re.search(SOLC_SHORT_VERSION_REGEX, solc_full_version) + if solc_short_version_match is None: + raise RuntimeError(f"Error extracting short version string from: {solc_full_version}.") + return solc_short_version_match.group(1) + + +def store_benchmark_report(self): + raise NotImplementedError() + + +def replace_version_pragmas(test_dir: Path): + """ + Replace fixed-version pragmas (part of Consensys best practice). + Include all directories to also cover node dependencies. + """ + print("Replacing fixed-version pragmas...") + for source in test_dir.glob("**/*.sol"): + content = source.read_text(encoding="utf-8") + content = re.sub(r"pragma solidity [^;]+;", r"pragma solidity >=0.0;", content) + with open(source, "w", encoding="utf-8") as f: + f.write(content) diff --git a/test/externalTests/prb-math.py b/test/externalTests/prb-math.py new file mode 100755 index 000000000..0a4ce8ff9 --- /dev/null +++ b/test/externalTests/prb-math.py @@ -0,0 +1,53 @@ +#!/usr/bin/env python3 + +# ------------------------------------------------------------------------------ +# 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 +# +# (c) 2023 solidity contributors. +# ------------------------------------------------------------------------------ + +import sys +from pathlib import Path + +# Our scripts/ is not a proper Python package so we need to modify PYTHONPATH to import from it +# pragma pylint: disable=import-error,wrong-import-position +PROJECT_ROOT = Path(__file__).parents[2] +sys.path.insert(0, f"{PROJECT_ROOT}/scripts/externalTests") + +from runners.base import run_test +from runners.base import TestConfig +from runners.foundry import FoundryRunner +from test_helpers import SettingsPreset + +test_config = TestConfig( + name="PRBMath", + repo_url="https://github.com/PaulRBerg/prb-math.git", + ref_type="branch", + ref="main", + compile_only_presets=[ + # pylint: disable=line-too-long + # SettingsPreset.IR_NO_OPTIMIZE, # Error: Yul exception:Variable expr_15699_address is 2 slot(s) too deep inside the stack. Stack too deep. + # SettingsPreset.IR_OPTIMIZE_EVM_ONLY, # Error: Yul exception:Variable expr_15699_address is 2 slot(s) too deep inside the stack. Stack too deep. + ], + settings_presets=[ + SettingsPreset.LEGACY_NO_OPTIMIZE, + SettingsPreset.LEGACY_OPTIMIZE_EVM_ONLY, + SettingsPreset.LEGACY_OPTIMIZE_EVM_YUL, + SettingsPreset.IR_OPTIMIZE_EVM_YUL, + ], +) + +sys.exit(run_test(FoundryRunner(argv=sys.argv[1:], config=test_config))) diff --git a/test/external_tests.py b/test/external_tests.py index 59b22af7e..a7b8e87e8 100755 --- a/test/external_tests.py +++ b/test/external_tests.py @@ -36,7 +36,7 @@ def detect_external_tests() -> dict: return { file_path.stem: file_path for file_path in Path(EXTERNAL_TESTS_DIR).iterdir() - if file_path.is_file() and file_path.suffix == ".sh" + if file_path.is_file() and file_path.suffix in (".sh", ".py") } From dcbd6457984844af420b3ee2abe461fb0859dcf3 Mon Sep 17 00:00:00 2001 From: r0qs Date: Wed, 19 Apr 2023 17:16:21 +0200 Subject: [PATCH 4/5] Delete old prb-math.sh script --- test/externalTests/prb-math.sh | 116 --------------------------------- 1 file changed, 116 deletions(-) delete mode 100755 test/externalTests/prb-math.sh diff --git a/test/externalTests/prb-math.sh b/test/externalTests/prb-math.sh deleted file mode 100755 index fcf1aa208..000000000 --- a/test/externalTests/prb-math.sh +++ /dev/null @@ -1,116 +0,0 @@ -#!/usr/bin/env bash - -# ------------------------------------------------------------------------------ -# 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 -# -# (c) 2022 solidity contributors. -#------------------------------------------------------------------------------ - -set -e - -source scripts/common.sh -source scripts/externalTests/common.sh - -REPO_ROOT=$(realpath "$(dirname "$0")/../..") - -verify_input "$@" -BINARY_TYPE="$1" -BINARY_PATH="$(realpath "$2")" -SELECTED_PRESETS="$3" - -function compile_fn { yarn compile; } -# NOTE: `yarn test` runs `mocha` which seems to disable the gas reporter. -function test_fn { npx --no hardhat --no-compile test; } - -function prb_math_test -{ - local repo="https://github.com/paulrberg/prb-math" - local ref_type=branch - # We currently pin the prb-math version to the latest version that support hardhat - # Please see here for details: https://github.com/ethereum/solidity/issues/13767 - local ref=v2.5.0 - local config_file="hardhat.config.ts" - local config_var="config" - - local compile_only_presets=( - ir-no-optimize # Tests fail with "Error: Transaction reverted: trying to deploy a contract whose code is too large" - ) - local settings_presets=( - "${compile_only_presets[@]}" - ir-optimize-evm-only - ir-optimize-evm+yul - legacy-optimize-evm-only - legacy-optimize-evm+yul - legacy-no-optimize - ) - - [[ $SELECTED_PRESETS != "" ]] || SELECTED_PRESETS=$(circleci_select_steps_multiarg "${settings_presets[@]}") - print_presets_or_exit "$SELECTED_PRESETS" - - setup_solc "$DIR" "$BINARY_TYPE" "$BINARY_PATH" - download_project "$repo" "$ref_type" "$ref" "$DIR" - - cp .env.example .env - - # The project has yarn 3.1.0 binary stored in the repo and yarnrc forces the yarn 1.x binary - # installed system-wide to use it. Unfortunately Yarn 3 fails in weird ways when we remove - # yarn.lock. Remove the config to restore Yarn 1.x. - rm .yarnrc.yml - - # Disable tests that won't pass on the ir presets due to Hardhat heuristics. Note that this also disables - # them for other presets but that's fine - we want same code run for benchmarks to be comparable. - # TODO: Remove this when Hardhat adjusts heuristics for IR (https://github.com/nomiclabs/hardhat/issues/3365). - pushd test/contracts/prbMathUd60x18/pure/ - sed -i 's|context(\("when the sum overflows"\)|context.skip(\1|g' add.test.ts - sed -i 's|context(\("when the sum does not overflow"\)|context.skip(\1|g' add.test.ts - sed -i 's|context(\("when both operands are zero"\)|context.skip(\1|g' avg.test.ts - sed -i 's|context(\("when one operand is zero and the other is not zero"\)|context.skip(\1|g' avg.test.ts - sed -i 's|context(\("when the denominator is zero"\)|context.skip(\1|g' div.test.ts - sed -i 's|context(\("when x is zero"\)|context.skip(\1|g' inv.test.ts - popd - pushd test/contracts/prbMathSd59x18/pure/ - sed -i 's|context(\("when the sum overflows"\)|context.skip(\1|g' add.test.ts - sed -i 's|context(\("when the sum underflows"\)|context.skip(\1|g' add.test.ts - sed -i 's|context(\("when the denominator is zero"\)|context.skip(\1|g' div.test.ts - sed -i 's|context(\("when x is zero"\)|context.skip(\1|g' inv.test.ts - sed -i 's|context(\("when the difference underflows"\)|context.skip(\1|g' sub.test.ts - sed -i 's|context(\("when the difference overflows"\)|context.skip(\1|g' sub.test.ts - popd - - neutralize_package_lock - neutralize_package_json_hooks - force_hardhat_compiler_binary "$config_file" "$BINARY_TYPE" "$BINARY_PATH" - force_hardhat_compiler_settings "$config_file" "$(first_word "$SELECTED_PRESETS")" "$config_var" - yarn install --no-lock-file - yarn add hardhat-gas-reporter - - # Workaround for error caused by the last release of hardhat-waffle@2.0.6 that bumps ethereum-waffle - # to version 4.0.10 and breaks prb-math build with the following error: - # - # Cannot find module 'ethereum-waffle/dist/cjs/src/deployContract' - # - # See: https://github.com/NomicFoundation/hardhat-waffle/commit/83ee9cb36ee59d0bedacbbd00043f030af104ad0 - yarn add '@nomiclabs/hardhat-waffle@2.0.5' - - replace_version_pragmas - - for preset in $SELECTED_PRESETS; do - hardhat_run_test "$config_file" "$preset" "${compile_only_presets[*]}" compile_fn test_fn "$config_var" - store_benchmark_report hardhat prb-math "$repo" "$preset" - done -} - -external_test PRBMath prb_math_test From 964bdc711ccd81253251ebc0af4fb1919de5681e Mon Sep 17 00:00:00 2001 From: Nikola Matic Date: Thu, 20 Jul 2023 13:28:03 +0200 Subject: [PATCH 5/5] Fix ICE when emitting event from another contract --- Changelog.md | 1 + libsolidity/interface/Natspec.cpp | 17 -- .../event_emitted_from_foreign_contract.sol | 112 +++++++ .../event_emitted_from_foreign_contract.json | 289 ++++++++++++++++++ .../event_emitted_from_foreign_contract.sol | 10 + ...itted_from_foreign_contract_parseOnly.json | 194 ++++++++++++ test/libsolidity/SolidityNatspecJSON.cpp | 173 +++++++++++ .../event_emit_from_a_foreign_contract.sol | 13 + ...emit_from_a_foreign_contract_same_name.sol | 17 ++ ...event_emit_interface_event_via_library.sol | 19 ++ .../events/event_emit_via_interface.sol | 13 + 11 files changed, 841 insertions(+), 17 deletions(-) create mode 100644 test/libsolidity/ABIJson/event_emitted_from_foreign_contract.sol create mode 100644 test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json create mode 100644 test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.sol create mode 100644 test/libsolidity/ASTJSON/event_emitted_from_foreign_contract_parseOnly.json create mode 100644 test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract.sol create mode 100644 test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract_same_name.sol create mode 100644 test/libsolidity/semanticTests/events/event_emit_interface_event_via_library.sol create mode 100644 test/libsolidity/semanticTests/events/event_emit_via_interface.sol diff --git a/Changelog.md b/Changelog.md index 4205e7416..38a8aae41 100644 --- a/Changelog.md +++ b/Changelog.md @@ -7,6 +7,7 @@ Compiler Features: Bugfixes: + * NatSpec: Fix internal error when requesting userdoc or devdoc for a contract that emits an event defined in a foreign contract or interface. ### 0.8.21 (2023-07-19) diff --git a/libsolidity/interface/Natspec.cpp b/libsolidity/interface/Natspec.cpp index b192dfda1..5733d3063 100644 --- a/libsolidity/interface/Natspec.cpp +++ b/libsolidity/interface/Natspec.cpp @@ -80,14 +80,6 @@ Json::Value Natspec::userDocumentation(ContractDefinition const& _contractDef) for (auto const& event: uniqueInterfaceEvents(_contractDef)) { - ContractDefinition const* eventOrigin = event->annotation().contract; - solAssert(eventOrigin); - solAssert( - *eventOrigin == _contractDef || - (!eventOrigin->isLibrary() && _contractDef.derivesFrom(*eventOrigin)) || - (eventOrigin->isLibrary() && !_contractDef.derivesFrom(*eventOrigin)) - ); - string value = extractDoc(event->annotation().docTags, "notice"); if (!value.empty()) doc["events"][event->functionType(true)->externalSignature()]["notice"] = value; @@ -178,16 +170,7 @@ Json::Value Natspec::devDocumentation(ContractDefinition const& _contractDef) for (auto const& event: uniqueInterfaceEvents(_contractDef)) if (auto devDoc = devDocumentation(event->annotation().docTags); !devDoc.empty()) - { - ContractDefinition const* eventOrigin = event->annotation().contract; - solAssert(eventOrigin); - solAssert( - *eventOrigin == _contractDef || - (!eventOrigin->isLibrary() && _contractDef.derivesFrom(*eventOrigin)) || - (eventOrigin->isLibrary() && !_contractDef.derivesFrom(*eventOrigin)) - ); doc["events"][event->functionType(true)->externalSignature()] = devDoc; - } for (auto const& error: _contractDef.interfaceErrors()) if (auto devDoc = devDocumentation(error->annotation().docTags); !devDoc.empty()) doc["errors"][error->functionType(true)->externalSignature()].append(devDoc); diff --git a/test/libsolidity/ABIJson/event_emitted_from_foreign_contract.sol b/test/libsolidity/ABIJson/event_emitted_from_foreign_contract.sol new file mode 100644 index 000000000..30c115669 --- /dev/null +++ b/test/libsolidity/ABIJson/event_emitted_from_foreign_contract.sol @@ -0,0 +1,112 @@ +interface I { + event Event(uint256 value); +} +contract C { + event Event(address indexed sender); +} +contract D { + event Event(address indexed sender); + function test(address sender) public { + emit I.Event(1); + emit C.Event(msg.sender); + emit Event(msg.sender); + } +} +// ---- +// :C +// [ +// { +// "anonymous": false, +// "inputs": +// [ +// { +// "indexed": true, +// "internalType": "address", +// "name": "sender", +// "type": "address" +// } +// ], +// "name": "Event", +// "type": "event" +// } +// ] +// +// +// :D +// [ +// { +// "anonymous": false, +// "inputs": +// [ +// { +// "indexed": false, +// "internalType": "uint256", +// "name": "value", +// "type": "uint256" +// } +// ], +// "name": "Event", +// "type": "event" +// }, +// { +// "anonymous": false, +// "inputs": +// [ +// { +// "indexed": true, +// "internalType": "address", +// "name": "sender", +// "type": "address" +// } +// ], +// "name": "Event", +// "type": "event" +// }, +// { +// "anonymous": false, +// "inputs": +// [ +// { +// "indexed": true, +// "internalType": "address", +// "name": "sender", +// "type": "address" +// } +// ], +// "name": "Event", +// "type": "event" +// }, +// { +// "inputs": +// [ +// { +// "internalType": "address", +// "name": "sender", +// "type": "address" +// } +// ], +// "name": "test", +// "outputs": [], +// "stateMutability": "nonpayable", +// "type": "function" +// } +// ] +// +// +// :I +// [ +// { +// "anonymous": false, +// "inputs": +// [ +// { +// "indexed": false, +// "internalType": "uint256", +// "name": "value", +// "type": "uint256" +// } +// ], +// "name": "Event", +// "type": "event" +// } +// ] diff --git a/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json new file mode 100644 index 000000000..2d70e2f9f --- /dev/null +++ b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.json @@ -0,0 +1,289 @@ +{ + "absolutePath": "a", + "exportedSymbols": + { + "C": + [ + 5 + ], + "D": + [ + 19 + ] + }, + "id": 20, + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "canonicalName": "C", + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 5, + "linearizedBaseContracts": + [ + 5 + ], + "name": "C", + "nameLocation": "9:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "anonymous": false, + "eventSelector": "bd1155618a34fd53d1a2de9f705f42f3582842cba0b985b25c59888d86e0c929", + "id": 4, + "name": "E", + "nameLocation": "23:1:1", + "nodeType": "EventDefinition", + "parameters": + { + "id": 3, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 2, + "indexed": true, + "mutability": "mutable", + "name": "sender", + "nameLocation": "41:6:1", + "nodeType": "VariableDeclaration", + "scope": 4, + "src": "25:22:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": + { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "typeName": + { + "id": 1, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "25:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": + { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "visibility": "internal" + } + ], + "src": "24:24:1" + }, + "src": "17:32:1" + } + ], + "scope": 20, + "src": "0:51:1", + "usedErrors": [], + "usedEvents": + [ + 4 + ] + }, + { + "abstract": false, + "baseContracts": [], + "canonicalName": "D", + "contractDependencies": [], + "contractKind": "contract", + "fullyImplemented": true, + "id": 19, + "linearizedBaseContracts": + [ + 19 + ], + "name": "D", + "nameLocation": "61:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "body": + { + "id": 17, + "nodeType": "Block", + "src": "106:37:1", + "statements": + [ + { + "eventCall": + { + "arguments": + [ + { + "expression": + { + "id": 13, + "name": "msg", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": -15, + "src": "125:3:1", + "typeDescriptions": + { + "typeIdentifier": "t_magic_message", + "typeString": "msg" + } + }, + "id": 14, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberLocation": "129:6:1", + "memberName": "sender", + "nodeType": "MemberAccess", + "src": "125:10:1", + "typeDescriptions": + { + "typeIdentifier": "t_address", + "typeString": "address" + } + } + ], + "expression": + { + "argumentTypes": + [ + { + "typeIdentifier": "t_address", + "typeString": "address" + } + ], + "expression": + { + "id": 10, + "name": "C", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "referencedDeclaration": 5, + "src": "121:1:1", + "typeDescriptions": + { + "typeIdentifier": "t_type$_t_contract$_C_$5_$", + "typeString": "type(contract C)" + } + }, + "id": 12, + "isConstant": false, + "isLValue": false, + "isPure": false, + "lValueRequested": false, + "memberLocation": "123:1:1", + "memberName": "E", + "nodeType": "MemberAccess", + "referencedDeclaration": 4, + "src": "121:3:1", + "typeDescriptions": + { + "typeIdentifier": "t_function_event_nonpayable$_t_address_$returns$__$", + "typeString": "function (address)" + } + }, + "id": 15, + "isConstant": false, + "isLValue": false, + "isPure": false, + "kind": "functionCall", + "lValueRequested": false, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "121:15:1", + "tryCall": false, + "typeDescriptions": + { + "typeIdentifier": "t_tuple$__$", + "typeString": "tuple()" + } + }, + "id": 16, + "nodeType": "EmitStatement", + "src": "116:20:1" + } + ] + }, + "functionSelector": "bb29998e", + "id": 18, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "test", + "nameLocation": "78:4:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 8, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 7, + "mutability": "mutable", + "name": "sender", + "nameLocation": "91:6:1", + "nodeType": "VariableDeclaration", + "scope": 18, + "src": "83:14:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": + { + "typeIdentifier": "t_address", + "typeString": "address" + }, + "typeName": + { + "id": 6, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "83:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": + { + "typeIdentifier": "t_address", + "typeString": "address" + } + }, + "visibility": "internal" + } + ], + "src": "82:16:1" + }, + "returnParameters": + { + "id": 9, + "nodeType": "ParameterList", + "parameters": [], + "src": "106:0:1" + }, + "scope": 19, + "src": "69:74:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + } + ], + "scope": 20, + "src": "52:93:1", + "usedErrors": [], + "usedEvents": + [ + 4 + ] + } + ], + "src": "0:146:1" +} diff --git a/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.sol b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.sol new file mode 100644 index 000000000..6cad968f6 --- /dev/null +++ b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract.sol @@ -0,0 +1,10 @@ +contract C { + event E(address indexed sender); +} +contract D { + function test(address sender) public { + emit C.E(msg.sender); + } +} + +// ---- diff --git a/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract_parseOnly.json b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract_parseOnly.json new file mode 100644 index 000000000..b6c0ca5e0 --- /dev/null +++ b/test/libsolidity/ASTJSON/event_emitted_from_foreign_contract_parseOnly.json @@ -0,0 +1,194 @@ +{ + "absolutePath": "a", + "id": 20, + "nodeType": "SourceUnit", + "nodes": + [ + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "id": 5, + "name": "C", + "nameLocation": "9:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "anonymous": false, + "id": 4, + "name": "E", + "nameLocation": "23:1:1", + "nodeType": "EventDefinition", + "parameters": + { + "id": 3, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 2, + "indexed": true, + "mutability": "mutable", + "name": "sender", + "nameLocation": "41:6:1", + "nodeType": "VariableDeclaration", + "src": "25:22:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 1, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "25:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "src": "24:24:1" + }, + "src": "17:32:1" + } + ], + "src": "0:51:1", + "usedErrors": [], + "usedEvents": [] + }, + { + "abstract": false, + "baseContracts": [], + "contractDependencies": [], + "contractKind": "contract", + "id": 19, + "name": "D", + "nameLocation": "61:1:1", + "nodeType": "ContractDefinition", + "nodes": + [ + { + "body": + { + "id": 17, + "nodeType": "Block", + "src": "106:37:1", + "statements": + [ + { + "eventCall": + { + "arguments": + [ + { + "expression": + { + "id": 13, + "name": "msg", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "src": "125:3:1", + "typeDescriptions": {} + }, + "id": 14, + "memberLocation": "129:6:1", + "memberName": "sender", + "nodeType": "MemberAccess", + "src": "125:10:1", + "typeDescriptions": {} + } + ], + "expression": + { + "expression": + { + "id": 10, + "name": "C", + "nodeType": "Identifier", + "overloadedDeclarations": [], + "src": "121:1:1", + "typeDescriptions": {} + }, + "id": 12, + "memberLocation": "123:1:1", + "memberName": "E", + "nodeType": "MemberAccess", + "src": "121:3:1", + "typeDescriptions": {} + }, + "id": 15, + "nameLocations": [], + "names": [], + "nodeType": "FunctionCall", + "src": "121:15:1", + "tryCall": false, + "typeDescriptions": {} + }, + "id": 16, + "nodeType": "EmitStatement", + "src": "116:20:1" + } + ] + }, + "id": 18, + "implemented": true, + "kind": "function", + "modifiers": [], + "name": "test", + "nameLocation": "78:4:1", + "nodeType": "FunctionDefinition", + "parameters": + { + "id": 8, + "nodeType": "ParameterList", + "parameters": + [ + { + "constant": false, + "id": 7, + "mutability": "mutable", + "name": "sender", + "nameLocation": "91:6:1", + "nodeType": "VariableDeclaration", + "src": "83:14:1", + "stateVariable": false, + "storageLocation": "default", + "typeDescriptions": {}, + "typeName": + { + "id": 6, + "name": "address", + "nodeType": "ElementaryTypeName", + "src": "83:7:1", + "stateMutability": "nonpayable", + "typeDescriptions": {} + }, + "visibility": "internal" + } + ], + "src": "82:16:1" + }, + "returnParameters": + { + "id": 9, + "nodeType": "ParameterList", + "parameters": [], + "src": "106:0:1" + }, + "src": "69:74:1", + "stateMutability": "nonpayable", + "virtual": false, + "visibility": "public" + } + ], + "src": "52:93:1", + "usedErrors": [], + "usedEvents": [] + } + ], + "src": "0:146:1" +} diff --git a/test/libsolidity/SolidityNatspecJSON.cpp b/test/libsolidity/SolidityNatspecJSON.cpp index a54460eb6..9ecd35aef 100644 --- a/test/libsolidity/SolidityNatspecJSON.cpp +++ b/test/libsolidity/SolidityNatspecJSON.cpp @@ -485,6 +485,179 @@ BOOST_AUTO_TEST_CASE(event) checkNatspec(sourceCode, "ERC20", userDoc, true); } +BOOST_AUTO_TEST_CASE(emit_event_from_foreign_contract) +{ + char const* sourceCode = R"( + contract X { + /// @notice Userdoc for event E. + /// @dev Devdoc for event E. + event E(); + } + + contract C { + function g() public { + emit X.E(); + } + } + )"; + + char const* devDoc = R"ABCDEF( + { + "events": + { + "E()": + { + "details": "Devdoc for event E." + } + }, + "kind": "dev", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "C", devDoc, false); + + char const* userDoc = R"ABCDEF( + { + "events": + { + "E()": + { + "notice": "Userdoc for event E." + } + }, + "kind": "user", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "C", userDoc, true); +} + +BOOST_AUTO_TEST_CASE(emit_event_from_foreign_contract_with_same_signature) +{ + char const* sourceCode = R"( + contract C { + /// @notice C.E event + /// @dev C.E event + event E(uint256 value); + } + + contract D { + /// @notice D.E event + /// @dev D.E event + event E(uint256 value); + + function test() public { + emit C.E(1); + emit E(2); + } + } + )"; + + char const* devDocC = R"ABCDEF( + { + "events": + { + "E(uint256)": + { + "details": "C.E event" + } + }, + "kind": "dev", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "C", devDocC, false); + + char const* devDocD = R"ABCDEF( + { + "events": + { + "E(uint256)": + { + "details": "D.E event" + } + }, + "kind": "dev", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "D", devDocD, false); + + char const* userDocC = R"ABCDEF( + { + "events": + { + "E(uint256)": + { + "notice": "C.E event" + } + }, + "kind": "user", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "C", userDocC, true); + + char const* userDocD = R"ABCDEF( + { + "events": + { + "E(uint256)": + { + "notice": "D.E event" + } + }, + "kind": "user", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "D", userDocD, true); +} + +// Tests that emitting an event from contract C in contract D does not inherit natspec from C.E +BOOST_AUTO_TEST_CASE(emit_event_from_foreign_contract_no_inheritance) +{ + char const* sourceCode = R"( + contract C { + /// @notice C.E event + /// @dev C.E event + event E(); + } + + contract D { + event E(); + + function test() public { + emit C.E(); + } + } + )"; + + char const* devDoc = R"ABCDEF( + { + "kind": "dev", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "D", devDoc, false); + + char const* userDoc = R"ABCDEF( + { + "kind": "user", + "methods": {}, + "version": 1 + } + )ABCDEF"; + checkNatspec(sourceCode, "D", userDoc, true); +} + BOOST_AUTO_TEST_CASE(emit_same_signature_event_library_contract) { char const* sourceCode = R"( diff --git a/test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract.sol b/test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract.sol new file mode 100644 index 000000000..fcd7b6f4c --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract.sol @@ -0,0 +1,13 @@ +contract C { + event E(); +} + +contract D { + function test() public { + emit C.E(); + } +} + +// ---- +// test() -> +// ~ emit E() diff --git a/test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract_same_name.sol b/test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract_same_name.sol new file mode 100644 index 000000000..05c03c20f --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_emit_from_a_foreign_contract_same_name.sol @@ -0,0 +1,17 @@ +contract C { + event E(uint256 value); +} + +contract D { + event E(uint256 value); + + function test() public { + emit C.E(1); + emit E(2); + } +} + +// ---- +// test() -> +// ~ emit E(uint256): 0x01 +// ~ emit E(uint256): 0x02 diff --git a/test/libsolidity/semanticTests/events/event_emit_interface_event_via_library.sol b/test/libsolidity/semanticTests/events/event_emit_interface_event_via_library.sol new file mode 100644 index 000000000..9e24287ab --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_emit_interface_event_via_library.sol @@ -0,0 +1,19 @@ +interface I { + event E(); +} + +library L { + function f() internal { + emit I.E(); + } +} + +contract C { + function g() public { + L.f(); + } +} + +// ---- +// g() -> +// ~ emit E() diff --git a/test/libsolidity/semanticTests/events/event_emit_via_interface.sol b/test/libsolidity/semanticTests/events/event_emit_via_interface.sol new file mode 100644 index 000000000..7268e9ac5 --- /dev/null +++ b/test/libsolidity/semanticTests/events/event_emit_via_interface.sol @@ -0,0 +1,13 @@ +interface I { + event Event(address indexed _from, uint256 _value); +} + +contract C { + function emitEvent(uint256 _value) public { + emit I.Event(msg.sender, _value); + } +} + +// ---- +// emitEvent(uint256): 100 -> +// ~ emit Event(address,uint256): #0x1212121212121212121212121212120000000012, 0x64