diff --git a/Changelog.md b/Changelog.md index 417dacef6..bfe5b0d01 100644 --- a/Changelog.md +++ b/Changelog.md @@ -5,7 +5,7 @@ Language Features: Compiler Features: * Yul: Raise warning for switch statements that only have a default and no other cases. - * Add error codes to JSON output. + * Output compilation error codes. Bugfixes: diff --git a/liblangutil/SourceReferenceExtractor.cpp b/liblangutil/SourceReferenceExtractor.cpp index 0a6ff0421..89f84011d 100644 --- a/liblangutil/SourceReferenceExtractor.cpp +++ b/liblangutil/SourceReferenceExtractor.cpp @@ -38,7 +38,15 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(util::Except for (auto const& info: secondaryLocation->infos) secondary.emplace_back(extract(&info.second, info.first)); - return Message{std::move(primary), _category, std::move(secondary)}; + return Message{std::move(primary), _category, std::move(secondary), nullopt}; +} + +SourceReferenceExtractor::Message SourceReferenceExtractor::extract(Error const& _error) +{ + string category = (_error.type() == Error::Type::Warning) ? "Warning" : "Error"; + Message message = extract(_error, category); + message.errorId = _error.errorId(); + return message; } SourceReference SourceReferenceExtractor::extract(SourceLocation const* _location, std::string message) diff --git a/liblangutil/SourceReferenceExtractor.h b/liblangutil/SourceReferenceExtractor.h index 6aa0ab34a..b9dababb9 100644 --- a/liblangutil/SourceReferenceExtractor.h +++ b/liblangutil/SourceReferenceExtractor.h @@ -16,16 +16,14 @@ */ #pragma once +#include + #include +#include #include #include #include -namespace solidity::util -{ -struct Exception; -} - namespace solidity::langutil { @@ -58,8 +56,6 @@ struct SourceReference } }; -struct SourceLocation; - namespace SourceReferenceExtractor { struct Message @@ -67,9 +63,11 @@ namespace SourceReferenceExtractor SourceReference primary; std::string category; // "Error", "Warning", ... std::vector secondary; + std::optional errorId; }; Message extract(util::Exception const& _exception, std::string _category); + Message extract(Error const& _error); SourceReference extract(SourceLocation const* _location, std::string message = ""); } diff --git a/liblangutil/SourceReferenceFormatter.cpp b/liblangutil/SourceReferenceFormatter.cpp index 965755a10..e10f251d5 100644 --- a/liblangutil/SourceReferenceFormatter.cpp +++ b/liblangutil/SourceReferenceFormatter.cpp @@ -80,10 +80,7 @@ void SourceReferenceFormatter::printExceptionInformation(util::Exception const& void SourceReferenceFormatter::printErrorInformation(Error const& _error) { - printExceptionInformation( - _error, - (_error.type() == Error::Type::Warning) ? "Warning" : "Error" - ); + printExceptionInformation(SourceReferenceExtractor::extract(_error)); } void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg) diff --git a/liblangutil/SourceReferenceFormatterHuman.cpp b/liblangutil/SourceReferenceFormatterHuman.cpp index 3560955c7..998ca7bf5 100644 --- a/liblangutil/SourceReferenceFormatterHuman.cpp +++ b/liblangutil/SourceReferenceFormatterHuman.cpp @@ -151,6 +151,8 @@ void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExt { // exception header line errorColored() << _msg.category; + if (m_withErrorIds && _msg.errorId.has_value()) + errorColored() << " (" << _msg.errorId.value().error << ")"; messageColored() << ": " << _msg.primary.message << '\n'; printSourceLocation(_msg.primary); diff --git a/liblangutil/SourceReferenceFormatterHuman.h b/liblangutil/SourceReferenceFormatterHuman.h index 060adc00e..b468f3756 100644 --- a/liblangutil/SourceReferenceFormatterHuman.h +++ b/liblangutil/SourceReferenceFormatterHuman.h @@ -29,22 +29,14 @@ #include #include -namespace solidity::util -{ -struct Exception; // forward -} - namespace solidity::langutil { -struct SourceLocation; -struct SourceReference; - class SourceReferenceFormatterHuman: public SourceReferenceFormatter { public: - SourceReferenceFormatterHuman(std::ostream& _stream, bool colored): - SourceReferenceFormatter{_stream}, m_colored{colored} + SourceReferenceFormatterHuman(std::ostream& _stream, bool _colored, bool _withErrorIds): + SourceReferenceFormatter{_stream}, m_colored{_colored}, m_withErrorIds(_withErrorIds) {} void printSourceLocation(SourceReference const& _ref) override; @@ -54,12 +46,13 @@ public: static std::string formatExceptionInformation( util::Exception const& _exception, std::string const& _name, - bool colored = false + bool _colored = false, + bool _withErrorIds = false ) { std::ostringstream errorOutput; - SourceReferenceFormatterHuman formatter(errorOutput, colored); + SourceReferenceFormatterHuman formatter(errorOutput, _colored, _withErrorIds); formatter.printExceptionInformation(_exception, _name); return errorOutput.str(); } @@ -75,6 +68,7 @@ private: private: bool m_colored; + bool m_withErrorIds; }; } diff --git a/solc/CommandLineInterface.cpp b/solc/CommandLineInterface.cpp index e84ce6dd3..8b6117a2d 100644 --- a/solc/CommandLineInterface.cpp +++ b/solc/CommandLineInterface.cpp @@ -177,6 +177,7 @@ static string const g_strVersion = "version"; static string const g_strIgnoreMissingFiles = "ignore-missing"; static string const g_strColor = "color"; static string const g_strNoColor = "no-color"; +static string const g_strErrorIds = "error-codes"; static string const g_strOldReporter = "old-reporter"; static string const g_argAbi = g_strAbi; @@ -222,6 +223,7 @@ static string const g_stdinFileName = g_stdinFileNameStr; static string const g_argIgnoreMissingFiles = g_strIgnoreMissingFiles; static string const g_argColor = g_strColor; static string const g_argNoColor = g_strNoColor; +static string const g_argErrorIds = g_strErrorIds; static string const g_argOldReporter = g_strOldReporter; /// Possible arguments to for --combined-json @@ -876,6 +878,10 @@ General Information)").c_str(), g_argNoColor.c_str(), "Explicitly disable colored output, disabling terminal auto-detection." ) + ( + g_argErrorIds.c_str(), + "Output error codes." + ) ( g_argOldReporter.c_str(), "Enables old diagnostics reporter (legacy option, will be removed)." @@ -989,6 +995,8 @@ General Information)").c_str(), m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor)); + m_withErrorIds = m_args.count(g_argErrorIds); + if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1)) { sout() << desc; @@ -1294,7 +1302,7 @@ bool CommandLineInterface::processInput() if (m_args.count(g_argOldReporter)) formatter = make_unique(serr(false)); else - formatter = make_unique(serr(false), m_coloredOutput); + formatter = make_unique(serr(false), m_coloredOutput, m_withErrorIds); try { @@ -1732,7 +1740,7 @@ bool CommandLineInterface::assemble( if (m_args.count(g_argOldReporter)) formatter = make_unique(serr(false)); else - formatter = make_unique(serr(false), m_coloredOutput); + formatter = make_unique(serr(false), m_coloredOutput, m_withErrorIds); for (auto const& error: stack.errors()) { diff --git a/solc/CommandLineInterface.h b/solc/CommandLineInterface.h index 00b9181ec..2c871a670 100644 --- a/solc/CommandLineInterface.h +++ b/solc/CommandLineInterface.h @@ -131,6 +131,8 @@ private: CompilerStack::MetadataHash m_metadataHash = CompilerStack::MetadataHash::IPFS; /// Whether or not to colorize diagnostics output. bool m_coloredOutput = true; + /// Whether or not to output error IDs. + bool m_withErrorIds = false; }; } diff --git a/test/cmdlineTests.sh b/test/cmdlineTests.sh index 07e249492..448ba5a6e 100755 --- a/test/cmdlineTests.sh +++ b/test/cmdlineTests.sh @@ -121,6 +121,7 @@ function test_solc_behaviour() rm "$stdout_path.bak" else sed -i.bak -e '/^Warning: This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" + sed -i.bak -e '/^Warning (3805): This is a pre-release compiler version, please do not use it in production./d' "$stderr_path" sed -i.bak -e 's/\(^[ ]*auxdata: \)0x[0-9a-f]*$/\1AUXDATA REMOVED/' "$stdout_path" sed -i.bak -e 's/ Consider adding "pragma .*$//' "$stderr_path" # Remove trailing empty lines. Needs a line break to make OSX sed happy. diff --git a/test/cmdlineTests/error_codes/args b/test/cmdlineTests/error_codes/args new file mode 100644 index 000000000..330f811c7 --- /dev/null +++ b/test/cmdlineTests/error_codes/args @@ -0,0 +1 @@ +--error-codes diff --git a/test/cmdlineTests/error_codes/err b/test/cmdlineTests/error_codes/err new file mode 100644 index 000000000..1d983a7fd --- /dev/null +++ b/test/cmdlineTests/error_codes/err @@ -0,0 +1,26 @@ +Error (4937): No visibility specified. Did you intend to add "public"? + --> error_codes/input.sol:4:5: + | +4 | function f() { + | ^ (Relevant source part starts here and spans across multiple lines). + +Warning (3420): Source file does not specify required compiler version! +--> error_codes/input.sol + +Error (4247): Expression has to be an lvalue. + --> error_codes/input.sol:5:9: + | +5 | 2=0; + | ^ + +Error (7407): Type int_const 0 is not implicitly convertible to expected type int_const 2. + --> error_codes/input.sol:5:11: + | +5 | 2=0; + | ^ + +Error (2614): Indexed expression has to be a type, mapping or array (is literal_string "") + --> error_codes/input.sol:6:9: + | +6 | ""[2]; + | ^^ diff --git a/test/cmdlineTests/error_codes/exit b/test/cmdlineTests/error_codes/exit new file mode 100644 index 000000000..d00491fd7 --- /dev/null +++ b/test/cmdlineTests/error_codes/exit @@ -0,0 +1 @@ +1 diff --git a/test/cmdlineTests/error_codes/input.sol b/test/cmdlineTests/error_codes/input.sol new file mode 100644 index 000000000..78aceb41f --- /dev/null +++ b/test/cmdlineTests/error_codes/input.sol @@ -0,0 +1,8 @@ +// SPDX-License-Identifier: GPL-3.0 + +contract C { + function f() { + 2=0; + ""[2]; + } +} diff --git a/test/libsolidity/ASTJSONTest.cpp b/test/libsolidity/ASTJSONTest.cpp index 3cc8b3ab3..974e0f486 100644 --- a/test/libsolidity/ASTJSONTest.cpp +++ b/test/libsolidity/ASTJSONTest.cpp @@ -134,7 +134,7 @@ TestCase::TestResult ASTJSONTest::run(ostream& _stream, string const& _linePrefi c.analyze(); else { - SourceReferenceFormatterHuman formatter(_stream, _formatted); + SourceReferenceFormatterHuman formatter(_stream, _formatted, false); for (auto const& error: c.errors()) formatter.printErrorInformation(*error); return TestResult::FatalError; diff --git a/test/libsolidity/GasTest.cpp b/test/libsolidity/GasTest.cpp index 893a20715..d76979c9c 100644 --- a/test/libsolidity/GasTest.cpp +++ b/test/libsolidity/GasTest.cpp @@ -118,7 +118,7 @@ TestCase::TestResult GasTest::run(ostream& _stream, string const& _linePrefix, b if (!compiler().parseAndAnalyze() || !compiler().compile()) { - SourceReferenceFormatterHuman formatter(_stream, _formatted); + SourceReferenceFormatterHuman formatter(_stream, _formatted, false); for (auto const& error: compiler().errors()) formatter.printErrorInformation(*error); return TestResult::FatalError; diff --git a/tools/solidityUpgrade/SourceUpgrade.cpp b/tools/solidityUpgrade/SourceUpgrade.cpp index 8c05ecc9f..7005fd336 100644 --- a/tools/solidityUpgrade/SourceUpgrade.cpp +++ b/tools/solidityUpgrade/SourceUpgrade.cpp @@ -390,7 +390,7 @@ void SourceUpgrade::applyChange( void SourceUpgrade::printErrors() const { - auto formatter = make_unique(cout, true); + auto formatter = make_unique(cout, true, false); for (auto const& error: m_compiler->errors()) if (error->type() != langutil::Error::Type::Warning) diff --git a/tools/solidityUpgrade/UpgradeChange.cpp b/tools/solidityUpgrade/UpgradeChange.cpp index ff7d6d68f..a897a4e13 100644 --- a/tools/solidityUpgrade/UpgradeChange.cpp +++ b/tools/solidityUpgrade/UpgradeChange.cpp @@ -36,7 +36,7 @@ void UpgradeChange::apply() void UpgradeChange::log(bool const _shorten) const { stringstream os; - SourceReferenceFormatterHuman formatter{os, true}; + SourceReferenceFormatterHuman formatter{os, true, false}; string start = to_string(m_location.start); string end = to_string(m_location.end);