forked from ethereum/solidity
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Merge pull request ethereum#1733 from ethereum/selfReferentialConstant
Detect cyclic dependencies between constants.
- Loading branch information
Showing
6 changed files
with
231 additions
and
8 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,108 @@ | ||
/* | ||
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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#include <libsolidity/analysis/PostTypeChecker.h> | ||
#include <libsolidity/ast/AST.h> | ||
#include <libsolidity/analysis/SemVerHandler.h> | ||
#include <libsolidity/interface/Version.h> | ||
|
||
#include <boost/range/adaptor/map.hpp> | ||
|
||
#include <memory> | ||
|
||
using namespace std; | ||
using namespace dev; | ||
using namespace dev::solidity; | ||
|
||
|
||
bool PostTypeChecker::check(ASTNode const& _astRoot) | ||
{ | ||
_astRoot.accept(*this); | ||
return Error::containsOnlyWarnings(m_errors); | ||
} | ||
|
||
void PostTypeChecker::typeError(SourceLocation const& _location, std::string const& _description) | ||
{ | ||
auto err = make_shared<Error>(Error::Type::TypeError); | ||
*err << | ||
errinfo_sourceLocation(_location) << | ||
errinfo_comment(_description); | ||
|
||
m_errors.push_back(err); | ||
} | ||
|
||
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)) | ||
typeError(declaration->location(), "The value of the constant " + declaration->name() + " has a cyclic dependency via " + identifier->name() + "."); | ||
} | ||
|
||
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<VariableDeclaration const*>(_identifier.annotation().referencedDeclaration)) | ||
if (var->isConstant()) | ||
m_constVariableDependencies[m_currentConstVariable].insert(var); | ||
return true; | ||
} | ||
|
||
VariableDeclaration const* PostTypeChecker::findCycle( | ||
VariableDeclaration const* _startingFrom, | ||
set<VariableDeclaration const*> const& _seen | ||
) | ||
{ | ||
if (_seen.count(_startingFrom)) | ||
return _startingFrom; | ||
else if (m_constVariableDependencies.count(_startingFrom)) | ||
{ | ||
set<VariableDeclaration const*> seen(_seen); | ||
seen.insert(_startingFrom); | ||
for (auto v: m_constVariableDependencies[_startingFrom]) | ||
if (findCycle(v, seen)) | ||
return v; | ||
} | ||
return nullptr; | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,69 @@ | ||
/* | ||
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 <http://www.gnu.org/licenses/>. | ||
*/ | ||
|
||
#pragma once | ||
|
||
#include <libsolidity/analysis/TypeChecker.h> | ||
#include <libsolidity/ast/Types.h> | ||
#include <libsolidity/ast/ASTAnnotations.h> | ||
#include <libsolidity/ast/ASTForward.h> | ||
#include <libsolidity/ast/ASTVisitor.h> | ||
|
||
namespace dev | ||
{ | ||
namespace solidity | ||
{ | ||
|
||
/** | ||
* This module performs analyses on the AST that are done after type checking and assignments of types: | ||
* - whether there are circular references in constant state variables | ||
* @TODO factor out each use-case into an individual class (but do the traversal only once) | ||
*/ | ||
class PostTypeChecker: private ASTConstVisitor | ||
{ | ||
public: | ||
/// @param _errors the reference to the list of errors and warnings to add them found during type checking. | ||
PostTypeChecker(ErrorList& _errors): m_errors(_errors) {} | ||
|
||
bool check(ASTNode const& _astRoot); | ||
|
||
private: | ||
/// Adds a new error to the list of errors. | ||
void typeError(SourceLocation const& _location, std::string const& _description); | ||
|
||
virtual bool visit(ContractDefinition const& _contract) override; | ||
virtual void endVisit(ContractDefinition const& _contract) override; | ||
|
||
virtual bool visit(VariableDeclaration const& _declaration) override; | ||
virtual void endVisit(VariableDeclaration const& _declaration) override; | ||
|
||
virtual bool visit(Identifier const& _identifier) override; | ||
|
||
VariableDeclaration const* findCycle( | ||
VariableDeclaration const* _startingFrom, | ||
std::set<VariableDeclaration const*> const& _seen = {} | ||
); | ||
|
||
ErrorList& m_errors; | ||
|
||
VariableDeclaration const* m_currentConstVariable = nullptr; | ||
std::vector<VariableDeclaration const*> m_constVariables; ///< Required for determinism. | ||
std::map<VariableDeclaration const*, std::set<VariableDeclaration const*>> m_constVariableDependencies; | ||
}; | ||
|
||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters