From 0e51e57971ea5c3980184a0ee41f2ad58a66c0b8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 29 Sep 2023 22:07:44 +0200 Subject: [PATCH 1/4] Add Error::parseErrorType() --- liblangutil/Exceptions.cpp | 20 ++++++++++++++++++++ liblangutil/Exceptions.h | 38 +++++++++++++++----------------------- 2 files changed, 35 insertions(+), 23 deletions(-) diff --git a/liblangutil/Exceptions.cpp b/liblangutil/Exceptions.cpp index 118720b74570..108acd1216ee 100644 --- a/liblangutil/Exceptions.cpp +++ b/liblangutil/Exceptions.cpp @@ -29,6 +29,26 @@ using namespace solidity; using namespace solidity::langutil; +std::map const Error::m_errorTypeNames = { + {Error::Type::IOError, "IOError"}, + {Error::Type::FatalError, "FatalError"}, + {Error::Type::JSONError, "JSONError"}, + {Error::Type::InternalCompilerError, "InternalCompilerError"}, + {Error::Type::CompilerError, "CompilerError"}, + {Error::Type::Exception, "Exception"}, + {Error::Type::CodeGenerationError, "CodeGenerationError"}, + {Error::Type::DeclarationError, "DeclarationError"}, + {Error::Type::DocstringParsingError, "DocstringParsingError"}, + {Error::Type::ParserError, "ParserError"}, + {Error::Type::SyntaxError, "SyntaxError"}, + {Error::Type::TypeError, "TypeError"}, + {Error::Type::UnimplementedFeatureError, "UnimplementedFeatureError"}, + {Error::Type::YulException, "YulException"}, + {Error::Type::SMTLogicException, "SMTLogicException"}, + {Error::Type::Warning, "Warning"}, + {Error::Type::Info, "Info"}, +}; + Error::Error( ErrorId _errorId, Error::Type _type, std::string const& _description, diff --git a/liblangutil/Exceptions.h b/liblangutil/Exceptions.h index 65362df31d40..b0701f99938e 100644 --- a/liblangutil/Exceptions.h +++ b/liblangutil/Exceptions.h @@ -33,11 +33,11 @@ #include #include +#include #include #include -#include -#include #include +#include namespace solidity::langutil { @@ -269,27 +269,17 @@ class Error: virtual public util::Exception static std::string formatErrorType(Type _type) { - switch (_type) - { - case Type::IOError: return "IOError"; - case Type::FatalError: return "FatalError"; - case Type::JSONError: return "JSONError"; - case Type::InternalCompilerError: return "InternalCompilerError"; - case Type::CompilerError: return "CompilerError"; - case Type::Exception: return "Exception"; - case Type::CodeGenerationError: return "CodeGenerationError"; - case Type::DeclarationError: return "DeclarationError"; - case Type::DocstringParsingError: return "DocstringParsingError"; - case Type::ParserError: return "ParserError"; - case Type::SyntaxError: return "SyntaxError"; - case Type::TypeError: return "TypeError"; - case Type::UnimplementedFeatureError: return "UnimplementedFeatureError"; - case Type::YulException: return "YulException"; - case Type::SMTLogicException: return "SMTLogicException"; - case Type::Warning: return "Warning"; - case Type::Info: return "Info"; - } - util::unreachable(); + return m_errorTypeNames.at(_type); + } + + static std::optional parseErrorType(std::string _name) + { + static std::map const m_errorTypesByName = util::invertMap(m_errorTypeNames); + + if (m_errorTypesByName.count(_name) == 0) + return std::nullopt; + + return m_errorTypesByName.at(_name); } static std::string formatTypeOrSeverity(std::variant _typeOrSeverity) @@ -309,6 +299,8 @@ class Error: virtual public util::Exception private: ErrorId m_errorId; Type m_type; + + static std::map const m_errorTypeNames; }; } From 2e8e1f3a12fe94675d354b0e4eca1aedb28e4374 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 29 Sep 2023 22:08:10 +0200 Subject: [PATCH 2/4] Store Error::Type rather than a string in SyntaxTestError --- test/CommonSyntaxTest.cpp | 14 +++++++++----- test/CommonSyntaxTest.h | 2 +- test/libsolidity/SyntaxTest.cpp | 4 ++-- test/libyul/SyntaxTest.cpp | 2 +- 4 files changed, 13 insertions(+), 9 deletions(-) diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 8e546017ff70..78bb9493633c 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -115,7 +115,7 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, { assert(static_cast(error.locationStart) <= source.length()); assert(static_cast(error.locationEnd) <= source.length()); - bool isWarning = error.type == "Warning"; + bool isWarning = (error.type == Error::Type::Warning); for (int i = error.locationStart; i < error.locationEnd; i++) if (isWarning) { @@ -190,8 +190,8 @@ void CommonSyntaxTest::printErrorList( for (auto const& error: _errorList) { { - util::AnsiColorized scope(_stream, _formatted, {BOLD, (error.type == "Warning") ? YELLOW : RED}); - _stream << _linePrefix << error.type; + util::AnsiColorized scope(_stream, _formatted, {BOLD, (error.type == Error::Type::Warning) ? YELLOW : RED}); + _stream << _linePrefix << Error::formatErrorType(error.type); if (error.errorId.has_value()) _stream << ' ' << error.errorId->error; _stream << ": "; @@ -244,7 +244,11 @@ vector CommonSyntaxTest::parseExpectations(istream& _stream) auto typeBegin = it; while (it != line.end() && isalpha(*it, locale::classic())) ++it; - string errorType(typeBegin, it); + + string errorTypeStr(typeBegin, it); + optional errorType = Error::parseErrorType(errorTypeStr); + if (!errorType.has_value()) + BOOST_THROW_EXCEPTION(runtime_error("Invalid error type: " + errorTypeStr)); skipWhitespace(it, line.end()); @@ -281,7 +285,7 @@ vector CommonSyntaxTest::parseExpectations(istream& _stream) string errorMessage(it, line.end()); expectations.emplace_back(SyntaxTestError{ - std::move(errorType), + errorType.value(), std::move(errorId), std::move(errorMessage), std::move(sourceName), diff --git a/test/CommonSyntaxTest.h b/test/CommonSyntaxTest.h index 606f61a88d0c..fb46c37a6401 100644 --- a/test/CommonSyntaxTest.h +++ b/test/CommonSyntaxTest.h @@ -34,7 +34,7 @@ namespace solidity::test struct SyntaxTestError { - std::string type; + langutil::Error::Type type; std::optional errorId; std::string message; std::string sourceName; diff --git a/test/libsolidity/SyntaxTest.cpp b/test/libsolidity/SyntaxTest.cpp index 49608244f3c4..7c4fa8da1e84 100644 --- a/test/libsolidity/SyntaxTest.cpp +++ b/test/libsolidity/SyntaxTest.cpp @@ -91,7 +91,7 @@ void SyntaxTest::parseAndAnalyze() catch (UnimplementedFeatureError const& _e) { m_errorList.emplace_back(SyntaxTestError{ - "UnimplementedFeatureError", + Error::Type::UnimplementedFeatureError, std::nullopt, errorMessage(_e), "", @@ -140,7 +140,7 @@ void SyntaxTest::filterObtainedErrors() } } m_errorList.emplace_back(SyntaxTestError{ - Error::formatErrorType(currentError->type()), + currentError->type(), currentError->errorId(), errorMessage(*currentError), sourceName, diff --git a/test/libyul/SyntaxTest.cpp b/test/libyul/SyntaxTest.cpp index cea1d5745044..20aadcf19ab4 100644 --- a/test/libyul/SyntaxTest.cpp +++ b/test/libyul/SyntaxTest.cpp @@ -61,7 +61,7 @@ void SyntaxTest::parseAndAnalyze() } m_errorList.emplace_back(SyntaxTestError{ - Error::formatErrorType(error->type()), + error->type(), error->errorId(), errorMessage(*error), name, From d4f55030c4c8b541a25bfb712c291512ae7cd2d2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Thu, 28 Sep 2023 18:30:26 +0200 Subject: [PATCH 3/4] CommonSyntaxTest: Fix info messages being colored as errors --- libsolutil/AnsiColorized.h | 1 + test/CommonSyntaxTest.cpp | 17 ++++++++++++++--- 2 files changed, 15 insertions(+), 3 deletions(-) diff --git a/libsolutil/AnsiColorized.h b/libsolutil/AnsiColorized.h index 69d10d727640..08b4a4d228ea 100644 --- a/libsolutil/AnsiColorized.h +++ b/libsolutil/AnsiColorized.h @@ -52,6 +52,7 @@ static constexpr char const* BLUE_BACKGROUND = "\033[44m"; static constexpr char const* MAGENTA_BACKGROUND = "\033[45m"; static constexpr char const* CYAN_BACKGROUND = "\033[46m"; static constexpr char const* WHITE_BACKGROUND = "\033[47m"; +static constexpr char const* GRAY_BACKGROUND = "\033[100m"; // 256-bit-colors (incomplete set) static constexpr char const* RED_BACKGROUND_256 = "\033[48;5;160m"; diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 78bb9493633c..93a8cef213a1 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -115,11 +115,18 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, { assert(static_cast(error.locationStart) <= source.length()); assert(static_cast(error.locationEnd) <= source.length()); - bool isWarning = (error.type == Error::Type::Warning); for (int i = error.locationStart; i < error.locationEnd; i++) - if (isWarning) + if (error.type == Error::Type::Info) { if (sourceFormatting[static_cast(i)] == util::formatting::RESET) + sourceFormatting[static_cast(i)] = util::formatting::GRAY_BACKGROUND; + } + else if (error.type == Error::Type::Warning) + { + if ( + sourceFormatting[static_cast(i)] == util::formatting::RESET || + sourceFormatting[static_cast(i)] == util::formatting::GRAY_BACKGROUND + ) sourceFormatting[static_cast(i)] = util::formatting::ORANGE_BACKGROUND_256; } else @@ -190,7 +197,11 @@ void CommonSyntaxTest::printErrorList( for (auto const& error: _errorList) { { - util::AnsiColorized scope(_stream, _formatted, {BOLD, (error.type == Error::Type::Warning) ? YELLOW : RED}); + util::AnsiColorized scope( + _stream, + _formatted, + {BOLD, error.type == Error::Type::Info ? WHITE : (error.type == Error::Type::Warning ? YELLOW : RED)} + ); _stream << _linePrefix << Error::formatErrorType(error.type); if (error.errorId.has_value()) _stream << ' ' << error.errorId->error; From 0da44caa06f005b688dcf4f01b962d5862b9805c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Kamil=20=C5=9Aliwak?= Date: Fri, 29 Sep 2023 22:43:49 +0200 Subject: [PATCH 4/4] Reuse color definitions between SourceReferenceFormatter and CommonSyntaxTest --- liblangutil/SourceReferenceFormatter.cpp | 35 ++++++++++++++++-------- liblangutil/SourceReferenceFormatter.h | 10 +++++++ test/CommonSyntaxTest.cpp | 33 +++++++++++----------- 3 files changed, 50 insertions(+), 28 deletions(-) diff --git a/liblangutil/SourceReferenceFormatter.cpp b/liblangutil/SourceReferenceFormatter.cpp index 4ce898b6f6bf..c48cb328d5f9 100644 --- a/liblangutil/SourceReferenceFormatter.cpp +++ b/liblangutil/SourceReferenceFormatter.cpp @@ -55,6 +55,28 @@ std::string SourceReferenceFormatter::formatErrorInformation(Error const& _error ); } +char const* SourceReferenceFormatter::errorTextColor(Error::Severity _severity) +{ + switch (_severity) + { + case Error::Severity::Error: return RED; + case Error::Severity::Warning: return YELLOW; + case Error::Severity::Info: return WHITE; + } + util::unreachable(); +} + +char const* SourceReferenceFormatter::errorHighlightColor(Error::Severity _severity) +{ + switch (_severity) + { + case Error::Severity::Error: return RED_BACKGROUND; + case Error::Severity::Warning: return ORANGE_BACKGROUND_256; + case Error::Severity::Info: return GRAY_BACKGROUND; + } + util::unreachable(); +} + AnsiColorized SourceReferenceFormatter::normalColored() const { return AnsiColorized(m_stream, m_colored, {WHITE}); @@ -67,18 +89,7 @@ AnsiColorized SourceReferenceFormatter::frameColored() const AnsiColorized SourceReferenceFormatter::errorColored(std::ostream& _stream, bool _colored, Error::Severity _severity) { - // We used to color messages of any severity as errors so this seems like a good default - // for cases where severity cannot be determined. - char const* textColor = RED; - - switch (_severity) - { - case Error::Severity::Error: textColor = RED; break; - case Error::Severity::Warning: textColor = YELLOW; break; - case Error::Severity::Info: textColor = WHITE; break; - } - - return AnsiColorized(_stream, _colored, {BOLD, textColor}); + return AnsiColorized(_stream, _colored, {BOLD, errorTextColor(_severity)}); } AnsiColorized SourceReferenceFormatter::messageColored(std::ostream& _stream, bool _colored) diff --git a/liblangutil/SourceReferenceFormatter.h b/liblangutil/SourceReferenceFormatter.h index 358a4738542c..7163199deea1 100644 --- a/liblangutil/SourceReferenceFormatter.h +++ b/liblangutil/SourceReferenceFormatter.h @@ -127,6 +127,16 @@ class SourceReferenceFormatter bool _withErrorIds = false ); + /// The default text color for printing error messages of a given severity in the terminal. + /// Assumes a dark background color. + static char const* errorTextColor(Error::Severity _severity); + + /// The default background color for highlighting source fragments corresponding to an error + /// of a given severity in the terminal. Assumes a light text color. + /// @note This is *not* meant to be used for the same text in combination with @a errorTextColor(). + /// It's an alternative way to highlight it, while preserving the original text color. + static char const* errorHighlightColor(Error::Severity _severity); + private: util::AnsiColorized normalColored() const; util::AnsiColorized frameColored() const; diff --git a/test/CommonSyntaxTest.cpp b/test/CommonSyntaxTest.cpp index 93a8cef213a1..0dedd1fb043b 100644 --- a/test/CommonSyntaxTest.cpp +++ b/test/CommonSyntaxTest.cpp @@ -19,12 +19,17 @@ #include #include #include + +#include + #include #include + #include #include #include #include + #include #include #include @@ -116,21 +121,17 @@ void CommonSyntaxTest::printSource(ostream& _stream, string const& _linePrefix, assert(static_cast(error.locationStart) <= source.length()); assert(static_cast(error.locationEnd) <= source.length()); for (int i = error.locationStart; i < error.locationEnd; i++) - if (error.type == Error::Type::Info) - { - if (sourceFormatting[static_cast(i)] == util::formatting::RESET) - sourceFormatting[static_cast(i)] = util::formatting::GRAY_BACKGROUND; - } - else if (error.type == Error::Type::Warning) - { - if ( - sourceFormatting[static_cast(i)] == util::formatting::RESET || - sourceFormatting[static_cast(i)] == util::formatting::GRAY_BACKGROUND - ) - sourceFormatting[static_cast(i)] = util::formatting::ORANGE_BACKGROUND_256; - } - else - sourceFormatting[static_cast(i)] = util::formatting::RED_BACKGROUND; + { + char const*& cellFormat = sourceFormatting[static_cast(i)]; + char const* infoBgColor = SourceReferenceFormatter::errorHighlightColor(Error::Severity::Info); + + if ( + (error.type != Error::Type::Warning && error.type != Error::Type::Info) || + (error.type == Error::Type::Warning && (cellFormat == RESET || cellFormat == infoBgColor)) || + (error.type == Error::Type::Info && cellFormat == RESET) + ) + cellFormat = SourceReferenceFormatter::errorHighlightColor(Error::errorSeverity(error.type)); + } } _stream << _linePrefix << sourceFormatting.front() << source.front(); @@ -200,7 +201,7 @@ void CommonSyntaxTest::printErrorList( util::AnsiColorized scope( _stream, _formatted, - {BOLD, error.type == Error::Type::Info ? WHITE : (error.type == Error::Type::Warning ? YELLOW : RED)} + {BOLD, SourceReferenceFormatter::errorTextColor(Error::errorSeverity(error.type))} ); _stream << _linePrefix << Error::formatErrorType(error.type); if (error.errorId.has_value())