diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp index 58eb9d79a..a18ee4320 100644 --- a/libsolidity/analysis/PostTypeChecker.cpp +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -62,6 +62,21 @@ void PostTypeChecker::endVisit(VariableDeclaration const& _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) { return callVisit(_identifier); @@ -229,6 +244,44 @@ private: /// Flag indicating whether we are currently inside the invocation of a modifier 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(_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) @@ -236,4 +289,5 @@ PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_err m_checkers.push_back(make_shared(_errorReporter)); m_checkers.push_back(make_shared(_errorReporter)); m_checkers.push_back(make_shared(_errorReporter)); + m_checkers.push_back(make_shared(_errorReporter)); } diff --git a/libsolidity/analysis/PostTypeChecker.h b/libsolidity/analysis/PostTypeChecker.h index 325d01ebb..7a48dfb22 100644 --- a/libsolidity/analysis/PostTypeChecker.h +++ b/libsolidity/analysis/PostTypeChecker.h @@ -37,6 +37,7 @@ namespace solidity::frontend * - whether there are circular references in constant state variables * - whether override specifiers are actually contracts * - 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 * checker uses exists in PostTypeChecker. Add missing ones. @@ -68,6 +69,11 @@ private: bool visit(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(ModifierInvocation const& _modifierInvocation) override; diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index ea0c976e0..6315ac15f 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -981,7 +981,6 @@ void TypeChecker::endVisit(EmitStatement const& _emit) dynamic_cast(*type(_emit.eventCall().expression())).kind() != FunctionType::Kind::Event ) m_errorReporter.typeError(_emit.eventCall().expression().location(), "Expression has to be an event invocation."); - m_insideEmitStatement = false; } namespace @@ -1715,13 +1714,6 @@ void TypeChecker::typeCheckFunctionCall( "\"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 typeCheckFunctionGeneralChecks(_functionCall, _functionType); } diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h index 455b60fb8..1e30ac1b5 100644 --- a/libsolidity/analysis/TypeChecker.h +++ b/libsolidity/analysis/TypeChecker.h @@ -126,7 +126,6 @@ private: bool visit(WhileStatement const& _whileStatement) override; bool visit(ForStatement const& _forStatement) override; void endVisit(Return const& _return) override; - bool visit(EmitStatement const&) override { m_insideEmitStatement = true; return true; } void endVisit(EmitStatement const& _emit) override; bool visit(VariableDeclarationStatement const& _variable) override; void endVisit(ExpressionStatement const& _statement) override; @@ -164,9 +163,6 @@ private: 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. bool m_insideStruct = false;