Check for circular constants across contracts.

This commit is contained in:
chriseth 2020-09-29 16:23:45 +02:00
parent c4d8b4fa0e
commit 21dee1c8ba
3 changed files with 36 additions and 10 deletions

View File

@ -38,6 +38,13 @@ bool PostTypeChecker::check(ASTNode const& _astRoot)
return Error::containsOnlyWarnings(m_errorReporter.errors());
}
bool PostTypeChecker::finalize()
{
for (auto& checker: m_checkers)
checker->finalize();
return Error::containsOnlyWarnings(m_errorReporter.errors());
}
bool PostTypeChecker::visit(ContractDefinition const& _contractDefinition)
{
return callVisit(_contractDefinition);
@ -83,6 +90,11 @@ bool PostTypeChecker::visit(Identifier const& _identifier)
return callVisit(_identifier);
}
bool PostTypeChecker::visit(MemberAccess const& _memberAccess)
{
return callVisit(_memberAccess);
}
bool PostTypeChecker::visit(StructDefinition const& _struct)
{
return callVisit(_struct);
@ -110,14 +122,7 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
ConstStateVarCircularReferenceChecker(ErrorReporter& _errorReporter):
Checker(_errorReporter) {}
bool visit(ContractDefinition const&) override
{
solAssert(!m_currentConstVariable, "");
solAssert(m_constVariableDependencies.empty(), "");
return true;
}
void endVisit(ContractDefinition const&) override
void finalize() override
{
solAssert(!m_currentConstVariable, "");
for (auto declaration: m_constVariables)
@ -128,9 +133,12 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
"The value of the constant " + declaration->name() +
" has a cyclic dependency via " + identifier->name() + "."
);
}
m_constVariables.clear();
m_constVariableDependencies.clear();
bool visit(ContractDefinition const&) override
{
solAssert(!m_currentConstVariable, "");
return true;
}
bool visit(VariableDeclaration const& _variable) override
@ -162,6 +170,15 @@ struct ConstStateVarCircularReferenceChecker: public PostTypeChecker::Checker
return true;
}
bool visit(MemberAccess const& _memberAccess) override
{
if (m_currentConstVariable)
if (auto var = dynamic_cast<VariableDeclaration const*>(_memberAccess.annotation().referencedDeclaration))
if (var->isConstant())
m_constVariableDependencies[m_currentConstVariable].insert(var);
return true;
}
VariableDeclaration const* findCycle(VariableDeclaration const& _startingFrom)
{
auto visitor = [&](VariableDeclaration const& _variable, util::CycleDetector<VariableDeclaration>& _cycleDetector, size_t _depth)

View File

@ -54,6 +54,9 @@ public:
{
Checker(langutil::ErrorReporter& _errorReporter):
m_errorReporter(_errorReporter) {}
/// Called after all source units have been visited.
virtual void finalize() {}
protected:
langutil::ErrorReporter& m_errorReporter;
};
@ -63,6 +66,9 @@ public:
bool check(ASTNode const& _astRoot);
/// Called after all source units have been visited.
bool finalize();
private:
bool visit(ContractDefinition const& _contract) override;
void endVisit(ContractDefinition const& _contract) override;
@ -77,6 +83,7 @@ private:
bool visit(FunctionCall const& _functionCall) override;
bool visit(Identifier const& _identifier) override;
bool visit(MemberAccess const& _identifier) override;
bool visit(StructDefinition const& _struct) override;
void endVisit(StructDefinition const& _struct) override;

View File

@ -387,6 +387,8 @@ bool CompilerStack::analyze()
for (Source const* source: m_sourceOrder)
if (source->ast && !postTypeChecker.check(*source->ast))
noErrors = false;
if (!postTypeChecker.finalize())
noErrors = false;
}
// Check that immutable variables are never read in c'tors and assigned