aboutsummaryrefslogtreecommitdiffstats
path: root/libsolidity/ast
diff options
context:
space:
mode:
Diffstat (limited to 'libsolidity/ast')
-rw-r--r--libsolidity/ast/AST.cpp22
-rw-r--r--libsolidity/ast/AST.h4
-rw-r--r--libsolidity/ast/Types.cpp238
-rw-r--r--libsolidity/ast/Types.h46
4 files changed, 290 insertions, 20 deletions
diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp
index fcd6e38c..8a43c3f7 100644
--- a/libsolidity/ast/AST.cpp
+++ b/libsolidity/ast/AST.cpp
@@ -34,11 +34,24 @@ using namespace std;
using namespace dev;
using namespace dev::solidity;
+class IDDispenser
+{
+public:
+ static size_t next() { return ++instance(); }
+ static void reset() { instance() = 0; }
+private:
+ static size_t& instance()
+ {
+ static IDDispenser dispenser;
+ return dispenser.id;
+ }
+ size_t id = 0;
+};
+
ASTNode::ASTNode(SourceLocation const& _location):
+ m_id(IDDispenser::next()),
m_location(_location)
{
- static size_t id = 0;
- m_id = ++id;
}
ASTNode::~ASTNode()
@@ -46,6 +59,11 @@ ASTNode::~ASTNode()
delete m_annotation;
}
+void ASTNode::resetID()
+{
+ IDDispenser::reset();
+}
+
ASTAnnotation& ASTNode::annotation() const
{
if (!m_annotation)
diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h
index 6e81892b..4c75f7ea 100644
--- a/libsolidity/ast/AST.h
+++ b/libsolidity/ast/AST.h
@@ -59,6 +59,8 @@ public:
/// @returns an identifier of this AST node that is unique for a single compilation run.
size_t id() const { return m_id; }
+ /// Resets the global ID counter. This invalidates all previous IDs.
+ static void resetID();
virtual void accept(ASTVisitor& _visitor) = 0;
virtual void accept(ASTConstVisitor& _visitor) const = 0;
@@ -97,7 +99,7 @@ public:
///@}
protected:
- size_t m_id = 0;
+ size_t const m_id = 0;
/// Annotation - is specialised in derived classes, is created upon request (because of polymorphism).
mutable ASTAnnotation* m_annotation = nullptr;
diff --git a/libsolidity/ast/Types.cpp b/libsolidity/ast/Types.cpp
index 03ff8471..cefd0603 100644
--- a/libsolidity/ast/Types.cpp
+++ b/libsolidity/ast/Types.cpp
@@ -21,15 +21,22 @@
*/
#include <libsolidity/ast/Types.h>
-#include <limits>
-#include <boost/range/adaptor/reversed.hpp>
-#include <boost/range/adaptor/sliced.hpp>
+
+#include <libsolidity/interface/Utils.h>
+#include <libsolidity/ast/AST.h>
+
#include <libdevcore/CommonIO.h>
#include <libdevcore/CommonData.h>
#include <libdevcore/SHA3.h>
#include <libdevcore/UTF8.h>
-#include <libsolidity/interface/Utils.h>
-#include <libsolidity/ast/AST.h>
+
+#include <boost/algorithm/string/join.hpp>
+#include <boost/algorithm/string/replace.hpp>
+#include <boost/range/adaptor/reversed.hpp>
+#include <boost/range/adaptor/sliced.hpp>
+#include <boost/range/adaptor/transformed.hpp>
+
+#include <limits>
using namespace std;
using namespace dev;
@@ -117,6 +124,51 @@ u256 const& MemberList::storageSize() const
return m_storageOffsets->storageSize();
}
+/// Helper functions for type identifier
+namespace
+{
+
+string parenthesizeIdentifier(string const& _internal)
+{
+ return "$_" + _internal + "_$";
+}
+
+template <class Range>
+string identifierList(Range const&& _list)
+{
+ return parenthesizeIdentifier(boost::algorithm::join(_list, "_$_"));
+}
+
+string identifier(TypePointer const& _type)
+{
+ return _type ? _type->identifier() : "";
+}
+
+string identifierList(vector<TypePointer> const& _list)
+{
+ return identifierList(_list | boost::adaptors::transformed(identifier));
+}
+
+string identifierList(TypePointer const& _type)
+{
+ return parenthesizeIdentifier(identifier(_type));
+}
+
+string identifierList(TypePointer const& _type1, TypePointer const& _type2)
+{
+ TypePointers list;
+ list.push_back(_type1);
+ list.push_back(_type2);
+ return identifierList(list);
+}
+
+string parenthesizeUserIdentifier(string const& _internal)
+{
+ return parenthesizeIdentifier(boost::algorithm::replace_all_copy(_internal, "$", "$$$"));
+}
+
+}
+
TypePointer Type::fromElementaryTypeName(ElementaryTypeNameToken const& _type)
{
solAssert(Token::isElementaryTypeName(_type.token()),
@@ -272,7 +324,15 @@ IntegerType::IntegerType(int _bits, IntegerType::Modifier _modifier):
solAssert(
m_bits > 0 && m_bits <= 256 && m_bits % 8 == 0,
"Invalid bit number for integer type: " + dev::toString(_bits)
- );
+ );
+}
+
+string IntegerType::identifier() const
+{
+ if (isAddress())
+ return "t_address";
+ else
+ return "t_" + string(isSigned() ? "" : "u") + "int" + std::to_string(numBits());
}
bool IntegerType::isImplicitlyConvertibleTo(Type const& _convertTo) const
@@ -412,7 +472,12 @@ FixedPointType::FixedPointType(int _integerBits, int _fractionalBits, FixedPoint
m_fractionalBits % 8 == 0,
"Invalid bit number(s) for fixed type: " +
dev::toString(_integerBits) + "x" + dev::toString(_fractionalBits)
- );
+ );
+}
+
+string FixedPointType::identifier() const
+{
+ return "t_" + string(isSigned() ? "" : "u") + "fixed" + std::to_string(integerBits()) + "x" + std::to_string(fractionalBits());
}
bool FixedPointType::isImplicitlyConvertibleTo(Type const& _convertTo) const
@@ -770,6 +835,11 @@ TypePointer RationalNumberType::binaryOperatorResult(Token::Value _operator, Typ
}
}
+string RationalNumberType::identifier() const
+{
+ return "t_rational_" + m_value.numerator().str() + "_by_" + m_value.denominator().str();
+}
+
bool RationalNumberType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -909,6 +979,13 @@ bool StringLiteralType::isImplicitlyConvertibleTo(Type const& _convertTo) const
return false;
}
+string StringLiteralType::identifier() const
+{
+ // Since we have to return a valid identifier and the string itself may contain
+ // anything, we hash it.
+ return "t_stringliteral_" + toHex(keccak256(m_value).asBytes());
+}
+
bool StringLiteralType::operator==(const Type& _other) const
{
if (_other.category() != category())
@@ -1002,6 +1079,11 @@ MemberList::MemberMap FixedBytesType::nativeMembers(const ContractDefinition*) c
return MemberList::MemberMap{MemberList::Member{"length", make_shared<IntegerType>(8)}};
}
+string FixedBytesType::identifier() const
+{
+ return "t_bytes" + std::to_string(m_bytes);
+}
+
bool FixedBytesType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -1115,6 +1197,20 @@ string ReferenceType::stringForReferencePart() const
return "";
}
+string ReferenceType::identifierLocationSuffix() const
+{
+ string id;
+ if (location() == DataLocation::Storage)
+ id += "_storage";
+ else if (location() == DataLocation::Memory)
+ id += "_memory";
+ else
+ id += "_calldata";
+ if (isPointer())
+ id += "_ptr";
+ return id;
+}
+
bool ArrayType::isImplicitlyConvertibleTo(const Type& _convertTo) const
{
if (_convertTo.category() != category())
@@ -1170,6 +1266,27 @@ bool ArrayType::isExplicitlyConvertibleTo(const Type& _convertTo) const
return true;
}
+string ArrayType::identifier() const
+{
+ string id;
+ if (isString())
+ id = "t_string";
+ else if (isByteArray())
+ id = "t_bytes";
+ else
+ {
+ id = "t_array";
+ id += identifierList(baseType());
+ if (isDynamicallySized())
+ id += "dyn";
+ else
+ id += length().str();
+ }
+ id += identifierLocationSuffix();
+
+ return id;
+}
+
bool ArrayType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -1184,7 +1301,7 @@ bool ArrayType::operator==(Type const& _other) const
return false;
if (*other.baseType() != *baseType())
return false;
- return isDynamicallySized() || length() == other.length();
+ return isDynamicallySized() || length() == other.length();
}
unsigned ArrayType::calldataEncodedSize(bool _padded) const
@@ -1356,6 +1473,11 @@ TypePointer ArrayType::copyForLocation(DataLocation _location, bool _isPointer)
return copy;
}
+string ContractType::identifier() const
+{
+ return (m_super ? "t_super" : "t_contract") + parenthesizeUserIdentifier(m_contract.name()) + std::to_string(m_contract.id());
+}
+
bool ContractType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -1465,6 +1587,11 @@ bool StructType::isImplicitlyConvertibleTo(const Type& _convertTo) const
return this->m_struct == convertTo.m_struct;
}
+string StructType::identifier() const
+{
+ return "t_struct" + parenthesizeUserIdentifier(m_struct.name()) + std::to_string(m_struct.id()) + identifierLocationSuffix();
+}
+
bool StructType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -1605,6 +1732,11 @@ TypePointer EnumType::unaryOperatorResult(Token::Value _operator) const
return _operator == Token::Delete ? make_shared<TupleType>() : TypePointer();
}
+string EnumType::identifier() const
+{
+ return "t_enum" + parenthesizeUserIdentifier(m_enum.name()) + std::to_string(m_enum.id());
+}
+
bool EnumType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -1686,6 +1818,11 @@ bool TupleType::isImplicitlyConvertibleTo(Type const& _other) const
return false;
}
+string TupleType::identifier() const
+{
+ return "t_tuple" + identifierList(components());
+}
+
bool TupleType::operator==(Type const& _other) const
{
if (auto tupleType = dynamic_cast<TupleType const*>(&_other))
@@ -1934,6 +2071,53 @@ TypePointers FunctionType::parameterTypes() const
return TypePointers(m_parameterTypes.cbegin() + 1, m_parameterTypes.cend());
}
+string FunctionType::identifier() const
+{
+ string id = "t_function_";
+ switch (location())
+ {
+ case Location::Internal: id += "internal"; break;
+ case Location::External: id += "external"; break;
+ case Location::CallCode: id += "callcode"; break;
+ case Location::DelegateCall: id += "delegatecall"; break;
+ case Location::Bare: id += "bare"; break;
+ case Location::BareCallCode: id += "barecallcode"; break;
+ case Location::BareDelegateCall: id += "baredelegatecall"; break;
+ case Location::Creation: id += "creation"; break;
+ case Location::Send: id += "send"; break;
+ case Location::SHA3: id += "sha3"; break;
+ case Location::Selfdestruct: id += "selfdestruct"; break;
+ case Location::ECRecover: id += "ecrecover"; break;
+ case Location::SHA256: id += "sha256"; break;
+ case Location::RIPEMD160: id += "ripemd160"; break;
+ case Location::Log0: id += "log0"; break;
+ case Location::Log1: id += "log1"; break;
+ case Location::Log2: id += "log2"; break;
+ case Location::Log3: id += "log3"; break;
+ case Location::Log4: id += "log4"; break;
+ case Location::Event: id += "event"; break;
+ case Location::SetGas: id += "setgas"; break;
+ case Location::SetValue: id += "setvalue"; break;
+ case Location::BlockHash: id += "blockhash"; break;
+ case Location::AddMod: id += "addmod"; break;
+ case Location::MulMod: id += "mulmod"; break;
+ case Location::ArrayPush: id += "arraypush"; break;
+ case Location::ByteArrayPush: id += "bytearraypush"; break;
+ case Location::ObjectCreation: id += "objectcreation"; break;
+ default: solAssert(false, "Unknown function location."); break;
+ }
+ if (isConstant())
+ id += "_constant";
+ id += identifierList(m_parameterTypes) + "returns" + identifierList(m_returnParameterTypes);
+ if (m_gasSet)
+ id += "gas";
+ if (m_valueSet)
+ id += "value";
+ if (bound())
+ id += "bound_to" + identifierList(selfType());
+ return id;
+}
+
bool FunctionType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -2338,7 +2522,7 @@ vector<string> const FunctionType::returnParameterTypeNames(bool _addDataLocatio
return names;
}
-TypePointer FunctionType::selfType() const
+TypePointer const& FunctionType::selfType() const
{
solAssert(bound(), "Function is not bound.");
solAssert(m_parameterTypes.size() > 0, "Function has no self type.");
@@ -2354,6 +2538,11 @@ ASTPointer<ASTString> FunctionType::documentation() const
return ASTPointer<ASTString>();
}
+string MappingType::identifier() const
+{
+ return "t_mapping" + identifierList(m_keyType, m_valueType);
+}
+
bool MappingType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -2372,6 +2561,11 @@ string MappingType::canonicalName(bool) const
return "mapping(" + keyType()->canonicalName(false) + " => " + valueType()->canonicalName(false) + ")";
}
+string TypeType::identifier() const
+{
+ return "t_type" + identifierList(actualType());
+}
+
bool TypeType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -2456,6 +2650,11 @@ u256 ModifierType::storageSize() const
<< errinfo_comment("Storage size of non-storable type type requested."));
}
+string ModifierType::identifier() const
+{
+ return "t_modifier" + identifierList(m_parameterTypes);
+}
+
bool ModifierType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -2480,6 +2679,11 @@ string ModifierType::toString(bool _short) const
return name + ")";
}
+string ModuleType::identifier() const
+{
+ return "t_module_" + std::to_string(m_sourceUnit.id());
+}
+
bool ModuleType::operator==(Type const& _other) const
{
if (_other.category() != category())
@@ -2501,6 +2705,22 @@ string ModuleType::toString(bool) const
return string("module \"") + m_sourceUnit.annotation().path + string("\"");
}
+string MagicType::identifier() const
+{
+ switch (m_kind)
+ {
+ case Kind::Block:
+ return "t_magic_block";
+ case Kind::Message:
+ return "t_magic_message";
+ case Kind::Transaction:
+ return "t_magic_transaction";
+ default:
+ solAssert(false, "Unknown kind of magic");
+ }
+ return "";
+}
+
bool MagicType::operator==(Type const& _other) const
{
if (_other.category() != category())
diff --git a/libsolidity/ast/Types.h b/libsolidity/ast/Types.h
index 26e2b8f2..1e94631e 100644
--- a/libsolidity/ast/Types.h
+++ b/libsolidity/ast/Types.h
@@ -22,18 +22,21 @@
#pragma once
-#include <memory>
-#include <string>
-#include <map>
-#include <boost/noncopyable.hpp>
-#include <boost/rational.hpp>
-#include <libdevcore/Common.h>
-#include <libdevcore/CommonIO.h>
#include <libsolidity/interface/Exceptions.h>
#include <libsolidity/ast/ASTForward.h>
#include <libsolidity/parsing/Token.h>
+
+#include <libdevcore/Common.h>
+#include <libdevcore/CommonIO.h>
#include <libdevcore/UndefMacros.h>
+#include <boost/noncopyable.hpp>
+#include <boost/rational.hpp>
+
+#include <memory>
+#include <string>
+#include <map>
+
namespace dev
{
namespace solidity
@@ -155,6 +158,13 @@ public:
static TypePointer commonType(TypePointer const& _a, TypePointer const& _b);
virtual Category category() const = 0;
+ /// @returns a valid solidity identifier such that two types should compare equal if and
+ /// only if they have the same identifier.
+ /// The identifier should start with "t_".
+ /// More complex identifier strings use "parentheses", where $_ is interpreted as as
+ /// "opening parenthesis", _$ as "closing parenthesis", _$_ as "comma" and any $ that
+ /// appears as part of a user-supplied identifier is escaped as _$$$_.
+ virtual std::string identifier() const = 0;
virtual bool isImplicitlyConvertibleTo(Type const& _other) const { return *this == _other; }
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const
{
@@ -288,6 +298,7 @@ public:
explicit IntegerType(int _bits, Modifier _modifier = Modifier::Unsigned);
+ virtual std::string identifier() const override;
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
@@ -329,6 +340,7 @@ public:
explicit FixedPointType(int _integerBits, int _fractionalBits, Modifier _modifier = Modifier::Unsigned);
+ virtual std::string identifier() const override;
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
@@ -378,6 +390,7 @@ public:
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
@@ -416,6 +429,7 @@ public:
return TypePointer();
}
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
@@ -449,6 +463,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
@@ -476,6 +491,7 @@ class BoolType: public Type
public:
BoolType() {}
virtual Category category() const override { return Category::Bool; }
+ virtual std::string identifier() const override { return "t_bool"; }
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual TypePointer binaryOperatorResult(Token::Value _operator, TypePointer const& _other) const override;
@@ -533,6 +549,8 @@ protected:
TypePointer copyForLocationIfReference(TypePointer const& _type) const;
/// @returns a human-readable description of the reference part of the type.
std::string stringForReferencePart() const;
+ /// @returns the suffix computed from the reference part to be used by identifier();
+ std::string identifierLocationSuffix() const;
DataLocation m_location = DataLocation::Storage;
bool m_isPointer = true;
@@ -573,6 +591,7 @@ public:
virtual bool isImplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
+ virtual std::string identifier() const override;
virtual bool operator==(const Type& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override;
virtual bool isDynamicallySized() const override { return m_hasDynamicLength; }
@@ -622,6 +641,7 @@ public:
/// Contracts can be converted to themselves and to integers.
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded ) const override
{
@@ -677,6 +697,7 @@ public:
explicit StructType(StructDefinition const& _struct, DataLocation _location = DataLocation::Storage):
ReferenceType(_location), m_struct(_struct) {}
virtual bool isImplicitlyConvertibleTo(const Type& _convertTo) const override;
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override;
u256 memorySize() const;
@@ -720,6 +741,7 @@ public:
virtual Category category() const override { return Category::Enum; }
explicit EnumType(EnumDefinition const& _enum): m_enum(_enum) {}
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual unsigned calldataEncodedSize(bool _padded) const override
{
@@ -760,6 +782,7 @@ public:
virtual Category category() const override { return Category::Tuple; }
explicit TupleType(std::vector<TypePointer> const& _types = std::vector<TypePointer>()): m_components(_types) {}
virtual bool isImplicitlyConvertibleTo(Type const& _other) const override;
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
virtual std::string toString(bool) const override;
@@ -895,8 +918,9 @@ public:
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
std::vector<std::string> const returnParameterTypeNames(bool _addDataLocation) const;
/// @returns the "self" parameter type for a bound function
- TypePointer selfType() const;
+ TypePointer const& selfType() const;
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
virtual std::string canonicalName(bool /*_addDataLocation*/) const override;
@@ -995,6 +1019,7 @@ public:
MappingType(TypePointer const& _keyType, TypePointer const& _valueType):
m_keyType(_keyType), m_valueType(_valueType) {}
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual std::string toString(bool _short) const override;
virtual std::string canonicalName(bool _addDataLocation) const override;
@@ -1029,6 +1054,7 @@ public:
TypePointer const& actualType() const { return m_actualType; }
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
virtual u256 storageSize() const override;
@@ -1056,6 +1082,7 @@ public:
virtual u256 storageSize() const override;
virtual bool canLiveOutsideStorage() const override { return false; }
virtual unsigned sizeOnStack() const override { return 0; }
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual std::string toString(bool _short) const override;
@@ -1080,6 +1107,7 @@ public:
return TypePointer();
}
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return true; }
@@ -1109,6 +1137,7 @@ public:
return TypePointer();
}
+ virtual std::string identifier() const override;
virtual bool operator==(Type const& _other) const override;
virtual bool canBeStored() const override { return false; }
virtual bool canLiveOutsideStorage() const override { return true; }
@@ -1132,6 +1161,7 @@ class InaccessibleDynamicType: public Type
public:
virtual Category category() const override { return Category::InaccessibleDynamic; }
+ virtual std::string identifier() const override { return "t_inaccessible"; }
virtual bool isImplicitlyConvertibleTo(Type const&) const override { return false; }
virtual bool isExplicitlyConvertibleTo(Type const&) const override { return false; }
virtual unsigned calldataEncodedSize(bool _padded) const override { (void)_padded; return 32; }