aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/analysis
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/analysis')
-rw-r--r--libsolidity/analysis/ConstantEvaluator.cpp2
-rw-r--r--libsolidity/analysis/ConstantEvaluator.h10
-rw-r--r--libsolidity/analysis/ContractLevelChecker.cpp463
-rw-r--r--libsolidity/analysis/ContractLevelChecker.h87
-rw-r--r--libsolidity/analysis/ControlFlowAnalyzer.cpp2
-rw-r--r--libsolidity/analysis/ControlFlowAnalyzer.h6
-rw-r--r--libsolidity/analysis/ControlFlowBuilder.h28
-rw-r--r--libsolidity/analysis/ControlFlowGraph.cpp3
-rw-r--r--libsolidity/analysis/ControlFlowGraph.h10
-rw-r--r--libsolidity/analysis/DocStringAnalyser.cpp3
-rw-r--r--libsolidity/analysis/DocStringAnalyser.h19
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.cpp15
-rw-r--r--libsolidity/analysis/NameAndTypeResolver.h19
-rw-r--r--libsolidity/analysis/PostTypeChecker.cpp3
-rw-r--r--libsolidity/analysis/PostTypeChecker.h24
-rw-r--r--libsolidity/analysis/ReferencesResolver.cpp26
-rw-r--r--libsolidity/analysis/ReferencesResolver.h55
-rw-r--r--libsolidity/analysis/SemVerHandler.h3
-rw-r--r--libsolidity/analysis/StaticAnalyzer.cpp3
-rw-r--r--libsolidity/analysis/StaticAnalyzer.h33
-rw-r--r--libsolidity/analysis/SyntaxChecker.cpp3
-rw-r--r--libsolidity/analysis/SyntaxChecker.h51
-rw-r--r--libsolidity/analysis/TypeChecker.cpp542
-rw-r--r--libsolidity/analysis/TypeChecker.h95
-rw-r--r--libsolidity/analysis/ViewPureChecker.cpp35
-rw-r--r--libsolidity/analysis/ViewPureChecker.h42
26 files changed, 888 insertions, 694 deletions
diff --git a/libsolidity/analysis/ConstantEvaluator.cpp b/libsolidity/analysis/ConstantEvaluator.cpp
index f9b00927..9d041ce5 100644
--- a/libsolidity/analysis/ConstantEvaluator.cpp
+++ b/libsolidity/analysis/ConstantEvaluator.cpp
@@ -22,7 +22,7 @@
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
using namespace std;
using namespace dev;
diff --git a/libsolidity/analysis/ConstantEvaluator.h b/libsolidity/analysis/ConstantEvaluator.h
index ac3a24a1..23ca3628 100644
--- a/libsolidity/analysis/ConstantEvaluator.h
+++ b/libsolidity/analysis/ConstantEvaluator.h
@@ -24,12 +24,16 @@
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
class TypeChecker;
/**
@@ -39,7 +43,7 @@ class ConstantEvaluator: private ASTConstVisitor
{
public:
ConstantEvaluator(
- ErrorReporter& _errorReporter,
+ langutil::ErrorReporter& _errorReporter,
size_t _newDepth = 0,
std::shared_ptr<std::map<ASTNode const*, TypePointer>> _types = std::make_shared<std::map<ASTNode const*, TypePointer>>()
):
@@ -61,7 +65,7 @@ private:
void setType(ASTNode const& _node, TypePointer const& _type);
TypePointer type(ASTNode const& _node);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Current recursion depth.
size_t m_depth = 0;
std::shared_ptr<std::map<ASTNode const*, TypePointer>> m_types;
diff --git a/libsolidity/analysis/ContractLevelChecker.cpp b/libsolidity/analysis/ContractLevelChecker.cpp
new file mode 100644
index 00000000..6dc564de
--- /dev/null
+++ b/libsolidity/analysis/ContractLevelChecker.cpp
@@ -0,0 +1,463 @@
+/*
+ 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/>.
+*/
+/**
+ * Component that verifies overloads, abstract contracts, function clashes and others
+ * checks at contract or function level.
+ */
+
+#include <libsolidity/analysis/ContractLevelChecker.h>
+#include <libsolidity/ast/AST.h>
+
+#include <liblangutil/ErrorReporter.h>
+
+#include <boost/range/adaptor/reversed.hpp>
+
+
+using namespace std;
+using namespace dev;
+using namespace langutil;
+using namespace dev::solidity;
+
+
+bool ContractLevelChecker::check(ContractDefinition const& _contract)
+{
+ checkDuplicateFunctions(_contract);
+ checkDuplicateEvents(_contract);
+ checkIllegalOverrides(_contract);
+ checkAbstractFunctions(_contract);
+ checkBaseConstructorArguments(_contract);
+ checkConstructor(_contract);
+ checkFallbackFunction(_contract);
+ checkExternalTypeClashes(_contract);
+ checkHashCollisions(_contract);
+ checkLibraryRequirements(_contract);
+
+ return Error::containsOnlyWarnings(m_errorReporter.errors());
+}
+
+void ContractLevelChecker::checkDuplicateFunctions(ContractDefinition const& _contract)
+{
+ /// Checks that two functions with the same name defined in this contract have different
+ /// argument types and that there is at most one constructor.
+ map<string, vector<FunctionDefinition const*>> functions;
+ FunctionDefinition const* constructor = nullptr;
+ FunctionDefinition const* fallback = nullptr;
+ for (FunctionDefinition const* function: _contract.definedFunctions())
+ if (function->isConstructor())
+ {
+ if (constructor)
+ m_errorReporter.declarationError(
+ function->location(),
+ SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
+ "More than one constructor defined."
+ );
+ constructor = function;
+ }
+ else if (function->isFallback())
+ {
+ if (fallback)
+ m_errorReporter.declarationError(
+ function->location(),
+ SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
+ "Only one fallback function is allowed."
+ );
+ fallback = function;
+ }
+ else
+ {
+ solAssert(!function->name().empty(), "");
+ functions[function->name()].push_back(function);
+ }
+
+ findDuplicateDefinitions(functions, "Function with same name and arguments defined twice.");
+}
+
+void ContractLevelChecker::checkDuplicateEvents(ContractDefinition const& _contract)
+{
+ /// Checks that two events with the same name defined in this contract have different
+ /// argument types
+ map<string, vector<EventDefinition const*>> events;
+ for (EventDefinition const* event: _contract.events())
+ events[event->name()].push_back(event);
+
+ findDuplicateDefinitions(events, "Event with same name and arguments defined twice.");
+}
+
+template <class T>
+void ContractLevelChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions, string _message)
+{
+ for (auto const& it: _definitions)
+ {
+ vector<T> const& overloads = it.second;
+ set<size_t> reported;
+ for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
+ {
+ SecondarySourceLocation ssl;
+
+ for (size_t j = i + 1; j < overloads.size(); ++j)
+ if (FunctionType(*overloads[i]).asCallableFunction(false)->hasEqualParameterTypes(
+ *FunctionType(*overloads[j]).asCallableFunction(false))
+ )
+ {
+ ssl.append("Other declaration is here:", overloads[j]->location());
+ reported.insert(j);
+ }
+
+ if (ssl.infos.size() > 0)
+ {
+ ssl.limitSize(_message);
+
+ m_errorReporter.declarationError(
+ overloads[i]->location(),
+ ssl,
+ _message
+ );
+ }
+ }
+ }
+}
+
+void ContractLevelChecker::checkIllegalOverrides(ContractDefinition const& _contract)
+{
+ // TODO unify this at a later point. for this we need to put the constness and the access specifier
+ // into the types
+ map<string, vector<FunctionDefinition const*>> functions;
+ map<string, ModifierDefinition const*> modifiers;
+
+ // We search from derived to base, so the stored item causes the error.
+ for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
+ {
+ for (FunctionDefinition const* function: contract->definedFunctions())
+ {
+ if (function->isConstructor())
+ continue; // constructors can neither be overridden nor override anything
+ string const& name = function->name();
+ if (modifiers.count(name))
+ m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier.");
+
+ for (FunctionDefinition const* overriding: functions[name])
+ checkFunctionOverride(*overriding, *function);
+
+ functions[name].push_back(function);
+ }
+ for (ModifierDefinition const* modifier: contract->functionModifiers())
+ {
+ string const& name = modifier->name();
+ ModifierDefinition const*& override = modifiers[name];
+ if (!override)
+ override = modifier;
+ else if (ModifierType(*override) != ModifierType(*modifier))
+ m_errorReporter.typeError(override->location(), "Override changes modifier signature.");
+ if (!functions[name].empty())
+ m_errorReporter.typeError(override->location(), "Override changes modifier to function.");
+ }
+ }
+}
+
+void ContractLevelChecker::checkFunctionOverride(FunctionDefinition const& _function, FunctionDefinition const& _super)
+{
+ FunctionTypePointer functionType = FunctionType(_function).asCallableFunction(false);
+ FunctionTypePointer superType = FunctionType(_super).asCallableFunction(false);
+
+ if (!functionType->hasEqualParameterTypes(*superType))
+ return;
+ if (!functionType->hasEqualReturnTypes(*superType))
+ overrideError(_function, _super, "Overriding function return types differ.");
+
+ if (!_function.annotation().superFunction)
+ _function.annotation().superFunction = &_super;
+
+ if (_function.visibility() != _super.visibility())
+ {
+ // Visibility change from external to public is fine.
+ // Any other change is disallowed.
+ if (!(
+ _super.visibility() == FunctionDefinition::Visibility::External &&
+ _function.visibility() == FunctionDefinition::Visibility::Public
+ ))
+ overrideError(_function, _super, "Overriding function visibility differs.");
+ }
+ if (_function.stateMutability() != _super.stateMutability())
+ overrideError(
+ _function,
+ _super,
+ "Overriding function changes state mutability from \"" +
+ stateMutabilityToString(_super.stateMutability()) +
+ "\" to \"" +
+ stateMutabilityToString(_function.stateMutability()) +
+ "\"."
+ );
+}
+
+void ContractLevelChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message)
+{
+ m_errorReporter.typeError(
+ function.location(),
+ SecondarySourceLocation().append("Overridden function is here:", super.location()),
+ message
+ );
+}
+
+void ContractLevelChecker::checkAbstractFunctions(ContractDefinition const& _contract)
+{
+ // Mapping from name to function definition (exactly one per argument type equality class) and
+ // flag to indicate whether it is fully implemented.
+ using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
+ map<string, vector<FunTypeAndFlag>> functions;
+
+ auto registerFunction = [&](Declaration const& _declaration, FunctionTypePointer const& _type, bool _implemented)
+ {
+ auto& overloads = functions[_declaration.name()];
+ auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
+ {
+ return _type->hasEqualParameterTypes(*_funAndFlag.first);
+ });
+ if (it == overloads.end())
+ overloads.push_back(make_pair(_type, _implemented));
+ else if (it->second)
+ {
+ if (!_implemented)
+ m_errorReporter.typeError(_declaration.location(), "Redeclaring an already implemented function as abstract");
+ }
+ else if (_implemented)
+ it->second = true;
+ };
+
+ // Search from base to derived, collect all functions and update
+ // the 'implemented' flag.
+ for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
+ {
+ for (VariableDeclaration const* v: contract->stateVariables())
+ if (v->isPartOfExternalInterface())
+ registerFunction(*v, make_shared<FunctionType>(*v), true);
+
+ for (FunctionDefinition const* function: contract->definedFunctions())
+ if (!function->isConstructor())
+ registerFunction(
+ *function,
+ make_shared<FunctionType>(*function)->asCallableFunction(false),
+ function->isImplemented()
+ );
+ }
+
+ // Set to not fully implemented if at least one flag is false.
+ for (auto const& it: functions)
+ for (auto const& funAndFlag: it.second)
+ if (!funAndFlag.second)
+ {
+ FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(&funAndFlag.first->declaration());
+ solAssert(function, "");
+ _contract.annotation().unimplementedFunctions.push_back(function);
+ break;
+ }
+}
+
+
+void ContractLevelChecker::checkBaseConstructorArguments(ContractDefinition const& _contract)
+{
+ vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
+
+ // Determine the arguments that are used for the base constructors.
+ for (ContractDefinition const* contract: bases)
+ {
+ if (FunctionDefinition const* constructor = contract->constructor())
+ for (auto const& modifier: constructor->modifiers())
+ if (auto baseContract = dynamic_cast<ContractDefinition const*>(
+ modifier->name()->annotation().referencedDeclaration
+ ))
+ {
+ if (modifier->arguments())
+ {
+ if (baseContract->constructor())
+ annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
+ }
+ else
+ m_errorReporter.declarationError(
+ modifier->location(),
+ "Modifier-style base constructor call without arguments."
+ );
+ }
+
+ for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
+ {
+ ContractDefinition const* baseContract = dynamic_cast<ContractDefinition const*>(
+ base->name().annotation().referencedDeclaration
+ );
+ solAssert(baseContract, "");
+
+ if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
+ annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
+ }
+ }
+
+ // check that we get arguments for all base constructors that need it.
+ // If not mark the contract as abstract (not fully implemented)
+ for (ContractDefinition const* contract: bases)
+ if (FunctionDefinition const* constructor = contract->constructor())
+ if (contract != &_contract && !constructor->parameters().empty())
+ if (!_contract.annotation().baseConstructorArguments.count(constructor))
+ _contract.annotation().unimplementedFunctions.push_back(constructor);
+}
+
+void ContractLevelChecker::annotateBaseConstructorArguments(
+ ContractDefinition const& _currentContract,
+ FunctionDefinition const* _baseConstructor,
+ ASTNode const* _argumentNode
+)
+{
+ solAssert(_baseConstructor, "");
+ solAssert(_argumentNode, "");
+
+ auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
+ std::make_pair(_baseConstructor, _argumentNode)
+ );
+ if (!insertionResult.second)
+ {
+ ASTNode const* previousNode = insertionResult.first->second;
+
+ SourceLocation const* mainLocation = nullptr;
+ SecondarySourceLocation ssl;
+
+ if (
+ _currentContract.location().contains(previousNode->location()) ||
+ _currentContract.location().contains(_argumentNode->location())
+ )
+ {
+ mainLocation = &previousNode->location();
+ ssl.append("Second constructor call is here:", _argumentNode->location());
+ }
+ else
+ {
+ mainLocation = &_currentContract.location();
+ ssl.append("First constructor call is here: ", _argumentNode->location());
+ ssl.append("Second constructor call is here: ", previousNode->location());
+ }
+
+ m_errorReporter.declarationError(
+ *mainLocation,
+ ssl,
+ "Base constructor arguments given twice."
+ );
+ }
+
+}
+
+void ContractLevelChecker::checkConstructor(ContractDefinition const& _contract)
+{
+ FunctionDefinition const* constructor = _contract.constructor();
+ if (!constructor)
+ return;
+
+ if (!constructor->returnParameters().empty())
+ m_errorReporter.typeError(constructor->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
+ if (constructor->stateMutability() != StateMutability::NonPayable && constructor->stateMutability() != StateMutability::Payable)
+ m_errorReporter.typeError(
+ constructor->location(),
+ "Constructor must be payable or non-payable, but is \"" +
+ stateMutabilityToString(constructor->stateMutability()) +
+ "\"."
+ );
+ if (constructor->visibility() != FunctionDefinition::Visibility::Public && constructor->visibility() != FunctionDefinition::Visibility::Internal)
+ m_errorReporter.typeError(constructor->location(), "Constructor must be public or internal.");
+}
+
+void ContractLevelChecker::checkFallbackFunction(ContractDefinition const& _contract)
+{
+ FunctionDefinition const* fallback = _contract.fallbackFunction();
+ if (!fallback)
+ return;
+
+ if (_contract.isLibrary())
+ m_errorReporter.typeError(fallback->location(), "Libraries cannot have fallback functions.");
+ if (fallback->stateMutability() != StateMutability::NonPayable && fallback->stateMutability() != StateMutability::Payable)
+ m_errorReporter.typeError(
+ fallback->location(),
+ "Fallback function must be payable or non-payable, but is \"" +
+ stateMutabilityToString(fallback->stateMutability()) +
+ "\"."
+ );
+ if (!fallback->parameters().empty())
+ m_errorReporter.typeError(fallback->parameterList().location(), "Fallback function cannot take parameters.");
+ if (!fallback->returnParameters().empty())
+ m_errorReporter.typeError(fallback->returnParameterList()->location(), "Fallback function cannot return values.");
+ if (fallback->visibility() != FunctionDefinition::Visibility::External)
+ m_errorReporter.typeError(fallback->location(), "Fallback function must be defined as \"external\".");
+}
+
+void ContractLevelChecker::checkExternalTypeClashes(ContractDefinition const& _contract)
+{
+ map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
+ for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
+ {
+ for (FunctionDefinition const* f: contract->definedFunctions())
+ if (f->isPartOfExternalInterface())
+ {
+ auto functionType = make_shared<FunctionType>(*f);
+ // under non error circumstances this should be true
+ if (functionType->interfaceFunctionType())
+ externalDeclarations[functionType->externalSignature()].push_back(
+ make_pair(f, functionType->asCallableFunction(false))
+ );
+ }
+ for (VariableDeclaration const* v: contract->stateVariables())
+ if (v->isPartOfExternalInterface())
+ {
+ auto functionType = make_shared<FunctionType>(*v);
+ // under non error circumstances this should be true
+ if (functionType->interfaceFunctionType())
+ externalDeclarations[functionType->externalSignature()].push_back(
+ make_pair(v, functionType->asCallableFunction(false))
+ );
+ }
+ }
+ for (auto const& it: externalDeclarations)
+ for (size_t i = 0; i < it.second.size(); ++i)
+ for (size_t j = i + 1; j < it.second.size(); ++j)
+ if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second))
+ m_errorReporter.typeError(
+ it.second[j].first->location(),
+ "Function overload clash during conversion to external types for arguments."
+ );
+}
+
+void ContractLevelChecker::checkHashCollisions(ContractDefinition const& _contract)
+{
+ set<FixedHash<4>> hashes;
+ for (auto const& it: _contract.interfaceFunctionList())
+ {
+ FixedHash<4> const& hash = it.first;
+ if (hashes.count(hash))
+ m_errorReporter.typeError(
+ _contract.location(),
+ string("Function signature hash collision for ") + it.second->externalSignature()
+ );
+ hashes.insert(hash);
+ }
+}
+
+void ContractLevelChecker::checkLibraryRequirements(ContractDefinition const& _contract)
+{
+ if (!_contract.isLibrary())
+ return;
+
+ if (!_contract.baseContracts().empty())
+ m_errorReporter.typeError(_contract.location(), "Library is not allowed to inherit.");
+
+ for (auto const& var: _contract.stateVariables())
+ if (!var->isConstant())
+ m_errorReporter.typeError(var->location(), "Library cannot have non-constant state variables");
+}
diff --git a/libsolidity/analysis/ContractLevelChecker.h b/libsolidity/analysis/ContractLevelChecker.h
new file mode 100644
index 00000000..15cbf45d
--- /dev/null
+++ b/libsolidity/analysis/ContractLevelChecker.h
@@ -0,0 +1,87 @@
+/*
+ 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/>.
+*/
+/**
+ * Component that verifies overloads, abstract contracts, function clashes and others
+ * checks at contract or function level.
+ */
+
+#pragma once
+
+#include <libsolidity/ast/ASTForward.h>
+
+#include <map>
+
+namespace langutil
+{
+class ErrorReporter;
+}
+
+namespace dev
+{
+namespace solidity
+{
+
+/**
+ * Component that verifies overloads, abstract contracts, function clashes and others
+ * checks at contract or function level.
+ */
+class ContractLevelChecker
+{
+public:
+ /// @param _errorReporter provides the error logging functionality.
+ explicit ContractLevelChecker(langutil::ErrorReporter& _errorReporter):
+ m_errorReporter(_errorReporter)
+ {}
+
+ /// Performs checks on the given contract.
+ /// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
+ bool check(ContractDefinition const& _contract);
+
+private:
+ /// Checks that two functions defined in this contract with the same name have different
+ /// arguments and that there is at most one constructor.
+ void checkDuplicateFunctions(ContractDefinition const& _contract);
+ void checkDuplicateEvents(ContractDefinition const& _contract);
+ template <class T>
+ void findDuplicateDefinitions(std::map<std::string, std::vector<T>> const& _definitions, std::string _message);
+ void checkIllegalOverrides(ContractDefinition const& _contract);
+ /// Reports a type error with an appropriate message if overridden function signature differs.
+ /// Also stores the direct super function in the AST annotations.
+ void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super);
+ void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message);
+ void checkAbstractFunctions(ContractDefinition const& _contract);
+ void checkBaseConstructorArguments(ContractDefinition const& _contract);
+ void annotateBaseConstructorArguments(
+ ContractDefinition const& _currentContract,
+ FunctionDefinition const* _baseConstructor,
+ ASTNode const* _argumentNode
+ );
+ void checkConstructor(ContractDefinition const& _contract);
+ void checkFallbackFunction(ContractDefinition const& _contract);
+ /// Checks that different functions with external visibility end up having different
+ /// external argument types (i.e. different signature).
+ void checkExternalTypeClashes(ContractDefinition const& _contract);
+ /// Checks for hash collisions in external function signatures.
+ void checkHashCollisions(ContractDefinition const& _contract);
+ /// Checks that all requirements for a library are fulfilled if this is a library.
+ void checkLibraryRequirements(ContractDefinition const& _contract);
+
+ langutil::ErrorReporter& m_errorReporter;
+};
+
+}
+}
diff --git a/libsolidity/analysis/ControlFlowAnalyzer.cpp b/libsolidity/analysis/ControlFlowAnalyzer.cpp
index 8a608552..fe58f0aa 100644
--- a/libsolidity/analysis/ControlFlowAnalyzer.cpp
+++ b/libsolidity/analysis/ControlFlowAnalyzer.cpp
@@ -16,8 +16,10 @@
*/
#include <libsolidity/analysis/ControlFlowAnalyzer.h>
+#include <liblangutil/SourceLocation.h>
using namespace std;
+using namespace langutil;
using namespace dev::solidity;
bool ControlFlowAnalyzer::analyze(ASTNode const& _astRoot)
diff --git a/libsolidity/analysis/ControlFlowAnalyzer.h b/libsolidity/analysis/ControlFlowAnalyzer.h
index 43e13fb6..411d57ff 100644
--- a/libsolidity/analysis/ControlFlowAnalyzer.h
+++ b/libsolidity/analysis/ControlFlowAnalyzer.h
@@ -29,12 +29,12 @@ namespace solidity
class ControlFlowAnalyzer: private ASTConstVisitor
{
public:
- explicit ControlFlowAnalyzer(CFG const& _cfg, ErrorReporter& _errorReporter):
+ explicit ControlFlowAnalyzer(CFG const& _cfg, langutil::ErrorReporter& _errorReporter):
m_cfg(_cfg), m_errorReporter(_errorReporter) {}
bool analyze(ASTNode const& _astRoot);
- virtual bool visit(FunctionDefinition const& _function) override;
+ bool visit(FunctionDefinition const& _function) override;
private:
static std::set<VariableDeclaration const*> variablesAssignedInNode(CFGNode const *node);
@@ -45,7 +45,7 @@ private:
) const;
CFG const& m_cfg;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/ControlFlowBuilder.h b/libsolidity/analysis/ControlFlowBuilder.h
index e9d96e5f..40605e00 100644
--- a/libsolidity/analysis/ControlFlowBuilder.h
+++ b/libsolidity/analysis/ControlFlowBuilder.h
@@ -46,19 +46,19 @@ public:
private:
explicit ControlFlowBuilder(CFG::NodeContainer& _nodeContainer, FunctionFlow const& _functionFlow);
- virtual bool visit(BinaryOperation const& _operation) override;
- virtual bool visit(Conditional const& _conditional) override;
- virtual bool visit(IfStatement const& _ifStatement) override;
- virtual bool visit(ForStatement const& _forStatement) override;
- virtual bool visit(WhileStatement const& _whileStatement) override;
- virtual bool visit(Break const&) override;
- virtual bool visit(Continue const&) override;
- virtual bool visit(Throw const&) override;
- virtual bool visit(Block const&) override;
- virtual void endVisit(Block const&) override;
- virtual bool visit(Return const& _return) override;
- virtual bool visit(PlaceholderStatement const&) override;
- virtual bool visit(FunctionCall const& _functionCall) override;
+ bool visit(BinaryOperation const& _operation) override;
+ bool visit(Conditional const& _conditional) override;
+ bool visit(IfStatement const& _ifStatement) override;
+ bool visit(ForStatement const& _forStatement) override;
+ bool visit(WhileStatement const& _whileStatement) override;
+ bool visit(Break const&) override;
+ bool visit(Continue const&) override;
+ bool visit(Throw const&) override;
+ bool visit(Block const&) override;
+ void endVisit(Block const&) override;
+ bool visit(Return const& _return) override;
+ bool visit(PlaceholderStatement const&) override;
+ bool visit(FunctionCall const& _functionCall) override;
/// Appends the control flow of @a _node to the current control flow.
@@ -74,7 +74,7 @@ private:
protected:
- virtual bool visitNode(ASTNode const& node) override;
+ bool visitNode(ASTNode const& node) override;
private:
diff --git a/libsolidity/analysis/ControlFlowGraph.cpp b/libsolidity/analysis/ControlFlowGraph.cpp
index 9b3da0eb..b8860158 100644
--- a/libsolidity/analysis/ControlFlowGraph.cpp
+++ b/libsolidity/analysis/ControlFlowGraph.cpp
@@ -23,6 +23,7 @@
#include <algorithm>
using namespace std;
+using namespace langutil;
using namespace dev::solidity;
bool CFG::constructFlow(ASTNode const& _astRoot)
@@ -133,4 +134,4 @@ void CFG::applyModifierFlowToFunctionFlow(
_functionFlow->entry = copySrcToCopyDst[_modifierFlow.entry];
_functionFlow->exit = copySrcToCopyDst[_modifierFlow.exit];
-} \ No newline at end of file
+}
diff --git a/libsolidity/analysis/ControlFlowGraph.h b/libsolidity/analysis/ControlFlowGraph.h
index c646e4f1..8fe9fe8e 100644
--- a/libsolidity/analysis/ControlFlowGraph.h
+++ b/libsolidity/analysis/ControlFlowGraph.h
@@ -19,7 +19,7 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ASTVisitor.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <map>
#include <memory>
@@ -101,12 +101,12 @@ struct ModifierFlow: FunctionFlow
class CFG: private ASTConstVisitor
{
public:
- explicit CFG(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ explicit CFG(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool constructFlow(ASTNode const& _astRoot);
- virtual bool visit(ModifierDefinition const& _modifier) override;
- virtual bool visit(FunctionDefinition const& _function) override;
+ bool visit(ModifierDefinition const& _modifier) override;
+ bool visit(FunctionDefinition const& _function) override;
FunctionFlow const& functionFlow(FunctionDefinition const& _function) const;
@@ -133,7 +133,7 @@ private:
FunctionFlow* _functionFlow
);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Node container.
/// All nodes allocated during the construction of the control flow graph
diff --git a/libsolidity/analysis/DocStringAnalyser.cpp b/libsolidity/analysis/DocStringAnalyser.cpp
index c1b97def..69a7a43c 100644
--- a/libsolidity/analysis/DocStringAnalyser.cpp
+++ b/libsolidity/analysis/DocStringAnalyser.cpp
@@ -23,11 +23,12 @@
#include <libsolidity/analysis/DocStringAnalyser.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libsolidity/parsing/DocStringParser.h>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
bool DocStringAnalyser::analyseDocStrings(SourceUnit const& _sourceUnit)
diff --git a/libsolidity/analysis/DocStringAnalyser.h b/libsolidity/analysis/DocStringAnalyser.h
index 5d339428..f6b236db 100644
--- a/libsolidity/analysis/DocStringAnalyser.h
+++ b/libsolidity/analysis/DocStringAnalyser.h
@@ -25,13 +25,16 @@
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* Parses and analyses the doc strings.
* Stores the parsing results in the AST annotations and reports errors.
@@ -39,14 +42,14 @@ class ErrorReporter;
class DocStringAnalyser: private ASTConstVisitor
{
public:
- DocStringAnalyser(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ DocStringAnalyser(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool analyseDocStrings(SourceUnit const& _sourceUnit);
private:
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual bool visit(ModifierDefinition const& _modifier) override;
- virtual bool visit(EventDefinition const& _event) override;
+ bool visit(ContractDefinition const& _contract) override;
+ bool visit(FunctionDefinition const& _function) override;
+ bool visit(ModifierDefinition const& _modifier) override;
+ bool visit(EventDefinition const& _event) override;
void checkParameters(
CallableDeclaration const& _callable,
@@ -75,7 +78,7 @@ private:
void appendError(std::string const& _description);
bool m_errorOccured = false;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp
index b452a49a..0528a200 100644
--- a/libsolidity/analysis/NameAndTypeResolver.cpp
+++ b/libsolidity/analysis/NameAndTypeResolver.cpp
@@ -24,12 +24,13 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/TypeChecker.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libdevcore/StringUtils.h>
#include <boost/algorithm/string.hpp>
using namespace std;
+using namespace langutil;
namespace dev
{
@@ -59,7 +60,7 @@ bool NameAndTypeResolver::registerDeclarations(SourceUnit& _sourceUnit, ASTNode
{
DeclarationRegistrationHelper registrar(m_scopes, _sourceUnit, m_errorReporter, _currentScope);
}
- catch (FatalError const&)
+ catch (langutil::FatalError const&)
{
if (m_errorReporter.errors().empty())
throw; // Something is weird here, rather throw again.
@@ -129,7 +130,7 @@ bool NameAndTypeResolver::resolveNamesAndTypes(ASTNode& _node, bool _resolveInsi
{
return resolveNamesAndTypesInternal(_node, _resolveInsideCode);
}
- catch (FatalError const&)
+ catch (langutil::FatalError const&)
{
if (m_errorReporter.errors().empty())
throw; // Something is weird here, rather throw again.
@@ -144,7 +145,7 @@ bool NameAndTypeResolver::updateDeclaration(Declaration const& _declaration)
m_scopes[nullptr]->registerDeclaration(_declaration, nullptr, false, true);
solAssert(_declaration.scope() == nullptr, "Updated declaration outside global scope.");
}
- catch (FatalError const&)
+ catch (langutil::FatalError const&)
{
if (m_errorReporter.errors().empty())
throw; // Something is weird here, rather throw again.
@@ -491,9 +492,9 @@ bool DeclarationRegistrationHelper::registerDeclaration(
Declaration const* conflictingDeclaration = _container.conflictingDeclaration(_declaration, _name);
solAssert(conflictingDeclaration, "");
bool const comparable =
- _errorLocation->sourceName &&
- conflictingDeclaration->location().sourceName &&
- *_errorLocation->sourceName == *conflictingDeclaration->location().sourceName;
+ _errorLocation->source &&
+ conflictingDeclaration->location().source &&
+ _errorLocation->source->name() == conflictingDeclaration->location().source->name();
if (comparable && _errorLocation->start < conflictingDeclaration->location().start)
{
firstDeclarationLocation = *_errorLocation;
diff --git a/libsolidity/analysis/NameAndTypeResolver.h b/libsolidity/analysis/NameAndTypeResolver.h
index a72c21e3..1b034ef4 100644
--- a/libsolidity/analysis/NameAndTypeResolver.h
+++ b/libsolidity/analysis/NameAndTypeResolver.h
@@ -30,13 +30,16 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/ASTAnnotations.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* Resolves name references, typenames and sets the (explicitly given) types for all variable
* declarations.
@@ -50,7 +53,7 @@ public:
NameAndTypeResolver(
std::vector<Declaration const*> const& _globals,
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes,
- ErrorReporter& _errorReporter
+ langutil::ErrorReporter& _errorReporter
);
/// Registers all declarations found in the AST node, usually a source unit.
/// @returns false in case of error.
@@ -125,7 +128,7 @@ private:
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes;
DeclarationContainer* m_currentScope = nullptr;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
/**
@@ -142,7 +145,7 @@ public:
DeclarationRegistrationHelper(
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& _scopes,
ASTNode& _astRoot,
- ErrorReporter& _errorReporter,
+ langutil::ErrorReporter& _errorReporter,
ASTNode const* _currentScope = nullptr
);
@@ -150,10 +153,10 @@ public:
DeclarationContainer& _container,
Declaration const& _declaration,
std::string const* _name,
- SourceLocation const* _errorLocation,
+ langutil::SourceLocation const* _errorLocation,
bool _warnOnShadow,
bool _inactive,
- ErrorReporter& _errorReporter
+ langutil::ErrorReporter& _errorReporter
);
private:
@@ -194,7 +197,7 @@ private:
std::map<ASTNode const*, std::shared_ptr<DeclarationContainer>>& m_scopes;
ASTNode const* m_currentScope = nullptr;
VariableScope* m_currentFunction = nullptr;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/PostTypeChecker.cpp b/libsolidity/analysis/PostTypeChecker.cpp
index 240d7973..27cbcd45 100644
--- a/libsolidity/analysis/PostTypeChecker.cpp
+++ b/libsolidity/analysis/PostTypeChecker.cpp
@@ -18,7 +18,7 @@
#include <libsolidity/analysis/PostTypeChecker.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/SemVerHandler.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libsolidity/interface/Version.h>
#include <libdevcore/Algorithms.h>
@@ -29,6 +29,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
diff --git a/libsolidity/analysis/PostTypeChecker.h b/libsolidity/analysis/PostTypeChecker.h
index 4f9dac6e..e428b81a 100644
--- a/libsolidity/analysis/PostTypeChecker.h
+++ b/libsolidity/analysis/PostTypeChecker.h
@@ -23,13 +23,17 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* 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
@@ -39,25 +43,25 @@ class PostTypeChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- PostTypeChecker(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ PostTypeChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool check(ASTNode const& _astRoot);
private:
/// Adds a new error to the list of errors.
- void typeError(SourceLocation const& _location, std::string const& _description);
+ void typeError(langutil::SourceLocation const& _location, std::string const& _description);
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual void endVisit(ContractDefinition const& _contract) override;
+ bool visit(ContractDefinition const& _contract) override;
+ void endVisit(ContractDefinition const& _contract) override;
- virtual bool visit(VariableDeclaration const& _variable) override;
- virtual void endVisit(VariableDeclaration const& _variable) override;
+ bool visit(VariableDeclaration const& _variable) override;
+ void endVisit(VariableDeclaration const& _variable) override;
- virtual bool visit(Identifier const& _identifier) override;
+ bool visit(Identifier const& _identifier) override;
VariableDeclaration const* findCycle(VariableDeclaration const& _startingFrom);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
VariableDeclaration const* m_currentConstVariable = nullptr;
std::vector<VariableDeclaration const*> m_constVariables; ///< Required for determinism.
diff --git a/libsolidity/analysis/ReferencesResolver.cpp b/libsolidity/analysis/ReferencesResolver.cpp
index 2adc8e77..c4931d98 100644
--- a/libsolidity/analysis/ReferencesResolver.cpp
+++ b/libsolidity/analysis/ReferencesResolver.cpp
@@ -23,12 +23,12 @@
#include <libsolidity/analysis/ReferencesResolver.h>
#include <libsolidity/ast/AST.h>
#include <libsolidity/analysis/NameAndTypeResolver.h>
-#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/analysis/ConstantEvaluator.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <libyul/AsmAnalysis.h>
+#include <libyul/AsmAnalysisInfo.h>
+#include <libyul/AsmData.h>
+#include <liblangutil/ErrorReporter.h>
+#include <liblangutil/Exceptions.h>
#include <libdevcore/StringUtils.h>
@@ -36,9 +36,12 @@
#include <boost/range/adaptor/transformed.hpp>
using namespace std;
-using namespace dev;
-using namespace dev::solidity;
+using namespace langutil;
+namespace dev
+{
+namespace solidity
+{
bool ReferencesResolver::resolve(ASTNode const& _root)
{
@@ -270,7 +273,7 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
ErrorList errors;
ErrorReporter errorsIgnored(errors);
yul::ExternalIdentifierAccess::Resolver resolver =
- [&](assembly::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) {
+ [&](yul::Identifier const& _identifier, yul::IdentifierContext, bool _crossesFunctionBoundary) {
auto declarations = m_resolver.nameFromCurrentScope(_identifier.name.str());
bool isSlot = boost::algorithm::ends_with(_identifier.name.str(), "_slot");
bool isOffset = boost::algorithm::ends_with(_identifier.name.str(), "_offset");
@@ -311,9 +314,9 @@ bool ReferencesResolver::visit(InlineAssembly const& _inlineAssembly)
// Will be re-generated later with correct information
// We use the latest EVM version because we will re-run it anyway.
- assembly::AsmAnalysisInfo analysisInfo;
+ yul::AsmAnalysisInfo analysisInfo;
boost::optional<Error::Type> errorTypeForLoose = Error::Type::SyntaxError;
- assembly::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, assembly::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
+ yul::AsmAnalyzer(analysisInfo, errorsIgnored, EVMVersion(), errorTypeForLoose, yul::AsmFlavour::Loose, resolver).analyze(_inlineAssembly.operations());
return false;
}
@@ -454,3 +457,6 @@ void ReferencesResolver::fatalDeclarationError(SourceLocation const& _location,
m_errorOccurred = true;
m_errorReporter.fatalDeclarationError(_location, _description);
}
+
+}
+}
diff --git a/libsolidity/analysis/ReferencesResolver.h b/libsolidity/analysis/ReferencesResolver.h
index 24ec4643..32c0553f 100644
--- a/libsolidity/analysis/ReferencesResolver.h
+++ b/libsolidity/analysis/ReferencesResolver.h
@@ -28,12 +28,17 @@
#include <libsolidity/ast/ASTVisitor.h>
#include <libsolidity/ast/ASTAnnotations.h>
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
class NameAndTypeResolver;
/**
@@ -44,7 +49,7 @@ class ReferencesResolver: private ASTConstVisitor
{
public:
ReferencesResolver(
- ErrorReporter& _errorReporter,
+ langutil::ErrorReporter& _errorReporter,
NameAndTypeResolver& _resolver,
bool _resolveInsideCode = false
):
@@ -57,38 +62,38 @@ public:
bool resolve(ASTNode const& _root);
private:
- virtual bool visit(Block const& _block) override;
- virtual void endVisit(Block const& _block) override;
- virtual bool visit(ForStatement const& _for) override;
- virtual void endVisit(ForStatement const& _for) override;
- virtual void endVisit(VariableDeclarationStatement const& _varDeclStatement) override;
- virtual bool visit(Identifier const& _identifier) override;
- virtual bool visit(ElementaryTypeName const& _typeName) override;
- virtual bool visit(FunctionDefinition const& _functionDefinition) override;
- virtual void endVisit(FunctionDefinition const& _functionDefinition) override;
- virtual bool visit(ModifierDefinition const& _modifierDefinition) override;
- virtual void endVisit(ModifierDefinition const& _modifierDefinition) override;
- virtual void endVisit(UserDefinedTypeName const& _typeName) override;
- virtual void endVisit(FunctionTypeName const& _typeName) override;
- virtual void endVisit(Mapping const& _typeName) override;
- virtual void endVisit(ArrayTypeName const& _typeName) override;
- virtual bool visit(InlineAssembly const& _inlineAssembly) override;
- virtual bool visit(Return const& _return) override;
- virtual void endVisit(VariableDeclaration const& _variable) override;
+ bool visit(Block const& _block) override;
+ void endVisit(Block const& _block) override;
+ bool visit(ForStatement const& _for) override;
+ void endVisit(ForStatement const& _for) override;
+ void endVisit(VariableDeclarationStatement const& _varDeclStatement) override;
+ bool visit(Identifier const& _identifier) override;
+ bool visit(ElementaryTypeName const& _typeName) override;
+ bool visit(FunctionDefinition const& _functionDefinition) override;
+ void endVisit(FunctionDefinition const& _functionDefinition) override;
+ bool visit(ModifierDefinition const& _modifierDefinition) override;
+ void endVisit(ModifierDefinition const& _modifierDefinition) override;
+ void endVisit(UserDefinedTypeName const& _typeName) override;
+ void endVisit(FunctionTypeName const& _typeName) override;
+ void endVisit(Mapping const& _typeName) override;
+ void endVisit(ArrayTypeName const& _typeName) override;
+ bool visit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(Return const& _return) override;
+ void endVisit(VariableDeclaration const& _variable) override;
/// Adds a new error to the list of errors.
- void typeError(SourceLocation const& _location, std::string const& _description);
+ void typeError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors and throws to abort reference resolving.
- void fatalTypeError(SourceLocation const& _location, std::string const& _description);
+ void fatalTypeError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors.
- void declarationError(SourceLocation const& _location, std::string const& _description);
+ void declarationError(langutil::SourceLocation const& _location, std::string const& _description);
/// Adds a new error to the list of errors and throws to abort reference resolving.
- void fatalDeclarationError(SourceLocation const& _location, std::string const& _description);
+ void fatalDeclarationError(langutil::SourceLocation const& _location, std::string const& _description);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
NameAndTypeResolver& m_resolver;
/// Stack of return parameters.
std::vector<ParameterList const*> m_returnParameters;
diff --git a/libsolidity/analysis/SemVerHandler.h b/libsolidity/analysis/SemVerHandler.h
index 03a557c5..80185612 100644
--- a/libsolidity/analysis/SemVerHandler.h
+++ b/libsolidity/analysis/SemVerHandler.h
@@ -22,8 +22,9 @@
#pragma once
-#include <vector>
#include <libsolidity/parsing/Token.h>
+#include <string>
+#include <vector>
namespace dev
{
diff --git a/libsolidity/analysis/StaticAnalyzer.cpp b/libsolidity/analysis/StaticAnalyzer.cpp
index 487a5cca..38391841 100644
--- a/libsolidity/analysis/StaticAnalyzer.cpp
+++ b/libsolidity/analysis/StaticAnalyzer.cpp
@@ -23,11 +23,12 @@
#include <libsolidity/analysis/StaticAnalyzer.h>
#include <libsolidity/analysis/ConstantEvaluator.h>
#include <libsolidity/ast/AST.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <memory>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
bool StaticAnalyzer::analyze(SourceUnit const& _sourceUnit)
diff --git a/libsolidity/analysis/StaticAnalyzer.h b/libsolidity/analysis/StaticAnalyzer.h
index 7f5c743a..ff33fa3a 100644
--- a/libsolidity/analysis/StaticAnalyzer.h
+++ b/libsolidity/analysis/StaticAnalyzer.h
@@ -28,6 +28,11 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
@@ -44,7 +49,7 @@ class StaticAnalyzer: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- explicit StaticAnalyzer(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ explicit StaticAnalyzer(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
/// Performs static analysis on the given source unit and all of its sub-nodes.
/// @returns true iff all checks passed. Note even if all checks passed, errors() can still contain warnings
@@ -52,25 +57,25 @@ public:
private:
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual void endVisit(ContractDefinition const& _contract) override;
+ bool visit(ContractDefinition const& _contract) override;
+ void endVisit(ContractDefinition const& _contract) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual void endVisit(FunctionDefinition const& _function) override;
+ bool visit(FunctionDefinition const& _function) override;
+ void endVisit(FunctionDefinition const& _function) override;
- virtual bool visit(ExpressionStatement const& _statement) override;
- virtual bool visit(VariableDeclaration const& _variable) override;
- virtual bool visit(Identifier const& _identifier) override;
- virtual bool visit(Return const& _return) override;
- virtual bool visit(MemberAccess const& _memberAccess) override;
- virtual bool visit(InlineAssembly const& _inlineAssembly) override;
- virtual bool visit(BinaryOperation const& _operation) override;
- virtual bool visit(FunctionCall const& _functionCall) override;
+ bool visit(ExpressionStatement const& _statement) override;
+ bool visit(VariableDeclaration const& _variable) override;
+ bool visit(Identifier const& _identifier) override;
+ bool visit(Return const& _return) override;
+ bool visit(MemberAccess const& _memberAccess) override;
+ bool visit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(BinaryOperation const& _operation) override;
+ bool visit(FunctionCall const& _functionCall) override;
/// @returns the size of this type in storage, including all sub-types.
static bigint structureSizeEstimate(Type const& _type, std::set<StructDefinition const*>& _structsSeen);
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Flag that indicates whether the current contract definition is a library.
bool m_library = false;
diff --git a/libsolidity/analysis/SyntaxChecker.cpp b/libsolidity/analysis/SyntaxChecker.cpp
index 3f9f8373..a73d7e5c 100644
--- a/libsolidity/analysis/SyntaxChecker.cpp
+++ b/libsolidity/analysis/SyntaxChecker.cpp
@@ -20,7 +20,7 @@
#include <libsolidity/ast/AST.h>
#include <libsolidity/ast/ExperimentalFeatures.h>
#include <libsolidity/analysis/SemVerHandler.h>
-#include <libsolidity/interface/ErrorReporter.h>
+#include <liblangutil/ErrorReporter.h>
#include <libsolidity/interface/Version.h>
#include <boost/algorithm/cxx11/all_of.hpp>
@@ -29,6 +29,7 @@
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
diff --git a/libsolidity/analysis/SyntaxChecker.h b/libsolidity/analysis/SyntaxChecker.h
index f5716bf9..c2463955 100644
--- a/libsolidity/analysis/SyntaxChecker.h
+++ b/libsolidity/analysis/SyntaxChecker.h
@@ -23,6 +23,11 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
@@ -39,49 +44,49 @@ class SyntaxChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- SyntaxChecker(ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
+ SyntaxChecker(langutil::ErrorReporter& _errorReporter): m_errorReporter(_errorReporter) {}
bool checkSyntax(ASTNode const& _astRoot);
private:
- virtual bool visit(SourceUnit const& _sourceUnit) override;
- virtual void endVisit(SourceUnit const& _sourceUnit) override;
- virtual bool visit(PragmaDirective const& _pragma) override;
+ bool visit(SourceUnit const& _sourceUnit) override;
+ void endVisit(SourceUnit const& _sourceUnit) override;
+ bool visit(PragmaDirective const& _pragma) override;
- virtual bool visit(ModifierDefinition const& _modifier) override;
- virtual void endVisit(ModifierDefinition const& _modifier) override;
+ bool visit(ModifierDefinition const& _modifier) override;
+ void endVisit(ModifierDefinition const& _modifier) override;
/// Reports an error if _statement is a VariableDeclarationStatement.
/// Used by if/while/for to check for single statement variable declarations
/// without a block.
void checkSingleStatementVariableDeclaration(ASTNode const& _statement);
- virtual bool visit(IfStatement const& _ifStatement) override;
- virtual bool visit(WhileStatement const& _whileStatement) override;
- virtual void endVisit(WhileStatement const& _whileStatement) override;
- virtual bool visit(ForStatement const& _forStatement) override;
- virtual void endVisit(ForStatement const& _forStatement) override;
+ bool visit(IfStatement const& _ifStatement) override;
+ bool visit(WhileStatement const& _whileStatement) override;
+ void endVisit(WhileStatement const& _whileStatement) override;
+ bool visit(ForStatement const& _forStatement) override;
+ void endVisit(ForStatement const& _forStatement) override;
- virtual bool visit(Continue const& _continueStatement) override;
- virtual bool visit(Break const& _breakStatement) override;
+ bool visit(Continue const& _continueStatement) override;
+ bool visit(Break const& _breakStatement) override;
- virtual bool visit(Throw const& _throwStatement) override;
+ bool visit(Throw const& _throwStatement) override;
- virtual bool visit(UnaryOperation const& _operation) override;
+ bool visit(UnaryOperation const& _operation) override;
- virtual bool visit(PlaceholderStatement const& _placeholderStatement) override;
+ bool visit(PlaceholderStatement const& _placeholderStatement) override;
- virtual bool visit(ContractDefinition const& _contract) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual bool visit(FunctionTypeName const& _node) override;
+ bool visit(ContractDefinition const& _contract) override;
+ bool visit(FunctionDefinition const& _function) override;
+ bool visit(FunctionTypeName const& _node) override;
- virtual bool visit(VariableDeclarationStatement const& _statement) override;
+ bool visit(VariableDeclarationStatement const& _statement) override;
- virtual bool visit(StructDefinition const& _struct) override;
- virtual bool visit(Literal const& _literal) override;
+ bool visit(StructDefinition const& _struct) override;
+ bool visit(Literal const& _literal) override;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
/// Flag that indicates whether a function modifier actually contains '_'.
bool m_placeholderFound = false;
diff --git a/libsolidity/analysis/TypeChecker.cpp b/libsolidity/analysis/TypeChecker.cpp
index c5e6488b..9350df05 100644
--- a/libsolidity/analysis/TypeChecker.cpp
+++ b/libsolidity/analysis/TypeChecker.cpp
@@ -21,20 +21,27 @@
*/
#include <libsolidity/analysis/TypeChecker.h>
-#include <memory>
+#include <libsolidity/ast/AST.h>
+
+#include <libyul/AsmAnalysis.h>
+#include <libyul/AsmAnalysisInfo.h>
+#include <libyul/AsmData.h>
+
+#include <liblangutil/ErrorReporter.h>
+
+#include <libdevcore/Algorithms.h>
+#include <libdevcore/StringUtils.h>
+
#include <boost/algorithm/cxx11/all_of.hpp>
#include <boost/algorithm/string/predicate.hpp>
#include <boost/algorithm/string/join.hpp>
-#include <boost/range/adaptor/reversed.hpp>
-#include <libsolidity/ast/AST.h>
-#include <libsolidity/inlineasm/AsmAnalysis.h>
-#include <libsolidity/inlineasm/AsmAnalysisInfo.h>
-#include <libsolidity/inlineasm/AsmData.h>
-#include <libsolidity/interface/ErrorReporter.h>
-#include <libdevcore/Algorithms.h>
+
+#include <memory>
+#include <vector>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace
@@ -81,418 +88,14 @@ bool TypeChecker::visit(ContractDefinition const& _contract)
{
m_scope = &_contract;
- // We force our own visiting order here. The structs have to be excluded below.
- set<ASTNode const*> visited;
- for (auto const& s: _contract.definedStructs())
- visited.insert(s);
- ASTNode::listAccept(_contract.definedStructs(), *this);
ASTNode::listAccept(_contract.baseContracts(), *this);
- checkContractDuplicateFunctions(_contract);
- checkContractDuplicateEvents(_contract);
- checkContractIllegalOverrides(_contract);
- checkContractAbstractFunctions(_contract);
- checkContractBaseConstructorArguments(_contract);
-
- FunctionDefinition const* function = _contract.constructor();
- if (function)
- {
- if (!function->returnParameters().empty())
- m_errorReporter.typeError(function->returnParameterList()->location(), "Non-empty \"returns\" directive for constructor.");
- if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
- m_errorReporter.typeError(
- function->location(),
- "Constructor must be payable or non-payable, but is \"" +
- stateMutabilityToString(function->stateMutability()) +
- "\"."
- );
- if (function->visibility() != FunctionDefinition::Visibility::Public && function->visibility() != FunctionDefinition::Visibility::Internal)
- m_errorReporter.typeError(function->location(), "Constructor must be public or internal.");
- }
-
- for (FunctionDefinition const* function: _contract.definedFunctions())
- if (function->isFallback())
- {
- if (_contract.isLibrary())
- m_errorReporter.typeError(function->location(), "Libraries cannot have fallback functions.");
- if (function->stateMutability() != StateMutability::NonPayable && function->stateMutability() != StateMutability::Payable)
- m_errorReporter.typeError(
- function->location(),
- "Fallback function must be payable or non-payable, but is \"" +
- stateMutabilityToString(function->stateMutability()) +
- "\"."
- );
- if (!function->parameters().empty())
- m_errorReporter.typeError(function->parameterList().location(), "Fallback function cannot take parameters.");
- if (!function->returnParameters().empty())
- m_errorReporter.typeError(function->returnParameterList()->location(), "Fallback function cannot return values.");
- if (function->visibility() != FunctionDefinition::Visibility::External)
- m_errorReporter.typeError(function->location(), "Fallback function must be defined as \"external\".");
- }
-
for (auto const& n: _contract.subNodes())
- if (!visited.count(n.get()))
- n->accept(*this);
-
- checkContractExternalTypeClashes(_contract);
- // check for hash collisions in function signatures
- set<FixedHash<4>> hashes;
- for (auto const& it: _contract.interfaceFunctionList())
- {
- FixedHash<4> const& hash = it.first;
- if (hashes.count(hash))
- m_errorReporter.typeError(
- _contract.location(),
- string("Function signature hash collision for ") + it.second->externalSignature()
- );
- hashes.insert(hash);
- }
-
- if (_contract.isLibrary())
- checkLibraryRequirements(_contract);
+ n->accept(*this);
return false;
}
-void TypeChecker::checkContractDuplicateFunctions(ContractDefinition const& _contract)
-{
- /// Checks that two functions with the same name defined in this contract have different
- /// argument types and that there is at most one constructor.
- map<string, vector<FunctionDefinition const*>> functions;
- FunctionDefinition const* constructor = nullptr;
- FunctionDefinition const* fallback = nullptr;
- for (FunctionDefinition const* function: _contract.definedFunctions())
- if (function->isConstructor())
- {
- if (constructor)
- m_errorReporter.declarationError(
- function->location(),
- SecondarySourceLocation().append("Another declaration is here:", constructor->location()),
- "More than one constructor defined."
- );
- constructor = function;
- }
- else if (function->isFallback())
- {
- if (fallback)
- m_errorReporter.declarationError(
- function->location(),
- SecondarySourceLocation().append("Another declaration is here:", fallback->location()),
- "Only one fallback function is allowed."
- );
- fallback = function;
- }
- else
- {
- solAssert(!function->name().empty(), "");
- functions[function->name()].push_back(function);
- }
-
- findDuplicateDefinitions(functions, "Function with same name and arguments defined twice.");
-}
-
-void TypeChecker::checkContractDuplicateEvents(ContractDefinition const& _contract)
-{
- /// Checks that two events with the same name defined in this contract have different
- /// argument types
- map<string, vector<EventDefinition const*>> events;
- for (EventDefinition const* event: _contract.events())
- events[event->name()].push_back(event);
-
- findDuplicateDefinitions(events, "Event with same name and arguments defined twice.");
-}
-
-template <class T>
-void TypeChecker::findDuplicateDefinitions(map<string, vector<T>> const& _definitions, string _message)
-{
- for (auto const& it: _definitions)
- {
- vector<T> const& overloads = it.second;
- set<size_t> reported;
- for (size_t i = 0; i < overloads.size() && !reported.count(i); ++i)
- {
- SecondarySourceLocation ssl;
-
- for (size_t j = i + 1; j < overloads.size(); ++j)
- if (FunctionType(*overloads[i]).hasEqualParameterTypes(FunctionType(*overloads[j])))
- {
- ssl.append("Other declaration is here:", overloads[j]->location());
- reported.insert(j);
- }
-
- if (ssl.infos.size() > 0)
- {
- ssl.limitSize(_message);
-
- m_errorReporter.declarationError(
- overloads[i]->location(),
- ssl,
- _message
- );
- }
- }
- }
-}
-
-void TypeChecker::checkContractAbstractFunctions(ContractDefinition const& _contract)
-{
- // Mapping from name to function definition (exactly one per argument type equality class) and
- // flag to indicate whether it is fully implemented.
- using FunTypeAndFlag = std::pair<FunctionTypePointer, bool>;
- map<string, vector<FunTypeAndFlag>> functions;
-
- // Search from base to derived
- for (ContractDefinition const* contract: boost::adaptors::reverse(_contract.annotation().linearizedBaseContracts))
- for (FunctionDefinition const* function: contract->definedFunctions())
- {
- // Take constructors out of overload hierarchy
- if (function->isConstructor())
- continue;
- auto& overloads = functions[function->name()];
- FunctionTypePointer funType = make_shared<FunctionType>(*function);
- auto it = find_if(overloads.begin(), overloads.end(), [&](FunTypeAndFlag const& _funAndFlag)
- {
- return funType->hasEqualParameterTypes(*_funAndFlag.first);
- });
- if (it == overloads.end())
- overloads.push_back(make_pair(funType, function->isImplemented()));
- else if (it->second)
- {
- if (!function->isImplemented())
- m_errorReporter.typeError(function->location(), "Redeclaring an already implemented function as abstract");
- }
- else if (function->isImplemented())
- it->second = true;
- }
-
- // Set to not fully implemented if at least one flag is false.
- for (auto const& it: functions)
- for (auto const& funAndFlag: it.second)
- if (!funAndFlag.second)
- {
- FunctionDefinition const* function = dynamic_cast<FunctionDefinition const*>(&funAndFlag.first->declaration());
- solAssert(function, "");
- _contract.annotation().unimplementedFunctions.push_back(function);
- break;
- }
-}
-
-void TypeChecker::checkContractBaseConstructorArguments(ContractDefinition const& _contract)
-{
- vector<ContractDefinition const*> const& bases = _contract.annotation().linearizedBaseContracts;
-
- // Determine the arguments that are used for the base constructors.
- for (ContractDefinition const* contract: bases)
- {
- if (FunctionDefinition const* constructor = contract->constructor())
- for (auto const& modifier: constructor->modifiers())
- if (auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(*modifier->name())))
- {
- if (modifier->arguments())
- {
- if (baseContract->constructor())
- annotateBaseConstructorArguments(_contract, baseContract->constructor(), modifier.get());
- }
- else
- m_errorReporter.declarationError(
- modifier->location(),
- "Modifier-style base constructor call without arguments."
- );
- }
-
- for (ASTPointer<InheritanceSpecifier> const& base: contract->baseContracts())
- {
- auto baseContract = dynamic_cast<ContractDefinition const*>(&dereference(base->name()));
- solAssert(baseContract, "");
-
- if (baseContract->constructor() && base->arguments() && !base->arguments()->empty())
- annotateBaseConstructorArguments(_contract, baseContract->constructor(), base.get());
- }
- }
-
- // check that we get arguments for all base constructors that need it.
- // If not mark the contract as abstract (not fully implemented)
- for (ContractDefinition const* contract: bases)
- if (FunctionDefinition const* constructor = contract->constructor())
- if (contract != &_contract && !constructor->parameters().empty())
- if (!_contract.annotation().baseConstructorArguments.count(constructor))
- _contract.annotation().unimplementedFunctions.push_back(constructor);
-}
-
-void TypeChecker::annotateBaseConstructorArguments(
- ContractDefinition const& _currentContract,
- FunctionDefinition const* _baseConstructor,
- ASTNode const* _argumentNode
-)
-{
- solAssert(_baseConstructor, "");
- solAssert(_argumentNode, "");
-
- auto insertionResult = _currentContract.annotation().baseConstructorArguments.insert(
- std::make_pair(_baseConstructor, _argumentNode)
- );
- if (!insertionResult.second)
- {
- ASTNode const* previousNode = insertionResult.first->second;
-
- SourceLocation const* mainLocation = nullptr;
- SecondarySourceLocation ssl;
-
- if (
- _currentContract.location().contains(previousNode->location()) ||
- _currentContract.location().contains(_argumentNode->location())
- )
- {
- mainLocation = &previousNode->location();
- ssl.append("Second constructor call is here:", _argumentNode->location());
- }
- else
- {
- mainLocation = &_currentContract.location();
- ssl.append("First constructor call is here: ", _argumentNode->location());
- ssl.append("Second constructor call is here: ", previousNode->location());
- }
-
- m_errorReporter.declarationError(
- *mainLocation,
- ssl,
- "Base constructor arguments given twice."
- );
- }
-
-}
-
-void TypeChecker::checkContractIllegalOverrides(ContractDefinition const& _contract)
-{
- // TODO unify this at a later point. for this we need to put the constness and the access specifier
- // into the types
- map<string, vector<FunctionDefinition const*>> functions;
- map<string, ModifierDefinition const*> modifiers;
-
- // We search from derived to base, so the stored item causes the error.
- for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
- {
- for (FunctionDefinition const* function: contract->definedFunctions())
- {
- if (function->isConstructor())
- continue; // constructors can neither be overridden nor override anything
- string const& name = function->name();
- if (modifiers.count(name))
- m_errorReporter.typeError(modifiers[name]->location(), "Override changes function to modifier.");
-
- for (FunctionDefinition const* overriding: functions[name])
- checkFunctionOverride(*overriding, *function);
-
- functions[name].push_back(function);
- }
- for (ModifierDefinition const* modifier: contract->functionModifiers())
- {
- string const& name = modifier->name();
- ModifierDefinition const*& override = modifiers[name];
- if (!override)
- override = modifier;
- else if (ModifierType(*override) != ModifierType(*modifier))
- m_errorReporter.typeError(override->location(), "Override changes modifier signature.");
- if (!functions[name].empty())
- m_errorReporter.typeError(override->location(), "Override changes modifier to function.");
- }
- }
-}
-
-void TypeChecker::checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super)
-{
- FunctionType functionType(function);
- FunctionType superType(super);
-
- if (!functionType.hasEqualParameterTypes(superType))
- return;
-
- if (!function.annotation().superFunction)
- function.annotation().superFunction = &super;
-
- if (function.visibility() != super.visibility())
- {
- // visibility is enforced to be external in interfaces, but a contract can override that with public
- if (
- super.inContractKind() == ContractDefinition::ContractKind::Interface &&
- function.inContractKind() != ContractDefinition::ContractKind::Interface &&
- function.visibility() == FunctionDefinition::Visibility::Public
- )
- return;
- overrideError(function, super, "Overriding function visibility differs.");
- }
-
- else if (function.stateMutability() != super.stateMutability())
- overrideError(
- function,
- super,
- "Overriding function changes state mutability from \"" +
- stateMutabilityToString(super.stateMutability()) +
- "\" to \"" +
- stateMutabilityToString(function.stateMutability()) +
- "\"."
- );
-
- else if (functionType != superType)
- overrideError(function, super, "Overriding function return types differ.");
-}
-
-void TypeChecker::overrideError(FunctionDefinition const& function, FunctionDefinition const& super, string message)
-{
- m_errorReporter.typeError(
- function.location(),
- SecondarySourceLocation().append("Overridden function is here:", super.location()),
- message
- );
-}
-
-void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _contract)
-{
- map<string, vector<pair<Declaration const*, FunctionTypePointer>>> externalDeclarations;
- for (ContractDefinition const* contract: _contract.annotation().linearizedBaseContracts)
- {
- for (FunctionDefinition const* f: contract->definedFunctions())
- if (f->isPartOfExternalInterface())
- {
- auto functionType = make_shared<FunctionType>(*f);
- // under non error circumstances this should be true
- if (functionType->interfaceFunctionType())
- externalDeclarations[functionType->externalSignature()].push_back(
- make_pair(f, functionType)
- );
- }
- for (VariableDeclaration const* v: contract->stateVariables())
- if (v->isPartOfExternalInterface())
- {
- auto functionType = make_shared<FunctionType>(*v);
- // under non error circumstances this should be true
- if (functionType->interfaceFunctionType())
- externalDeclarations[functionType->externalSignature()].push_back(
- make_pair(v, functionType)
- );
- }
- }
- for (auto const& it: externalDeclarations)
- for (size_t i = 0; i < it.second.size(); ++i)
- for (size_t j = i + 1; j < it.second.size(); ++j)
- if (!it.second[i].second->hasEqualParameterTypes(*it.second[j].second))
- m_errorReporter.typeError(
- it.second[j].first->location(),
- "Function overload clash during conversion to external types for arguments."
- );
-}
-
-void TypeChecker::checkLibraryRequirements(ContractDefinition const& _contract)
-{
- solAssert(_contract.isLibrary(), "");
- if (!_contract.baseContracts().empty())
- m_errorReporter.typeError(_contract.location(), "Library is not allowed to inherit.");
-
- for (auto const& var: _contract.stateVariables())
- if (!var->isConstant())
- m_errorReporter.typeError(var->location(), "Library cannot have non-constant state variables");
-}
-
void TypeChecker::checkDoubleStorageAssignment(Assignment const& _assignment)
{
TupleType const& lhs = dynamic_cast<TupleType const&>(*type(_assignment.leftHandSide()));
@@ -697,20 +300,22 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
}
for (ASTPointer<VariableDeclaration> const& var: _function.parameters() + _function.returnParameters())
{
+ if (type(*var)->category() == Type::Category::Mapping)
+ {
+ if (!type(*var)->dataStoredIn(DataLocation::Storage))
+ m_errorReporter.typeError(var->location(), "Mapping types can only have a data location of \"storage\"." );
+ else if (!isLibraryFunction && _function.isPublic())
+ m_errorReporter.typeError(var->location(), "Mapping types for parameters or return variables can only be used in internal or library functions.");
+ }
+ else
+ {
+ if (!type(*var)->canLiveOutsideStorage() && _function.isPublic())
+ m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
+ if (_function.isPublic() && !(type(*var)->interfaceType(isLibraryFunction)))
+ m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions.");
+ }
if (
- type(*var)->category() == Type::Category::Mapping &&
- !type(*var)->dataStoredIn(DataLocation::Storage)
- )
- m_errorReporter.typeError(var->location(), "Mapping types can only have a data location of \"storage\".");
- else if (
- !type(*var)->canLiveOutsideStorage() &&
- _function.visibility() > FunctionDefinition::Visibility::Internal
- )
- m_errorReporter.typeError(var->location(), "Type is required to live outside storage.");
- if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction)))
- m_errorReporter.fatalTypeError(var->location(), "Internal or recursive type is not allowed for public or external functions.");
- if (
- _function.visibility() > FunctionDefinition::Visibility::Internal &&
+ _function.isPublic() &&
!_function.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2) &&
!typeSupportedByOldABIEncoder(*type(*var))
)
@@ -775,15 +380,10 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
)
m_errorReporter.typeError(_variable.location(), "Variables cannot be declared in interfaces.");
- // Variables can be declared without type (with "var"), in which case the first assignment
- // sets the type.
- // Note that assignments before the first declaration are legal because of the special scoping
- // rules inherited from JavaScript.
-
// type is filled either by ReferencesResolver directly from the type name or by
// TypeChecker at the VariableDeclarationStatement level.
TypePointer varType = _variable.annotation().type;
- solAssert(!!varType, "Failed to infer variable type.");
+ solAssert(!!varType, "Variable type not provided.");
if (_variable.value())
expectType(*_variable.value(), *varType);
@@ -812,11 +412,25 @@ bool TypeChecker::visit(VariableDeclaration const& _variable)
if (!varType->canLiveOutsideStorage())
m_errorReporter.typeError(_variable.location(), "Type " + varType->toString() + " is only valid in storage.");
}
- else if (
- _variable.visibility() >= VariableDeclaration::Visibility::Public &&
- !FunctionType(_variable).interfaceFunctionType()
- )
- m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
+ else if (_variable.visibility() >= VariableDeclaration::Visibility::Public)
+ {
+ FunctionType getter(_variable);
+ if (!_variable.sourceUnit().annotation().experimentalFeatures.count(ExperimentalFeature::ABIEncoderV2))
+ {
+ vector<string> unsupportedTypes;
+ for (auto const& param: getter.parameterTypes() + getter.returnParameterTypes())
+ if (!typeSupportedByOldABIEncoder(*param))
+ unsupportedTypes.emplace_back(param->toString());
+ if (!unsupportedTypes.empty())
+ m_errorReporter.typeError(_variable.location(),
+ "The following types are only supported for getters in the new experimental ABI encoder: " +
+ joinHumanReadable(unsupportedTypes) +
+ ". Either remove \"public\" or use \"pragma experimental ABIEncoderV2;\" to enable the feature."
+ );
+ }
+ if (!getter.interfaceFunctionType())
+ m_errorReporter.typeError(_variable.location(), "Internal or recursive type is not allowed for public state variables.");
+ }
switch (varType->category())
{
@@ -953,7 +567,7 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
// External references have already been resolved in a prior stage and stored in the annotation.
// We run the resolve step again regardless.
yul::ExternalIdentifierAccess::Resolver identifierAccess = [&](
- assembly::Identifier const& _identifier,
+ yul::Identifier const& _identifier,
yul::IdentifierContext _context,
bool
)
@@ -1038,13 +652,13 @@ bool TypeChecker::visit(InlineAssembly const& _inlineAssembly)
return size_t(1);
};
solAssert(!_inlineAssembly.annotation().analysisInfo, "");
- _inlineAssembly.annotation().analysisInfo = make_shared<assembly::AsmAnalysisInfo>();
- assembly::AsmAnalyzer analyzer(
+ _inlineAssembly.annotation().analysisInfo = make_shared<yul::AsmAnalysisInfo>();
+ yul::AsmAnalyzer analyzer(
*_inlineAssembly.annotation().analysisInfo,
m_errorReporter,
m_evmVersion,
Error::Type::SyntaxError,
- assembly::AsmFlavour::Loose,
+ yul::AsmFlavour::Loose,
identifierAccess
);
if (!analyzer.analyze(_inlineAssembly.operations()))
@@ -1590,6 +1204,9 @@ bool TypeChecker::visit(TupleExpression const& _tuple)
{
if (!inlineArrayType)
m_errorReporter.fatalTypeError(_tuple.location(), "Unable to deduce common type for array elements.");
+ else if (!inlineArrayType->canLiveOutsideStorage())
+ m_errorReporter.fatalTypeError(_tuple.location(), "Type " + inlineArrayType->toString() + " is only valid in storage.");
+
_tuple.annotation().type = make_shared<ArrayType>(DataLocation::Memory, inlineArrayType, types.size());
}
else
@@ -1806,26 +1423,6 @@ void TypeChecker::typeCheckFunctionCall(
"\"staticcall\" is not supported by the VM version."
);
- // Check for deprecated function names
- if (_functionType->kind() == FunctionType::Kind::KECCAK256)
- {
- if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
- if (functionName->name() == "sha3")
- m_errorReporter.typeError(
- _functionCall.location(),
- "\"sha3\" has been deprecated in favour of \"keccak256\""
- );
- }
- else if (_functionType->kind() == FunctionType::Kind::Selfdestruct)
- {
- if (auto functionName = dynamic_cast<Identifier const*>(&_functionCall.expression()))
- if (functionName->name() == "suicide")
- m_errorReporter.typeError(
- _functionCall.location(),
- "\"suicide\" has been deprecated in favour of \"selfdestruct\""
- );
- }
-
// Check for event outside of emit statement
if (!m_insideEmitStatement && _functionType->kind() == FunctionType::Kind::Event)
m_errorReporter.typeError(
@@ -2488,7 +2085,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
}
else
{
- expectType(*index, IntegerType(256));
+ expectType(*index, IntegerType::uint256());
if (!m_errorReporter.hasErrors())
if (auto numberType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
{
@@ -2519,7 +2116,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
resultType = make_shared<TypeType>(make_shared<ArrayType>(DataLocation::Memory, typeType.actualType()));
else
{
- expectType(*index, IntegerType(256));
+ expectType(*index, IntegerType::uint256());
if (auto length = dynamic_cast<RationalNumberType const*>(type(*index).get()))
resultType = make_shared<TypeType>(make_shared<ArrayType>(
DataLocation::Memory,
@@ -2538,7 +2135,7 @@ bool TypeChecker::visit(IndexAccess const& _access)
m_errorReporter.typeError(_access.location(), "Index expression cannot be omitted.");
else
{
- if (!expectType(*index, IntegerType(256)))
+ if (!expectType(*index, IntegerType::uint256()))
m_errorReporter.fatalTypeError(_access.location(), "Index expression cannot be represented as an unsigned integer.");
if (auto integerType = dynamic_cast<RationalNumberType const*>(type(*index).get()))
if (bytesType.numBytes() <= integerType->literalValue(nullptr))
@@ -2621,6 +2218,23 @@ bool TypeChecker::visit(Identifier const& _identifier)
else if (dynamic_cast<MagicVariableDeclaration const*>(annotation.referencedDeclaration))
if (dynamic_cast<FunctionType const*>(annotation.type.get()))
annotation.isPure = true;
+
+ // Check for deprecated function names.
+ // The check is done here for the case without an actual function call.
+ if (FunctionType const* fType = dynamic_cast<FunctionType const*>(_identifier.annotation().type.get()))
+ {
+ if (_identifier.name() == "sha3" && fType->kind() == FunctionType::Kind::KECCAK256)
+ m_errorReporter.typeError(
+ _identifier.location(),
+ "\"sha3\" has been deprecated in favour of \"keccak256\""
+ );
+ else if (_identifier.name() == "suicide" && fType->kind() == FunctionType::Kind::Selfdestruct)
+ m_errorReporter.typeError(
+ _identifier.location(),
+ "\"suicide\" has been deprecated in favour of \"selfdestruct\""
+ );
+ }
+
return false;
}
diff --git a/libsolidity/analysis/TypeChecker.h b/libsolidity/analysis/TypeChecker.h
index c76fa466..ebfcdadc 100644
--- a/libsolidity/analysis/TypeChecker.h
+++ b/libsolidity/analysis/TypeChecker.h
@@ -22,20 +22,23 @@
#pragma once
-#include <libsolidity/interface/EVMVersion.h>
+#include <liblangutil/EVMVersion.h>
#include <libsolidity/ast/Types.h>
#include <libsolidity/ast/ASTAnnotations.h>
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
+namespace langutil
+{
+class ErrorReporter;
+}
+
namespace dev
{
namespace solidity
{
-class ErrorReporter;
-
/**
* The module that performs type analysis on the AST, checks the applicability of operations on
* those types and stores errors for invalid operations.
@@ -45,7 +48,7 @@ class TypeChecker: private ASTConstVisitor
{
public:
/// @param _errorReporter provides the error logging functionality.
- TypeChecker(EVMVersion _evmVersion, ErrorReporter& _errorReporter):
+ TypeChecker(EVMVersion _evmVersion, langutil::ErrorReporter& _errorReporter):
m_evmVersion(_evmVersion),
m_errorReporter(_errorReporter)
{}
@@ -62,28 +65,7 @@ public:
private:
- virtual bool visit(ContractDefinition const& _contract) override;
- /// Checks that two functions defined in this contract with the same name have different
- /// arguments and that there is at most one constructor.
- void checkContractDuplicateFunctions(ContractDefinition const& _contract);
- void checkContractDuplicateEvents(ContractDefinition const& _contract);
- void checkContractIllegalOverrides(ContractDefinition const& _contract);
- /// Reports a type error with an appropriate message if overridden function signature differs.
- /// Also stores the direct super function in the AST annotations.
- void checkFunctionOverride(FunctionDefinition const& function, FunctionDefinition const& super);
- void overrideError(FunctionDefinition const& function, FunctionDefinition const& super, std::string message);
- void checkContractAbstractFunctions(ContractDefinition const& _contract);
- void checkContractBaseConstructorArguments(ContractDefinition const& _contract);
- void annotateBaseConstructorArguments(
- ContractDefinition const& _currentContract,
- FunctionDefinition const* _baseConstructor,
- ASTNode const* _argumentNode
- );
- /// Checks that different functions with external visibility end up having different
- /// external argument types (i.e. different signature).
- void checkContractExternalTypeClashes(ContractDefinition const& _contract);
- /// Checks that all requirements for a library are fulfilled if this is a library.
- void checkLibraryRequirements(ContractDefinition const& _contract);
+ bool visit(ContractDefinition const& _contract) override;
/// Checks (and warns) if a tuple assignment might cause unexpected overwrites in storage.
/// Should only be called if the left hand side is tuple-typed.
void checkDoubleStorageAssignment(Assignment const& _assignment);
@@ -122,40 +104,37 @@ private:
FunctionTypePointer _functionType
);
- virtual void endVisit(InheritanceSpecifier const& _inheritance) override;
- virtual void endVisit(UsingForDirective const& _usingFor) override;
- virtual bool visit(StructDefinition const& _struct) override;
- virtual bool visit(FunctionDefinition const& _function) override;
- virtual bool visit(VariableDeclaration const& _variable) override;
+ void endVisit(InheritanceSpecifier const& _inheritance) override;
+ void endVisit(UsingForDirective const& _usingFor) override;
+ bool visit(StructDefinition const& _struct) override;
+ bool visit(FunctionDefinition const& _function) override;
+ bool visit(VariableDeclaration const& _variable) override;
/// We need to do this manually because we want to pass the bases of the current contract in
/// case this is a base constructor call.
void visitManually(ModifierInvocation const& _modifier, std::vector<ContractDefinition const*> const& _bases);
- virtual bool visit(EventDefinition const& _eventDef) override;
- virtual void endVisit(FunctionTypeName const& _funType) override;
- virtual bool visit(InlineAssembly const& _inlineAssembly) override;
- virtual bool visit(IfStatement const& _ifStatement) override;
- virtual bool visit(WhileStatement const& _whileStatement) override;
- virtual bool visit(ForStatement const& _forStatement) override;
- virtual void endVisit(Return const& _return) override;
- virtual bool visit(EmitStatement const&) override { m_insideEmitStatement = true; return true; }
- virtual void endVisit(EmitStatement const& _emit) override;
- virtual bool visit(VariableDeclarationStatement const& _variable) override;
- virtual void endVisit(ExpressionStatement const& _statement) override;
- virtual bool visit(Conditional const& _conditional) override;
- virtual bool visit(Assignment const& _assignment) override;
- virtual bool visit(TupleExpression const& _tuple) override;
- virtual void endVisit(BinaryOperation const& _operation) override;
- virtual bool visit(UnaryOperation const& _operation) override;
- virtual bool visit(FunctionCall const& _functionCall) override;
- virtual void endVisit(NewExpression const& _newExpression) override;
- virtual bool visit(MemberAccess const& _memberAccess) override;
- virtual bool visit(IndexAccess const& _indexAccess) override;
- virtual bool visit(Identifier const& _identifier) override;
- virtual void endVisit(ElementaryTypeNameExpression const& _expr) override;
- virtual void endVisit(Literal const& _literal) override;
-
- template <class T>
- void findDuplicateDefinitions(std::map<std::string, std::vector<T>> const& _definitions, std::string _message);
+ bool visit(EventDefinition const& _eventDef) override;
+ void endVisit(FunctionTypeName const& _funType) override;
+ bool visit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(IfStatement const& _ifStatement) override;
+ bool visit(WhileStatement const& _whileStatement) override;
+ bool visit(ForStatement const& _forStatement) override;
+ void endVisit(Return const& _return) override;
+ bool visit(EmitStatement const&) override { m_insideEmitStatement = true; return true; }
+ void endVisit(EmitStatement const& _emit) override;
+ bool visit(VariableDeclarationStatement const& _variable) override;
+ void endVisit(ExpressionStatement const& _statement) override;
+ bool visit(Conditional const& _conditional) override;
+ bool visit(Assignment const& _assignment) override;
+ bool visit(TupleExpression const& _tuple) override;
+ void endVisit(BinaryOperation const& _operation) override;
+ bool visit(UnaryOperation const& _operation) override;
+ bool visit(FunctionCall const& _functionCall) override;
+ void endVisit(NewExpression const& _newExpression) override;
+ bool visit(MemberAccess const& _memberAccess) override;
+ bool visit(IndexAccess const& _indexAccess) override;
+ bool visit(Identifier const& _identifier) override;
+ void endVisit(ElementaryTypeNameExpression const& _expr) override;
+ void endVisit(Literal const& _literal) override;
bool contractDependenciesAreCyclic(
ContractDefinition const& _contract,
@@ -183,7 +162,7 @@ private:
/// Flag indicating whether we are currently inside a StructDefinition.
bool m_insideStruct = false;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
};
}
diff --git a/libsolidity/analysis/ViewPureChecker.cpp b/libsolidity/analysis/ViewPureChecker.cpp
index b0cacc43..1112d682 100644
--- a/libsolidity/analysis/ViewPureChecker.cpp
+++ b/libsolidity/analysis/ViewPureChecker.cpp
@@ -19,13 +19,16 @@
#include <libevmasm/SemanticInformation.h>
-#include <libsolidity/inlineasm/AsmData.h>
#include <libsolidity/ast/ExperimentalFeatures.h>
+#include <libyul/AsmData.h>
+
+#include <liblangutil/ErrorReporter.h>
#include <functional>
using namespace std;
using namespace dev;
+using namespace langutil;
using namespace dev::solidity;
namespace
@@ -37,48 +40,48 @@ public:
explicit AssemblyViewPureChecker(std::function<void(StateMutability, SourceLocation const&)> _reportMutability):
m_reportMutability(_reportMutability) {}
- void operator()(assembly::Label const&) { }
- void operator()(assembly::Instruction const& _instruction)
+ void operator()(yul::Label const&) { }
+ void operator()(yul::Instruction const& _instruction)
{
checkInstruction(_instruction.location, _instruction.instruction);
}
- void operator()(assembly::Literal const&) {}
- void operator()(assembly::Identifier const&) {}
- void operator()(assembly::FunctionalInstruction const& _instr)
+ void operator()(yul::Literal const&) {}
+ void operator()(yul::Identifier const&) {}
+ void operator()(yul::FunctionalInstruction const& _instr)
{
checkInstruction(_instr.location, _instr.instruction);
for (auto const& arg: _instr.arguments)
boost::apply_visitor(*this, arg);
}
- void operator()(assembly::ExpressionStatement const& _expr)
+ void operator()(yul::ExpressionStatement const& _expr)
{
boost::apply_visitor(*this, _expr.expression);
}
- void operator()(assembly::StackAssignment const&) {}
- void operator()(assembly::Assignment const& _assignment)
+ void operator()(yul::StackAssignment const&) {}
+ void operator()(yul::Assignment const& _assignment)
{
boost::apply_visitor(*this, *_assignment.value);
}
- void operator()(assembly::VariableDeclaration const& _varDecl)
+ void operator()(yul::VariableDeclaration const& _varDecl)
{
if (_varDecl.value)
boost::apply_visitor(*this, *_varDecl.value);
}
- void operator()(assembly::FunctionDefinition const& _funDef)
+ void operator()(yul::FunctionDefinition const& _funDef)
{
(*this)(_funDef.body);
}
- void operator()(assembly::FunctionCall const& _funCall)
+ void operator()(yul::FunctionCall const& _funCall)
{
for (auto const& arg: _funCall.arguments)
boost::apply_visitor(*this, arg);
}
- void operator()(assembly::If const& _if)
+ void operator()(yul::If const& _if)
{
boost::apply_visitor(*this, *_if.condition);
(*this)(_if.body);
}
- void operator()(assembly::Switch const& _switch)
+ void operator()(yul::Switch const& _switch)
{
boost::apply_visitor(*this, *_switch.expression);
for (auto const& _case: _switch.cases)
@@ -88,14 +91,14 @@ public:
(*this)(_case.body);
}
}
- void operator()(assembly::ForLoop const& _for)
+ void operator()(yul::ForLoop const& _for)
{
(*this)(_for.pre);
boost::apply_visitor(*this, *_for.condition);
(*this)(_for.body);
(*this)(_for.post);
}
- void operator()(assembly::Block const& _block)
+ void operator()(yul::Block const& _block)
{
for (auto const& s: _block.statements)
boost::apply_visitor(*this, s);
diff --git a/libsolidity/analysis/ViewPureChecker.h b/libsolidity/analysis/ViewPureChecker.h
index faa5b698..fd2432a7 100644
--- a/libsolidity/analysis/ViewPureChecker.h
+++ b/libsolidity/analysis/ViewPureChecker.h
@@ -21,11 +21,15 @@
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/ast/ASTVisitor.h>
-#include <libsolidity/interface/ErrorReporter.h>
-
#include <map>
#include <memory>
+namespace langutil
+{
+class ErrorReporter;
+struct SourceLocation;
+}
+
namespace dev
{
namespace solidity
@@ -34,7 +38,7 @@ namespace solidity
class ViewPureChecker: private ASTConstVisitor
{
public:
- ViewPureChecker(std::vector<std::shared_ptr<ASTNode>> const& _ast, ErrorReporter& _errorReporter):
+ ViewPureChecker(std::vector<std::shared_ptr<ASTNode>> const& _ast, langutil::ErrorReporter& _errorReporter):
m_ast(_ast), m_errorReporter(_errorReporter) {}
bool check();
@@ -43,34 +47,34 @@ private:
struct MutabilityAndLocation
{
StateMutability mutability;
- SourceLocation location;
+ langutil::SourceLocation location;
};
- virtual bool visit(FunctionDefinition const& _funDef) override;
- virtual void endVisit(FunctionDefinition const& _funDef) override;
- virtual bool visit(ModifierDefinition const& _modifierDef) override;
- virtual void endVisit(ModifierDefinition const& _modifierDef) override;
- virtual void endVisit(Identifier const& _identifier) override;
- virtual bool visit(MemberAccess const& _memberAccess) override;
- virtual void endVisit(MemberAccess const& _memberAccess) override;
- virtual void endVisit(IndexAccess const& _indexAccess) override;
- virtual void endVisit(ModifierInvocation const& _modifier) override;
- virtual void endVisit(FunctionCall const& _functionCall) override;
- virtual void endVisit(InlineAssembly const& _inlineAssembly) override;
+ bool visit(FunctionDefinition const& _funDef) override;
+ void endVisit(FunctionDefinition const& _funDef) override;
+ bool visit(ModifierDefinition const& _modifierDef) override;
+ void endVisit(ModifierDefinition const& _modifierDef) override;
+ void endVisit(Identifier const& _identifier) override;
+ bool visit(MemberAccess const& _memberAccess) override;
+ void endVisit(MemberAccess const& _memberAccess) override;
+ void endVisit(IndexAccess const& _indexAccess) override;
+ void endVisit(ModifierInvocation const& _modifier) override;
+ void endVisit(FunctionCall const& _functionCall) override;
+ void endVisit(InlineAssembly const& _inlineAssembly) override;
/// Called when an element of mutability @a _mutability is encountered.
/// Creates appropriate warnings and errors and sets @a m_currentBestMutability.
void reportMutability(
StateMutability _mutability,
- SourceLocation const& _location,
- boost::optional<SourceLocation> const& _nestedLocation = {}
+ langutil::SourceLocation const& _location,
+ boost::optional<langutil::SourceLocation> const& _nestedLocation = {}
);
std::vector<std::shared_ptr<ASTNode>> const& m_ast;
- ErrorReporter& m_errorReporter;
+ langutil::ErrorReporter& m_errorReporter;
bool m_errors = false;
- MutabilityAndLocation m_bestMutabilityAndLocation = MutabilityAndLocation{StateMutability::Payable, SourceLocation()};
+ MutabilityAndLocation m_bestMutabilityAndLocation = MutabilityAndLocation{StateMutability::Payable, langutil::SourceLocation()};
FunctionDefinition const* m_currentFunction = nullptr;
std::map<ModifierDefinition const*, MutabilityAndLocation> m_inferredMutability;
};