diff options
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/analysis/GlobalContext.cpp | 5 | ||||
-rw-r--r-- | libsolidity/analysis/PostTypeChecker.cpp | 108 | ||||
-rw-r--r-- | libsolidity/analysis/PostTypeChecker.h | 69 | ||||
-rw-r--r-- | libsolidity/analysis/StaticAnalyzer.h | 3 | ||||
-rw-r--r-- | libsolidity/analysis/TypeChecker.cpp | 13 | ||||
-rw-r--r-- | libsolidity/codegen/ExpressionCompiler.cpp | 5 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 9 | ||||
-rw-r--r-- | libsolidity/interface/Exceptions.cpp | 8 | ||||
-rw-r--r-- | libsolidity/interface/Exceptions.h | 6 |
9 files changed, 216 insertions, 10 deletions
diff --git a/libsolidity/analysis/GlobalContext.cpp b/libsolidity/analysis/GlobalContext.cpp index 4f100cd0..069d10f5 100644 --- a/libsolidity/analysis/GlobalContext.cpp +++ b/libsolidity/analysis/GlobalContext.cpp @@ -66,8 +66,9 @@ m_magicVariables(vector<shared_ptr<MagicVariableDeclaration const>>{make_shared< make_shared<FunctionType>(strings{"bytes32", "uint8", "bytes32", "bytes32"}, strings{"address"}, FunctionType::Location::ECRecover)), make_shared<MagicVariableDeclaration>("ripemd160", make_shared<FunctionType>(strings(), strings{"bytes20"}, FunctionType::Location::RIPEMD160, true)), - make_shared<MagicVariableDeclaration>("assert", - make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Assert)), +// Disabled until decision about semantics of assert is made. +// make_shared<MagicVariableDeclaration>("assert", +// make_shared<FunctionType>(strings{"bool"}, strings{}, FunctionType::Location::Assert)), make_shared<MagicVariableDeclaration>("revert", make_shared<FunctionType>(strings(), strings(), FunctionType::Location::Revert))}) { diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp new file mode 100644 index 00000000..cae77c74 --- /dev/null +++ b/libsolidity/analysis/PostTypeChecker.cpp @@ -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; +} diff --git a/libsolidity/analysis/PostTypeChecker.h b/libsolidity/analysis/PostTypeChecker.h new file mode 100644 index 00000000..8774f413 --- /dev/null +++ b/libsolidity/analysis/PostTypeChecker.h @@ -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; +}; + +} +} diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h index b6cf783e..0cb961bd 100644 --- a/libsolidity/analysis/StaticAnalyzer.h +++ b/libsolidity/analysis/StaticAnalyzer.h @@ -36,6 +36,9 @@ namespace solidity /** * The module that performs static analysis on the AST. + * In this context, static analysis is anything that can produce warnings which can help + * programmers write cleaner code. For every warning generated eher, it has to be possible to write + * equivalent code that does generate the warning. */ class StaticAnalyzer: private ASTConstVisitor { diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp index 10406400..93b183a2 100644 --- a/libsolidity/analysis/TypeChecker.cpp +++ b/libsolidity/analysis/TypeChecker.cpp @@ -737,13 +737,16 @@ bool TypeChecker::visit(VariableDeclarationStatement const& _statement) if (auto ref = dynamic_cast<ReferenceType const*>(type(varDecl).get())) { if (ref->dataStoredIn(DataLocation::Storage)) - { warning( varDecl.location(), "Uninitialized storage pointer. Did you mean '<type> memory " + varDecl.name() + "'?" ); - } } + else if (dynamic_cast<MappingType const*>(type(varDecl).get())) + typeError( + varDecl.location(), + "Uninitialized mapping. Mappings cannot be created dynamically, you have to assign them from a state variable." + ); varDecl.accept(*this); return false; } @@ -1587,7 +1590,11 @@ void TypeChecker::endVisit(Literal const& _literal) return; } else - warning(_literal.location(), "This looks like an address but has an invalid checksum."); + warning( + _literal.location(), + "This looks like an address but has an invalid checksum. " + "If this is not used as an address, please prepend '00'." + ); } _literal.annotation().type = Type::forLiteral(_literal); if (!_literal.annotation().type) diff --git a/libsolidity/codegen/ExpressionCompiler.cpp b/libsolidity/codegen/ExpressionCompiler.cpp index aac4c0c6..5192ffa6 100644 --- a/libsolidity/codegen/ExpressionCompiler.cpp +++ b/libsolidity/codegen/ExpressionCompiler.cpp @@ -885,9 +885,8 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) // jump if condition was met m_context << Instruction::ISZERO << Instruction::ISZERO; auto success = m_context.appendConditionalJump(); - // condition was not met, abort - m_context << u256(0) << u256(0); - m_context << Instruction::REVERT; + // condition was not met, flag an error + m_context << Instruction::INVALID; // the success branch m_context << success; break; diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 9d8d872f..594efb1e 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -34,6 +34,7 @@ #include <libsolidity/analysis/TypeChecker.h> #include <libsolidity/analysis/DocStringAnalyser.h> #include <libsolidity/analysis/StaticAnalyzer.h> +#include <libsolidity/analysis/PostTypeChecker.h> #include <libsolidity/analysis/SyntaxChecker.h> #include <libsolidity/codegen/Compiler.h> #include <libsolidity/interface/InterfaceHandler.h> @@ -219,6 +220,14 @@ bool CompilerStack::parse() if (noErrors) { + PostTypeChecker postTypeChecker(m_errors); + for (Source const* source: m_sourceOrder) + if (!postTypeChecker.check(*source->ast)) + noErrors = false; + } + + if (noErrors) + { StaticAnalyzer staticAnalyzer(m_errors); for (Source const* source: m_sourceOrder) if (!staticAnalyzer.analyze(*source->ast)) diff --git a/libsolidity/interface/Exceptions.cpp b/libsolidity/interface/Exceptions.cpp index 20f9dd75..968a24ad 100644 --- a/libsolidity/interface/Exceptions.cpp +++ b/libsolidity/interface/Exceptions.cpp @@ -27,7 +27,8 @@ using namespace std; using namespace dev; using namespace dev::solidity; -Error::Error(Type _type): m_type(_type) +Error::Error(Type _type, SourceLocation const& _location, string const& _description): + m_type(_type) { switch(m_type) { @@ -56,6 +57,11 @@ Error::Error(Type _type): m_type(_type) solAssert(false, ""); break; } + + if (!_location.isEmpty()) + *this << errinfo_sourceLocation(_location); + if (!_description.empty()) + *this << errinfo_comment(_description); } Error::Error(Error::Type _type, const std::string& _description, const SourceLocation& _location): diff --git a/libsolidity/interface/Exceptions.h b/libsolidity/interface/Exceptions.h index 71699da8..0803d8cc 100644 --- a/libsolidity/interface/Exceptions.h +++ b/libsolidity/interface/Exceptions.h @@ -53,7 +53,11 @@ public: Warning }; - explicit Error(Type _type); + explicit Error( + Type _type, + SourceLocation const& _location = SourceLocation(), + std::string const& _description = std::string() + ); Error(Type _type, std::string const& _description, SourceLocation const& _location = SourceLocation()); |