mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
parent
21844aa545
commit
2179562785
@ -82,6 +82,16 @@ bool PostTypeChecker::visit(Identifier const& _identifier)
|
||||
return callVisit(_identifier);
|
||||
}
|
||||
|
||||
bool PostTypeChecker::visit(StructDefinition const& _struct)
|
||||
{
|
||||
return callVisit(_struct);
|
||||
}
|
||||
|
||||
void PostTypeChecker::endVisit(StructDefinition const& _struct)
|
||||
{
|
||||
callEndVisit(_struct);
|
||||
}
|
||||
|
||||
bool PostTypeChecker::visit(ModifierInvocation const& _modifierInvocation)
|
||||
{
|
||||
return callVisit(_modifierInvocation);
|
||||
@ -282,6 +292,55 @@ private:
|
||||
bool m_insideEmitStatement = false;
|
||||
};
|
||||
|
||||
struct NoVariablesInInterfaceChecker: public PostTypeChecker::Checker
|
||||
{
|
||||
NoVariablesInInterfaceChecker(ErrorReporter& _errorReporter):
|
||||
Checker(_errorReporter)
|
||||
{}
|
||||
|
||||
bool visit(VariableDeclaration const& _variable) override
|
||||
{
|
||||
// Forbid any variable declarations inside interfaces unless they are part of
|
||||
// * a function's input/output parameters,
|
||||
// * or inside of a struct definition.
|
||||
if (
|
||||
m_scope && m_scope->isInterface()
|
||||
&& !_variable.isCallableOrCatchParameter()
|
||||
&& !m_insideStruct
|
||||
)
|
||||
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool visit(ContractDefinition const& _contract) override
|
||||
{
|
||||
m_scope = &_contract;
|
||||
return true;
|
||||
}
|
||||
|
||||
void endVisit(ContractDefinition const&) override
|
||||
{
|
||||
m_scope = nullptr;
|
||||
}
|
||||
|
||||
bool visit(StructDefinition const&) override
|
||||
{
|
||||
solAssert(m_insideStruct >= 0, "");
|
||||
m_insideStruct++;
|
||||
return true;
|
||||
}
|
||||
|
||||
void endVisit(StructDefinition const&) override
|
||||
{
|
||||
m_insideStruct--;
|
||||
solAssert(m_insideStruct >= 0, "");
|
||||
}
|
||||
private:
|
||||
ContractDefinition const* m_scope = nullptr;
|
||||
/// Flag indicating whether we are currently inside a StructDefinition.
|
||||
int m_insideStruct = 0;
|
||||
};
|
||||
}
|
||||
|
||||
PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter)
|
||||
@ -290,4 +349,5 @@ PostTypeChecker::PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_err
|
||||
m_checkers.push_back(make_shared<OverrideSpecifierChecker>(_errorReporter));
|
||||
m_checkers.push_back(make_shared<ModifierContextChecker>(_errorReporter));
|
||||
m_checkers.push_back(make_shared<EventOutsideEmitChecker>(_errorReporter));
|
||||
m_checkers.push_back(make_shared<NoVariablesInInterfaceChecker>(_errorReporter));
|
||||
}
|
||||
|
@ -38,6 +38,7 @@ namespace solidity::frontend
|
||||
* - whether override specifiers are actually contracts
|
||||
* - whether a modifier is in a function header
|
||||
* - whether an event is used outside of an emit statement
|
||||
* - whether a variable is declared in a interface
|
||||
*
|
||||
* When adding a new checker, make sure a visitor that forwards calls that your
|
||||
* checker uses exists in PostTypeChecker. Add missing ones.
|
||||
@ -76,6 +77,9 @@ private:
|
||||
|
||||
bool visit(Identifier const& _identifier) override;
|
||||
|
||||
bool visit(StructDefinition const& _struct) override;
|
||||
void endVisit(StructDefinition const& _struct) override;
|
||||
|
||||
bool visit(ModifierInvocation const& _modifierInvocation) override;
|
||||
void endVisit(ModifierInvocation const& _modifierInvocation) override;
|
||||
|
||||
|
@ -317,10 +317,7 @@ bool TypeChecker::visit(StructDefinition const& _struct)
|
||||
if (CycleDetector<StructDefinition>(visitor).run(_struct) != nullptr)
|
||||
m_errorReporter.fatalTypeError(_struct.location(), "Recursive struct definition.");
|
||||
|
||||
bool insideStruct = true;
|
||||
swap(insideStruct, m_insideStruct);
|
||||
ASTNode::listAccept(_struct.members(), *this);
|
||||
m_insideStruct = insideStruct;
|
||||
|
||||
return false;
|
||||
}
|
||||
@ -451,16 +448,6 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
|
||||
bool TypeChecker::visit(VariableDeclaration const& _variable)
|
||||
{
|
||||
// Forbid any variable declarations inside interfaces unless they are part of
|
||||
// * a function's input/output parameters,
|
||||
// * or inside of a struct definition.
|
||||
if (
|
||||
m_scope->isInterface()
|
||||
&& !_variable.isCallableOrCatchParameter()
|
||||
&& !m_insideStruct
|
||||
)
|
||||
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
|
||||
|
||||
if (_variable.typeName())
|
||||
_variable.typeName()->accept(*this);
|
||||
|
||||
|
@ -163,9 +163,6 @@ private:
|
||||
|
||||
langutil::EVMVersion m_evmVersion;
|
||||
|
||||
/// Flag indicating whether we are currently inside a StructDefinition.
|
||||
bool m_insideStruct = false;
|
||||
|
||||
langutil::ErrorReporter& m_errorReporter;
|
||||
};
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user