aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/ast
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/ast')
-rw-r--r--libsolidity/ast/AST.cpp11
-rw-r--r--libsolidity/ast/AST.h50
-rw-r--r--libsolidity/ast/ASTAnnotations.h3
-rw-r--r--libsolidity/ast/ASTEnums.h54
-rw-r--r--libsolidity/ast/ASTForward.h1
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp80
-rw-r--r--libsolidity/ast/ASTJsonConverter.h21
-rw-r--r--libsolidity/ast/ASTPrinter.cpp14
-rw-r--r--libsolidity/ast/ASTPrinter.h4
-rw-r--r--libsolidity/ast/ASTVisitor.h4
-rw-r--r--libsolidity/ast/AST_accept.h12
-rw-r--r--libsolidity/ast/ExperimentalFeatures.h53
-rw-r--r--libsolidity/ast/Types.cpp155
-rw-r--r--libsolidity/ast/Types.h27
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;
};