/* This file is part of solidity. solidity is free software: you can redistribute it and/or modify it under the terms of the GNU General Public License as published by the Free Software Foundation, either version 3 of the License, or (at your option) any later version. solidity is distributed in the hope that it will be useful, but WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more details. You should have received a copy of the GNU General Public License along with solidity. If not, see . */ #include #include #include #include #include #include #include using namespace std; using namespace dev; using namespace dev::solidity; bool PostTypeChecker::check(ASTNode const& _astRoot) { _astRoot.accept(*this); return Error::containsOnlyWarnings(m_errorReporter.errors()); } bool PostTypeChecker::visit(ContractDefinition const&) { solAssert(!m_currentConstVariable, ""); solAssert(m_constVariableDependencies.empty(), ""); return true; } void PostTypeChecker::endVisit(ContractDefinition const&) { solAssert(!m_currentConstVariable, ""); for (auto declaration: m_constVariables) if (auto identifier = findCycle(declaration)) m_errorReporter.typeError( declaration->location(), "The value of the constant " + declaration->name() + " has a cyclic dependency via " + identifier->name() + "." ); m_constVariables.clear(); m_constVariableDependencies.clear(); } bool PostTypeChecker::visit(VariableDeclaration const& _variable) { solAssert(!m_currentConstVariable, ""); if (_variable.isConstant()) { m_currentConstVariable = &_variable; m_constVariables.push_back(&_variable); } return true; } void PostTypeChecker::endVisit(VariableDeclaration const& _variable) { if (_variable.isConstant()) { solAssert(m_currentConstVariable == &_variable, ""); m_currentConstVariable = nullptr; } } bool PostTypeChecker::visit(Identifier const& _identifier) { if (m_currentConstVariable) if (auto var = dynamic_cast(_identifier.annotation().referencedDeclaration)) if (var->isConstant()) m_constVariableDependencies[m_currentConstVariable].insert(var); return true; } VariableDeclaration const* PostTypeChecker::findCycle( VariableDeclaration const* _startingFrom, set const& _seen ) { if (_seen.count(_startingFrom)) return _startingFrom; else if (m_constVariableDependencies.count(_startingFrom)) { set seen(_seen); seen.insert(_startingFrom); for (auto v: m_constVariableDependencies[_startingFrom]) if (findCycle(v, seen)) return v; } return nullptr; }