mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Compute canonical names of types for function signatures.
This commit is contained in:
parent
ce25ddfa6a
commit
bc609c55c0
@ -135,7 +135,7 @@ vector<pair<FixedHash<4>, FunctionTypePointer>> const& ContractDefinition::inter
|
||||
FunctionType ftype(*v);
|
||||
solAssert(!!v->annotation().type.get(), "");
|
||||
functionsSeen.insert(v->name());
|
||||
FixedHash<4> hash(dev::sha3(ftype.externalSignature(v->name())));
|
||||
FixedHash<4> hash(dev::sha3(ftype.externalSignature()));
|
||||
m_interfaceFunctionList->push_back(make_pair(hash, make_shared<FunctionType>(*v)));
|
||||
}
|
||||
}
|
||||
@ -215,6 +215,13 @@ TypePointer StructDefinition::type(ContractDefinition const*) const
|
||||
return make_shared<TypeType>(make_shared<StructType>(*this));
|
||||
}
|
||||
|
||||
TypeDeclarationAnnotation& StructDefinition::annotation() const
|
||||
{
|
||||
if (!m_annotation)
|
||||
m_annotation = new TypeDeclarationAnnotation();
|
||||
return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
|
||||
}
|
||||
|
||||
TypePointer EnumValue::type(ContractDefinition const*) const
|
||||
{
|
||||
auto parentDef = dynamic_cast<EnumDefinition const*>(scope());
|
||||
@ -227,6 +234,13 @@ TypePointer EnumDefinition::type(ContractDefinition const*) const
|
||||
return make_shared<TypeType>(make_shared<EnumType>(*this));
|
||||
}
|
||||
|
||||
TypeDeclarationAnnotation& EnumDefinition::annotation() const
|
||||
{
|
||||
if (!m_annotation)
|
||||
m_annotation = new TypeDeclarationAnnotation();
|
||||
return static_cast<TypeDeclarationAnnotation&>(*m_annotation);
|
||||
}
|
||||
|
||||
TypePointer FunctionDefinition::type(ContractDefinition const*) const
|
||||
{
|
||||
return make_shared<FunctionType>(*this);
|
||||
@ -234,7 +248,7 @@ TypePointer FunctionDefinition::type(ContractDefinition const*) const
|
||||
|
||||
string FunctionDefinition::externalSignature() const
|
||||
{
|
||||
return FunctionType(*this).externalSignature(name());
|
||||
return FunctionType(*this).externalSignature();
|
||||
}
|
||||
|
||||
TypePointer ModifierDefinition::type(ContractDefinition const*) const
|
||||
|
@ -352,6 +352,8 @@ public:
|
||||
|
||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
||||
|
||||
virtual TypeDeclarationAnnotation& annotation() const override;
|
||||
|
||||
private:
|
||||
std::vector<ASTPointer<VariableDeclaration>> m_members;
|
||||
};
|
||||
@ -372,6 +374,8 @@ public:
|
||||
|
||||
virtual TypePointer type(ContractDefinition const* m_currentContract) const override;
|
||||
|
||||
virtual TypeDeclarationAnnotation& annotation() const override;
|
||||
|
||||
private:
|
||||
std::vector<ASTPointer<EnumValue>> m_members;
|
||||
};
|
||||
|
@ -40,7 +40,13 @@ struct ASTAnnotation
|
||||
virtual ~ASTAnnotation() {}
|
||||
};
|
||||
|
||||
struct ContractDefinitionAnnotation: ASTAnnotation
|
||||
struct TypeDeclarationAnnotation: ASTAnnotation
|
||||
{
|
||||
/// The name of this type, prefixed by proper namespaces if globally accessible.
|
||||
std::string canonicalName;
|
||||
};
|
||||
|
||||
struct ContractDefinitionAnnotation: TypeDeclarationAnnotation
|
||||
{
|
||||
/// Whether all functions are implemented.
|
||||
bool isFullyImplemented = true;
|
||||
|
@ -130,12 +130,15 @@ bool CompilerStack::parse()
|
||||
m_globalContext->setCurrentContract(*contract);
|
||||
resolver.updateDeclaration(*m_globalContext->currentThis());
|
||||
TypeChecker typeChecker;
|
||||
if (!typeChecker.checkTypeRequirements(*contract))
|
||||
if (typeChecker.checkTypeRequirements(*contract))
|
||||
{
|
||||
contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract));
|
||||
contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract));
|
||||
}
|
||||
else
|
||||
typesFine = false;
|
||||
m_errors += typeChecker.errors();
|
||||
contract->setDevDocumentation(interfaceHandler.devDocumentation(*contract));
|
||||
contract->setUserDocumentation(interfaceHandler.userDocumentation(*contract));
|
||||
m_contracts[contract->name()].contract = contract;
|
||||
m_errors += typeChecker.errors();
|
||||
}
|
||||
m_parseSuccessful = typesFine;
|
||||
return m_parseSuccessful;
|
||||
|
@ -40,8 +40,10 @@ namespace solidity
|
||||
class DeclarationContainer
|
||||
{
|
||||
public:
|
||||
explicit DeclarationContainer(Declaration const* _enclosingDeclaration = nullptr,
|
||||
DeclarationContainer const* _enclosingContainer = nullptr):
|
||||
explicit DeclarationContainer(
|
||||
Declaration const* _enclosingDeclaration = nullptr,
|
||||
DeclarationContainer const* _enclosingContainer = nullptr
|
||||
):
|
||||
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
|
||||
/// Registers the declaration in the scope unless its name is already declared or the name is empty.
|
||||
/// @param _invisible if true, registers the declaration, reports name clashes but does not return it in @a resolveName
|
||||
|
@ -585,7 +585,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall)
|
||||
}
|
||||
if (!event.isAnonymous())
|
||||
{
|
||||
m_context << u256(h256::Arith(dev::sha3(function.externalSignature(event.name()))));
|
||||
m_context << u256(h256::Arith(dev::sha3(function.externalSignature())));
|
||||
++numIndexed;
|
||||
}
|
||||
solAssert(numIndexed <= 4, "Too many indexed arguments.");
|
||||
|
@ -64,11 +64,11 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef)
|
||||
method["constant"] = it.second->isConstant();
|
||||
method["inputs"] = populateParameters(
|
||||
externalFunctionType->parameterNames(),
|
||||
externalFunctionType->parameterTypeNames()
|
||||
externalFunctionType->parameterTypeNames(_contractDef.isLibrary())
|
||||
);
|
||||
method["outputs"] = populateParameters(
|
||||
externalFunctionType->returnParameterNames(),
|
||||
externalFunctionType->returnParameterTypeNames()
|
||||
externalFunctionType->returnParameterTypeNames(_contractDef.isLibrary())
|
||||
);
|
||||
abi.append(method);
|
||||
}
|
||||
@ -80,7 +80,7 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef)
|
||||
solAssert(!!externalFunction, "");
|
||||
method["inputs"] = populateParameters(
|
||||
externalFunction->parameterNames(),
|
||||
externalFunction->parameterTypeNames()
|
||||
externalFunction->parameterTypeNames(_contractDef.isLibrary())
|
||||
);
|
||||
abi.append(method);
|
||||
}
|
||||
@ -96,7 +96,7 @@ string InterfaceHandler::abiInterface(ContractDefinition const& _contractDef)
|
||||
{
|
||||
Json::Value input;
|
||||
input["name"] = p->name();
|
||||
input["type"] = p->annotation().type->toString(true);
|
||||
input["type"] = p->annotation().type->canonicalName(false);
|
||||
input["indexed"] = p->isIndexed();
|
||||
params.append(input);
|
||||
}
|
||||
@ -125,16 +125,24 @@ string InterfaceHandler::ABISolidityInterface(ContractDefinition const& _contrac
|
||||
ret +=
|
||||
"function " +
|
||||
_contractDef.name() +
|
||||
populateParameters(externalFunction->parameterNames(), externalFunction->parameterTypeNames()) +
|
||||
populateParameters(
|
||||
externalFunction->parameterNames(),
|
||||
externalFunction->parameterTypeNames(_contractDef.isLibrary())
|
||||
) +
|
||||
";";
|
||||
}
|
||||
for (auto const& it: _contractDef.interfaceFunctions())
|
||||
{
|
||||
ret += "function " + it.second->declaration().name() +
|
||||
populateParameters(it.second->parameterNames(), it.second->parameterTypeNames()) +
|
||||
(it.second->isConstant() ? "constant " : "");
|
||||
populateParameters(
|
||||
it.second->parameterNames(),
|
||||
it.second->parameterTypeNames(_contractDef.isLibrary())
|
||||
) + (it.second->isConstant() ? "constant " : "");
|
||||
if (it.second->returnParameterTypes().size())
|
||||
ret += "returns" + populateParameters(it.second->returnParameterNames(), it.second->returnParameterTypeNames());
|
||||
ret += "returns" + populateParameters(
|
||||
it.second->returnParameterNames(),
|
||||
it.second->returnParameterTypeNames(_contractDef.isLibrary())
|
||||
);
|
||||
else if (ret.back() == ' ')
|
||||
ret.pop_back();
|
||||
ret += ";";
|
||||
|
@ -263,6 +263,7 @@ DeclarationRegistrationHelper::DeclarationRegistrationHelper(map<ASTNode const*,
|
||||
bool DeclarationRegistrationHelper::visit(ContractDefinition& _contract)
|
||||
{
|
||||
registerDeclaration(_contract, true);
|
||||
_contract.annotation().canonicalName = currentCanonicalName();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -274,6 +275,7 @@ void DeclarationRegistrationHelper::endVisit(ContractDefinition&)
|
||||
bool DeclarationRegistrationHelper::visit(StructDefinition& _struct)
|
||||
{
|
||||
registerDeclaration(_struct, true);
|
||||
_struct.annotation().canonicalName = currentCanonicalName();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -285,6 +287,7 @@ void DeclarationRegistrationHelper::endVisit(StructDefinition&)
|
||||
bool DeclarationRegistrationHelper::visit(EnumDefinition& _enum)
|
||||
{
|
||||
registerDeclaration(_enum, true);
|
||||
_enum.annotation().canonicalName = currentCanonicalName();
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -400,5 +403,21 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
|
||||
enterNewSubScope(_declaration);
|
||||
}
|
||||
|
||||
string DeclarationRegistrationHelper::currentCanonicalName() const
|
||||
{
|
||||
string ret;
|
||||
for (
|
||||
Declaration const* scope = m_currentScope;
|
||||
scope != nullptr;
|
||||
scope = m_scopes[scope].enclosingDeclaration()
|
||||
)
|
||||
{
|
||||
if (!ret.empty())
|
||||
ret = "." + ret;
|
||||
ret = scope->name() + ret;
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
@ -119,6 +119,9 @@ private:
|
||||
void closeCurrentScope();
|
||||
void registerDeclaration(Declaration& _declaration, bool _opensScope);
|
||||
|
||||
/// @returns the canonical name of the current scope.
|
||||
std::string currentCanonicalName() const;
|
||||
|
||||
std::map<ASTNode const*, DeclarationContainer>& m_scopes;
|
||||
Declaration const* m_currentScope;
|
||||
VariableScope* m_currentFunction;
|
||||
|
@ -299,7 +299,7 @@ void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _co
|
||||
if (f->isPartOfExternalInterface())
|
||||
{
|
||||
auto functionType = make_shared<FunctionType>(*f);
|
||||
externalDeclarations[functionType->externalSignature(f->name())].push_back(
|
||||
externalDeclarations[functionType->externalSignature()].push_back(
|
||||
make_pair(f.get(), functionType)
|
||||
);
|
||||
}
|
||||
@ -307,7 +307,7 @@ void TypeChecker::checkContractExternalTypeClashes(ContractDefinition const& _co
|
||||
if (v->isPartOfExternalInterface())
|
||||
{
|
||||
auto functionType = make_shared<FunctionType>(*v);
|
||||
externalDeclarations[functionType->externalSignature(v->name())].push_back(
|
||||
externalDeclarations[functionType->externalSignature()].push_back(
|
||||
make_pair(v.get(), functionType)
|
||||
);
|
||||
}
|
||||
@ -403,7 +403,7 @@ bool TypeChecker::visit(FunctionDefinition const& _function)
|
||||
if (!type(*var)->canLiveOutsideStorage())
|
||||
typeError(*var, "Type is required to live outside storage.");
|
||||
if (_function.visibility() >= FunctionDefinition::Visibility::Public && !(type(*var)->interfaceType(isLibraryFunction)))
|
||||
typeError(*var, "Internal type is not allowed for public and external functions.");
|
||||
fatalTypeError(*var, "Internal type is not allowed for public or external functions.");
|
||||
}
|
||||
for (ASTPointer<ModifierInvocation> const& modifier: _function.modifiers())
|
||||
visitManually(
|
||||
|
@ -839,6 +839,25 @@ string ArrayType::toString(bool _short) const
|
||||
return ret;
|
||||
}
|
||||
|
||||
string ArrayType::canonicalName(bool _addDataLocation) const
|
||||
{
|
||||
string ret;
|
||||
if (isString())
|
||||
ret = "string";
|
||||
else if (isByteArray())
|
||||
ret = "bytes";
|
||||
else
|
||||
{
|
||||
ret = baseType()->canonicalName(false) + "[";
|
||||
if (!isDynamicallySized())
|
||||
ret += length().str();
|
||||
ret += "]";
|
||||
}
|
||||
if (_addDataLocation && location() == DataLocation::Storage)
|
||||
ret += " storage";
|
||||
return ret;
|
||||
}
|
||||
|
||||
TypePointer ArrayType::encodingType() const
|
||||
{
|
||||
if (location() == DataLocation::Storage)
|
||||
@ -912,6 +931,11 @@ string ContractType::toString(bool) const
|
||||
m_contract.name();
|
||||
}
|
||||
|
||||
string ContractType::canonicalName(bool) const
|
||||
{
|
||||
return m_contract.annotation().canonicalName;
|
||||
}
|
||||
|
||||
MemberList const& ContractType::members() const
|
||||
{
|
||||
// We need to lazy-initialize it because of recursive references.
|
||||
@ -1093,6 +1117,14 @@ TypePointer StructType::copyForLocation(DataLocation _location, bool _isPointer)
|
||||
return copy;
|
||||
}
|
||||
|
||||
string StructType::canonicalName(bool _addDataLocation) const
|
||||
{
|
||||
string ret = m_struct.annotation().canonicalName;
|
||||
if (_addDataLocation && location() == DataLocation::Storage)
|
||||
ret += " storage";
|
||||
return ret;
|
||||
}
|
||||
|
||||
FunctionTypePointer StructType::constructorType() const
|
||||
{
|
||||
TypePointers paramTypes;
|
||||
@ -1168,6 +1200,11 @@ string EnumType::toString(bool) const
|
||||
return string("enum ") + m_enum.name();
|
||||
}
|
||||
|
||||
string EnumType::canonicalName(bool) const
|
||||
{
|
||||
return m_enum.annotation().canonicalName;
|
||||
}
|
||||
|
||||
bool EnumType::isExplicitlyConvertibleTo(Type const& _convertTo) const
|
||||
{
|
||||
return _convertTo.category() == category() || _convertTo.category() == Category::Integer;
|
||||
@ -1483,15 +1520,13 @@ bool FunctionType::isBareCall() const
|
||||
}
|
||||
}
|
||||
|
||||
string FunctionType::externalSignature(std::string const& _name) const
|
||||
string FunctionType::externalSignature() const
|
||||
{
|
||||
std::string funcName = _name;
|
||||
if (_name == "")
|
||||
{
|
||||
solAssert(m_declaration != nullptr, "Function type without name needs a declaration");
|
||||
funcName = m_declaration->name();
|
||||
}
|
||||
string ret = funcName + "(";
|
||||
solAssert(m_declaration != nullptr, "External signature of function needs declaration");
|
||||
|
||||
bool _inLibrary = dynamic_cast<ContractDefinition const&>(*m_declaration->scope()).isLibrary();
|
||||
|
||||
string ret = m_declaration->name() + "(";
|
||||
|
||||
FunctionTypePointer external = interfaceFunctionType();
|
||||
solAssert(!!external, "External function type requested.");
|
||||
@ -1499,7 +1534,7 @@ string FunctionType::externalSignature(std::string const& _name) const
|
||||
for (auto it = externalParameterTypes.cbegin(); it != externalParameterTypes.cend(); ++it)
|
||||
{
|
||||
solAssert(!!(*it), "Parameter should have external type");
|
||||
ret += (*it)->toString(true) + (it + 1 == externalParameterTypes.cend() ? "" : ",");
|
||||
ret += (*it)->canonicalName(_inLibrary) + (it + 1 == externalParameterTypes.cend() ? "" : ",");
|
||||
}
|
||||
|
||||
return ret + ")";
|
||||
@ -1567,20 +1602,20 @@ FunctionTypePointer FunctionType::asMemberFunction(bool _inLibrary) const
|
||||
);
|
||||
}
|
||||
|
||||
vector<string> const FunctionType::parameterTypeNames() const
|
||||
vector<string> const FunctionType::parameterTypeNames(bool _addDataLocation) const
|
||||
{
|
||||
vector<string> names;
|
||||
for (TypePointer const& t: m_parameterTypes)
|
||||
names.push_back(t->toString(true));
|
||||
names.push_back(t->canonicalName(_addDataLocation));
|
||||
|
||||
return names;
|
||||
}
|
||||
|
||||
vector<string> const FunctionType::returnParameterTypeNames() const
|
||||
vector<string> const FunctionType::returnParameterTypeNames(bool _addDataLocation) const
|
||||
{
|
||||
vector<string> names;
|
||||
for (TypePointer const& t: m_returnParameterTypes)
|
||||
names.push_back(t->toString(true));
|
||||
names.push_back(t->canonicalName(_addDataLocation));
|
||||
|
||||
return names;
|
||||
}
|
||||
@ -1607,6 +1642,11 @@ string MappingType::toString(bool _short) const
|
||||
return "mapping(" + keyType()->toString(_short) + " => " + valueType()->toString(_short) + ")";
|
||||
}
|
||||
|
||||
string MappingType::canonicalName(bool) const
|
||||
{
|
||||
return "mapping(" + keyType()->canonicalName(false) + " => " + valueType()->canonicalName(false) + ")";
|
||||
}
|
||||
|
||||
u256 VoidType::storageSize() const
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(
|
||||
|
@ -218,6 +218,9 @@ public:
|
||||
|
||||
virtual std::string toString(bool _short) const = 0;
|
||||
std::string toString() const { return toString(false); }
|
||||
/// @returns the canonical name of this type for use in function signatures.
|
||||
/// @param _addDataLocation if true, includes data location for reference types if it is "storage".
|
||||
virtual std::string canonicalName(bool /*_addDataLocation*/) const { return toString(true); }
|
||||
virtual u256 literalValue(Literal const*) const
|
||||
{
|
||||
BOOST_THROW_EXCEPTION(
|
||||
@ -501,6 +504,7 @@ public:
|
||||
virtual bool canLiveOutsideStorage() const override { return m_baseType->canLiveOutsideStorage(); }
|
||||
virtual unsigned sizeOnStack() const override;
|
||||
virtual std::string toString(bool _short) const override;
|
||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||
virtual MemberList const& members() const override
|
||||
{
|
||||
return isString() ? EmptyMemberList : s_arrayTypeMemberList;
|
||||
@ -554,6 +558,7 @@ public:
|
||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||
virtual bool isValueType() const override { return true; }
|
||||
virtual std::string toString(bool _short) const override;
|
||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||
|
||||
virtual MemberList const& members() const override;
|
||||
virtual TypePointer encodingType() const override
|
||||
@ -617,6 +622,8 @@ public:
|
||||
|
||||
TypePointer copyForLocation(DataLocation _location, bool _isPointer) const override;
|
||||
|
||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||
|
||||
/// @returns a function that peforms the type conversion between a list of struct members
|
||||
/// and a memory struct of this type.
|
||||
FunctionTypePointer constructorType() const;
|
||||
@ -652,6 +659,7 @@ public:
|
||||
virtual unsigned storageBytes() const override;
|
||||
virtual bool canLiveOutsideStorage() const override { return true; }
|
||||
virtual std::string toString(bool _short) const override;
|
||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||
virtual bool isValueType() const override { return true; }
|
||||
|
||||
virtual bool isExplicitlyConvertibleTo(Type const& _convertTo) const override;
|
||||
@ -756,10 +764,10 @@ public:
|
||||
|
||||
TypePointers const& parameterTypes() const { return m_parameterTypes; }
|
||||
std::vector<std::string> const& parameterNames() const { return m_parameterNames; }
|
||||
std::vector<std::string> const parameterTypeNames() const;
|
||||
std::vector<std::string> const parameterTypeNames(bool _addDataLocation) const;
|
||||
TypePointers const& returnParameterTypes() const { return m_returnParameterTypes; }
|
||||
std::vector<std::string> const& returnParameterNames() const { return m_returnParameterNames; }
|
||||
std::vector<std::string> const returnParameterTypeNames() const;
|
||||
std::vector<std::string> const returnParameterTypeNames(bool _addDataLocation) const;
|
||||
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
virtual std::string toString(bool _short) const override;
|
||||
@ -786,9 +794,7 @@ public:
|
||||
bool isBareCall() const;
|
||||
Location const& location() const { return m_location; }
|
||||
/// @returns the external signature of this function type given the function name
|
||||
/// If @a _name is not provided (empty string) then the @c m_declaration member of the
|
||||
/// function type is used
|
||||
std::string externalSignature(std::string const& _name = "") const;
|
||||
std::string externalSignature() const;
|
||||
/// @returns the external identifier of this function (the hash of the signature).
|
||||
u256 externalIdentifier() const;
|
||||
Declaration const& declaration() const
|
||||
@ -849,6 +855,7 @@ public:
|
||||
|
||||
virtual bool operator==(Type const& _other) const override;
|
||||
virtual std::string toString(bool _short) const override;
|
||||
virtual std::string canonicalName(bool _addDataLocation) const override;
|
||||
virtual bool canLiveOutsideStorage() const override { return false; }
|
||||
virtual TypePointer encodingType() const override
|
||||
{
|
||||
|
@ -595,6 +595,36 @@ BOOST_AUTO_TEST_CASE(strings_and_arrays)
|
||||
checkInterface(sourceCode, interface);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(library_function)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
library test {
|
||||
struct StructType { uint a; }
|
||||
function f(StructType storage b, uint[] storage c, test d) returns (uint[] e, StructType storage f){}
|
||||
}
|
||||
)";
|
||||
|
||||
char const* interface = R"(
|
||||
[
|
||||
{
|
||||
"constant" : false,
|
||||
"name": "f",
|
||||
"inputs": [
|
||||
{ "name": "b", "type": "test.StructType storage" },
|
||||
{ "name": "c", "type": "uint256[] storage" },
|
||||
{ "name": "d", "type": "test" }
|
||||
],
|
||||
"outputs": [
|
||||
{ "name": "e", "type": "uint256[]" },
|
||||
{ "name": "f", "type": "test.StructType storage" }
|
||||
],
|
||||
"type" : "function"
|
||||
}
|
||||
]
|
||||
)";
|
||||
checkInterface(sourceCode, interface);
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -5383,32 +5383,6 @@ BOOST_AUTO_TEST_CASE(internal_types_in_library)
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(4), u256(17)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(differentiate_storage_and_memory_in_libraries)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
library Lib {
|
||||
function f(uint[] storage x) returns (uint) { return 1; }
|
||||
function f(uint[] memory x) returns (uint) { return 2; }
|
||||
}
|
||||
contract Test {
|
||||
uint[] data;
|
||||
function f() returns (uint a,)
|
||||
{
|
||||
uint[] memory d = data;
|
||||
Lib.f(d)
|
||||
data["abc"].length = 20;
|
||||
data["abc"][4] = 9;
|
||||
data["abc"][17] = 3;
|
||||
a = Lib.find(data["abc"], 9);
|
||||
b = Lib.find(data["abc"], 3);
|
||||
}
|
||||
}
|
||||
)";
|
||||
compileAndRun(sourceCode, 0, "Lib");
|
||||
compileAndRun(sourceCode, 0, "Test", bytes(), map<string, Address>{{"Lib", m_contractAddress}});
|
||||
BOOST_CHECK(callContractFunction("f()") == encodeArgs(u256(4), u256(17)));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(short_strings)
|
||||
{
|
||||
// This test verifies that the byte array encoding that combines length and data works
|
||||
|
@ -142,6 +142,21 @@ BOOST_AUTO_TEST_CASE(inheritance)
|
||||
sourcePart(*contract.definedFunctions().at(1))}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_CASE(libraries)
|
||||
{
|
||||
char const* sourceCode = R"(
|
||||
library Lib {
|
||||
struct Str { uint a; }
|
||||
enum E { E1, E2 }
|
||||
function f(uint[] x,Str storage y,E z) external;
|
||||
}
|
||||
)";
|
||||
ContractDefinition const& contract = checkInterface(sourceCode);
|
||||
set<string> expectedFunctions({"function f(uint256[] x,Lib.Str y,Lib.E z);"});
|
||||
BOOST_REQUIRE_EQUAL(1, contract.definedFunctions().size());
|
||||
BOOST_CHECK(expectedFunctions == set<string>({sourcePart(*contract.definedFunctions().at(0))}));
|
||||
}
|
||||
|
||||
BOOST_AUTO_TEST_SUITE_END()
|
||||
|
||||
}
|
||||
|
@ -933,24 +933,24 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors)
|
||||
BOOST_REQUIRE((contract = retrieveContract(source, 0)) != nullptr);
|
||||
FunctionTypePointer function = retrieveFunctionBySignature(contract, "foo()");
|
||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||
auto returnParams = function->returnParameterTypeNames();
|
||||
auto returnParams = function->returnParameterTypeNames(false);
|
||||
BOOST_CHECK_EQUAL(returnParams.at(0), "uint256");
|
||||
BOOST_CHECK(function->isConstant());
|
||||
|
||||
function = retrieveFunctionBySignature(contract, "map(uint256)");
|
||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||
auto params = function->parameterTypeNames();
|
||||
auto params = function->parameterTypeNames(false);
|
||||
BOOST_CHECK_EQUAL(params.at(0), "uint256");
|
||||
returnParams = function->returnParameterTypeNames();
|
||||
returnParams = function->returnParameterTypeNames(false);
|
||||
BOOST_CHECK_EQUAL(returnParams.at(0), "bytes4");
|
||||
BOOST_CHECK(function->isConstant());
|
||||
|
||||
function = retrieveFunctionBySignature(contract, "multiple_map(uint256,uint256)");
|
||||
BOOST_REQUIRE(function && function->hasDeclaration());
|
||||
params = function->parameterTypeNames();
|
||||
params = function->parameterTypeNames(false);
|
||||
BOOST_CHECK_EQUAL(params.at(0), "uint256");
|
||||
BOOST_CHECK_EQUAL(params.at(1), "uint256");
|
||||
returnParams = function->returnParameterTypeNames();
|
||||
returnParams = function->returnParameterTypeNames(false);
|
||||
BOOST_CHECK_EQUAL(returnParams.at(0), "bytes4");
|
||||
BOOST_CHECK(function->isConstant());
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user