diff options
Diffstat (limited to 'libsolidity/ast')
-rw-r--r-- | libsolidity/ast/AST.cpp | 11 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 50 | ||||
-rw-r--r-- | libsolidity/ast/ASTAnnotations.h | 3 | ||||
-rw-r--r-- | libsolidity/ast/ASTEnums.h | 54 | ||||
-rw-r--r-- | libsolidity/ast/ASTForward.h | 1 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.cpp | 80 | ||||
-rw-r--r-- | libsolidity/ast/ASTJsonConverter.h | 21 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.cpp | 14 | ||||
-rw-r--r-- | libsolidity/ast/ASTPrinter.h | 4 | ||||
-rw-r--r-- | libsolidity/ast/ASTVisitor.h | 4 | ||||
-rw-r--r-- | libsolidity/ast/AST_accept.h | 12 | ||||
-rw-r--r-- | libsolidity/ast/ExperimentalFeatures.h | 53 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 155 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 27 |
14 files changed, 299 insertions, 190 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 1d68231e..7f4dea0e 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -22,6 +22,7 @@ #include <libsolidity/ast/AST.h> #include <libsolidity/ast/ASTVisitor.h> +#include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/AST_accept.h> #include <libdevcore/SHA3.h> @@ -188,7 +189,6 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter { if (!m_interfaceFunctionList) { - set<string> functionsSeen; set<string> signaturesSeen; m_interfaceFunctionList.reset(new vector<pair<FixedHash<4>, FunctionTypePointer>>()); for (ContractDefinition const* contract: annotation().linearizedBaseContracts) @@ -371,6 +371,15 @@ string FunctionDefinition::externalSignature() const return FunctionType(*this).externalSignature(); } +string FunctionDefinition::fullyQualifiedName() const +{ + auto const* contract = dynamic_cast<ContractDefinition const*>(scope()); + solAssert(contract, "Enclosing scope of function definition was not set."); + + auto fname = name().empty() ? "<fallback>" : name(); + return sourceUnitName() + ":" + contract->name() + "." + fname; +} + FunctionDefinitionAnnotation& FunctionDefinition::annotation() const { if (!m_annotation) diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 3e97286b..4592a190 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -28,6 +28,7 @@ #include <libsolidity/ast/Types.h> #include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/ASTAnnotations.h> +#include <libsolidity/ast/ASTEnums.h> #include <libevmasm/SourceLocation.h> #include <libevmasm/Instruction.h> @@ -152,6 +153,24 @@ public: /// Visibility ordered from restricted to unrestricted. enum class Visibility { Default, Private, Internal, Public, External }; + static std::string visibilityToString(Declaration::Visibility _visibility) + { + switch(_visibility) + { + case Declaration::Visibility::Public: + return "public"; + case Declaration::Visibility::Internal: + return "internal"; + case Declaration::Visibility::Private: + return "private"; + case Declaration::Visibility::External: + return "external"; + default: + solAssert(false, "Invalid visibility specifier."); + } + return std::string(); + } + Declaration( SourceLocation const& _location, ASTPointer<ASTString> const& _name, @@ -566,21 +585,19 @@ public: SourceLocation const& _location, ASTPointer<ASTString> const& _name, Declaration::Visibility _visibility, + StateMutability _stateMutability, bool _isConstructor, ASTPointer<ASTString> const& _documentation, ASTPointer<ParameterList> const& _parameters, - bool _isDeclaredConst, std::vector<ASTPointer<ModifierInvocation>> const& _modifiers, ASTPointer<ParameterList> const& _returnParameters, - bool _isPayable, ASTPointer<Block> const& _body ): CallableDeclaration(_location, _name, _visibility, _parameters, _returnParameters), Documented(_documentation), ImplementationOptional(_body != nullptr), + m_stateMutability(_stateMutability), m_isConstructor(_isConstructor), - m_isDeclaredConst(_isDeclaredConst), - m_isPayable(_isPayable), m_functionModifiers(_modifiers), m_body(_body) {} @@ -588,13 +605,14 @@ public: virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; + StateMutability stateMutability() const { return m_stateMutability; } bool isConstructor() const { return m_isConstructor; } bool isFallback() const { return name().empty(); } - bool isDeclaredConst() const { return m_isDeclaredConst; } - bool isPayable() const { return m_isPayable; } + bool isPayable() const { return m_stateMutability == StateMutability::Payable; } std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; } std::vector<ASTPointer<VariableDeclaration>> const& returnParameters() const { return m_returnParameters->parameters(); } Block const& body() const { solAssert(m_body, ""); return *m_body; } + std::string fullyQualifiedName() const; virtual bool isVisibleInContract() const override { return Declaration::isVisibleInContract() && !isConstructor() && !isFallback(); @@ -615,9 +633,8 @@ public: virtual FunctionDefinitionAnnotation& annotation() const override; private: + StateMutability m_stateMutability; bool m_isConstructor; - bool m_isDeclaredConst; - bool m_isPayable; std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers; ASTPointer<Block> m_body; }; @@ -819,11 +836,10 @@ private: */ class TypeName: public ASTNode { -public: +protected: explicit TypeName(SourceLocation const& _location): ASTNode(_location) {} - virtual void accept(ASTVisitor& _visitor) override; - virtual void accept(ASTConstVisitor& _visitor) const override; +public: virtual TypeNameAnnotation& annotation() const override; }; @@ -877,11 +893,10 @@ public: ASTPointer<ParameterList> const& _parameterTypes, ASTPointer<ParameterList> const& _returnTypes, Declaration::Visibility _visibility, - bool _isDeclaredConst, - bool _isPayable + StateMutability _stateMutability ): TypeName(_location), m_parameterTypes(_parameterTypes), m_returnTypes(_returnTypes), - m_visibility(_visibility), m_isDeclaredConst(_isDeclaredConst), m_isPayable(_isPayable) + m_visibility(_visibility), m_stateMutability(_stateMutability) {} virtual void accept(ASTVisitor& _visitor) override; virtual void accept(ASTConstVisitor& _visitor) const override; @@ -895,15 +910,14 @@ public: { return m_visibility == Declaration::Visibility::Default ? Declaration::Visibility::Internal : m_visibility; } - bool isDeclaredConst() const { return m_isDeclaredConst; } - bool isPayable() const { return m_isPayable; } + StateMutability stateMutability() const { return m_stateMutability; } + bool isPayable() const { return m_stateMutability == StateMutability::Payable; } private: ASTPointer<ParameterList> m_parameterTypes; ASTPointer<ParameterList> m_returnTypes; Declaration::Visibility m_visibility; - bool m_isDeclaredConst; - bool m_isPayable; + StateMutability m_stateMutability; }; /** diff --git a/libsolidity/ast/ASTAnnotations.h b/libsolidity/ast/ASTAnnotations.h index f757f03c..fd9efb4d 100644 --- a/libsolidity/ast/ASTAnnotations.h +++ b/libsolidity/ast/ASTAnnotations.h @@ -23,6 +23,7 @@ #pragma once #include <libsolidity/ast/ASTForward.h> +#include <libsolidity/ast/ExperimentalFeatures.h> #include <map> #include <memory> @@ -61,6 +62,8 @@ struct SourceUnitAnnotation: ASTAnnotation std::string path; /// The exported symbols (all global symbols). std::map<ASTString, std::vector<Declaration const*>> exportedSymbols; + /// Experimental features. + std::set<ExperimentalFeature> experimentalFeatures; }; struct ImportAnnotation: ASTAnnotation diff --git a/libsolidity/ast/ASTEnums.h b/libsolidity/ast/ASTEnums.h new file mode 100644 index 00000000..5ba21907 --- /dev/null +++ b/libsolidity/ast/ASTEnums.h @@ -0,0 +1,54 @@ +/* + 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/>. +*/ +/** + * @date 2017 + * Enums for AST classes. + */ + +#pragma once + +#include <libsolidity/interface/Exceptions.h> + +#include <string> + +namespace dev +{ +namespace solidity +{ + +// How a function can mutate the EVM state. +enum class StateMutability { Pure, View, NonPayable, Payable }; + +inline std::string stateMutabilityToString(StateMutability const& _stateMutability) +{ + switch(_stateMutability) + { + case StateMutability::Pure: + return "pure"; + case StateMutability::View: + return "view"; + case StateMutability::NonPayable: + return "nonpayable"; + case StateMutability::Payable: + return "payable"; + default: + solAssert(false, "Unknown state mutability."); + } +} + +} +} diff --git a/libsolidity/ast/ASTForward.h b/libsolidity/ast/ASTForward.h index cfeeaa58..15735368 100644 --- a/libsolidity/ast/ASTForward.h +++ b/libsolidity/ast/ASTForward.h @@ -95,6 +95,5 @@ using ASTPointer = std::shared_ptr<T>; using ASTString = std::string; - } } diff --git a/libsolidity/ast/ASTJsonConverter.cpp b/libsolidity/ast/ASTJsonConverter.cpp index e4a602cb..afc53bfe 100644 --- a/libsolidity/ast/ASTJsonConverter.cpp +++ b/libsolidity/ast/ASTJsonConverter.cpp @@ -15,8 +15,7 @@ along with solidity. If not, see <http://www.gnu.org/licenses/>. */ /** - * @author Lefteris <lefteris@ethdev.com> - * @date 2015 + * @date 2017 * Converts the AST into json format */ @@ -81,28 +80,30 @@ void ASTJsonConverter::setJsonNode( (_nodeType == "InlineAssembly") || (_nodeType == "Throw") ) - { - Json::Value children(Json::arrayValue); - m_currentValue["children"] = children; - } + m_currentValue["children"] = Json::arrayValue; for (auto& e: _attributes) { - if ( - (!e.second.isNull()) && - ( - (e.second.isObject() && e.second.isMember("name")) || - (e.second.isArray() && e.second[0].isObject() && e.second[0].isMember("name")) || - (e.first == "declarations") // (in the case (_,x)= ... there's a nullpointer at [0] - ) - ) + if ((!e.second.isNull()) && ( + (e.second.isObject() && e.second.isMember("name")) || + (e.second.isArray() && e.second[0].isObject() && e.second[0].isMember("name")) || + (e.first == "declarations") // (in the case (_,x)= ... there's a nullpointer at [0] + )) { if (e.second.isObject()) - m_currentValue["children"].append(std::move(e.second)); + { + if (!m_currentValue["children"].isArray()) + m_currentValue["children"] = Json::arrayValue; + appendMove(m_currentValue["children"], std::move(e.second)); + } if (e.second.isArray()) for (auto& child: e.second) if (!child.isNull()) - m_currentValue["children"].append(std::move(child)); + { + if (!m_currentValue["children"].isArray()) + m_currentValue["children"] = Json::arrayValue; + appendMove(m_currentValue["children"], std::move(child)); + } } else { @@ -147,7 +148,7 @@ Json::Value ASTJsonConverter::typePointerToJson(std::shared_ptr<std::vector<Type { Json::Value arguments(Json::arrayValue); for (auto const& tp: *_tps) - arguments.append(typePointerToJson(tp)); + appendMove(arguments, typePointerToJson(tp)); return arguments; } else @@ -186,7 +187,7 @@ void ASTJsonConverter::print(ostream& _stream, ASTNode const& _node) _stream << toJson(_node); } -Json::Value ASTJsonConverter::toJson(ASTNode const& _node) +Json::Value&& ASTJsonConverter::toJson(ASTNode const& _node) { _node.accept(*this); return std::move(m_currentValue); @@ -285,7 +286,7 @@ bool ASTJsonConverter::visit(StructDefinition const& _node) { setJsonNode(_node, "StructDefinition", { make_pair("name", _node.name()), - make_pair("visibility", visibility(_node.visibility())), + make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("canonicalName", _node.annotation().canonicalName), make_pair("members", toJson(_node.members())), make_pair("scope", idOrNull(_node.scope())) @@ -323,9 +324,11 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node) { std::vector<pair<string, Json::Value>> attributes = { make_pair("name", _node.name()), - make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()), + // FIXME: remove with next breaking release + make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View), make_pair("payable", _node.isPayable()), - make_pair("visibility", visibility(_node.visibility())), + make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), + make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("parameters", toJson(_node.parameterList())), make_pair("isConstructor", _node.isConstructor()), make_pair("returnParameters", toJson(*_node.returnParameterList())), @@ -346,7 +349,7 @@ bool ASTJsonConverter::visit(VariableDeclaration const& _node) make_pair("constant", _node.isConstant()), make_pair("stateVariable", _node.isStateVariable()), make_pair("storageLocation", location(_node.referenceLocation())), - make_pair("visibility", visibility(_node.visibility())), + make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("value", _node.value() ? toJson(*_node.value()) : Json::nullValue), make_pair("scope", idOrNull(_node.scope())), make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) @@ -361,7 +364,7 @@ bool ASTJsonConverter::visit(ModifierDefinition const& _node) { setJsonNode(_node, "ModifierDefinition", { make_pair("name", _node.name()), - make_pair("visibility", visibility(_node.visibility())), + make_pair("visibility", Declaration::visibilityToString(_node.visibility())), make_pair("parameters", toJson(_node.parameterList())), make_pair("body", toJson(_node.body())) }); @@ -377,12 +380,6 @@ bool ASTJsonConverter::visit(ModifierInvocation const& _node) return false; } -bool ASTJsonConverter::visit(TypeName const&) -{ - solAssert(false, "AST node of abstract type used."); - return false; -} - bool ASTJsonConverter::visit(EventDefinition const& _node) { m_inEvent = true; @@ -418,8 +415,10 @@ bool ASTJsonConverter::visit(FunctionTypeName const& _node) { setJsonNode(_node, "FunctionTypeName", { make_pair("payable", _node.isPayable()), - make_pair("visibility", visibility(_node.visibility())), - make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()), + make_pair("visibility", Declaration::visibilityToString(_node.visibility())), + make_pair("stateMutability", stateMutabilityToString(_node.stateMutability())), + // FIXME: remove with next breaking release + make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.stateMutability() <= StateMutability::View), make_pair("parameterTypes", toJson(*_node.parameterTypeList())), make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())), make_pair("typeDescriptions", typePointerToJson(_node.annotation().type)) @@ -545,7 +544,7 @@ bool ASTJsonConverter::visit(VariableDeclarationStatement const& _node) { Json::Value varDecs(Json::arrayValue); for (auto const& v: _node.annotation().assignments) - varDecs.append(idOrNull(v)); + appendMove(varDecs, idOrNull(v)); setJsonNode(_node, "VariableDeclarationStatement", { make_pair("assignments", std::move(varDecs)), make_pair("declarations", toJson(_node.declarations())), @@ -730,23 +729,6 @@ void ASTJsonConverter::endVisit(EventDefinition const&) m_inEvent = false; } -string ASTJsonConverter::visibility(Declaration::Visibility const& _visibility) -{ - switch (_visibility) - { - case Declaration::Visibility::Private: - return "private"; - case Declaration::Visibility::Internal: - return "internal"; - case Declaration::Visibility::Public: - return "public"; - case Declaration::Visibility::External: - return "external"; - default: - solAssert(false, "Unknown declaration visibility."); - } -} - string ASTJsonConverter::location(VariableDeclaration::Location _location) { switch (_location) diff --git a/libsolidity/ast/ASTJsonConverter.h b/libsolidity/ast/ASTJsonConverter.h index 27114c2a..60c660c1 100644 --- a/libsolidity/ast/ASTJsonConverter.h +++ b/libsolidity/ast/ASTJsonConverter.h @@ -49,13 +49,16 @@ public: ); /// Output the json representation of the AST to _stream. void print(std::ostream& _stream, ASTNode const& _node); - Json::Value toJson(ASTNode const& _node); + Json::Value&& toJson(ASTNode const& _node); template <class T> Json::Value toJson(std::vector<ASTPointer<T>> const& _nodes) { Json::Value ret(Json::arrayValue); for (auto const& n: _nodes) - ret.append(n ? toJson(*n) : Json::nullValue); + if (n) + appendMove(ret, toJson(*n)); + else + ret.append(Json::nullValue); return ret; } bool visit(SourceUnit const& _node) override; @@ -73,7 +76,6 @@ public: bool visit(ModifierDefinition const& _node) override; bool visit(ModifierInvocation const& _node) override; bool visit(EventDefinition const& _node) override; - bool visit(TypeName const& _node) override; bool visit(ElementaryTypeName const& _node) override; bool visit(UserDefinedTypeName const& _node) override; bool visit(FunctionTypeName const& _node) override; @@ -119,7 +121,7 @@ private: ); std::string sourceLocationToString(SourceLocation const& _location) const; std::string namePathToString(std::vector<ASTString> const& _namePath) const; - Json::Value idOrNull(ASTNode const* _pt) + static Json::Value idOrNull(ASTNode const* _pt) { return _pt ? Json::Value(nodeId(*_pt)) : Json::nullValue; } @@ -128,19 +130,18 @@ private: return _node ? toJson(*_node) : Json::nullValue; } Json::Value inlineAssemblyIdentifierToJson(std::pair<assembly::Identifier const* , InlineAssemblyAnnotation::ExternalIdentifierInfo> _info); - std::string visibility(Declaration::Visibility const& _visibility); std::string location(VariableDeclaration::Location _location); std::string contractKind(ContractDefinition::ContractKind _kind); std::string functionCallKind(FunctionCallKind _kind); std::string literalTokenKind(Token::Value _token); std::string type(Expression const& _expression); std::string type(VariableDeclaration const& _varDecl); - int nodeId(ASTNode const& _node) + static int nodeId(ASTNode const& _node) { return _node.id(); } template<class Container> - Json::Value getContainerIds(Container const& container) + static Json::Value getContainerIds(Container const& container) { Json::Value tmp(Json::arrayValue); for (auto const& element: container) @@ -156,6 +157,12 @@ private: std::vector<std::pair<std::string, Json::Value>> &_attributes, ExpressionAnnotation const& _annotation ); + static void appendMove(Json::Value& _array, Json::Value&& _value) + { + solAssert(_array.isArray(), ""); + _array.append(std::move(_value)); + } + bool m_legacy = false; ///< if true, use legacy format bool m_inEvent = false; ///< whether we are currently inside an event or not Json::Value m_currentValue; diff --git a/libsolidity/ast/ASTPrinter.cpp b/libsolidity/ast/ASTPrinter.cpp index 23eb3b64..392179ef 100644 --- a/libsolidity/ast/ASTPrinter.cpp +++ b/libsolidity/ast/ASTPrinter.cpp @@ -105,7 +105,7 @@ bool ASTPrinter::visit(FunctionDefinition const& _node) { writeLine("FunctionDefinition \"" + _node.name() + "\"" + (_node.isPublic() ? " - public" : "") + - (_node.isDeclaredConst() ? " - const" : "")); + (_node.stateMutability() == StateMutability::View ? " - const" : "")); printSourcePart(_node); return goDeeper(); } @@ -143,13 +143,6 @@ bool ASTPrinter::visit(EventDefinition const& _node) return goDeeper(); } -bool ASTPrinter::visit(TypeName const& _node) -{ - writeLine("TypeName"); - printSourcePart(_node); - return goDeeper(); -} - bool ASTPrinter::visit(ElementaryTypeName const& _node) { writeLine(string("ElementaryTypeName ") + _node.typeName().toString()); @@ -434,11 +427,6 @@ void ASTPrinter::endVisit(EventDefinition const&) m_indentation--; } -void ASTPrinter::endVisit(TypeName const&) -{ - m_indentation--; -} - void ASTPrinter::endVisit(ElementaryTypeName const&) { m_indentation--; diff --git a/libsolidity/ast/ASTPrinter.h b/libsolidity/ast/ASTPrinter.h index 4a37f17f..d6897dfd 100644 --- a/libsolidity/ast/ASTPrinter.h +++ b/libsolidity/ast/ASTPrinter.h @@ -60,7 +60,6 @@ public: bool visit(ModifierDefinition const& _node) override; bool visit(ModifierInvocation const& _node) override; bool visit(EventDefinition const& _node) override; - bool visit(TypeName const& _node) override; bool visit(ElementaryTypeName const& _node) override; bool visit(UserDefinedTypeName const& _node) override; bool visit(FunctionTypeName const& _node) override; @@ -104,7 +103,6 @@ public: void endVisit(ModifierDefinition const&) override; void endVisit(ModifierInvocation const&) override; void endVisit(EventDefinition const&) override; - void endVisit(TypeName const&) override; void endVisit(ElementaryTypeName const&) override; void endVisit(UserDefinedTypeName const&) override; void endVisit(FunctionTypeName const&) override; @@ -146,7 +144,7 @@ private: std::string m_source; ASTNode const* m_ast; GasEstimator::ASTGasConsumption m_gasCosts; - std::ostream* m_ostream; + std::ostream* m_ostream = nullptr; }; } diff --git a/libsolidity/ast/ASTVisitor.h b/libsolidity/ast/ASTVisitor.h index 20be634b..b726d592 100644 --- a/libsolidity/ast/ASTVisitor.h +++ b/libsolidity/ast/ASTVisitor.h @@ -58,7 +58,6 @@ public: virtual bool visit(ModifierDefinition& _node) { return visitNode(_node); } virtual bool visit(ModifierInvocation& _node) { return visitNode(_node); } virtual bool visit(EventDefinition& _node) { return visitNode(_node); } - virtual bool visit(TypeName& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeName& _node) { return visitNode(_node); } virtual bool visit(UserDefinedTypeName& _node) { return visitNode(_node); } virtual bool visit(FunctionTypeName& _node) { return visitNode(_node); } @@ -104,7 +103,6 @@ public: virtual void endVisit(ModifierDefinition& _node) { endVisitNode(_node); } virtual void endVisit(ModifierInvocation& _node) { endVisitNode(_node); } virtual void endVisit(EventDefinition& _node) { endVisitNode(_node); } - virtual void endVisit(TypeName& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeName& _node) { endVisitNode(_node); } virtual void endVisit(UserDefinedTypeName& _node) { endVisitNode(_node); } virtual void endVisit(FunctionTypeName& _node) { endVisitNode(_node); } @@ -162,7 +160,6 @@ public: virtual bool visit(ModifierDefinition const& _node) { return visitNode(_node); } virtual bool visit(ModifierInvocation const& _node) { return visitNode(_node); } virtual bool visit(EventDefinition const& _node) { return visitNode(_node); } - virtual bool visit(TypeName const& _node) { return visitNode(_node); } virtual bool visit(ElementaryTypeName const& _node) { return visitNode(_node); } virtual bool visit(UserDefinedTypeName const& _node) { return visitNode(_node); } virtual bool visit(FunctionTypeName const& _node) { return visitNode(_node); } @@ -208,7 +205,6 @@ public: virtual void endVisit(ModifierDefinition const& _node) { endVisitNode(_node); } virtual void endVisit(ModifierInvocation const& _node) { endVisitNode(_node); } virtual void endVisit(EventDefinition const& _node) { endVisitNode(_node); } - virtual void endVisit(TypeName const& _node) { endVisitNode(_node); } virtual void endVisit(ElementaryTypeName const& _node) { endVisitNode(_node); } virtual void endVisit(UserDefinedTypeName const& _node) { endVisitNode(_node); } virtual void endVisit(FunctionTypeName const& _node) { endVisitNode(_node); } diff --git a/libsolidity/ast/AST_accept.h b/libsolidity/ast/AST_accept.h index 7c1c64b0..904d9ff6 100644 --- a/libsolidity/ast/AST_accept.h +++ b/libsolidity/ast/AST_accept.h @@ -291,18 +291,6 @@ void EventDefinition::accept(ASTConstVisitor& _visitor) const _visitor.endVisit(*this); } -void TypeName::accept(ASTVisitor& _visitor) -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - -void TypeName::accept(ASTConstVisitor& _visitor) const -{ - _visitor.visit(*this); - _visitor.endVisit(*this); -} - void ElementaryTypeName::accept(ASTVisitor& _visitor) { _visitor.visit(*this); diff --git a/libsolidity/ast/ExperimentalFeatures.h b/libsolidity/ast/ExperimentalFeatures.h new file mode 100644 index 00000000..2c089671 --- /dev/null +++ b/libsolidity/ast/ExperimentalFeatures.h @@ -0,0 +1,53 @@ +/* + 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/>. +*/ +/** + * List of experimental features. + */ + +#pragma once + +#include <map> + +namespace dev +{ +namespace solidity +{ + +enum class ExperimentalFeature +{ + SMTChecker, + ABIEncoderV2, // new ABI encoder that makes use of JULIA + Test, + TestOnlyAnalysis +}; + +static const std::map<ExperimentalFeature, bool> ExperimentalFeatureOnlyAnalysis = +{ + { ExperimentalFeature::SMTChecker, true }, + { ExperimentalFeature::TestOnlyAnalysis, true }, +}; + +static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames = +{ + { "SMTChecker", ExperimentalFeature::SMTChecker }, + { "ABIEncoderV2", ExperimentalFeature::ABIEncoderV2 }, + { "__test", ExperimentalFeature::Test }, + { "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis }, +}; + +} +} diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp index 56fdd508..5e61cdee 100644 --- a/libsolidity/ast/Types.cpp +++ b/libsolidity/ast/Types.cpp @@ -477,8 +477,8 @@ MemberList::MemberMap IntegerType::nativeMembers(ContractDefinition const*) cons if (isAddress()) return { {"balance", make_shared<IntegerType >(256)}, - {"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, false, true)}, - {"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, false, true)}, + {"call", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCall, true, StateMutability::Payable)}, + {"callcode", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareCallCode, true, StateMutability::Payable)}, {"delegatecall", make_shared<FunctionType>(strings(), strings{"bool"}, FunctionType::Kind::BareDelegateCall, true)}, {"send", make_shared<FunctionType>(strings{"uint"}, strings{"bool"}, FunctionType::Kind::Send)}, {"transfer", make_shared<FunctionType>(strings{"uint"}, strings(), FunctionType::Kind::Transfer)} @@ -525,19 +525,20 @@ bool FixedPointType::isExplicitlyConvertibleTo(Type const& _convertTo) const TypePointer FixedPointType::unaryOperatorResult(Token::Value _operator) const { - // "delete" is ok for all fixed types - if (_operator == Token::Delete) + switch(_operator) + { + case Token::Delete: + // "delete" is ok for all fixed types return make_shared<TupleType>(); - // for fixed, we allow +, -, ++ and -- - else if ( - _operator == Token::Add || - _operator == Token::Sub || - _operator == Token::Inc || - _operator == Token::Dec - ) + case Token::Add: + case Token::Sub: + case Token::Inc: + case Token::Dec: + // for fixed, we allow +, -, ++ and -- return shared_from_this(); - else + default: return TypePointer(); + } } bool FixedPointType::operator==(Type const& _other) const @@ -738,18 +739,18 @@ bool RationalNumberType::isImplicitlyConvertibleTo(Type const& _convertTo) const { if (_convertTo.category() == Category::Integer) { - auto targetType = dynamic_cast<IntegerType const*>(&_convertTo); if (m_value == rational(0)) return true; if (isFractional()) return false; - int forSignBit = (targetType->isSigned() ? 1 : 0); + IntegerType const& targetType = dynamic_cast<IntegerType const&>(_convertTo); + int forSignBit = (targetType.isSigned() ? 1 : 0); if (m_value > rational(0)) { - if (m_value.numerator() <= (u256(-1) >> (256 - targetType->numBits() + forSignBit))) + if (m_value.numerator() <= (u256(-1) >> (256 - targetType.numBits() + forSignBit))) return true; } - else if (targetType->isSigned() && -m_value.numerator() <= (u256(1) << (targetType->numBits() - forSignBit))) + else if (targetType.isSigned() && -m_value.numerator() <= (u256(1) << (targetType.numBits() - forSignBit))) return true; return false; } @@ -1408,6 +1409,11 @@ unsigned ArrayType::calldataEncodedSize(bool _padded) const return unsigned(size); } +bool ArrayType::isDynamicallyEncoded() const +{ + return isDynamicallySized() || baseType()->isDynamicallyEncoded(); +} + u256 ArrayType::storageSize() const { if (isDynamicallySized()) @@ -1523,8 +1529,6 @@ TypePointer ArrayType::interfaceType(bool _inLibrary) const TypePointer baseExt = m_baseType->interfaceType(_inLibrary); if (!baseExt) return TypePointer(); - if (m_baseType->category() == Category::Array && m_baseType->isDynamicallySized()) - return TypePointer(); if (isDynamicallySized()) return make_shared<ArrayType>(DataLocation::Memory, baseExt); @@ -1710,6 +1714,11 @@ unsigned StructType::calldataEncodedSize(bool _padded) const return size; } +bool StructType::isDynamicallyEncoded() const +{ + solAssert(false, "Structs are not yet supported in the ABI."); +} + u256 StructType::memorySize() const { u256 size; @@ -1989,8 +1998,7 @@ TypePointer TupleType::closestTemporaryType(TypePointer const& _targetType) cons FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal): m_kind(_isInternal ? Kind::Internal : Kind::External), - m_isConstant(_function.isDeclaredConst()), - m_isPayable(_isInternal ? false : _function.isPayable()), + m_stateMutability(_function.stateMutability()), m_declaration(&_function) { TypePointers params; @@ -1998,6 +2006,9 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal TypePointers retParams; vector<string> retParamNames; + if (_isInternal && m_stateMutability == StateMutability::Payable) + m_stateMutability = StateMutability::NonPayable; + params.reserve(_function.parameters().size()); paramNames.reserve(_function.parameters().size()); for (ASTPointer<VariableDeclaration> const& var: _function.parameters()) @@ -2019,7 +2030,7 @@ FunctionType::FunctionType(FunctionDefinition const& _function, bool _isInternal } FunctionType::FunctionType(VariableDeclaration const& _varDecl): - m_kind(Kind::External), m_isConstant(true), m_declaration(&_varDecl) + m_kind(Kind::External), m_stateMutability(StateMutability::View), m_declaration(&_varDecl) { TypePointers paramTypes; vector<string> paramNames; @@ -2079,7 +2090,7 @@ FunctionType::FunctionType(VariableDeclaration const& _varDecl): } FunctionType::FunctionType(EventDefinition const& _event): - m_kind(Kind::Event), m_isConstant(true), m_declaration(&_event) + m_kind(Kind::Event), m_stateMutability(StateMutability::View), m_declaration(&_event) { TypePointers params; vector<string> paramNames; @@ -2096,14 +2107,10 @@ FunctionType::FunctionType(EventDefinition const& _event): FunctionType::FunctionType(FunctionTypeName const& _typeName): m_kind(_typeName.visibility() == VariableDeclaration::Visibility::External ? Kind::External : Kind::Internal), - m_isConstant(_typeName.isDeclaredConst()), - m_isPayable(_typeName.isPayable()) + m_stateMutability(_typeName.stateMutability()) { if (_typeName.isPayable()) - { solAssert(m_kind == Kind::External, "Internal payable function type used."); - solAssert(!m_isConstant, "Payable constant function"); - } for (auto const& t: _typeName.parameterTypes()) { solAssert(t->annotation().type, "Type not set for parameter."); @@ -2131,7 +2138,9 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c FunctionDefinition const* constructor = _contract.constructor(); TypePointers parameters; strings parameterNames; - bool payable = false; + StateMutability stateMutability = StateMutability::NonPayable; + + solAssert(_contract.contractKind() != ContractDefinition::ContractKind::Interface, ""); if (constructor) { @@ -2140,8 +2149,10 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c parameterNames.push_back(var->name()); parameters.push_back(var->annotation().type); } - payable = constructor->isPayable(); + if (constructor->isPayable()) + stateMutability = StateMutability::Payable; } + return make_shared<FunctionType>( parameters, TypePointers{make_shared<ContractType>(_contract)}, @@ -2150,8 +2161,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c Kind::Creation, false, nullptr, - false, - payable + stateMutability ); } @@ -2208,8 +2218,7 @@ string FunctionType::identifier() const case Kind::Require: id += "require";break; default: solAssert(false, "Unknown function location."); break; } - if (isConstant()) - id += "_constant"; + id += "_" + stateMutabilityToString(m_stateMutability); id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes); if (m_gasSet) id += "gas"; @@ -2224,23 +2233,21 @@ bool FunctionType::operator==(Type const& _other) const { if (_other.category() != category()) return false; - FunctionType const& other = dynamic_cast<FunctionType const&>(_other); - if (m_kind != other.m_kind) - return false; - if (m_isConstant != other.isConstant()) + FunctionType const& other = dynamic_cast<FunctionType const&>(_other); + if ( + m_kind != other.m_kind || + m_stateMutability != other.stateMutability() || + m_parameterTypes.size() != other.m_parameterTypes.size() || + m_returnParameterTypes.size() != other.m_returnParameterTypes.size() + ) return false; - if (m_parameterTypes.size() != other.m_parameterTypes.size() || - m_returnParameterTypes.size() != other.m_returnParameterTypes.size()) - return false; auto typeCompare = [](TypePointer const& _a, TypePointer const& _b) -> bool { return *_a == *_b; }; - - if (!equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(), - other.m_parameterTypes.cbegin(), typeCompare)) - return false; - if (!equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(), - other.m_returnParameterTypes.cbegin(), typeCompare)) + if ( + !equal(m_parameterTypes.cbegin(), m_parameterTypes.cend(), other.m_parameterTypes.cbegin(), typeCompare) || + !equal(m_returnParameterTypes.cbegin(), m_returnParameterTypes.cend(), other.m_returnParameterTypes.cbegin(), typeCompare) + ) return false; //@todo this is ugly, but cannot be prevented right now if (m_gasSet != other.m_gasSet || m_valueSet != other.m_valueSet) @@ -2292,10 +2299,8 @@ string FunctionType::toString(bool _short) const for (auto it = m_parameterTypes.begin(); it != m_parameterTypes.end(); ++it) name += (*it)->toString(_short) + (it + 1 == m_parameterTypes.end() ? "" : ","); name += ")"; - if (m_isConstant) - name += " constant"; - if (m_isPayable) - name += " payable"; + if (m_stateMutability != StateMutability::NonPayable) + name += " " + stateMutabilityToString(m_stateMutability); if (m_kind == Kind::External) name += " external"; if (!m_returnParameterTypes.empty()) @@ -2344,14 +2349,26 @@ unsigned FunctionType::sizeOnStack() const } unsigned size = 0; - if (kind == Kind::External || kind == Kind::CallCode || kind == Kind::DelegateCall) + + switch(kind) + { + case Kind::External: + case Kind::CallCode: + case Kind::DelegateCall: size = 2; - else if (kind == Kind::BareCall || kind == Kind::BareCallCode || kind == Kind::BareDelegateCall) - size = 1; - else if (kind == Kind::Internal) - size = 1; - else if (kind == Kind::ArrayPush || kind == Kind::ByteArrayPush) + break; + case Kind::BareCall: + case Kind::BareCallCode: + case Kind::BareDelegateCall: + case Kind::Internal: + case Kind::ArrayPush: + case Kind::ByteArrayPush: size = 1; + break; + default: + break; + } + if (m_gasSet) size++; if (m_valueSet) @@ -2389,10 +2406,14 @@ FunctionTypePointer FunctionType::interfaceFunctionType() const return FunctionTypePointer(); return make_shared<FunctionType>( - paramTypes, retParamTypes, - m_parameterNames, m_returnParameterNames, - m_kind, m_arbitraryParameters, - m_declaration, m_isConstant, m_isPayable + paramTypes, + retParamTypes, + m_parameterNames, + m_returnParameterNames, + m_kind, + m_arbitraryParameters, + m_declaration, + m_stateMutability ); } @@ -2409,7 +2430,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con MemberList::MemberMap members; if (m_kind != Kind::BareDelegateCall && m_kind != Kind::DelegateCall) { - if (m_isPayable) + if (isPayable()) members.push_back(MemberList::Member( "value", make_shared<FunctionType>( @@ -2420,8 +2441,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con Kind::SetValue, false, nullptr, - false, - false, + StateMutability::NonPayable, m_gasSet, m_valueSet ) @@ -2438,8 +2458,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con Kind::SetGas, false, nullptr, - false, - false, + StateMutability::NonPayable, m_gasSet, m_valueSet ) @@ -2575,8 +2594,7 @@ TypePointer FunctionType::copyAndSetGasOrValue(bool _setGas, bool _setValue) con m_kind, m_arbitraryParameters, m_declaration, - m_isConstant, - m_isPayable, + m_stateMutability, m_gasSet || _setGas, m_valueSet || _setValue, m_bound @@ -2625,8 +2643,7 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary, bool _bound) kind, m_arbitraryParameters, m_declaration, - m_isConstant, - m_isPayable, + m_stateMutability, m_gasSet, m_valueSet, _bound diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h index 5d2bdca0..ce2d3bf8 100644 --- a/libsolidity/ast/Types.h +++ b/libsolidity/ast/Types.h @@ -24,6 +24,7 @@ #include <libsolidity/interface/Exceptions.h> #include <libsolidity/ast/ASTForward.h> +#include <libsolidity/ast/ASTEnums.h> #include <libsolidity/parsing/Token.h> #include <libdevcore/Common.h> @@ -187,6 +188,7 @@ public: /// @returns number of bytes used by this type when encoded for CALL. If it is a dynamic type, /// returns the size of the pointer (usually 32). Returns 0 if the type cannot be encoded /// in calldata. + /// @note: This should actually not be called on types, where isDynamicallyEncoded returns true. /// If @a _padded then it is assumed that each element is padded to a multiple of 32 bytes. virtual unsigned calldataEncodedSize(bool _padded) const { (void)_padded; return 0; } /// @returns the size of this data type in bytes when stored in memory. For memory-reference @@ -194,8 +196,10 @@ public: virtual unsigned memoryHeadSize() const { return calldataEncodedSize(); } /// Convenience version of @see calldataEncodedSize(bool) unsigned calldataEncodedSize() const { return calldataEncodedSize(true); } - /// @returns true if the type is dynamically encoded in calldata + /// @returns true if the type is a dynamic array virtual bool isDynamicallySized() const { return false; } + /// @returns true if the type is dynamically encoded in the ABI + virtual bool isDynamicallyEncoded() const { return false; } /// @returns the number of storage slots required to hold this value in storage. /// For dynamically "allocated" types, it returns the size of the statically allocated head, virtual u256 storageSize() const { return 1; } @@ -609,6 +613,7 @@ public: virtual bool operator==(const Type& _other) const override; virtual unsigned calldataEncodedSize(bool _padded) const override; virtual bool isDynamicallySized() const override { return m_hasDynamicLength; } + virtual bool isDynamicallyEncoded() const override; virtual u256 storageSize() const override; virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); } virtual unsigned sizeOnStack() const override; @@ -723,6 +728,7 @@ public: virtual std::string identifier() const override; virtual bool operator==(Type const& _other) const override; virtual unsigned calldataEncodedSize(bool _padded) const override; + virtual bool isDynamicallyEncoded() const override; u256 memorySize() const; virtual u256 storageSize() const override; virtual bool canLiveOutsideStorage() const override { return true; } @@ -884,8 +890,7 @@ public: strings const& _returnParameterTypes, Kind _kind = Kind::Internal, bool _arbitraryParameters = false, - bool _constant = false, - bool _payable = false + StateMutability _stateMutability = StateMutability::NonPayable ): FunctionType( parseElementaryTypeVector(_parameterTypes), parseElementaryTypeVector(_returnParameterTypes), @@ -894,8 +899,7 @@ public: _kind, _arbitraryParameters, nullptr, - _constant, - _payable + _stateMutability ) { } @@ -912,8 +916,7 @@ public: Kind _kind = Kind::Internal, bool _arbitraryParameters = false, Declaration const* _declaration = nullptr, - bool _isConstant = false, - bool _isPayable = false, + StateMutability _stateMutability = StateMutability::NonPayable, bool _gasSet = false, bool _valueSet = false, bool _bound = false @@ -923,12 +926,11 @@ public: m_parameterNames(_parameterNames), m_returnParameterNames(_returnParameterNames), m_kind(_kind), + m_stateMutability(_stateMutability), m_arbitraryParameters(_arbitraryParameters), m_gasSet(_gasSet), m_valueSet(_valueSet), m_bound(_bound), - m_isConstant(_isConstant), - m_isPayable(_isPayable), m_declaration(_declaration) { solAssert( @@ -980,6 +982,7 @@ public: /// @returns true if the ABI is used for this call (only meaningful for external calls) bool isBareCall() const; Kind const& kind() const { return m_kind; } + StateMutability stateMutability() const { return m_stateMutability; } /// @returns the external signature of this function type given the function name std::string externalSignature() const; /// @returns the external identifier of this function (the hash of the signature). @@ -990,12 +993,11 @@ public: return *m_declaration; } bool hasDeclaration() const { return !!m_declaration; } - bool isConstant() const { return m_isConstant; } /// @returns true if the the result of this function only depends on its arguments /// and it does not modify the state. /// Currently, this will only return true for internal functions like keccak and ecrecover. bool isPure() const; - bool isPayable() const { return m_isPayable; } + bool isPayable() const { return m_stateMutability == StateMutability::Payable; } /// @return A shared pointer of an ASTString. /// Can contain a nullptr in which case indicates absence of documentation ASTPointer<ASTString> documentation() const; @@ -1028,13 +1030,12 @@ private: std::vector<std::string> m_parameterNames; std::vector<std::string> m_returnParameterNames; Kind const m_kind; + StateMutability m_stateMutability = StateMutability::NonPayable; /// true if the function takes an arbitrary number of arguments of arbitrary types bool const m_arbitraryParameters = false; bool const m_gasSet = false; ///< true iff the gas value to be used is on the stack bool const m_valueSet = false; ///< true iff the value to be sent is on the stack bool const m_bound = false; ///< true iff the function is called as arg1.fun(arg2, ..., argn) - bool m_isConstant = false; - bool m_isPayable = false; Declaration const* m_declaration = nullptr; }; |