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.h52
-rw-r--r--libsolidity/ast/ASTAnnotations.h7
-rw-r--r--libsolidity/ast/ASTEnums.h52
-rw-r--r--libsolidity/ast/ASTForward.h1
-rw-r--r--libsolidity/ast/ASTJsonConverter.cpp29
-rw-r--r--libsolidity/ast/ASTJsonConverter.h1
-rw-r--r--libsolidity/ast/ExperimentalFeatures.h50
-rw-r--r--libsolidity/ast/Types.cpp152
-rw-r--r--libsolidity/ast/Types.h30
10 files changed, 259 insertions, 126 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index ebc8bd48..e173237e 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -162,7 +162,7 @@ FunctionDefinition const* ContractDefinition::fallbackFunction() const
{
for (ContractDefinition const* contract: annotation().linearizedBaseContracts)
for (FunctionDefinition const* f: contract->definedFunctions())
- if (f->name().empty())
+ if (f->isFallback())
return f;
return nullptr;
}
@@ -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 e4656f72..8a577c0c 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,17 +605,20 @@ 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 isDeclaredConst() const { return m_isDeclaredConst; }
- bool isPayable() const { return m_isPayable; }
+ bool isFallback() const { return name().empty(); }
+ bool isDeclaredConst() const { return m_stateMutability == StateMutability::View; }
+ 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() && !name().empty();
+ return Declaration::isVisibleInContract() && !isConstructor() && !isFallback();
}
- virtual bool isPartOfExternalInterface() const override { return isPublic() && !m_isConstructor && !name().empty(); }
+ virtual bool isPartOfExternalInterface() const override { return isPublic() && !isConstructor() && !isFallback(); }
/// @returns the external signature of the function
/// That consists of the name of the function followed by the types of the
@@ -614,9 +634,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;
};
@@ -876,11 +895,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;
@@ -894,15 +912,15 @@ 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 isDeclaredConst() const { return m_stateMutability == StateMutability::View; }
+ 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 45a6dd1a..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
@@ -79,8 +82,8 @@ struct TypeDeclarationAnnotation: ASTAnnotation
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation, DocumentedAnnotation
{
- /// Whether all functions are implemented.
- bool isFullyImplemented = true;
+ /// List of functions without a body. Can also contain functions from base classes.
+ std::vector<FunctionDefinition const*> unimplementedFunctions;
/// List of all (direct and indirect) base contracts in order from derived to
/// base, including the contract itself.
std::vector<ContractDefinition const*> linearizedBaseContracts;
diff --git a/libsolidity/ast/ASTEnums.h b/libsolidity/ast/ASTEnums.h
new file mode 100644
index 00000000..f7c75878
--- /dev/null
+++ b/libsolidity/ast/ASTEnums.h
@@ -0,0 +1,52 @@
+/*
+ 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 { View, NonPayable, Payable };
+
+inline std::string stateMutabilityToString(StateMutability const& _stateMutability)
+{
+ switch(_stateMutability)
+ {
+ 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 eda70b63..abee55ee 100644
--- a/libsolidity/ast/ASTJsonConverter.cpp
+++ b/libsolidity/ast/ASTJsonConverter.cpp
@@ -253,7 +253,7 @@ bool ASTJsonConverter::visit(ContractDefinition const& _node)
make_pair("name", _node.name()),
make_pair("documentation", _node.documentation() ? Json::Value(*_node.documentation()) : Json::nullValue),
make_pair("contractKind", contractKind(_node.contractKind())),
- make_pair("fullyImplemented", _node.annotation().isFullyImplemented),
+ make_pair("fullyImplemented", _node.annotation().unimplementedFunctions.empty()),
make_pair("linearizedBaseContracts", getContainerIds(_node.annotation().linearizedBaseContracts)),
make_pair("baseContracts", toJson(_node.baseContracts())),
make_pair("contractDependencies", getContainerIds(_node.annotation().contractDependencies)),
@@ -285,7 +285,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()))
@@ -325,7 +325,7 @@ bool ASTJsonConverter::visit(FunctionDefinition const& _node)
make_pair("name", _node.name()),
make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()),
make_pair("payable", _node.isPayable()),
- make_pair("visibility", visibility(_node.visibility())),
+ 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 +346,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 +361,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()))
});
@@ -418,7 +418,7 @@ bool ASTJsonConverter::visit(FunctionTypeName const& _node)
{
setJsonNode(_node, "FunctionTypeName", {
make_pair("payable", _node.isPayable()),
- make_pair("visibility", visibility(_node.visibility())),
+ make_pair("visibility", Declaration::visibilityToString(_node.visibility())),
make_pair(m_legacy ? "constant" : "isDeclaredConst", _node.isDeclaredConst()),
make_pair("parameterTypes", toJson(*_node.parameterTypeList())),
make_pair("returnParameterTypes", toJson(*_node.returnParameterTypeList())),
@@ -730,23 +730,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..70e260db 100644
--- a/libsolidity/ast/ASTJsonConverter.h
+++ b/libsolidity/ast/ASTJsonConverter.h
@@ -128,7 +128,6 @@ 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);
diff --git a/libsolidity/ast/ExperimentalFeatures.h b/libsolidity/ast/ExperimentalFeatures.h
new file mode 100644
index 00000000..0c03ea4a
--- /dev/null
+++ b/libsolidity/ast/ExperimentalFeatures.h
@@ -0,0 +1,50 @@
+/*
+ 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
+{
+ ABIEncoderV2, // new ABI encoder that makes use of JULIA
+ Test,
+ TestOnlyAnalysis
+};
+
+static const std::map<ExperimentalFeature, bool> ExperimentalFeatureOnlyAnalysis =
+{
+ { ExperimentalFeature::TestOnlyAnalysis, true },
+};
+
+static const std::map<std::string, ExperimentalFeature> ExperimentalFeatureNames =
+{
+ { "ABIEncoderV2", ExperimentalFeature::ABIEncoderV2 },
+ { "__test", ExperimentalFeature::Test },
+ { "__testOnlyAnalysis", ExperimentalFeature::TestOnlyAnalysis },
+};
+
+}
+}
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 84e4a077..302f1022 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::Bare, 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
@@ -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,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
FunctionDefinition const* constructor = _contract.constructor();
TypePointers parameters;
strings parameterNames;
- bool payable = false;
+ StateMutability stateMutability = StateMutability::NonPayable;
if (constructor)
{
@@ -2140,7 +2147,8 @@ 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,
@@ -2150,8 +2158,7 @@ FunctionTypePointer FunctionType::newExpressionType(ContractDefinition const& _c
Kind::Creation,
false,
nullptr,
- false,
- payable
+ stateMutability
);
}
@@ -2178,7 +2185,7 @@ string FunctionType::identifier() const
case Kind::External: id += "external"; break;
case Kind::CallCode: id += "callcode"; break;
case Kind::DelegateCall: id += "delegatecall"; break;
- case Kind::Bare: id += "bare"; break;
+ case Kind::BareCall: id += "barecall"; break;
case Kind::BareCallCode: id += "barecallcode"; break;
case Kind::BareDelegateCall: id += "baredelegatecall"; break;
case Kind::Creation: id += "creation"; break;
@@ -2210,6 +2217,8 @@ string FunctionType::identifier() const
}
if (isConstant())
id += "_constant";
+ if (isPayable())
+ id += "_payable";
id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
if (m_gasSet)
id += "gas";
@@ -2224,23 +2233,22 @@ 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 ||
+ isConstant() != other.isConstant() ||
+ isPayable() != other.isPayable() ||
+ 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,9 +2300,9 @@ 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)
+ if (isConstant())
name += " constant";
- if (m_isPayable)
+ if (isPayable())
name += " payable";
if (m_kind == Kind::External)
name += " external";
@@ -2344,14 +2352,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::Bare || 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 +2409,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
);
}
@@ -2402,17 +2426,14 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
{
case Kind::External:
case Kind::Creation:
- case Kind::ECRecover:
- case Kind::SHA256:
- case Kind::RIPEMD160:
- case Kind::Bare:
+ case Kind::BareCall:
case Kind::BareCallCode:
case Kind::BareDelegateCall:
{
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>(
@@ -2423,8 +2444,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
Kind::SetValue,
false,
nullptr,
- false,
- false,
+ StateMutability::NonPayable,
m_gasSet,
m_valueSet
)
@@ -2441,8 +2461,7 @@ MemberList::MemberMap FunctionType::nativeMembers(ContractDefinition const*) con
Kind::SetGas,
false,
nullptr,
- false,
- false,
+ StateMutability::NonPayable,
m_gasSet,
m_valueSet
)
@@ -2509,7 +2528,7 @@ bool FunctionType::isBareCall() const
{
switch (m_kind)
{
- case Kind::Bare:
+ case Kind::BareCall:
case Kind::BareCallCode:
case Kind::BareDelegateCall:
case Kind::ECRecover:
@@ -2524,6 +2543,7 @@ bool FunctionType::isBareCall() const
string FunctionType::externalSignature() const
{
solAssert(m_declaration != nullptr, "External signature of function needs declaration");
+ solAssert(!m_declaration->name().empty(), "Fallback function has no signature.");
bool _inLibrary = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
@@ -2577,8 +2597,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
@@ -2627,8 +2646,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 1db46355..56546a82 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; }
@@ -838,7 +844,7 @@ public:
External, ///< external call using CALL
CallCode, ///< external call using CALLCODE, i.e. not exchanging the storage
DelegateCall, ///< external call using DELEGATECALL, i.e. not exchanging the storage
- Bare, ///< CALL without function hash
+ BareCall, ///< CALL without function hash
BareCallCode, ///< CALLCODE without function hash
BareDelegateCall, ///< DELEGATECALL without function hash
Creation, ///< external call using CREATE
@@ -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,12 @@ public:
return *m_declaration;
}
bool hasDeclaration() const { return !!m_declaration; }
- bool isConstant() const { return m_isConstant; }
+ bool isConstant() const { return m_stateMutability == StateMutability::View; }
/// @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 +1031,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;
};