diff options
author | Yoichi Hirai <i@yoichihirai.com> | 2017-01-20 23:18:57 +0800 |
---|---|---|
committer | GitHub <noreply@github.com> | 2017-01-20 23:18:57 +0800 |
commit | 12b002b3b8575539f332c30691e880bcc2fac5bc (patch) | |
tree | b971790458cd78a794d10dc3248fef5d9d88271d /libsolidity | |
parent | 09403dd5ede68e020cb2ff17a7958bf5b42979df (diff) | |
parent | 07b0a0a56028c5ea9bf3dc4fc3b7fda6e4d97ec9 (diff) | |
download | dexon-solidity-12b002b3b8575539f332c30691e880bcc2fac5bc.tar.gz dexon-solidity-12b002b3b8575539f332c30691e880bcc2fac5bc.tar.zst dexon-solidity-12b002b3b8575539f332c30691e880bcc2fac5bc.zip |
Merge pull request #1576 from ethereum/typeIdentifiers
Type identifiers.
Diffstat (limited to 'libsolidity')
-rw-r--r-- | libsolidity/ast/AST.cpp | 22 | ||||
-rw-r--r-- | libsolidity/ast/AST.h | 4 | ||||
-rw-r--r-- | libsolidity/ast/Types.cpp | 238 | ||||
-rw-r--r-- | libsolidity/ast/Types.h | 46 | ||||
-rw-r--r-- | libsolidity/interface/CompilerStack.cpp | 1 |
5 files changed, 291 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; } diff --git a/libsolidity/interface/CompilerStack.cpp b/libsolidity/interface/CompilerStack.cpp index 61fc7728..85ec0fb1 100644 --- a/libsolidity/interface/CompilerStack.cpp +++ b/libsolidity/interface/CompilerStack.cpp @@ -112,6 +112,7 @@ bool CompilerStack::parse() { //reset m_errors.clear(); + ASTNode::resetID(); m_parseSuccessful = false; if (SemVerVersion{string(VersionString)}.isPrerelease()) |