Move event-outside-emit check to PostTypeChecker

refs #7566
This commit is contained in:
Mathias Baumann 2019-12-17 16:04:18 +00:00 committed by chriseth
parent 9f8d49e358
commit 21844aa545
4 changed files with 60 additions and 12 deletions

View File

@ -62,6 +62,21 @@ void PostTypeChecker::endVisit(VariableDeclaration const& _variable)
callEndVisit(_variable); callEndVisit(_variable);
} }
bool PostTypeChecker::visit(EmitStatement const& _emit)
{
return callVisit(_emit);
}
void PostTypeChecker::endVisit(EmitStatement const& _emit)
{
callEndVisit(_emit);
}
bool PostTypeChecker::visit(FunctionCall const& _functionCall)
{
return callVisit(_functionCall);
}
bool PostTypeChecker::visit(Identifier const& _identifier) bool PostTypeChecker::visit(Identifier const& _identifier)
{ {
return callVisit(_identifier); return callVisit(_identifier);
@ -229,6 +244,44 @@ private:
/// Flag indicating whether we are currently inside the invocation of a modifier /// Flag indicating whether we are currently inside the invocation of a modifier
bool m_insideModifierInvocation = false; bool m_insideModifierInvocation = false;
}; };
struct EventOutsideEmitChecker: public PostTypeChecker::Checker
{
EventOutsideEmitChecker(ErrorReporter& _errorReporter):
Checker(_errorReporter) {}
bool visit(EmitStatement const&) override
{
m_insideEmitStatement = true;
return true;
}
void endVisit(EmitStatement const&) override
{
m_insideEmitStatement = true;
}
bool visit(FunctionCall const& _functionCall) override
{
if (_functionCall.annotation().kind != FunctionCallKind::FunctionCall)
return true;
if (FunctionTypePointer const functionType = dynamic_cast<FunctionTypePointer const>(_functionCall.expression().annotation().type))
// Check for event outside of emit statement
if (!m_insideEmitStatement && functionType->kind() == FunctionType::Kind::Event)
m_errorReporter.typeError(
_functionCall.location(),
"Event invocations have to be prefixed by \"emit\"."
);
return true;
}
private:
/// Flag indicating whether we are currently inside an EmitStatement.
bool m_insideEmitStatement = false;
};
} }
PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter)
@ -236,4 +289,5 @@ PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_err
m_checkers.push_back(make_shared<ConstStateVarCircularReferenceChecker>(_errorReporter)); m_checkers.push_back(make_shared<ConstStateVarCircularReferenceChecker>(_errorReporter));
m_checkers.push_back(make_shared<OverrideSpecifierChecker>(_errorReporter)); m_checkers.push_back(make_shared<OverrideSpecifierChecker>(_errorReporter));
m_checkers.push_back(make_shared<ModifierContextChecker>(_errorReporter)); m_checkers.push_back(make_shared<ModifierContextChecker>(_errorReporter));
m_checkers.push_back(make_shared<EventOutsideEmitChecker>(_errorReporter));
} }

View File

@ -37,6 +37,7 @@ namespace solidity::frontend
* - whether there are circular references in constant state variables * - whether there are circular references in constant state variables
* - whether override specifiers are actually contracts * - whether override specifiers are actually contracts
* - whether a modifier is in a function header * - whether a modifier is in a function header
* - whether an event is used outside of an emit statement
* *
* When adding a new checker, make sure a visitor that forwards calls that your * When adding a new checker, make sure a visitor that forwards calls that your
* checker uses exists in PostTypeChecker. Add missing ones. * checker uses exists in PostTypeChecker. Add missing ones.
@ -68,6 +69,11 @@ private:
bool visit(VariableDeclaration const& _variable) override; bool visit(VariableDeclaration const& _variable) override;
void endVisit(VariableDeclaration const& _variable) override; void endVisit(VariableDeclaration const& _variable) override;
bool visit(EmitStatement const& _emit) override;
void endVisit(EmitStatement const& _emit) override;
bool visit(FunctionCall const& _functionCall) override;
bool visit(Identifier const& _identifier) override; bool visit(Identifier const& _identifier) override;
bool visit(ModifierInvocation const& _modifierInvocation) override; bool visit(ModifierInvocation const& _modifierInvocation) override;

View File

@ -981,7 +981,6 @@ void TypeChecker::endVisit(EmitStatement const& _emit)
dynamic_cast<FunctionType const&>(*type(_emit.eventCall().expression())).kind() != FunctionType::Kind::Event dynamic_cast<FunctionType const&>(*type(_emit.eventCall().expression())).kind() != FunctionType::Kind::Event
) )
m_errorReporter.typeError(_emit.eventCall().expression().location(), "Expression has to be an event invocation."); m_errorReporter.typeError(_emit.eventCall().expression().location(), "Expression has to be an event invocation.");
m_insideEmitStatement = false;
} }
namespace namespace
@ -1715,13 +1714,6 @@ void TypeChecker::typeCheckFunctionCall(
"\"staticcall\" is not supported by the VM version." "\"staticcall\" is not supported by the VM version."
); );
// Check for event outside of emit statement
if (!m_insideEmitStatement && _functionType->kind() == FunctionType::Kind::Event)
m_errorReporter.typeError(
_functionCall.location(),
"Event invocations have to be prefixed by \"emit\"."
);
// Perform standard function call type checking // Perform standard function call type checking
typeCheckFunctionGeneralChecks(_functionCall, _functionType); typeCheckFunctionGeneralChecks(_functionCall, _functionType);
} }

View File

@ -126,7 +126,6 @@ private:
bool visit(WhileStatement const& _whileStatement) override; bool visit(WhileStatement const& _whileStatement) override;
bool visit(ForStatement const& _forStatement) override; bool visit(ForStatement const& _forStatement) override;
void endVisit(Return const& _return) override; void endVisit(Return const& _return) override;
bool visit(EmitStatement const&) override { m_insideEmitStatement = true; return true; }
void endVisit(EmitStatement const& _emit) override; void endVisit(EmitStatement const& _emit) override;
bool visit(VariableDeclarationStatement const& _variable) override; bool visit(VariableDeclarationStatement const& _variable) override;
void endVisit(ExpressionStatement const& _statement) override; void endVisit(ExpressionStatement const& _statement) override;
@ -164,9 +163,6 @@ private:
langutil::EVMVersion m_evmVersion; langutil::EVMVersion m_evmVersion;
/// Flag indicating whether we are currently inside an EmitStatement.
bool m_insideEmitStatement = false;
/// Flag indicating whether we are currently inside a StructDefinition. /// Flag indicating whether we are currently inside a StructDefinition.
bool m_insideStruct = false; bool m_insideStruct = false;