mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Merge pull request #8956 from a3d4/partfix-5819-introduce-errorwatcher
Introduce ErrorWatcher
This commit is contained in:
commit
a05e8c1a0e
@ -143,6 +143,28 @@ public:
|
|||||||
// @returns true if the maximum error count has been reached.
|
// @returns true if the maximum error count has been reached.
|
||||||
bool hasExcessiveErrors() const;
|
bool hasExcessiveErrors() const;
|
||||||
|
|
||||||
|
class ErrorWatcher
|
||||||
|
{
|
||||||
|
public:
|
||||||
|
ErrorWatcher(ErrorReporter const& _errorReporter):
|
||||||
|
m_errorReporter(_errorReporter),
|
||||||
|
m_initialErrorCount(_errorReporter.errorCount())
|
||||||
|
{}
|
||||||
|
bool ok() const
|
||||||
|
{
|
||||||
|
solAssert(m_initialErrorCount <= m_errorReporter.errorCount(), "Unexpected error count.");
|
||||||
|
return m_initialErrorCount == m_errorReporter.errorCount();
|
||||||
|
}
|
||||||
|
private:
|
||||||
|
ErrorReporter const& m_errorReporter;
|
||||||
|
unsigned const m_initialErrorCount;
|
||||||
|
};
|
||||||
|
|
||||||
|
ErrorWatcher errorWatcher() const
|
||||||
|
{
|
||||||
|
return ErrorWatcher(*this);
|
||||||
|
}
|
||||||
|
|
||||||
private:
|
private:
|
||||||
void error(
|
void error(
|
||||||
ErrorId _error,
|
ErrorId _error,
|
||||||
|
@ -45,22 +45,20 @@ using namespace solidity::langutil;
|
|||||||
|
|
||||||
bool AsmAnalyzer::analyze(Block const& _block)
|
bool AsmAnalyzer::analyze(Block const& _block)
|
||||||
{
|
{
|
||||||
m_success = true;
|
auto watcher = m_errorReporter.errorWatcher();
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
if (!(ScopeFiller(m_info, m_errorReporter))(_block))
|
if (!(ScopeFiller(m_info, m_errorReporter))(_block))
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
(*this)(_block);
|
(*this)(_block);
|
||||||
if (!m_success)
|
|
||||||
yulAssert(m_errorReporter.hasErrors(), "No success but no error.");
|
|
||||||
}
|
}
|
||||||
catch (FatalError const&)
|
catch (FatalError const&)
|
||||||
{
|
{
|
||||||
// This FatalError con occur if the errorReporter has too many errors.
|
// This FatalError con occur if the errorReporter has too many errors.
|
||||||
yulAssert(!m_errorReporter.errors().empty(), "Fatal error detected, but no error is reported.");
|
yulAssert(!watcher.ok(), "Fatal error detected, but no error is reported.");
|
||||||
}
|
}
|
||||||
return m_success && !m_errorReporter.hasErrors();
|
return watcher.ok();
|
||||||
}
|
}
|
||||||
|
|
||||||
AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object)
|
AsmAnalysisInfo AsmAnalyzer::analyzeStrictAssertCorrect(Dialect const& _dialect, Object const& _object)
|
||||||
@ -105,7 +103,7 @@ vector<YulString> AsmAnalyzer::operator()(Literal const& _literal)
|
|||||||
vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
||||||
{
|
{
|
||||||
yulAssert(!_identifier.name.empty(), "");
|
yulAssert(!_identifier.name.empty(), "");
|
||||||
size_t numErrorsBefore = m_errorReporter.errors().size();
|
auto watcher = m_errorReporter.errorWatcher();
|
||||||
YulString type = m_dialect.defaultType;
|
YulString type = m_dialect.defaultType;
|
||||||
|
|
||||||
if (m_currentScope->lookup(_identifier.name, GenericVisitor{
|
if (m_currentScope->lookup(_identifier.name, GenericVisitor{
|
||||||
@ -141,13 +139,9 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
|||||||
yulAssert(stackSize == 1, "Invalid stack size of external reference.");
|
yulAssert(stackSize == 1, "Invalid stack size of external reference.");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (!found)
|
if (!found && watcher.ok())
|
||||||
{
|
|
||||||
// Only add an error message if the callback did not do it.
|
// Only add an error message if the callback did not do it.
|
||||||
if (numErrorsBefore == m_errorReporter.errors().size())
|
declarationError(_identifier.location, "Identifier not found.");
|
||||||
declarationError(_identifier.location, "Identifier not found.");
|
|
||||||
m_success = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
return {type};
|
return {type};
|
||||||
@ -155,8 +149,9 @@ vector<YulString> AsmAnalyzer::operator()(Identifier const& _identifier)
|
|||||||
|
|
||||||
void AsmAnalyzer::operator()(ExpressionStatement const& _statement)
|
void AsmAnalyzer::operator()(ExpressionStatement const& _statement)
|
||||||
{
|
{
|
||||||
|
auto watcher = m_errorReporter.errorWatcher();
|
||||||
vector<YulString> types = std::visit(*this, _statement.expression);
|
vector<YulString> types = std::visit(*this, _statement.expression);
|
||||||
if (m_success && !types.empty())
|
if (watcher.ok() && !types.empty())
|
||||||
typeError(_statement.location,
|
typeError(_statement.location,
|
||||||
"Top-level expressions are not supposed to return values (this expression returns " +
|
"Top-level expressions are not supposed to return values (this expression returns " +
|
||||||
to_string(types.size()) +
|
to_string(types.size()) +
|
||||||
@ -253,6 +248,7 @@ void AsmAnalyzer::operator()(FunctionDefinition const& _funDef)
|
|||||||
vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
||||||
{
|
{
|
||||||
yulAssert(!_funCall.functionName.name.empty(), "");
|
yulAssert(!_funCall.functionName.name.empty(), "");
|
||||||
|
auto watcher = m_errorReporter.errorWatcher();
|
||||||
vector<YulString> const* parameterTypes = nullptr;
|
vector<YulString> const* parameterTypes = nullptr;
|
||||||
vector<YulString> const* returnTypes = nullptr;
|
vector<YulString> const* returnTypes = nullptr;
|
||||||
vector<bool> const* needsLiteralArguments = nullptr;
|
vector<bool> const* needsLiteralArguments = nullptr;
|
||||||
@ -281,7 +277,7 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
|||||||
{
|
{
|
||||||
if (!warnOnInstructions(_funCall.functionName.name.str(), _funCall.functionName.location))
|
if (!warnOnInstructions(_funCall.functionName.name.str(), _funCall.functionName.location))
|
||||||
declarationError(_funCall.functionName.location, "Function not found.");
|
declarationError(_funCall.functionName.location, "Function not found.");
|
||||||
m_success = false;
|
yulAssert(!watcher.ok(), "Expected a reported error.");
|
||||||
}
|
}
|
||||||
if (parameterTypes && _funCall.arguments.size() != parameterTypes->size())
|
if (parameterTypes && _funCall.arguments.size() != parameterTypes->size())
|
||||||
typeError(
|
typeError(
|
||||||
@ -323,7 +319,7 @@ vector<YulString> AsmAnalyzer::operator()(FunctionCall const& _funCall)
|
|||||||
for (size_t i = 0; i < parameterTypes->size(); ++i)
|
for (size_t i = 0; i < parameterTypes->size(); ++i)
|
||||||
expectType((*parameterTypes)[i], argTypes[i], locationOf(_funCall.arguments[i]));
|
expectType((*parameterTypes)[i], argTypes[i], locationOf(_funCall.arguments[i]));
|
||||||
|
|
||||||
if (m_success)
|
if (watcher.ok())
|
||||||
{
|
{
|
||||||
yulAssert(parameterTypes && parameterTypes->size() == argTypes.size(), "");
|
yulAssert(parameterTypes && parameterTypes->size() == argTypes.size(), "");
|
||||||
yulAssert(returnTypes, "");
|
yulAssert(returnTypes, "");
|
||||||
@ -353,6 +349,8 @@ void AsmAnalyzer::operator()(Switch const& _switch)
|
|||||||
{
|
{
|
||||||
if (_case.value)
|
if (_case.value)
|
||||||
{
|
{
|
||||||
|
auto watcher = m_errorReporter.errorWatcher();
|
||||||
|
|
||||||
expectType(valueType, _case.value->type, _case.value->location);
|
expectType(valueType, _case.value->type, _case.value->location);
|
||||||
|
|
||||||
// We cannot use "expectExpression" here because *_case.value is not an
|
// We cannot use "expectExpression" here because *_case.value is not an
|
||||||
@ -360,7 +358,7 @@ void AsmAnalyzer::operator()(Switch const& _switch)
|
|||||||
(*this)(*_case.value);
|
(*this)(*_case.value);
|
||||||
|
|
||||||
/// Note: the parser ensures there is only one default case
|
/// Note: the parser ensures there is only one default case
|
||||||
if (m_success && !cases.insert(valueOfLiteral(*_case.value)).second)
|
if (watcher.ok() && !cases.insert(valueOfLiteral(*_case.value)).second)
|
||||||
declarationError(_case.location, "Duplicate case defined.");
|
declarationError(_case.location, "Duplicate case defined.");
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -432,7 +430,7 @@ void AsmAnalyzer::expectBoolExpression(Expression const& _expr)
|
|||||||
void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueType)
|
void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueType)
|
||||||
{
|
{
|
||||||
yulAssert(!_variable.name.empty(), "");
|
yulAssert(!_variable.name.empty(), "");
|
||||||
size_t numErrorsBefore = m_errorReporter.errors().size();
|
auto watcher = m_errorReporter.errorWatcher();
|
||||||
YulString const* variableType = nullptr;
|
YulString const* variableType = nullptr;
|
||||||
bool found = false;
|
bool found = false;
|
||||||
if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
|
if (Scope::Identifier const* var = m_currentScope->lookup(_variable.name))
|
||||||
@ -461,13 +459,9 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if (!found)
|
if (!found && watcher.ok())
|
||||||
{
|
|
||||||
m_success = false;
|
|
||||||
// Only add message if the callback did not.
|
// Only add message if the callback did not.
|
||||||
if (numErrorsBefore == m_errorReporter.errors().size())
|
declarationError(_variable.location, "Variable not found or variable not lvalue.");
|
||||||
declarationError(_variable.location, "Variable not found or variable not lvalue.");
|
|
||||||
}
|
|
||||||
if (variableType && *variableType != _valueType)
|
if (variableType && *variableType != _valueType)
|
||||||
typeError(_variable.location,
|
typeError(_variable.location,
|
||||||
"Assigning a value of type \"" +
|
"Assigning a value of type \"" +
|
||||||
@ -477,8 +471,7 @@ void AsmAnalyzer::checkAssignment(Identifier const& _variable, YulString _valueT
|
|||||||
"\"."
|
"\"."
|
||||||
);
|
);
|
||||||
|
|
||||||
if (m_success)
|
yulAssert(!watcher.ok() || variableType, "");
|
||||||
yulAssert(variableType, "");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
Scope& AsmAnalyzer::scope(Block const* _block)
|
Scope& AsmAnalyzer::scope(Block const* _block)
|
||||||
@ -545,43 +538,28 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
|
|||||||
_instr == evmasm::Instruction::RETURNDATACOPY ||
|
_instr == evmasm::Instruction::RETURNDATACOPY ||
|
||||||
_instr == evmasm::Instruction::RETURNDATASIZE
|
_instr == evmasm::Instruction::RETURNDATASIZE
|
||||||
) && !m_evmVersion.supportsReturndata())
|
) && !m_evmVersion.supportsReturndata())
|
||||||
{
|
|
||||||
errorForVM("only available for Byzantium-compatible");
|
errorForVM("only available for Byzantium-compatible");
|
||||||
}
|
|
||||||
else if (_instr == evmasm::Instruction::STATICCALL && !m_evmVersion.hasStaticCall())
|
else if (_instr == evmasm::Instruction::STATICCALL && !m_evmVersion.hasStaticCall())
|
||||||
{
|
|
||||||
errorForVM("only available for Byzantium-compatible");
|
errorForVM("only available for Byzantium-compatible");
|
||||||
}
|
|
||||||
else if ((
|
else if ((
|
||||||
_instr == evmasm::Instruction::SHL ||
|
_instr == evmasm::Instruction::SHL ||
|
||||||
_instr == evmasm::Instruction::SHR ||
|
_instr == evmasm::Instruction::SHR ||
|
||||||
_instr == evmasm::Instruction::SAR
|
_instr == evmasm::Instruction::SAR
|
||||||
) && !m_evmVersion.hasBitwiseShifting())
|
) && !m_evmVersion.hasBitwiseShifting())
|
||||||
{
|
|
||||||
errorForVM("only available for Constantinople-compatible");
|
errorForVM("only available for Constantinople-compatible");
|
||||||
}
|
|
||||||
else if (_instr == evmasm::Instruction::CREATE2 && !m_evmVersion.hasCreate2())
|
else if (_instr == evmasm::Instruction::CREATE2 && !m_evmVersion.hasCreate2())
|
||||||
{
|
|
||||||
errorForVM("only available for Constantinople-compatible");
|
errorForVM("only available for Constantinople-compatible");
|
||||||
}
|
|
||||||
else if (_instr == evmasm::Instruction::EXTCODEHASH && !m_evmVersion.hasExtCodeHash())
|
else if (_instr == evmasm::Instruction::EXTCODEHASH && !m_evmVersion.hasExtCodeHash())
|
||||||
{
|
|
||||||
errorForVM("only available for Constantinople-compatible");
|
errorForVM("only available for Constantinople-compatible");
|
||||||
}
|
|
||||||
else if (_instr == evmasm::Instruction::CHAINID && !m_evmVersion.hasChainID())
|
else if (_instr == evmasm::Instruction::CHAINID && !m_evmVersion.hasChainID())
|
||||||
{
|
|
||||||
errorForVM("only available for Istanbul-compatible");
|
errorForVM("only available for Istanbul-compatible");
|
||||||
}
|
|
||||||
else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
|
else if (_instr == evmasm::Instruction::SELFBALANCE && !m_evmVersion.hasSelfBalance())
|
||||||
{
|
|
||||||
errorForVM("only available for Istanbul-compatible");
|
errorForVM("only available for Istanbul-compatible");
|
||||||
}
|
|
||||||
else if (
|
else if (
|
||||||
_instr == evmasm::Instruction::JUMP ||
|
_instr == evmasm::Instruction::JUMP ||
|
||||||
_instr == evmasm::Instruction::JUMPI ||
|
_instr == evmasm::Instruction::JUMPI ||
|
||||||
_instr == evmasm::Instruction::JUMPDEST
|
_instr == evmasm::Instruction::JUMPDEST
|
||||||
)
|
)
|
||||||
{
|
|
||||||
m_errorReporter.error(
|
m_errorReporter.error(
|
||||||
4316_error,
|
4316_error,
|
||||||
Error::Type::SyntaxError,
|
Error::Type::SyntaxError,
|
||||||
@ -590,8 +568,6 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
|
|||||||
"incorrect stack access. Because of that they are disallowed in strict assembly. "
|
"incorrect stack access. Because of that they are disallowed in strict assembly. "
|
||||||
"Use functions, \"switch\", \"if\" or \"for\" statements instead."
|
"Use functions, \"switch\", \"if\" or \"for\" statements instead."
|
||||||
);
|
);
|
||||||
m_success = false;
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
return false;
|
return false;
|
||||||
|
|
||||||
@ -601,12 +577,9 @@ bool AsmAnalyzer::warnOnInstructions(evmasm::Instruction _instr, SourceLocation
|
|||||||
void AsmAnalyzer::typeError(SourceLocation const& _location, string const& _description)
|
void AsmAnalyzer::typeError(SourceLocation const& _location, string const& _description)
|
||||||
{
|
{
|
||||||
m_errorReporter.typeError(7569_error, _location, _description);
|
m_errorReporter.typeError(7569_error, _location, _description);
|
||||||
m_success = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void AsmAnalyzer::declarationError(SourceLocation const& _location, string const& _description)
|
void AsmAnalyzer::declarationError(SourceLocation const& _location, string const& _description)
|
||||||
{
|
{
|
||||||
m_errorReporter.declarationError(9595_error, _location, _description);
|
m_errorReporter.declarationError(9595_error, _location, _description);
|
||||||
m_success = false;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -115,8 +115,6 @@ private:
|
|||||||
void typeError(langutil::SourceLocation const& _location, std::string const& _description);
|
void typeError(langutil::SourceLocation const& _location, std::string const& _description);
|
||||||
void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
|
void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
|
||||||
|
|
||||||
/// Success-flag, can be set to false at any time.
|
|
||||||
bool m_success = true;
|
|
||||||
yul::ExternalIdentifierAccess::Resolver m_resolver;
|
yul::ExternalIdentifierAccess::Resolver m_resolver;
|
||||||
Scope* m_currentScope = nullptr;
|
Scope* m_currentScope = nullptr;
|
||||||
/// Variables that are active at the current point in assembly (as opposed to
|
/// Variables that are active at the current point in assembly (as opposed to
|
||||||
|
Loading…
Reference in New Issue
Block a user