mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Function signatures containing structs.
This commit is contained in:
parent
22f85d5af3
commit
080be885f8
@ -33,6 +33,7 @@
|
|||||||
#include <boost/algorithm/string/replace.hpp>
|
#include <boost/algorithm/string/replace.hpp>
|
||||||
#include <boost/algorithm/string/predicate.hpp>
|
#include <boost/algorithm/string/predicate.hpp>
|
||||||
#include <boost/range/adaptor/reversed.hpp>
|
#include <boost/range/adaptor/reversed.hpp>
|
||||||
|
#include <boost/range/algorithm/copy.hpp>
|
||||||
#include <boost/range/adaptor/sliced.hpp>
|
#include <boost/range/adaptor/sliced.hpp>
|
||||||
#include <boost/range/adaptor/transformed.hpp>
|
#include <boost/range/adaptor/transformed.hpp>
|
||||||
|
|
||||||
@ -1470,7 +1471,7 @@ string ArrayType::toString(bool _short) const
|
|||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
string ArrayType::canonicalName(bool _addDataLocation) const
|
string ArrayType::canonicalName() const
|
||||||
{
|
{
|
||||||
string ret;
|
string ret;
|
||||||
if (isString())
|
if (isString())
|
||||||
@ -1479,16 +1480,29 @@ string ArrayType::canonicalName(bool _addDataLocation) const
|
|||||||
ret = "bytes";
|
ret = "bytes";
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
ret = baseType()->canonicalName(false) + "[";
|
ret = baseType()->canonicalName() + "[";
|
||||||
if (!isDynamicallySized())
|
if (!isDynamicallySized())
|
||||||
ret += length().str();
|
ret += length().str();
|
||||||
ret += "]";
|
ret += "]";
|
||||||
}
|
}
|
||||||
if (_addDataLocation && location() == DataLocation::Storage)
|
|
||||||
ret += " storage";
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
string ArrayType::signatureInExternalFunction(bool _structsByName) const
|
||||||
|
{
|
||||||
|
if (isByteArray())
|
||||||
|
return canonicalName();
|
||||||
|
else
|
||||||
|
{
|
||||||
|
solAssert(baseType(), "");
|
||||||
|
return
|
||||||
|
baseType()->signatureInExternalFunction(_structsByName) +
|
||||||
|
"[" +
|
||||||
|
(isDynamicallySized() ? "" : length().str()) +
|
||||||
|
"]";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
|
MemberList::MemberMap ArrayType::nativeMembers(ContractDefinition const*) const
|
||||||
{
|
{
|
||||||
MemberList::MemberMap members;
|
MemberList::MemberMap members;
|
||||||
@ -1597,7 +1611,7 @@ string ContractType::toString(bool) const
|
|||||||
m_contract.name();
|
m_contract.name();
|
||||||
}
|
}
|
||||||
|
|
||||||
string ContractType::canonicalName(bool) const
|
string ContractType::canonicalName() const
|
||||||
{
|
{
|
||||||
return m_contract.annotation().canonicalName;
|
return m_contract.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
@ -1727,9 +1741,8 @@ bool StructType::isDynamicallyEncoded() const
|
|||||||
u256 StructType::memorySize() const
|
u256 StructType::memorySize() const
|
||||||
{
|
{
|
||||||
u256 size;
|
u256 size;
|
||||||
for (auto const& member: members(nullptr))
|
for (auto const& t: memoryMemberTypes())
|
||||||
if (member.type->canLiveOutsideStorage())
|
size += t->memoryHeadSize();
|
||||||
size += member.type->memoryHeadSize();
|
|
||||||
return size;
|
return size;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -1782,12 +1795,25 @@ TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer)
|
|||||||
return copy;
|
return copy;
|
||||||
}
|
}
|
||||||
|
|
||||||
string StructType::canonicalName(bool _addDataLocation) const
|
string StructType::signatureInExternalFunction(bool _structsByName) const
|
||||||
{
|
{
|
||||||
string ret = m_struct.annotation().canonicalName;
|
if (_structsByName)
|
||||||
if (_addDataLocation && location() == DataLocation::Storage)
|
return canonicalName();
|
||||||
ret += " storage";
|
else
|
||||||
return ret;
|
{
|
||||||
|
TypePointers memberTypes = memoryMemberTypes();
|
||||||
|
auto memberTypeStrings = memberTypes | boost::adaptors::transformed([&](TypePointer _t) -> string
|
||||||
|
{
|
||||||
|
solAssert(_t, "Parameter should have external type.");
|
||||||
|
return _t->signatureInExternalFunction(_structsByName);
|
||||||
|
});
|
||||||
|
return "(" + boost::algorithm::join(memberTypeStrings, ",") + ")";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
string StructType::canonicalName() const
|
||||||
|
{
|
||||||
|
return m_struct.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
FunctionTypePointer StructType::constructorType() const
|
FunctionTypePointer StructType::constructorType() const
|
||||||
@ -1829,6 +1855,15 @@ u256 StructType::memoryOffsetOfMember(string const& _name) const
|
|||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
TypePointers StructType::memoryMemberTypes() const
|
||||||
|
{
|
||||||
|
TypePointers types;
|
||||||
|
for (ASTPointer<VariableDeclaration> const& variable: m_struct.members())
|
||||||
|
if (variable->annotation().type->canLiveOutsideStorage())
|
||||||
|
types.push_back(variable->annotation().type);
|
||||||
|
return types;
|
||||||
|
}
|
||||||
|
|
||||||
set<string> StructType::membersMissingInMemory() const
|
set<string> StructType::membersMissingInMemory() const
|
||||||
{
|
{
|
||||||
set<string> missing;
|
set<string> missing;
|
||||||
@ -1893,7 +1928,7 @@ string EnumType::toString(bool) const
|
|||||||
return string("enum ") + m_enum.annotation().canonicalName;
|
return string("enum ") + m_enum.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
|
|
||||||
string EnumType::canonicalName(bool) const
|
string EnumType::canonicalName() const
|
||||||
{
|
{
|
||||||
return m_enum.annotation().canonicalName;
|
return m_enum.annotation().canonicalName;
|
||||||
}
|
}
|
||||||
@ -2320,7 +2355,7 @@ TypePointer FunctionType::binaryOperatorResult(Token::Value _operator, TypePoint
|
|||||||
return TypePointer();
|
return TypePointer();
|
||||||
}
|
}
|
||||||
|
|
||||||
string FunctionType::canonicalName(bool) const
|
string FunctionType::canonicalName() const
|
||||||
{
|
{
|
||||||
solAssert(m_kind == Kind::External, "");
|
solAssert(m_kind == Kind::External, "");
|
||||||
return "function";
|
return "function";
|
||||||
@ -2580,20 +2615,19 @@ string FunctionType::externalSignature() const
|
|||||||
solAssert(m_declaration != nullptr, "External signature of function needs declaration");
|
solAssert(m_declaration != nullptr, "External signature of function needs declaration");
|
||||||
solAssert(!m_declaration->name().empty(), "Fallback function has no signature.");
|
solAssert(!m_declaration->name().empty(), "Fallback function has no signature.");
|
||||||
|
|
||||||
bool _inLibrary = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
|
bool const inLibrary = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
|
||||||
|
|
||||||
string ret = m_declaration->name() + "(";
|
|
||||||
|
|
||||||
FunctionTypePointer external = interfaceFunctionType();
|
FunctionTypePointer external = interfaceFunctionType();
|
||||||
solAssert(!!external, "External function type requested.");
|
solAssert(!!external, "External function type requested.");
|
||||||
TypePointers externalParameterTypes = external->parameterTypes();
|
auto parameterTypes = external->parameterTypes();
|
||||||
for (auto it = externalParameterTypes.cbegin(); it != externalParameterTypes.cend(); ++it)
|
auto typeStrings = parameterTypes | boost::adaptors::transformed([&](TypePointer _t) -> string
|
||||||
{
|
{
|
||||||
solAssert(!!(*it), "Parameter should have external type");
|
solAssert(_t, "Parameter should have external type.");
|
||||||
ret += (*it)->canonicalName(_inLibrary) + (it + 1 == externalParameterTypes.cend() ? "" : ",");
|
string typeName = _t->signatureInExternalFunction(inLibrary);
|
||||||
}
|
if (inLibrary && _t->dataStoredIn(DataLocation::Storage))
|
||||||
|
typeName += " storage";
|
||||||
return ret + ")";
|
return typeName;
|
||||||
|
});
|
||||||
|
return m_declaration->name() + "(" + boost::algorithm::join(typeStrings, ",") + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
u256 FunctionType::externalIdentifier() const
|
u256 FunctionType::externalIdentifier() const
|
||||||
@ -2724,9 +2758,9 @@ string MappingType::toString(bool _short) const
|
|||||||
return "mapping(" + keyType()->toString(_short) + " => " + valueType()->toString(_short) + ")";
|
return "mapping(" + keyType()->toString(_short) + " => " + valueType()->toString(_short) + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
string MappingType::canonicalName(bool) const
|
string MappingType::canonicalName() const
|
||||||
{
|
{
|
||||||
return "mapping(" + keyType()->canonicalName(false) + " => " + valueType()->canonicalName(false) + ")";
|
return "mapping(" + keyType()->canonicalName() + " => " + valueType()->canonicalName() + ")";
|
||||||
}
|
}
|
||||||
|
|
||||||
string TypeType::identifier() const
|
string TypeType::identifier() const
|
||||||
|
@ -245,9 +245,15 @@ public:
|
|||||||
|
|
||||||
virtual std::string toString(bool _short) const = 0;
|
virtual std::string toString(bool _short) const = 0;
|
||||||
std::string toString() const { return toString(false); }
|
std::string toString() const { return toString(false); }
|
||||||
/// @returns the canonical name of this type for use in function signatures.
|
/// @returns the canonical name of this type for use in library function signatures.
|
||||||
/// @param _addDataLocation if true, includes data location for reference types if it is "storage".
|
virtual std::string canonicalName() const { return toString(true); }
|
||||||
virtual std::string canonicalName(bool /*_addDataLocation*/) const { return toString(true); }
|
/// @returns the signature of this type in external functions, i.e. `uint256` for integers
|
||||||
|
/// or `(uint256, bytes8)[2]` for an array of structs. If @a _structsByName,
|
||||||
|
/// structs are given by canonical name like `ContractName.StructName[2]`.
|
||||||
|
virtual std::string signatureInExternalFunction(bool /*_structsByName*/) const
|
||||||
|
{
|
||||||
|
return canonicalName();
|
||||||
|
}
|
||||||
virtual u256 literalValue(Literal const*) const
|
virtual u256 literalValue(Literal const*) const
|
||||||
{
|
{
|
||||||
solAssert(false, "Literal value requested for type without literals.");
|
solAssert(false, "Literal value requested for type without literals.");
|
||||||
@ -619,7 +625,8 @@ public:
|
|||||||
virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
|
virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
|
||||||
virtual unsigned sizeOnStack() const override;
|
virtual unsigned sizeOnStack() const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
virtual std::string canonicalName() const override;
|
||||||
|
virtual std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||||
virtual TypePointer encodingType() const override;
|
virtual TypePointer encodingType() const override;
|
||||||
virtual TypePointer decodingType() const override;
|
virtual TypePointer decodingType() const override;
|
||||||
@ -677,7 +684,7 @@ public:
|
|||||||
virtual unsigned sizeOnStack() const override { return m_super ? 0 : 1; }
|
virtual unsigned sizeOnStack() const override { return m_super ? 0 : 1; }
|
||||||
virtual bool isValueType() const override { return true; }
|
virtual bool isValueType() const override { return true; }
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
virtual std::string canonicalName() const override;
|
||||||
|
|
||||||
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
virtual MemberList::MemberMap nativeMembers(ContractDefinition const* _currentScope) const override;
|
||||||
virtual TypePointer encodingType() const override
|
virtual TypePointer encodingType() const override
|
||||||
@ -744,7 +751,8 @@ public:
|
|||||||
|
|
||||||
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||||
|
|
||||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
virtual std::string canonicalName() const override;
|
||||||
|
virtual std::string signatureInExternalFunction(bool _structsByName) const override;
|
||||||
|
|
||||||
/// @returns a function that peforms the type conversion between a list of struct members
|
/// @returns a function that peforms the type conversion between a list of struct members
|
||||||
/// and a memory struct of this type.
|
/// and a memory struct of this type.
|
||||||
@ -755,6 +763,8 @@ public:
|
|||||||
|
|
||||||
StructDefinition const& structDefinition() const { return m_struct; }
|
StructDefinition const& structDefinition() const { return m_struct; }
|
||||||
|
|
||||||
|
/// @returns the vector of types of members available in memory.
|
||||||
|
TypePointers memoryMemberTypes() const;
|
||||||
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
/// @returns the set of all members that are removed in the memory version (typically mappings).
|
||||||
std::set<std::string> membersMissingInMemory() const;
|
std::set<std::string> membersMissingInMemory() const;
|
||||||
|
|
||||||
@ -784,7 +794,7 @@ public:
|
|||||||
virtual unsigned storageBytes() const override;
|
virtual unsigned storageBytes() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
virtual std::string canonicalName() const override;
|
||||||
virtual bool isValueType() const override { return true; }
|
virtual bool isValueType() const override { return true; }
|
||||||
|
|
||||||
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
@ -955,7 +965,7 @@ public:
|
|||||||
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||||
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
virtual TypePointer unaryOperatorResult(Token::Value _operator) const override;
|
||||||
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override;
|
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override;
|
||||||
virtual std::string canonicalName(bool /*_addDataLocation*/) const override;
|
virtual std::string canonicalName() const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual unsigned calldataEncodedSize(bool _padded) const override;
|
virtual unsigned calldataEncodedSize(bool _padded) const override;
|
||||||
virtual bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
virtual bool canBeStored() const override { return m_kind == Kind::Internal || m_kind == Kind::External; }
|
||||||
@ -1057,7 +1067,7 @@ public:
|
|||||||
virtual std::string identifier() const override;
|
virtual std::string identifier() const override;
|
||||||
virtual bool operator==(Type const& _other) const override;
|
virtual bool operator==(Type const& _other) const override;
|
||||||
virtual std::string toString(bool _short) const override;
|
virtual std::string toString(bool _short) const override;
|
||||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
virtual std::string canonicalName() const override;
|
||||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||||
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
|
virtual TypePointer binaryOperatorResult(Token::Value, TypePointer const&) const override { return TypePointer(); }
|
||||||
virtual TypePointer encodingType() const override
|
virtual TypePointer encodingType() const override
|
||||||
|
@ -120,12 +120,13 @@ Json::Value ABI::formatType(string const& _name, Type const& _type, bool _forLib
|
|||||||
{
|
{
|
||||||
Json::Value ret;
|
Json::Value ret;
|
||||||
ret["name"] = _name;
|
ret["name"] = _name;
|
||||||
|
string suffix = (_forLibrary && _type.dataStoredIn(DataLocation::Storage)) ? " storage" : "";
|
||||||
if (_type.isValueType() || (_forLibrary && _type.dataStoredIn(DataLocation::Storage)))
|
if (_type.isValueType() || (_forLibrary && _type.dataStoredIn(DataLocation::Storage)))
|
||||||
ret["type"] = _type.canonicalName(_forLibrary);
|
ret["type"] = _type.canonicalName() + suffix;
|
||||||
else if (ArrayType const* arrayType = dynamic_cast<ArrayType const*>(&_type))
|
else if (ArrayType const* arrayType = dynamic_cast<ArrayType const*>(&_type))
|
||||||
{
|
{
|
||||||
if (arrayType->isByteArray())
|
if (arrayType->isByteArray())
|
||||||
ret["type"] = _type.canonicalName(_forLibrary);
|
ret["type"] = _type.canonicalName() + suffix;
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
string suffix;
|
string suffix;
|
||||||
|
@ -599,6 +599,14 @@ BOOST_AUTO_TEST_CASE(enum_external_type)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
BOOST_AUTO_TEST_CASE(external_structs)
|
||||||
|
{
|
||||||
|
BOOST_FAIL("This should test external structs");
|
||||||
|
// More test ideas:
|
||||||
|
// external function type as part of a struct and array
|
||||||
|
// external function type taking structs and arrays...
|
||||||
|
}
|
||||||
|
|
||||||
BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
|
BOOST_AUTO_TEST_CASE(function_external_call_allowed_conversion)
|
||||||
{
|
{
|
||||||
char const* text = R"(
|
char const* text = R"(
|
||||||
@ -980,24 +988,24 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
|
|||||||
FunctionTypePointer function = retrieveFunctionBySignature(*contract, "foo()");
|
FunctionTypePointer function = retrieveFunctionBySignature(*contract, "foo()");
|
||||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||||
auto returnParams = function->returnParameterTypes();
|
auto returnParams = function->returnParameterTypes();
|
||||||
BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(false), "uint256");
|
BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(), "uint256");
|
||||||
BOOST_CHECK(function->stateMutability() == StateMutability::View);
|
BOOST_CHECK(function->stateMutability() == StateMutability::View);
|
||||||
|
|
||||||
function = retrieveFunctionBySignature(*contract, "map(uint256)");
|
function = retrieveFunctionBySignature(*contract, "map(uint256)");
|
||||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||||
auto params = function->parameterTypes();
|
auto params = function->parameterTypes();
|
||||||
BOOST_CHECK_EQUAL(params.at(0)->canonicalName(false), "uint256");
|
BOOST_CHECK_EQUAL(params.at(0)->canonicalName(), "uint256");
|
||||||
returnParams = function->returnParameterTypes();
|
returnParams = function->returnParameterTypes();
|
||||||
BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(false), "bytes4");
|
BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(), "bytes4");
|
||||||
BOOST_CHECK(function->stateMutability() == StateMutability::View);
|
BOOST_CHECK(function->stateMutability() == StateMutability::View);
|
||||||
|
|
||||||
function = retrieveFunctionBySignature(*contract, "multiple_map(uint256,uint256)");
|
function = retrieveFunctionBySignature(*contract, "multiple_map(uint256,uint256)");
|
||||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||||
params = function->parameterTypes();
|
params = function->parameterTypes();
|
||||||
BOOST_CHECK_EQUAL(params.at(0)->canonicalName(false), "uint256");
|
BOOST_CHECK_EQUAL(params.at(0)->canonicalName(), "uint256");
|
||||||
BOOST_CHECK_EQUAL(params.at(1)->canonicalName(false), "uint256");
|
BOOST_CHECK_EQUAL(params.at(1)->canonicalName(), "uint256");
|
||||||
returnParams = function->returnParameterTypes();
|
returnParams = function->returnParameterTypes();
|
||||||
BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(false), "bytes4");
|
BOOST_CHECK_EQUAL(returnParams.at(0)->canonicalName(), "bytes4");
|
||||||
BOOST_CHECK(function->stateMutability() == StateMutability::View);
|
BOOST_CHECK(function->stateMutability() == StateMutability::View);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user