Cleaning up helpers around errors

This commit is contained in:
nishant-sachdeva 2022-06-17 08:55:52 +05:30
parent 1fbee8259a
commit c8011d8719
21 changed files with 271 additions and 231 deletions

View File

@ -39,34 +39,6 @@ Error::Error(
m_errorId(_errorId), m_errorId(_errorId),
m_type(_type) m_type(_type)
{ {
switch (m_type)
{
case Type::CodeGenerationError:
m_typeName = "CodeGenerationError";
break;
case Type::DeclarationError:
m_typeName = "DeclarationError";
break;
case Type::DocstringParsingError:
m_typeName = "DocstringParsingError";
break;
case Type::Info:
m_typeName = "Info";
break;
case Type::ParserError:
m_typeName = "ParserError";
break;
case Type::SyntaxError:
m_typeName = "SyntaxError";
break;
case Type::TypeError:
m_typeName = "TypeError";
break;
case Type::Warning:
m_typeName = "Warning";
break;
}
if (_location.isValid()) if (_location.isValid())
*this << errinfo_sourceLocation(_location); *this << errinfo_sourceLocation(_location);
if (!_secondaryLocation.infos.empty()) if (!_secondaryLocation.infos.empty())
@ -84,15 +56,3 @@ SecondarySourceLocation const* Error::secondarySourceLocation() const noexcept
{ {
return boost::get_error_info<errinfo_secondarySourceLocation>(*this); return boost::get_error_info<errinfo_secondarySourceLocation>(*this);
} }
optional<Error::Severity> Error::severityFromString(string _input)
{
boost::algorithm::to_lower(_input);
boost::algorithm::trim(_input);
for (Severity severity: {Severity::Error, Severity::Warning, Severity::Info})
if (_input == formatErrorSeverityLowercase(severity))
return severity;
return nullopt;
}

View File

@ -31,6 +31,7 @@
#include <boost/preprocessor/cat.hpp> #include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/facilities/empty.hpp> #include <boost/preprocessor/facilities/empty.hpp>
#include <boost/preprocessor/facilities/overload.hpp> #include <boost/preprocessor/facilities/overload.hpp>
#include <boost/algorithm/string/case_conv.hpp>
#include <string> #include <string>
#include <utility> #include <utility>
@ -174,6 +175,15 @@ public:
ParserError, ParserError,
TypeError, TypeError,
SyntaxError, SyntaxError,
IOError,
FatalError,
JSONError,
InternalCompilerError,
CompilerError,
Exception,
UnimplementedFeatureError,
YulException,
SMTLogicException,
Warning, Warning,
Info Info
}; };
@ -195,7 +205,6 @@ public:
ErrorId errorId() const { return m_errorId; } ErrorId errorId() const { return m_errorId; }
Type type() const { return m_type; } Type type() const { return m_type; }
std::string const& typeName() const { return m_typeName; }
SourceLocation const* sourceLocation() const noexcept; SourceLocation const* sourceLocation() const noexcept;
SecondarySourceLocation const* secondarySourceLocation() const noexcept; SecondarySourceLocation const* secondarySourceLocation() const noexcept;
@ -211,11 +220,12 @@ public:
static constexpr Severity errorSeverity(Type _type) static constexpr Severity errorSeverity(Type _type)
{ {
if (_type == Type::Info) switch (_type)
return Severity::Info; {
if (_type == Type::Warning) case Type::Info: return Severity::Info;
return Severity::Warning; case Type::Warning: return Severity::Warning;
return Severity::Error; default: return Severity::Error;
}
} }
static bool isError(Severity _severity) static bool isError(Severity _severity)
@ -238,35 +248,50 @@ public:
static std::string formatErrorSeverity(Severity _severity) static std::string formatErrorSeverity(Severity _severity)
{ {
if (_severity == Severity::Info) switch (_severity)
return "Info"; {
if (_severity == Severity::Warning) case Severity::Info: return "Info";
return "Warning"; case Severity::Warning: return "Warning";
solAssert(isError(_severity), ""); case Severity::Error: return "Error";
return "Error"; }
util::unreachable();
}
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();
} }
static std::string formatErrorSeverityLowercase(Severity _severity) static std::string formatErrorSeverityLowercase(Severity _severity)
{ {
switch (_severity) std::string severityValue = formatErrorSeverity(_severity);
{ boost::algorithm::to_lower(severityValue);
case Severity::Info: return severityValue;
return "info";
case Severity::Warning:
return "warning";
case Severity::Error:
solAssert(isError(_severity), "");
return "error";
} }
solAssert(false, "");
}
static std::optional<Severity> severityFromString(std::string _input);
private: private:
ErrorId m_errorId; ErrorId m_errorId;
Type m_type; Type m_type;
std::string m_typeName;
}; };
} }

View File

@ -30,7 +30,7 @@ using namespace solidity::langutil;
SourceReferenceExtractor::Message SourceReferenceExtractor::extract( SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
CharStreamProvider const& _charStreamProvider, CharStreamProvider const& _charStreamProvider,
util::Exception const& _exception, util::Exception const& _exception,
string _severity Error::Type _type
) )
{ {
SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception); SourceLocation const* location = boost::get_error_info<errinfo_sourceLocation>(_exception);
@ -44,7 +44,7 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
for (auto const& info: secondaryLocation->infos) for (auto const& info: secondaryLocation->infos)
secondary.emplace_back(extract(_charStreamProvider, &info.second, info.first)); secondary.emplace_back(extract(_charStreamProvider, &info.second, info.first));
return Message{std::move(primary), _severity, std::move(secondary), nullopt}; return Message{std::move(primary), _type, std::move(secondary), nullopt};
} }
SourceReferenceExtractor::Message SourceReferenceExtractor::extract( SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
@ -52,8 +52,7 @@ SourceReferenceExtractor::Message SourceReferenceExtractor::extract(
Error const& _error Error const& _error
) )
{ {
string severity = Error::formatErrorSeverity(Error::errorSeverity(_error.type())); Message message = extract(_charStreamProvider, _error, _error.type());
Message message = extract(_charStreamProvider, _error, severity);
message.errorId = _error.errorId(); message.errorId = _error.errorId();
return message; return message;
} }

View File

@ -55,12 +55,12 @@ namespace SourceReferenceExtractor
struct Message struct Message
{ {
SourceReference primary; SourceReference primary;
std::string severity; // "Error", "Warning", "Info", ... Error::Type type;
std::vector<SourceReference> secondary; std::vector<SourceReference> secondary;
std::optional<ErrorId> errorId; std::optional<ErrorId> errorId;
}; };
Message extract(CharStreamProvider const& _charStreamProvider, util::Exception const& _exception, std::string _severity); Message extract(CharStreamProvider const& _charStreamProvider, util::Exception const& _exception, Error::Type _type);
Message extract(CharStreamProvider const& _charStreamProvider, Error const& _error); Message extract(CharStreamProvider const& _charStreamProvider, Error const& _error);
SourceReference extract(CharStreamProvider const& _charStreamProvider, SourceLocation const* _location, std::string message = ""); SourceReference extract(CharStreamProvider const& _charStreamProvider, SourceLocation const* _location, std::string message = "");
} }

View File

@ -65,14 +65,13 @@ AnsiColorized SourceReferenceFormatter::frameColored() const
return AnsiColorized(m_stream, m_colored, {BOLD, BLUE}); return AnsiColorized(m_stream, m_colored, {BOLD, BLUE});
} }
AnsiColorized SourceReferenceFormatter::errorColored(optional<Error::Severity> _severity) const AnsiColorized SourceReferenceFormatter::errorColored(Error::Severity _severity) const
{ {
// We used to color messages of any severity as errors so this seems like a good default // We used to color messages of any severity as errors so this seems like a good default
// for cases where severity cannot be determined. // for cases where severity cannot be determined.
char const* textColor = RED; char const* textColor = RED;
if (_severity.has_value()) switch (_severity)
switch (_severity.value())
{ {
case Error::Severity::Error: textColor = RED; break; case Error::Severity::Error: textColor = RED; break;
case Error::Severity::Warning: textColor = YELLOW; break; case Error::Severity::Warning: textColor = YELLOW; break;
@ -176,15 +175,18 @@ void SourceReferenceFormatter::printSourceLocation(SourceReference const& _ref)
} }
} }
void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg) void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtractor::Message const& _msg, bool _printFullType)
{ {
// exception header line errorColored(Error::errorSeverity(_msg.type)) << (
optional<Error::Severity> severity = Error::severityFromString(_msg.severity); _printFullType ?
errorColored(severity) << _msg.severity; Error::formatErrorType(_msg.type) :
if (m_withErrorIds && _msg.errorId.has_value()) Error::formatErrorSeverity(Error::errorSeverity(_msg.type))
errorColored(severity) << " (" << _msg.errorId.value().error << ")"; );
messageColored() << ": " << _msg.primary.message << '\n';
if (m_withErrorIds && _msg.errorId.has_value())
errorColored(Error::errorSeverity(_msg.type)) << " (" << _msg.errorId.value().error << ")";
messageColored() << ": " << _msg.primary.message << '\n';
printSourceLocation(_msg.primary); printSourceLocation(_msg.primary);
for (auto const& secondary: _msg.secondary) for (auto const& secondary: _msg.secondary)
@ -197,9 +199,9 @@ void SourceReferenceFormatter::printExceptionInformation(SourceReferenceExtracto
m_stream << '\n'; m_stream << '\n';
} }
void SourceReferenceFormatter::printExceptionInformation(util::Exception const& _exception, std::string const& _severity) void SourceReferenceFormatter::printExceptionInformation(util::Exception const& _exception, Error::Type _type, bool _printFullType)
{ {
printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _exception, _severity)); printExceptionInformation(SourceReferenceExtractor::extract(m_charStreamProvider, _exception, _type), _printFullType);
} }
void SourceReferenceFormatter::printErrorInformation(ErrorList const& _errors) void SourceReferenceFormatter::printErrorInformation(ErrorList const& _errors)

View File

@ -51,22 +51,23 @@ public:
/// Prints source location if it is given. /// Prints source location if it is given.
void printSourceLocation(SourceReference const& _ref); void printSourceLocation(SourceReference const& _ref);
void printExceptionInformation(SourceReferenceExtractor::Message const& _msg); void printExceptionInformation(SourceReferenceExtractor::Message const& _msg, bool _printFullType=false);
void printExceptionInformation(util::Exception const& _exception, std::string const& _severity); void printExceptionInformation(util::Exception const& _exception, Error::Type _type, bool _printFullType=false);
void printErrorInformation(langutil::ErrorList const& _errors); void printErrorInformation(langutil::ErrorList const& _errors);
void printErrorInformation(Error const& _error); void printErrorInformation(Error const& _error);
static std::string formatExceptionInformation( static std::string formatExceptionInformation(
util::Exception const& _exception, util::Exception const& _exception,
std::string const& _name, Error::Type _type,
CharStreamProvider const& _charStreamProvider, CharStreamProvider const& _charStreamProvider,
bool _colored = false, bool _colored = false,
bool _withErrorIds = false bool _withErrorIds = false,
bool _printFullType = false
) )
{ {
std::ostringstream errorOutput; std::ostringstream errorOutput;
SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, _withErrorIds); SourceReferenceFormatter formatter(errorOutput, _charStreamProvider, _colored, _withErrorIds);
formatter.printExceptionInformation(_exception, _name); formatter.printExceptionInformation(_exception, _type, _printFullType);
return errorOutput.str(); return errorOutput.str();
} }
@ -77,7 +78,7 @@ public:
{ {
return formatExceptionInformation( return formatExceptionInformation(
_error, _error,
Error::formatErrorSeverity(Error::errorSeverity(_error.type())), _error.type(),
_charStreamProvider _charStreamProvider
); );
} }
@ -87,7 +88,7 @@ public:
private: private:
util::AnsiColorized normalColored() const; util::AnsiColorized normalColored() const;
util::AnsiColorized frameColored() const; util::AnsiColorized frameColored() const;
util::AnsiColorized errorColored(std::optional<langutil::Error::Severity> _severity) const; util::AnsiColorized errorColored(langutil::Error::Severity _severity) const;
util::AnsiColorized messageColored() const; util::AnsiColorized messageColored() const;
util::AnsiColorized secondaryColored() const; util::AnsiColorized secondaryColored() const;
util::AnsiColorized highlightColored() const; util::AnsiColorized highlightColored() const;

View File

@ -54,8 +54,7 @@ namespace
{ {
Json::Value formatError( Json::Value formatError(
Error::Severity _severity, Error::Type _type,
string const& _type,
string const& _component, string const& _component,
string const& _message, string const& _message,
string const& _formattedMessage = "", string const& _formattedMessage = "",
@ -64,9 +63,9 @@ Json::Value formatError(
) )
{ {
Json::Value error{Json::objectValue}; Json::Value error{Json::objectValue};
error["type"] = _type; error["type"] = Error::formatErrorType(_type);
error["component"] = _component; error["component"] = _component;
error["severity"] = Error::formatErrorSeverityLowercase(_severity); error["severity"] = Error::formatErrorSeverityLowercase(Error::errorSeverity(_type));
error["message"] = _message; error["message"] = _message;
error["formattedMessage"] = (_formattedMessage.length() > 0) ? _formattedMessage : _message; error["formattedMessage"] = (_formattedMessage.length() > 0) ? _formattedMessage : _message;
if (_sourceLocation.isObject()) if (_sourceLocation.isObject())
@ -76,11 +75,11 @@ Json::Value formatError(
return error; return error;
} }
Json::Value formatFatalError(string const& _type, string const& _message) Json::Value formatFatalError(Error::Type _type, string const& _message)
{ {
Json::Value output{Json::objectValue}; Json::Value output{Json::objectValue};
output["errors"] = Json::arrayValue; output["errors"] = Json::arrayValue;
output["errors"].append(formatError(Error::Severity::Error, _type, "general", _message)); output["errors"].append(formatError(_type, "general", _message));
return output; return output;
} }
@ -114,8 +113,7 @@ Json::Value formatSecondarySourceLocation(SecondarySourceLocation const* _second
Json::Value formatErrorWithException( Json::Value formatErrorWithException(
CharStreamProvider const& _charStreamProvider, CharStreamProvider const& _charStreamProvider,
util::Exception const& _exception, util::Exception const& _exception,
Error::Severity _severity, Error::Type _type,
string const& _type,
string const& _component, string const& _component,
string const& _message, string const& _message,
optional<ErrorId> _errorId = nullopt optional<ErrorId> _errorId = nullopt
@ -126,7 +124,10 @@ Json::Value formatErrorWithException(
string formattedMessage = SourceReferenceFormatter::formatExceptionInformation( string formattedMessage = SourceReferenceFormatter::formatExceptionInformation(
_exception, _exception,
_type, _type,
_charStreamProvider _charStreamProvider,
false, // colored
false, // _withErrorIds
true // _printFullType
); );
if (string const* description = _exception.comment()) if (string const* description = _exception.comment())
@ -135,7 +136,6 @@ Json::Value formatErrorWithException(
message = _message; message = _message;
Json::Value error = formatError( Json::Value error = formatError(
_severity,
_type, _type,
_component, _component,
message, message,
@ -410,11 +410,11 @@ Json::Value collectEVMObject(
std::optional<Json::Value> checkKeys(Json::Value const& _input, set<string> const& _keys, string const& _name) std::optional<Json::Value> checkKeys(Json::Value const& _input, set<string> const& _keys, string const& _name)
{ {
if (!!_input && !_input.isObject()) if (!!_input && !_input.isObject())
return formatFatalError("JSONError", "\"" + _name + "\" must be an object"); return formatFatalError(Error::Type::JSONError, "\"" + _name + "\" must be an object");
for (auto const& member: _input.getMemberNames()) for (auto const& member: _input.getMemberNames())
if (!_keys.count(member)) if (!_keys.count(member))
return formatFatalError("JSONError", "Unknown key \"" + member + "\""); return formatFatalError(Error::Type::JSONError, "Unknown key \"" + member + "\"");
return std::nullopt; return std::nullopt;
} }
@ -466,7 +466,7 @@ std::optional<Json::Value> checkOptimizerDetail(Json::Value const& _details, std
if (_details.isMember(_name)) if (_details.isMember(_name))
{ {
if (!_details[_name].isBool()) if (!_details[_name].isBool())
return formatFatalError("JSONError", "\"settings.optimizer.details." + _name + "\" must be Boolean"); return formatFatalError(Error::Type::JSONError, "\"settings.optimizer.details." + _name + "\" must be Boolean");
_setting = _details[_name].asBool(); _setting = _details[_name].asBool();
} }
return {}; return {};
@ -485,7 +485,7 @@ std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details
catch (yul::OptimizerException const& _exception) catch (yul::OptimizerException const& _exception)
{ {
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"Invalid optimizer step sequence in \"settings.optimizer.details." + _name + "\": " + _exception.what() "Invalid optimizer step sequence in \"settings.optimizer.details." + _name + "\": " + _exception.what()
); );
} }
@ -500,7 +500,7 @@ std::optional<Json::Value> checkOptimizerDetailSteps(Json::Value const& _details
solAssert(_cleanupSetting == OptimiserSettings::DefaultYulOptimiserCleanupSteps); solAssert(_cleanupSetting == OptimiserSettings::DefaultYulOptimiserCleanupSteps);
} }
else else
return formatFatalError("JSONError", "\"settings.optimizer.details." + _name + "\" must be a string"); return formatFatalError(Error::Type::JSONError, "\"settings.optimizer.details." + _name + "\" must be a string");
} }
return {}; return {};
@ -511,11 +511,11 @@ std::optional<Json::Value> checkMetadataKeys(Json::Value const& _input)
if (_input.isObject()) if (_input.isObject())
{ {
if (_input.isMember("useLiteralContent") && !_input["useLiteralContent"].isBool()) if (_input.isMember("useLiteralContent") && !_input["useLiteralContent"].isBool())
return formatFatalError("JSONError", "\"settings.metadata.useLiteralContent\" must be Boolean"); return formatFatalError(Error::Type::JSONError, "\"settings.metadata.useLiteralContent\" must be Boolean");
static set<string> hashes{"ipfs", "bzzr1", "none"}; static set<string> hashes{"ipfs", "bzzr1", "none"};
if (_input.isMember("bytecodeHash") && !hashes.count(_input["bytecodeHash"].asString())) if (_input.isMember("bytecodeHash") && !hashes.count(_input["bytecodeHash"].asString()))
return formatFatalError("JSONError", "\"settings.metadata.bytecodeHash\" must be \"ipfs\", \"bzzr1\" or \"none\""); return formatFatalError(Error::Type::JSONError, "\"settings.metadata.bytecodeHash\" must be \"ipfs\", \"bzzr1\" or \"none\"");
} }
static set<string> keys{"useLiteralContent", "bytecodeHash"}; static set<string> keys{"useLiteralContent", "bytecodeHash"};
return checkKeys(_input, keys, "settings.metadata"); return checkKeys(_input, keys, "settings.metadata");
@ -524,7 +524,7 @@ std::optional<Json::Value> checkMetadataKeys(Json::Value const& _input)
std::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelection) std::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelection)
{ {
if (!!_outputSelection && !_outputSelection.isObject()) if (!!_outputSelection && !_outputSelection.isObject())
return formatFatalError("JSONError", "\"settings.outputSelection\" must be an object"); return formatFatalError(Error::Type::JSONError, "\"settings.outputSelection\" must be an object");
for (auto const& sourceName: _outputSelection.getMemberNames()) for (auto const& sourceName: _outputSelection.getMemberNames())
{ {
@ -532,7 +532,7 @@ std::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelect
if (!sourceVal.isObject()) if (!sourceVal.isObject())
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"\"settings.outputSelection." + sourceName + "\" must be an object" "\"settings.outputSelection." + sourceName + "\" must be an object"
); );
@ -542,7 +542,7 @@ std::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelect
if (!contractVal.isArray()) if (!contractVal.isArray())
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"\"settings.outputSelection." + "\"settings.outputSelection." +
sourceName + sourceName +
"." + "." +
@ -553,7 +553,7 @@ std::optional<Json::Value> checkOutputSelection(Json::Value const& _outputSelect
for (auto const& output: contractVal) for (auto const& output: contractVal)
if (!output.isString()) if (!output.isString())
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"\"settings.outputSelection." + "\"settings.outputSelection." +
sourceName + sourceName +
"." + "." +
@ -578,7 +578,7 @@ std::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Value
if (_jsonInput.isMember("enabled")) if (_jsonInput.isMember("enabled"))
{ {
if (!_jsonInput["enabled"].isBool()) if (!_jsonInput["enabled"].isBool())
return formatFatalError("JSONError", "The \"enabled\" setting must be a Boolean."); return formatFatalError(Error::Type::JSONError, "The \"enabled\" setting must be a Boolean.");
if (_jsonInput["enabled"].asBool()) if (_jsonInput["enabled"].asBool())
settings = OptimiserSettings::standard(); settings = OptimiserSettings::standard();
@ -587,7 +587,7 @@ std::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Value
if (_jsonInput.isMember("runs")) if (_jsonInput.isMember("runs"))
{ {
if (!_jsonInput["runs"].isUInt()) if (!_jsonInput["runs"].isUInt())
return formatFatalError("JSONError", "The \"runs\" setting must be an unsigned number."); return formatFatalError(Error::Type::JSONError, "The \"runs\" setting must be an unsigned number.");
settings.expectedExecutionsPerDeployment = _jsonInput["runs"].asUInt(); settings.expectedExecutionsPerDeployment = _jsonInput["runs"].asUInt();
} }
@ -617,7 +617,7 @@ std::variant<OptimiserSettings, Json::Value> parseOptimizerSettings(Json::Value
if (details.isMember("yulDetails")) if (details.isMember("yulDetails"))
{ {
if (!settings.runYulOptimiser) if (!settings.runYulOptimiser)
return formatFatalError("JSONError", "\"Providing yulDetails requires Yul optimizer to be enabled."); return formatFatalError(Error::Type::JSONError, "\"Providing yulDetails requires Yul optimizer to be enabled.");
if (auto result = checkKeys(details["yulDetails"], {"stackAllocation", "optimizerSteps"}, "settings.optimizer.details.yulDetails")) if (auto result = checkKeys(details["yulDetails"], {"stackAllocation", "optimizerSteps"}, "settings.optimizer.details.yulDetails"))
return *result; return *result;
@ -638,7 +638,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
InputsAndSettings ret; InputsAndSettings ret;
if (!_input.isObject()) if (!_input.isObject())
return formatFatalError("JSONError", "Input is not a JSON object."); return formatFatalError(Error::Type::JSONError, "Input is not a JSON object.");
if (auto result = checkRootKeys(_input)) if (auto result = checkRootKeys(_input))
return *result; return *result;
@ -648,10 +648,10 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
Json::Value const& sources = _input["sources"]; Json::Value const& sources = _input["sources"];
if (!sources.isObject() && !sources.isNull()) if (!sources.isObject() && !sources.isNull())
return formatFatalError("JSONError", "\"sources\" is not a JSON object."); return formatFatalError(Error::Type::JSONError, "\"sources\" is not a JSON object.");
if (sources.empty()) if (sources.empty())
return formatFatalError("JSONError", "No input sources specified."); return formatFatalError(Error::Type::JSONError, "No input sources specified.");
ret.errors = Json::arrayValue; ret.errors = Json::arrayValue;
@ -670,8 +670,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
string content = sources[sourceName]["content"].asString(); string content = sources[sourceName]["content"].asString();
if (!hash.empty() && !hashMatchesContent(hash, content)) if (!hash.empty() && !hashMatchesContent(hash, content))
ret.errors.append(formatError( ret.errors.append(formatError(
Error::Severity::Error, Error::Type::IOError,
"IOError",
"general", "general",
"Mismatch between content and supplied hash for \"" + sourceName + "\"" "Mismatch between content and supplied hash for \"" + sourceName + "\""
)); ));
@ -681,22 +680,21 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
else if (sources[sourceName]["urls"].isArray()) else if (sources[sourceName]["urls"].isArray())
{ {
if (!m_readFile) if (!m_readFile)
return formatFatalError("JSONError", "No import callback supplied, but URL is requested."); return formatFatalError(Error::Type::JSONError, "No import callback supplied, but URL is requested.");
bool found = false;
vector<string> failures; vector<string> failures;
bool found = false;
for (auto const& url: sources[sourceName]["urls"]) for (auto const& url: sources[sourceName]["urls"])
{ {
if (!url.isString()) if (!url.isString())
return formatFatalError("JSONError", "URL must be a string."); return formatFatalError(Error::Type::JSONError, "URL must be a string.");
ReadCallback::Result result = m_readFile(ReadCallback::kindString(ReadCallback::Kind::ReadFile), url.asString()); ReadCallback::Result result = m_readFile(ReadCallback::kindString(ReadCallback::Kind::ReadFile), url.asString());
if (result.success) if (result.success)
{ {
if (!hash.empty() && !hashMatchesContent(hash, result.responseOrErrorMessage)) if (!hash.empty() && !hashMatchesContent(hash, result.responseOrErrorMessage))
ret.errors.append(formatError( ret.errors.append(formatError(
Error::Severity::Error, Error::Type::IOError,
"IOError",
"general", "general",
"Mismatch between content and supplied hash for \"" + sourceName + "\" at \"" + url.asString() + "\"" "Mismatch between content and supplied hash for \"" + sourceName + "\" at \"" + url.asString() + "\""
)); ));
@ -715,15 +713,14 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{ {
/// If the import succeeded, let mark all the others as warnings, otherwise all of them are errors. /// If the import succeeded, let mark all the others as warnings, otherwise all of them are errors.
ret.errors.append(formatError( ret.errors.append(formatError(
found ? Error::Severity::Warning : Error::Severity::Error, found ? Error::Type::Warning : Error::Type::IOError,
"IOError",
"general", "general",
failure failure
)); ));
} }
} }
else else
return formatFatalError("JSONError", "Invalid input source specified."); return formatFatalError(Error::Type::JSONError, "Invalid input source specified.");
} }
Json::Value const& auxInputs = _input["auxiliaryInput"]; Json::Value const& auxInputs = _input["auxiliaryInput"];
@ -737,7 +734,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (!!smtlib2Responses) if (!!smtlib2Responses)
{ {
if (!smtlib2Responses.isObject()) if (!smtlib2Responses.isObject())
return formatFatalError("JSONError", "\"auxiliaryInput.smtlib2responses\" must be an object."); return formatFatalError(Error::Type::JSONError, "\"auxiliaryInput.smtlib2responses\" must be an object.");
for (auto const& hashString: smtlib2Responses.getMemberNames()) for (auto const& hashString: smtlib2Responses.getMemberNames())
{ {
@ -748,12 +745,12 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
} }
catch (util::BadHexCharacter const&) catch (util::BadHexCharacter const&)
{ {
return formatFatalError("JSONError", "Invalid hex encoding of SMTLib2 auxiliary input."); return formatFatalError(Error::Type::JSONError, "Invalid hex encoding of SMTLib2 auxiliary input.");
} }
if (!smtlib2Responses[hashString].isString()) if (!smtlib2Responses[hashString].isString())
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"\"smtlib2Responses." + hashString + "\" must be a string." "\"smtlib2Responses." + hashString + "\" must be a string."
); );
@ -770,10 +767,10 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (settings.isMember("stopAfter")) if (settings.isMember("stopAfter"))
{ {
if (!settings["stopAfter"].isString()) if (!settings["stopAfter"].isString())
return formatFatalError("JSONError", "\"settings.stopAfter\" must be a string."); return formatFatalError(Error::Type::JSONError, "\"settings.stopAfter\" must be a string.");
if (settings["stopAfter"].asString() != "parsing") if (settings["stopAfter"].asString() != "parsing")
return formatFatalError("JSONError", "Invalid value for \"settings.stopAfter\". Only valid value is \"parsing\"."); return formatFatalError(Error::Type::JSONError, "Invalid value for \"settings.stopAfter\". Only valid value is \"parsing\".");
ret.stopAfter = CompilerStack::State::Parsed; ret.stopAfter = CompilerStack::State::Parsed;
} }
@ -781,24 +778,24 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (settings.isMember("parserErrorRecovery")) if (settings.isMember("parserErrorRecovery"))
{ {
if (!settings["parserErrorRecovery"].isBool()) if (!settings["parserErrorRecovery"].isBool())
return formatFatalError("JSONError", "\"settings.parserErrorRecovery\" must be a Boolean."); return formatFatalError(Error::Type::JSONError, "\"settings.parserErrorRecovery\" must be a Boolean.");
ret.parserErrorRecovery = settings["parserErrorRecovery"].asBool(); ret.parserErrorRecovery = settings["parserErrorRecovery"].asBool();
} }
if (settings.isMember("viaIR")) if (settings.isMember("viaIR"))
{ {
if (!settings["viaIR"].isBool()) if (!settings["viaIR"].isBool())
return formatFatalError("JSONError", "\"settings.viaIR\" must be a Boolean."); return formatFatalError(Error::Type::JSONError, "\"settings.viaIR\" must be a Boolean.");
ret.viaIR = settings["viaIR"].asBool(); ret.viaIR = settings["viaIR"].asBool();
} }
if (settings.isMember("evmVersion")) if (settings.isMember("evmVersion"))
{ {
if (!settings["evmVersion"].isString()) if (!settings["evmVersion"].isString())
return formatFatalError("JSONError", "evmVersion must be a string."); return formatFatalError(Error::Type::JSONError, "evmVersion must be a string.");
std::optional<langutil::EVMVersion> version = langutil::EVMVersion::fromString(settings["evmVersion"].asString()); std::optional<langutil::EVMVersion> version = langutil::EVMVersion::fromString(settings["evmVersion"].asString());
if (!version) if (!version)
return formatFatalError("JSONError", "Invalid EVM version requested."); return formatFatalError(Error::Type::JSONError, "Invalid EVM version requested.");
ret.evmVersion = *version; ret.evmVersion = *version;
} }
@ -810,13 +807,13 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (settings["debug"].isMember("revertStrings")) if (settings["debug"].isMember("revertStrings"))
{ {
if (!settings["debug"]["revertStrings"].isString()) if (!settings["debug"]["revertStrings"].isString())
return formatFatalError("JSONError", "settings.debug.revertStrings must be a string."); return formatFatalError(Error::Type::JSONError, "settings.debug.revertStrings must be a string.");
std::optional<RevertStrings> revertStrings = revertStringsFromString(settings["debug"]["revertStrings"].asString()); std::optional<RevertStrings> revertStrings = revertStringsFromString(settings["debug"]["revertStrings"].asString());
if (!revertStrings) if (!revertStrings)
return formatFatalError("JSONError", "Invalid value for settings.debug.revertStrings."); return formatFatalError(Error::Type::JSONError, "Invalid value for settings.debug.revertStrings.");
if (*revertStrings == RevertStrings::VerboseDebug) if (*revertStrings == RevertStrings::VerboseDebug)
return formatFatalError( return formatFatalError(
"UnimplementedFeatureError", Error::Type::UnimplementedFeatureError,
"Only \"default\", \"strip\" and \"debug\" are implemented for settings.debug.revertStrings for now." "Only \"default\", \"strip\" and \"debug\" are implemented for settings.debug.revertStrings for now."
); );
ret.revertStrings = *revertStrings; ret.revertStrings = *revertStrings;
@ -825,7 +822,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (settings["debug"].isMember("debugInfo")) if (settings["debug"].isMember("debugInfo"))
{ {
if (!settings["debug"]["debugInfo"].isArray()) if (!settings["debug"]["debugInfo"].isArray())
return formatFatalError("JSONError", "settings.debug.debugInfo must be an array."); return formatFatalError(Error::Type::JSONError, "settings.debug.debugInfo must be an array.");
vector<string> components; vector<string> components;
for (Json::Value const& arrayValue: settings["debug"]["debugInfo"]) for (Json::Value const& arrayValue: settings["debug"]["debugInfo"])
@ -836,11 +833,11 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
true /* _acceptWildcards */ true /* _acceptWildcards */
); );
if (!debugInfoSelection.has_value()) if (!debugInfoSelection.has_value())
return formatFatalError("JSONError", "Invalid value in settings.debug.debugInfo."); return formatFatalError(Error::Type::JSONError, "Invalid value in settings.debug.debugInfo.");
if (debugInfoSelection->snippet && !debugInfoSelection->location) if (debugInfoSelection->snippet && !debugInfoSelection->location)
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"To use 'snippet' with settings.debug.debugInfo you must select also 'location'." "To use 'snippet' with settings.debug.debugInfo you must select also 'location'."
); );
@ -849,16 +846,16 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
} }
if (settings.isMember("remappings") && !settings["remappings"].isArray()) if (settings.isMember("remappings") && !settings["remappings"].isArray())
return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings."); return formatFatalError(Error::Type::JSONError, "\"settings.remappings\" must be an array of strings.");
for (auto const& remapping: settings.get("remappings", Json::Value())) for (auto const& remapping: settings.get("remappings", Json::Value()))
{ {
if (!remapping.isString()) if (!remapping.isString())
return formatFatalError("JSONError", "\"settings.remappings\" must be an array of strings"); return formatFatalError(Error::Type::JSONError, "\"settings.remappings\" must be an array of strings");
if (auto r = ImportRemapper::parseRemapping(remapping.asString())) if (auto r = ImportRemapper::parseRemapping(remapping.asString()))
ret.remappings.emplace_back(std::move(*r)); ret.remappings.emplace_back(std::move(*r));
else else
return formatFatalError("JSONError", "Invalid remapping: \"" + remapping.asString() + "\""); return formatFatalError(Error::Type::JSONError, "Invalid remapping: \"" + remapping.asString() + "\"");
} }
if (settings.isMember("optimizer")) if (settings.isMember("optimizer"))
@ -872,27 +869,27 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
Json::Value jsonLibraries = settings.get("libraries", Json::Value(Json::objectValue)); Json::Value jsonLibraries = settings.get("libraries", Json::Value(Json::objectValue));
if (!jsonLibraries.isObject()) if (!jsonLibraries.isObject())
return formatFatalError("JSONError", "\"libraries\" is not a JSON object."); return formatFatalError(Error::Type::JSONError, "\"libraries\" is not a JSON object.");
for (auto const& sourceName: jsonLibraries.getMemberNames()) for (auto const& sourceName: jsonLibraries.getMemberNames())
{ {
auto const& jsonSourceName = jsonLibraries[sourceName]; auto const& jsonSourceName = jsonLibraries[sourceName];
if (!jsonSourceName.isObject()) if (!jsonSourceName.isObject())
return formatFatalError("JSONError", "Library entry is not a JSON object."); return formatFatalError(Error::Type::JSONError, "Library entry is not a JSON object.");
for (auto const& library: jsonSourceName.getMemberNames()) for (auto const& library: jsonSourceName.getMemberNames())
{ {
if (!jsonSourceName[library].isString()) if (!jsonSourceName[library].isString())
return formatFatalError("JSONError", "Library address must be a string."); return formatFatalError(Error::Type::JSONError, "Library address must be a string.");
string address = jsonSourceName[library].asString(); string address = jsonSourceName[library].asString();
if (!boost::starts_with(address, "0x")) if (!boost::starts_with(address, "0x"))
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"Library address is not prefixed with \"0x\"." "Library address is not prefixed with \"0x\"."
); );
if (address.length() != 42) if (address.length() != 42)
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"Library address is of invalid length." "Library address is of invalid length."
); );
@ -903,7 +900,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
catch (util::BadHexCharacter const&) catch (util::BadHexCharacter const&)
{ {
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"Invalid library address (\"" + address + "\") supplied." "Invalid library address (\"" + address + "\") supplied."
); );
} }
@ -936,7 +933,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (ret.stopAfter != CompilerStack::State::CompilationSuccessful && isBinaryRequested(ret.outputSelection)) if (ret.stopAfter != CompilerStack::State::CompilationSuccessful && isBinaryRequested(ret.outputSelection))
return formatFatalError( return formatFatalError(
"JSONError", Error::Type::JSONError,
"Requested output selection conflicts with \"settings.stopAfter\"." "Requested output selection conflicts with \"settings.stopAfter\"."
); );
@ -949,29 +946,29 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{ {
auto const& sources = modelCheckerSettings["contracts"]; auto const& sources = modelCheckerSettings["contracts"];
if (!sources.isObject() && !sources.isNull()) if (!sources.isObject() && !sources.isNull())
return formatFatalError("JSONError", "settings.modelChecker.contracts is not a JSON object."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.contracts is not a JSON object.");
map<string, set<string>> sourceContracts; map<string, set<string>> sourceContracts;
for (auto const& source: sources.getMemberNames()) for (auto const& source: sources.getMemberNames())
{ {
if (source.empty()) if (source.empty())
return formatFatalError("JSONError", "Source name cannot be empty."); return formatFatalError(Error::Type::JSONError, "Source name cannot be empty.");
auto const& contracts = sources[source]; auto const& contracts = sources[source];
if (!contracts.isArray()) if (!contracts.isArray())
return formatFatalError("JSONError", "Source contracts must be an array."); return formatFatalError(Error::Type::JSONError, "Source contracts must be an array.");
for (auto const& contract: contracts) for (auto const& contract: contracts)
{ {
if (!contract.isString()) if (!contract.isString())
return formatFatalError("JSONError", "Every contract in settings.modelChecker.contracts must be a string."); return formatFatalError(Error::Type::JSONError, "Every contract in settings.modelChecker.contracts must be a string.");
if (contract.asString().empty()) if (contract.asString().empty())
return formatFatalError("JSONError", "Contract name cannot be empty."); return formatFatalError(Error::Type::JSONError, "Contract name cannot be empty.");
sourceContracts[source].insert(contract.asString()); sourceContracts[source].insert(contract.asString());
} }
if (sourceContracts[source].empty()) if (sourceContracts[source].empty())
return formatFatalError("JSONError", "Source contracts must be a non-empty array."); return formatFatalError(Error::Type::JSONError, "Source contracts must be a non-empty array.");
} }
ret.modelCheckerSettings.contracts = {std::move(sourceContracts)}; ret.modelCheckerSettings.contracts = {std::move(sourceContracts)};
} }
@ -980,17 +977,17 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{ {
auto const& divModNoSlacks = modelCheckerSettings["divModNoSlacks"]; auto const& divModNoSlacks = modelCheckerSettings["divModNoSlacks"];
if (!divModNoSlacks.isBool()) if (!divModNoSlacks.isBool())
return formatFatalError("JSONError", "settings.modelChecker.divModNoSlacks must be a Boolean."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.divModNoSlacks must be a Boolean.");
ret.modelCheckerSettings.divModNoSlacks = divModNoSlacks.asBool(); ret.modelCheckerSettings.divModNoSlacks = divModNoSlacks.asBool();
} }
if (modelCheckerSettings.isMember("engine")) if (modelCheckerSettings.isMember("engine"))
{ {
if (!modelCheckerSettings["engine"].isString()) if (!modelCheckerSettings["engine"].isString())
return formatFatalError("JSONError", "settings.modelChecker.engine must be a string."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.engine must be a string.");
std::optional<ModelCheckerEngine> engine = ModelCheckerEngine::fromString(modelCheckerSettings["engine"].asString()); std::optional<ModelCheckerEngine> engine = ModelCheckerEngine::fromString(modelCheckerSettings["engine"].asString());
if (!engine) if (!engine)
return formatFatalError("JSONError", "Invalid model checker engine requested."); return formatFatalError(Error::Type::JSONError, "Invalid model checker engine requested.");
ret.modelCheckerSettings.engine = *engine; ret.modelCheckerSettings.engine = *engine;
} }
@ -998,19 +995,19 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{ {
auto const& invariantsArray = modelCheckerSettings["invariants"]; auto const& invariantsArray = modelCheckerSettings["invariants"];
if (!invariantsArray.isArray()) if (!invariantsArray.isArray())
return formatFatalError("JSONError", "settings.modelChecker.invariants must be an array."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.invariants must be an array.");
ModelCheckerInvariants invariants; ModelCheckerInvariants invariants;
for (auto const& i: invariantsArray) for (auto const& i: invariantsArray)
{ {
if (!i.isString()) if (!i.isString())
return formatFatalError("JSONError", "Every invariant type in settings.modelChecker.invariants must be a string."); return formatFatalError(Error::Type::JSONError, "Every invariant type in settings.modelChecker.invariants must be a string.");
if (!invariants.setFromString(i.asString())) if (!invariants.setFromString(i.asString()))
return formatFatalError("JSONError", "Invalid model checker invariants requested."); return formatFatalError(Error::Type::JSONError, "Invalid model checker invariants requested.");
} }
if (invariants.invariants.empty()) if (invariants.invariants.empty())
return formatFatalError("JSONError", "settings.modelChecker.invariants must be a non-empty array."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.invariants must be a non-empty array.");
ret.modelCheckerSettings.invariants = invariants; ret.modelCheckerSettings.invariants = invariants;
} }
@ -1019,7 +1016,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{ {
auto const& showUnproved = modelCheckerSettings["showUnproved"]; auto const& showUnproved = modelCheckerSettings["showUnproved"];
if (!showUnproved.isBool()) if (!showUnproved.isBool())
return formatFatalError("JSONError", "settings.modelChecker.showUnproved must be a Boolean value."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.showUnproved must be a Boolean value.");
ret.modelCheckerSettings.showUnproved = showUnproved.asBool(); ret.modelCheckerSettings.showUnproved = showUnproved.asBool();
} }
@ -1027,15 +1024,15 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{ {
auto const& solversArray = modelCheckerSettings["solvers"]; auto const& solversArray = modelCheckerSettings["solvers"];
if (!solversArray.isArray()) if (!solversArray.isArray())
return formatFatalError("JSONError", "settings.modelChecker.solvers must be an array."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.solvers must be an array.");
smtutil::SMTSolverChoice solvers; smtutil::SMTSolverChoice solvers;
for (auto const& s: solversArray) for (auto const& s: solversArray)
{ {
if (!s.isString()) if (!s.isString())
return formatFatalError("JSONError", "Every target in settings.modelChecker.solvers must be a string."); return formatFatalError(Error::Type::JSONError, "Every target in settings.modelChecker.solvers must be a string.");
if (!solvers.setSolver(s.asString())) if (!solvers.setSolver(s.asString()))
return formatFatalError("JSONError", "Invalid model checker solvers requested."); return formatFatalError(Error::Type::JSONError, "Invalid model checker solvers requested.");
} }
ret.modelCheckerSettings.solvers = solvers; ret.modelCheckerSettings.solvers = solvers;
@ -1045,19 +1042,19 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
{ {
auto const& targetsArray = modelCheckerSettings["targets"]; auto const& targetsArray = modelCheckerSettings["targets"];
if (!targetsArray.isArray()) if (!targetsArray.isArray())
return formatFatalError("JSONError", "settings.modelChecker.targets must be an array."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.targets must be an array.");
ModelCheckerTargets targets; ModelCheckerTargets targets;
for (auto const& t: targetsArray) for (auto const& t: targetsArray)
{ {
if (!t.isString()) if (!t.isString())
return formatFatalError("JSONError", "Every target in settings.modelChecker.targets must be a string."); return formatFatalError(Error::Type::JSONError, "Every target in settings.modelChecker.targets must be a string.");
if (!targets.setFromString(t.asString())) if (!targets.setFromString(t.asString()))
return formatFatalError("JSONError", "Invalid model checker targets requested."); return formatFatalError(Error::Type::JSONError, "Invalid model checker targets requested.");
} }
if (targets.targets.empty()) if (targets.targets.empty())
return formatFatalError("JSONError", "settings.modelChecker.targets must be a non-empty array."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.targets must be a non-empty array.");
ret.modelCheckerSettings.targets = targets; ret.modelCheckerSettings.targets = targets;
} }
@ -1065,7 +1062,7 @@ std::variant<StandardCompiler::InputsAndSettings, Json::Value> StandardCompiler:
if (modelCheckerSettings.isMember("timeout")) if (modelCheckerSettings.isMember("timeout"))
{ {
if (!modelCheckerSettings["timeout"].isUInt()) if (!modelCheckerSettings["timeout"].isUInt())
return formatFatalError("JSONError", "settings.modelChecker.timeout must be an unsigned integer."); return formatFatalError(Error::Type::JSONError, "settings.modelChecker.timeout must be an unsigned integer.");
ret.modelCheckerSettings.timeout = modelCheckerSettings["timeout"].asUInt(); ret.modelCheckerSettings.timeout = modelCheckerSettings["timeout"].asUInt();
} }
@ -1116,8 +1113,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
errors.append(formatErrorWithException( errors.append(formatErrorWithException(
compilerStack, compilerStack,
*error, *error,
Error::errorSeverity(err.type()), err.type(),
err.typeName(),
"general", "general",
"", "",
err.errorId() err.errorId()
@ -1130,8 +1126,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
errors.append(formatErrorWithException( errors.append(formatErrorWithException(
compilerStack, compilerStack,
_error, _error,
Error::Severity::Error, _error.type(),
_error.typeName(),
"general", "general",
"Uncaught error: " "Uncaught error: "
)); ));
@ -1140,8 +1135,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
catch (FatalError const& _exception) catch (FatalError const& _exception)
{ {
errors.append(formatError( errors.append(formatError(
Error::Severity::Error, Error::Type::FatalError,
"FatalError",
"general", "general",
"Uncaught fatal error: " + boost::diagnostic_information(_exception) "Uncaught fatal error: " + boost::diagnostic_information(_exception)
)); ));
@ -1151,8 +1145,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
errors.append(formatErrorWithException( errors.append(formatErrorWithException(
compilerStack, compilerStack,
_exception, _exception,
Error::Severity::Error, Error::Type::CompilerError,
"CompilerError",
"general", "general",
"Compiler error (" + _exception.lineInfo() + ")" "Compiler error (" + _exception.lineInfo() + ")"
)); ));
@ -1162,8 +1155,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
errors.append(formatErrorWithException( errors.append(formatErrorWithException(
compilerStack, compilerStack,
_exception, _exception,
Error::Severity::Error, Error::Type::InternalCompilerError,
"InternalCompilerError",
"general", "general",
"Internal compiler error (" + _exception.lineInfo() + ")" "Internal compiler error (" + _exception.lineInfo() + ")"
)); ));
@ -1173,8 +1165,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
errors.append(formatErrorWithException( errors.append(formatErrorWithException(
compilerStack, compilerStack,
_exception, _exception,
Error::Severity::Error, Error::Type::UnimplementedFeatureError,
"UnimplementedFeatureError",
"general", "general",
"Unimplemented feature (" + _exception.lineInfo() + ")" "Unimplemented feature (" + _exception.lineInfo() + ")"
)); ));
@ -1184,8 +1175,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
errors.append(formatErrorWithException( errors.append(formatErrorWithException(
compilerStack, compilerStack,
_exception, _exception,
Error::Severity::Error, Error::Type::YulException,
"YulException",
"general", "general",
"Yul exception" "Yul exception"
)); ));
@ -1195,8 +1185,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
errors.append(formatErrorWithException( errors.append(formatErrorWithException(
compilerStack, compilerStack,
_exception, _exception,
Error::Severity::Error, Error::Type::SMTLogicException,
"SMTLogicException",
"general", "general",
"SMT logic exception" "SMT logic exception"
)); ));
@ -1204,8 +1193,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
catch (util::Exception const& _exception) catch (util::Exception const& _exception)
{ {
errors.append(formatError( errors.append(formatError(
Error::Severity::Error, Error::Type::Exception,
"Exception",
"general", "general",
"Exception during compilation: " + boost::diagnostic_information(_exception) "Exception during compilation: " + boost::diagnostic_information(_exception)
)); ));
@ -1213,8 +1201,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
catch (std::exception const& _exception) catch (std::exception const& _exception)
{ {
errors.append(formatError( errors.append(formatError(
Error::Severity::Error, Error::Type::Exception,
"Exception",
"general", "general",
"Unknown exception during compilation: " + boost::diagnostic_information(_exception) "Unknown exception during compilation: " + boost::diagnostic_information(_exception)
)); ));
@ -1222,8 +1209,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
catch (...) catch (...)
{ {
errors.append(formatError( errors.append(formatError(
Error::Severity::Error, Error::Type::Exception,
"Exception",
"general", "general",
"Unknown exception during compilation: " + boost::current_exception_diagnostic_information() "Unknown exception during compilation: " + boost::current_exception_diagnostic_information()
)); ));
@ -1240,7 +1226,7 @@ Json::Value StandardCompiler::compileSolidity(StandardCompiler::InputsAndSetting
((binariesRequested && !compilationSuccess) || !analysisPerformed) && ((binariesRequested && !compilationSuccess) || !analysisPerformed) &&
(errors.empty() && _inputsAndSettings.stopAfter >= CompilerStack::State::AnalysisPerformed) (errors.empty() && _inputsAndSettings.stopAfter >= CompilerStack::State::AnalysisPerformed)
) )
return formatFatalError("InternalCompilerError", "No error reported, but compilation failed."); return formatFatalError(Error::Type::InternalCompilerError, "No error reported, but compilation failed.");
Json::Value output = Json::objectValue; Json::Value output = Json::objectValue;
@ -1376,8 +1362,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
if (_inputsAndSettings.sources.size() != 1) if (_inputsAndSettings.sources.size() != 1)
{ {
output["errors"].append(formatError( output["errors"].append(formatError(
Error::Severity::Error, Error::Type::JSONError,
"JSONError",
"general", "general",
"Yul mode only supports exactly one input file." "Yul mode only supports exactly one input file."
)); ));
@ -1386,8 +1371,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
if (!_inputsAndSettings.smtLib2Responses.empty()) if (!_inputsAndSettings.smtLib2Responses.empty())
{ {
output["errors"].append(formatError( output["errors"].append(formatError(
Error::Severity::Error, Error::Type::JSONError,
"JSONError",
"general", "general",
"Yul mode does not support smtlib2responses." "Yul mode does not support smtlib2responses."
)); ));
@ -1396,8 +1380,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
if (!_inputsAndSettings.remappings.empty()) if (!_inputsAndSettings.remappings.empty())
{ {
output["errors"].append(formatError( output["errors"].append(formatError(
Error::Severity::Error, Error::Type::JSONError,
"JSONError",
"general", "general",
"Field \"settings.remappings\" cannot be used for Yul." "Field \"settings.remappings\" cannot be used for Yul."
)); ));
@ -1406,8 +1389,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
if (_inputsAndSettings.revertStrings != RevertStrings::Default) if (_inputsAndSettings.revertStrings != RevertStrings::Default)
{ {
output["errors"].append(formatError( output["errors"].append(formatError(
Error::Severity::Error, Error::Type::JSONError,
"JSONError",
"general", "general",
"Field \"settings.debug.revertStrings\" cannot be used for Yul." "Field \"settings.debug.revertStrings\" cannot be used for Yul."
)); ));
@ -1429,8 +1411,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
if (!stack.parseAndAnalyze(sourceName, sourceContents) && stack.errors().empty()) if (!stack.parseAndAnalyze(sourceName, sourceContents) && stack.errors().empty())
{ {
output["errors"].append(formatError( output["errors"].append(formatError(
Error::Severity::Error, Error::Type::InternalCompilerError,
"InternalCompilerError",
"general", "general",
"No error reported, but compilation failed." "No error reported, but compilation failed."
)); ));
@ -1446,8 +1427,7 @@ Json::Value StandardCompiler::compileYul(InputsAndSettings _inputsAndSettings)
output["errors"].append(formatErrorWithException( output["errors"].append(formatErrorWithException(
stack, stack,
*error, *error,
Error::errorSeverity(err->type()), err->type(),
err->typeName(),
"general", "general",
"" ""
)); ));
@ -1523,23 +1503,23 @@ Json::Value StandardCompiler::compile(Json::Value const& _input) noexcept
else if (settings.language == "Yul") else if (settings.language == "Yul")
return compileYul(std::move(settings)); return compileYul(std::move(settings));
else else
return formatFatalError("JSONError", "Only \"Solidity\" or \"Yul\" is supported as a language."); return formatFatalError(Error::Type::JSONError, "Only \"Solidity\" or \"Yul\" is supported as a language.");
} }
catch (Json::LogicError const& _exception) catch (Json::LogicError const& _exception)
{ {
return formatFatalError("InternalCompilerError", string("JSON logic exception: ") + _exception.what()); return formatFatalError(Error::Type::InternalCompilerError, string("JSON logic exception: ") + _exception.what());
} }
catch (Json::RuntimeError const& _exception) catch (Json::RuntimeError const& _exception)
{ {
return formatFatalError("InternalCompilerError", string("JSON runtime exception: ") + _exception.what()); return formatFatalError(Error::Type::InternalCompilerError, string("JSON runtime exception: ") + _exception.what());
} }
catch (util::Exception const& _exception) catch (util::Exception const& _exception)
{ {
return formatFatalError("InternalCompilerError", "Internal exception in StandardCompiler::compile: " + boost::diagnostic_information(_exception)); return formatFatalError(Error::Type::InternalCompilerError, "Internal exception in StandardCompiler::compile: " + boost::diagnostic_information(_exception));
} }
catch (...) catch (...)
{ {
return formatFatalError("InternalCompilerError", "Internal exception in StandardCompiler::compile: " + boost::current_exception_diagnostic_information()); return formatFatalError(Error::Type::InternalCompilerError, "Internal exception in StandardCompiler::compile: " + boost::current_exception_diagnostic_information());
} }
} }
@ -1550,7 +1530,7 @@ string StandardCompiler::compile(string const& _input) noexcept
try try
{ {
if (!util::jsonParseStrict(_input, input, &errors)) if (!util::jsonParseStrict(_input, input, &errors))
return util::jsonPrint(formatFatalError("JSONError", errors), m_jsonPrintingFormat); return util::jsonPrint(formatFatalError(Error::Type::JSONError, errors), m_jsonPrintingFormat);
} }
catch (...) catch (...)
{ {

View File

@ -286,7 +286,7 @@ void LanguageServer::compileAndUpdateDiagnostics()
jsonDiag["source"] = "solc"; jsonDiag["source"] = "solc";
jsonDiag["severity"] = toDiagnosticSeverity(error->type()); jsonDiag["severity"] = toDiagnosticSeverity(error->type());
jsonDiag["code"] = Json::UInt64{error->errorId().error}; jsonDiag["code"] = Json::UInt64{error->errorId().error};
string message = error->typeName() + ":"; string message = Error::formatErrorType(error->type()) + ":";
if (string const* comment = error->comment()) if (string const* comment = error->comment())
message += " " + *comment; message += " " + *comment;
jsonDiag["message"] = std::move(message); jsonDiag["message"] = std::move(message);

View File

@ -765,7 +765,7 @@ void CommandLineInterface::compile()
catch (CompilerError const& _exception) catch (CompilerError const& _exception)
{ {
m_hasOutput = true; m_hasOutput = true;
formatter.printExceptionInformation(_exception, "Compiler error"); formatter.printExceptionInformation(_exception, Error::Type::CompilerError);
solThrow(CommandLineExecutionError, ""); solThrow(CommandLineExecutionError, "");
} }
catch (Error const& _error) catch (Error const& _error)
@ -778,7 +778,7 @@ void CommandLineInterface::compile()
else else
{ {
m_hasOutput = true; m_hasOutput = true;
formatter.printExceptionInformation(_error, _error.typeName()); formatter.printExceptionInformation(_error, _error.type());
solThrow(CommandLineExecutionError, ""); solThrow(CommandLineExecutionError, "");
} }
} }

View File

@ -0,0 +1 @@
--pretty-json --json-indent 4

View File

@ -0,0 +1,2 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity *;

View File

@ -0,0 +1,13 @@
{
"language": "Solidity",
"sources": {
"url_not_found.sol": {
"urls": [
"standard_urls_existing_and_missing/non-existent-contract-1.sol",
"standard_urls_existing_and_missing/contract.sol",
"standard_urls_existing_and_missing/non-existent-contract-2.sol"
]
}
},
"settings": {"outputSelection": {"*": { "*": ["metadata", "evm.bytecode"]}}}
}

View File

@ -0,0 +1,18 @@
{
"errors":
[
{
"component": "general",
"formattedMessage": "Cannot import url (\"standard_urls_existing_and_missing/non-existent-contract-1.sol\"): File not found. Searched the following locations: \"\".",
"message": "Cannot import url (\"standard_urls_existing_and_missing/non-existent-contract-1.sol\"): File not found. Searched the following locations: \"\".",
"severity": "warning",
"type": "Warning"
}],
"sources":
{
"url_not_found.sol":
{
"id": 0
}
}
}

View File

@ -0,0 +1 @@
--pretty-json --json-indent 4

View File

@ -0,0 +1,2 @@
// SPDX-License-Identifier: GPL-3.0
pragma solidity *;

View File

@ -0,0 +1,13 @@
{
"language": "Solidity",
"sources": {
"url_not_found.sol": {
"urls": [
"standard_urls_missing/non-existent-contract-1.sol",
"standard_urls_missing/non-existent-contract.sol",
"standard_urls_missing/non-existent-contract-2.sol"
]
}
},
"settings": {"outputSelection": {"*": { "*": ["metadata", "evm.bytecode"]}}}
}

View File

@ -0,0 +1,26 @@
{
"errors":
[
{
"component": "general",
"formattedMessage": "Cannot import url (\"standard_urls_missing/non-existent-contract-1.sol\"): File not found. Searched the following locations: \"\".",
"message": "Cannot import url (\"standard_urls_missing/non-existent-contract-1.sol\"): File not found. Searched the following locations: \"\".",
"severity": "error",
"type": "IOError"
},
{
"component": "general",
"formattedMessage": "Cannot import url (\"standard_urls_missing/non-existent-contract.sol\"): File not found. Searched the following locations: \"\".",
"message": "Cannot import url (\"standard_urls_missing/non-existent-contract.sol\"): File not found. Searched the following locations: \"\".",
"severity": "error",
"type": "IOError"
},
{
"component": "general",
"formattedMessage": "Cannot import url (\"standard_urls_missing/non-existent-contract-2.sol\"): File not found. Searched the following locations: \"\".",
"message": "Cannot import url (\"standard_urls_missing/non-existent-contract-2.sol\"): File not found. Searched the following locations: \"\".",
"severity": "error",
"type": "IOError"
}],
"sources": {}
}

View File

@ -71,7 +71,7 @@ string solidity::frontend::test::searchErrors(ErrorList const& _errors, vector<p
break; break;
} }
if (!found) if (!found)
return "Unexpected error: " + error->typeName() + ": " + msg; return "Unexpected error: " + Error::formatErrorType(error->type()) + ": " + msg;
} }
if (!expectations.empty()) if (!expectations.empty())
{ {

View File

@ -145,7 +145,7 @@ void SyntaxTest::filterObtainedErrors()
} }
} }
m_errorList.emplace_back(SyntaxTestError{ m_errorList.emplace_back(SyntaxTestError{
currentError->typeName(), Error::formatErrorType(currentError->type()),
currentError->errorId(), currentError->errorId(),
errorMessage(*currentError), errorMessage(*currentError),
sourceName, sourceName,

View File

@ -61,7 +61,7 @@ void SyntaxTest::parseAndAnalyze()
} }
m_errorList.emplace_back(SyntaxTestError{ m_errorList.emplace_back(SyntaxTestError{
error->typeName(), Error::formatErrorType(error->type()),
error->errorId(), error->errorId(),
errorMessage(*error), errorMessage(*error),
name, name,

View File

@ -79,10 +79,7 @@ DEFINE_PROTO_FUZZER(Program const& _input)
SourceReferenceFormatter formatter(std::cout, stack, false, false); SourceReferenceFormatter formatter(std::cout, stack, false, false);
for (auto const& error: stack.errors()) for (auto const& error: stack.errors())
formatter.printExceptionInformation( formatter.printExceptionInformation(*error, error->type());
*error,
(error->type() == Error::Type::Warning) ? "Warning" : "Error"
);
yulAssert(false, "Proto fuzzer generated malformed program"); yulAssert(false, "Proto fuzzer generated malformed program");
} }