mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #5511 from ethereum/cp-error-output
[solc] colorized diagnostics output
This commit is contained in:
commit
8992024302
@ -13,7 +13,8 @@ Language Features:
|
||||
|
||||
Compiler Features:
|
||||
* C API (``libsolc`` / raw ``soljson.js``): Introduce ``solidity_free`` method which releases all internal buffers to save memory.
|
||||
|
||||
* Commandline interface: Adds new option ``--new-reporter`` for improved diagnostics formatting
|
||||
along with ``--color`` and ``--no-color`` for colorized output to be forced (or explicitly disabled).
|
||||
|
||||
Bugfixes:
|
||||
|
||||
|
91
libdevcore/AnsiColorized.h
Normal file
91
libdevcore/AnsiColorized.h
Normal file
@ -0,0 +1,91 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <ostream>
|
||||
#include <vector>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
|
||||
namespace formatting
|
||||
{
|
||||
|
||||
// control codes
|
||||
static constexpr char const* RESET = "\033[0m";
|
||||
static constexpr char const* INVERSE = "\033[7m";
|
||||
static constexpr char const* BOLD = "\033[1m";
|
||||
static constexpr char const* BRIGHT = BOLD;
|
||||
|
||||
// standard foreground colors
|
||||
static constexpr char const* BLACK = "\033[30m";
|
||||
static constexpr char const* RED = "\033[31m";
|
||||
static constexpr char const* GREEN = "\033[32m";
|
||||
static constexpr char const* YELLOW = "\033[33m";
|
||||
static constexpr char const* BLUE = "\033[34m";
|
||||
static constexpr char const* MAGENTA = "\033[35m";
|
||||
static constexpr char const* CYAN = "\033[36m";
|
||||
static constexpr char const* WHITE = "\033[37m";
|
||||
|
||||
// standard background colors
|
||||
static constexpr char const* BLACK_BACKGROUND = "\033[40m";
|
||||
static constexpr char const* RED_BACKGROUND = "\033[41m";
|
||||
static constexpr char const* GREEN_BACKGROUND = "\033[42m";
|
||||
static constexpr char const* YELLOW_BACKGROUND = "\033[43m";
|
||||
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";
|
||||
|
||||
// 256-bit-colors (incomplete set)
|
||||
static constexpr char const* RED_BACKGROUND_256 = "\033[48;5;160m";
|
||||
static constexpr char const* ORANGE_BACKGROUND_256 = "\033[48;5;166m";
|
||||
|
||||
}
|
||||
|
||||
/// AnsiColorized provides a convenience helper to colorize ostream with formatting-reset assured.
|
||||
class AnsiColorized
|
||||
{
|
||||
public:
|
||||
AnsiColorized(std::ostream& _os, bool const _enabled, std::vector<char const*>&& _formatting):
|
||||
m_stream{_os}, m_enabled{_enabled}, m_codes{std::move(_formatting)}
|
||||
{
|
||||
if (m_enabled)
|
||||
for (auto const& code: m_codes)
|
||||
m_stream << code;
|
||||
}
|
||||
|
||||
~AnsiColorized()
|
||||
{
|
||||
if (m_enabled)
|
||||
m_stream << formatting::RESET;
|
||||
}
|
||||
|
||||
template <typename T>
|
||||
std::ostream& operator<<(T&& _t)
|
||||
{
|
||||
return m_stream << std::forward<T>(_t);
|
||||
}
|
||||
|
||||
private:
|
||||
std::ostream& m_stream;
|
||||
bool m_enabled;
|
||||
std::vector<char const*> m_codes;
|
||||
};
|
||||
|
||||
}
|
@ -1,5 +1,6 @@
|
||||
set(sources
|
||||
Algorithms.h
|
||||
AnsiColorized.h
|
||||
Assertions.h
|
||||
Common.h
|
||||
CommonData.cpp
|
||||
|
@ -16,6 +16,8 @@ set(sources
|
||||
SourceReferenceExtractor.h
|
||||
SourceReferenceFormatter.cpp
|
||||
SourceReferenceFormatter.h
|
||||
SourceReferenceFormatterHuman.cpp
|
||||
SourceReferenceFormatterHuman.h
|
||||
Token.cpp
|
||||
Token.h
|
||||
UndefMacros.h
|
||||
|
@ -44,11 +44,14 @@ public:
|
||||
m_stream(_stream)
|
||||
{}
|
||||
|
||||
virtual ~SourceReferenceFormatter() = default;
|
||||
|
||||
/// Prints source location if it is given.
|
||||
void printSourceLocation(SourceLocation const* _location);
|
||||
void printSourceLocation(SourceReference const& _ref);
|
||||
void printExceptionInformation(dev::Exception const& _error, std::string const& _category);
|
||||
void printExceptionInformation(SourceReferenceExtractor::Message const& _msg);
|
||||
virtual void printSourceLocation(SourceReference const& _ref);
|
||||
virtual void printExceptionInformation(SourceReferenceExtractor::Message const& _msg);
|
||||
|
||||
virtual void printSourceLocation(SourceLocation const* _location);
|
||||
virtual void printExceptionInformation(dev::Exception const& _error, std::string const& _category);
|
||||
|
||||
static std::string formatExceptionInformation(
|
||||
dev::Exception const& _exception,
|
||||
@ -62,7 +65,7 @@ public:
|
||||
return errorOutput.str();
|
||||
}
|
||||
|
||||
private:
|
||||
protected:
|
||||
/// Prints source name if location is given.
|
||||
void printSourceName(SourceReference const& _ref);
|
||||
|
||||
|
136
liblangutil/SourceReferenceFormatterHuman.cpp
Normal file
136
liblangutil/SourceReferenceFormatterHuman.cpp
Normal file
@ -0,0 +1,136 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Formatting functions for errors referencing positions and locations in the source.
|
||||
*/
|
||||
|
||||
#include <liblangutil/SourceReferenceFormatterHuman.h>
|
||||
#include <liblangutil/Scanner.h>
|
||||
#include <liblangutil/Exceptions.h>
|
||||
#include <cmath>
|
||||
#include <iomanip>
|
||||
|
||||
using namespace std;
|
||||
using namespace dev;
|
||||
using namespace dev::formatting;
|
||||
using namespace langutil;
|
||||
|
||||
AnsiColorized SourceReferenceFormatterHuman::normalColored() const
|
||||
{
|
||||
return AnsiColorized(m_stream, m_colored, {WHITE});
|
||||
}
|
||||
|
||||
AnsiColorized SourceReferenceFormatterHuman::frameColored() const
|
||||
{
|
||||
return AnsiColorized(m_stream, m_colored, {BOLD, BLUE});
|
||||
}
|
||||
|
||||
AnsiColorized SourceReferenceFormatterHuman::errorColored() const
|
||||
{
|
||||
return AnsiColorized(m_stream, m_colored, {BOLD, RED});
|
||||
}
|
||||
|
||||
AnsiColorized SourceReferenceFormatterHuman::messageColored() const
|
||||
{
|
||||
return AnsiColorized(m_stream, m_colored, {BOLD, WHITE});
|
||||
}
|
||||
|
||||
AnsiColorized SourceReferenceFormatterHuman::secondaryColored() const
|
||||
{
|
||||
return AnsiColorized(m_stream, m_colored, {BOLD, CYAN});
|
||||
}
|
||||
|
||||
AnsiColorized SourceReferenceFormatterHuman::highlightColored() const
|
||||
{
|
||||
return AnsiColorized(m_stream, m_colored, {YELLOW});
|
||||
}
|
||||
|
||||
AnsiColorized SourceReferenceFormatterHuman::diagColored() const
|
||||
{
|
||||
return AnsiColorized(m_stream, m_colored, {BOLD, YELLOW});
|
||||
}
|
||||
|
||||
void SourceReferenceFormatterHuman::printSourceLocation(SourceReference const& _ref)
|
||||
{
|
||||
if (_ref.position.line < 0)
|
||||
return; // Nothing we can print here
|
||||
|
||||
int const leftpad = static_cast<int>(log10(max(_ref.position.line, 1))) + 1;
|
||||
|
||||
// line 0: source name
|
||||
frameColored() << string(leftpad, ' ') << "--> ";
|
||||
m_stream << _ref.sourceName << ":" << (_ref.position.line + 1) << ":" << (_ref.position.column + 1) << ": " << '\n';
|
||||
|
||||
if (!_ref.multiline)
|
||||
{
|
||||
int const locationLength = _ref.endColumn - _ref.startColumn;
|
||||
|
||||
// line 1:
|
||||
m_stream << string(leftpad, ' ');
|
||||
frameColored() << " |" << '\n';
|
||||
|
||||
// line 2:
|
||||
frameColored() << (_ref.position.line + 1) << " | ";
|
||||
m_stream << _ref.text.substr(0, _ref.startColumn);
|
||||
highlightColored() << _ref.text.substr(_ref.startColumn, locationLength);
|
||||
m_stream << _ref.text.substr(_ref.endColumn) << '\n';
|
||||
|
||||
// line 3:
|
||||
m_stream << string(leftpad, ' ');
|
||||
frameColored() << " | ";
|
||||
for_each(
|
||||
_ref.text.cbegin(),
|
||||
_ref.text.cbegin() + _ref.startColumn,
|
||||
[this](char ch) { m_stream << (ch == '\t' ? '\t' : ' '); }
|
||||
);
|
||||
diagColored() << string(locationLength, '^') << '\n';
|
||||
}
|
||||
else
|
||||
{
|
||||
// line 1:
|
||||
m_stream << string(leftpad, ' ');
|
||||
frameColored() << " |" << '\n';
|
||||
|
||||
// line 2:
|
||||
frameColored() << (_ref.position.line + 1) << " | ";
|
||||
m_stream << _ref.text.substr(0, _ref.startColumn);
|
||||
highlightColored() << _ref.text.substr(_ref.startColumn) << '\n';
|
||||
|
||||
// line 3:
|
||||
frameColored() << string(leftpad, ' ') << " | ";
|
||||
m_stream << string(_ref.startColumn, ' ');
|
||||
diagColored() << "^ (Relevant source part starts here and spans across multiple lines).\n";
|
||||
}
|
||||
}
|
||||
|
||||
void SourceReferenceFormatterHuman::printExceptionInformation(SourceReferenceExtractor::Message const& _msg)
|
||||
{
|
||||
// exception header line
|
||||
errorColored() << _msg.category;
|
||||
messageColored() << ": " << _msg.primary.message << '\n';
|
||||
|
||||
printSourceLocation(_msg.primary);
|
||||
|
||||
for (auto const& secondary: _msg.secondary)
|
||||
{
|
||||
secondaryColored() << "Note";
|
||||
messageColored() << ": " << secondary.message << '\n';
|
||||
printSourceLocation(secondary);
|
||||
}
|
||||
|
||||
m_stream << '\n';
|
||||
}
|
80
liblangutil/SourceReferenceFormatterHuman.h
Normal file
80
liblangutil/SourceReferenceFormatterHuman.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
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/>.
|
||||
*/
|
||||
/**
|
||||
* Formatting functions for errors referencing positions and locations in the source.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <liblangutil/SourceReferenceExtractor.h>
|
||||
#include <liblangutil/SourceReferenceFormatter.h> // SourceReferenceFormatterBase
|
||||
|
||||
#include <libdevcore/AnsiColorized.h>
|
||||
|
||||
#include <ostream>
|
||||
#include <sstream>
|
||||
#include <functional>
|
||||
|
||||
namespace dev
|
||||
{
|
||||
struct Exception; // forward
|
||||
}
|
||||
|
||||
namespace langutil
|
||||
{
|
||||
|
||||
struct SourceLocation;
|
||||
struct SourceReference;
|
||||
|
||||
class SourceReferenceFormatterHuman: public SourceReferenceFormatter
|
||||
{
|
||||
public:
|
||||
SourceReferenceFormatterHuman(std::ostream& _stream, bool colored):
|
||||
SourceReferenceFormatter{_stream}, m_colored{colored}
|
||||
{}
|
||||
|
||||
void printSourceLocation(SourceReference const& _ref) override;
|
||||
void printExceptionInformation(SourceReferenceExtractor::Message const& _msg) override;
|
||||
using SourceReferenceFormatter::printExceptionInformation;
|
||||
|
||||
static std::string formatExceptionInformation(
|
||||
dev::Exception const& _exception,
|
||||
std::string const& _name,
|
||||
bool colored = false
|
||||
)
|
||||
{
|
||||
std::ostringstream errorOutput;
|
||||
|
||||
SourceReferenceFormatterHuman formatter(errorOutput, colored);
|
||||
formatter.printExceptionInformation(_exception, _name);
|
||||
return errorOutput.str();
|
||||
}
|
||||
|
||||
private:
|
||||
dev::AnsiColorized normalColored() const;
|
||||
dev::AnsiColorized frameColored() const;
|
||||
dev::AnsiColorized errorColored() const;
|
||||
dev::AnsiColorized messageColored() const;
|
||||
dev::AnsiColorized secondaryColored() const;
|
||||
dev::AnsiColorized highlightColored() const;
|
||||
dev::AnsiColorized diagColored() const;
|
||||
|
||||
private:
|
||||
bool m_colored;
|
||||
};
|
||||
|
||||
}
|
@ -35,6 +35,7 @@
|
||||
#include <libsolidity/interface/CompilerStack.h>
|
||||
#include <libsolidity/interface/StandardCompiler.h>
|
||||
#include <liblangutil/SourceReferenceFormatter.h>
|
||||
#include <liblangutil/SourceReferenceFormatterHuman.h>
|
||||
#include <libsolidity/interface/GasEstimator.h>
|
||||
#include <libsolidity/interface/AssemblyStack.h>
|
||||
|
||||
@ -46,6 +47,8 @@
|
||||
#include <libdevcore/CommonIO.h>
|
||||
#include <libdevcore/JSON.h>
|
||||
|
||||
#include <memory>
|
||||
|
||||
#include <boost/filesystem.hpp>
|
||||
#include <boost/filesystem/operations.hpp>
|
||||
#include <boost/algorithm/string.hpp>
|
||||
@ -134,6 +137,9 @@ static string const g_strStrictAssembly = "strict-assembly";
|
||||
static string const g_strPrettyJson = "pretty-json";
|
||||
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_strNewReporter = "new-reporter";
|
||||
|
||||
static string const g_argAbi = g_strAbi;
|
||||
static string const g_argPrettyJson = g_strPrettyJson;
|
||||
@ -169,6 +175,9 @@ static string const g_argStrictAssembly = g_strStrictAssembly;
|
||||
static string const g_argVersion = g_strVersion;
|
||||
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_argNewReporter = g_strNewReporter;
|
||||
|
||||
/// Possible arguments to for --combined-json
|
||||
static set<string> const g_combinedJsonArgs
|
||||
@ -652,6 +661,9 @@ Allowed options)",
|
||||
po::value<string>()->value_name("path(s)"),
|
||||
"Allow a given path for imports. A list of paths can be supplied by separating them with a comma."
|
||||
)
|
||||
(g_argColor.c_str(), "Force colored output.")
|
||||
(g_argNoColor.c_str(), "Explicitly disable colored output, disabling terminal auto-detection.")
|
||||
(g_argNewReporter.c_str(), "Enables new diagnostics reporter.")
|
||||
(g_argIgnoreMissingFiles.c_str(), "Ignore missing files.");
|
||||
po::options_description outputComponents("Output Components");
|
||||
outputComponents.add_options()
|
||||
@ -691,6 +703,14 @@ Allowed options)",
|
||||
return false;
|
||||
}
|
||||
|
||||
if (m_args.count(g_argColor) && m_args.count(g_argNoColor))
|
||||
{
|
||||
serr() << "Option " << g_argColor << " and " << g_argNoColor << " are mutualy exclusive." << endl;
|
||||
return false;
|
||||
}
|
||||
|
||||
m_coloredOutput = !m_args.count(g_argNoColor) && (isatty(STDERR_FILENO) || m_args.count(g_argColor));
|
||||
|
||||
if (m_args.count(g_argHelp) || (isatty(fileno(stdin)) && _argc == 1))
|
||||
{
|
||||
sout() << desc;
|
||||
@ -858,7 +878,11 @@ bool CommandLineInterface::processInput()
|
||||
|
||||
m_compiler.reset(new CompilerStack(fileReader));
|
||||
|
||||
SourceReferenceFormatter formatter(serr(false));
|
||||
unique_ptr<SourceReferenceFormatter> formatter;
|
||||
if (m_args.count(g_argNewReporter))
|
||||
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput);
|
||||
else
|
||||
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
||||
|
||||
try
|
||||
{
|
||||
@ -881,7 +905,7 @@ bool CommandLineInterface::processInput()
|
||||
for (auto const& error: m_compiler->errors())
|
||||
{
|
||||
g_hasOutput = true;
|
||||
formatter.printExceptionInformation(
|
||||
formatter->printExceptionInformation(
|
||||
*error,
|
||||
(error->type() == Error::Type::Warning) ? "Warning" : "Error"
|
||||
);
|
||||
@ -893,7 +917,7 @@ bool CommandLineInterface::processInput()
|
||||
catch (CompilerError const& _exception)
|
||||
{
|
||||
g_hasOutput = true;
|
||||
formatter.printExceptionInformation(_exception, "Compiler error");
|
||||
formatter->printExceptionInformation(_exception, "Compiler error");
|
||||
return false;
|
||||
}
|
||||
catch (InternalCompilerError const& _exception)
|
||||
@ -915,7 +939,7 @@ bool CommandLineInterface::processInput()
|
||||
else
|
||||
{
|
||||
g_hasOutput = true;
|
||||
formatter.printExceptionInformation(_error, _error.typeName());
|
||||
formatter->printExceptionInformation(_error, _error.typeName());
|
||||
}
|
||||
|
||||
return false;
|
||||
@ -1221,12 +1245,16 @@ bool CommandLineInterface::assemble(
|
||||
for (auto const& sourceAndStack: assemblyStacks)
|
||||
{
|
||||
auto const& stack = sourceAndStack.second;
|
||||
SourceReferenceFormatter formatter(serr(false));
|
||||
unique_ptr<SourceReferenceFormatter> formatter;
|
||||
if (m_args.count(g_argNewReporter))
|
||||
formatter = make_unique<SourceReferenceFormatterHuman>(serr(false), m_coloredOutput);
|
||||
else
|
||||
formatter = make_unique<SourceReferenceFormatter>(serr(false));
|
||||
|
||||
for (auto const& error: stack.errors())
|
||||
{
|
||||
g_hasOutput = true;
|
||||
formatter.printExceptionInformation(
|
||||
formatter->printExceptionInformation(
|
||||
*error,
|
||||
(error->type() == Error::Type::Warning) ? "Warning" : "Error"
|
||||
);
|
||||
|
@ -109,6 +109,8 @@ private:
|
||||
std::unique_ptr<dev::solidity::CompilerStack> m_compiler;
|
||||
/// EVM version to use
|
||||
EVMVersion m_evmVersion;
|
||||
/// Whether or not to colorize diagnostics output.
|
||||
bool m_coloredOutput = true;
|
||||
};
|
||||
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user