diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 63f3d772b..2e24d4f9d 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -88,7 +88,7 @@ void ContractDefinition::checkTypeRequirements() if (hashes.count(hash)) BOOST_THROW_EXCEPTION(createTypeError( std::string("Function signature hash collision for ") + - it.second->getCanonicalSignature())); + it.second->externalTypes())); hashes.insert(hash); } } @@ -192,7 +192,7 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn if (functionsSeen.count(f->getName()) == 0 && f->isPartOfExternalInterface()) { functionsSeen.insert(f->getName()); - FixedHash<4> hash(dev::sha3(f->getCanonicalSignature())); + FixedHash<4> hash(dev::sha3(f->externalTypes())); m_interfaceFunctionList->push_back(make_pair(hash, make_shared(*f, false))); } @@ -200,8 +200,9 @@ vector, FunctionTypePointer>> const& ContractDefinition::getIn if (functionsSeen.count(v->getName()) == 0 && v->isPartOfExternalInterface()) { FunctionType ftype(*v); + solAssert(v->getType().get(), ""); functionsSeen.insert(v->getName()); - FixedHash<4> hash(dev::sha3(ftype.getCanonicalSignature(v->getName()))); + FixedHash<4> hash(dev::sha3(ftype.externalTypes(v->getName()))); m_interfaceFunctionList->push_back(make_pair(hash, make_shared(*v))); } } @@ -319,9 +320,9 @@ void FunctionDefinition::checkTypeRequirements() m_body->checkTypeRequirements(); } -string FunctionDefinition::getCanonicalSignature() const +string FunctionDefinition::externalTypes() const { - return FunctionType(*this).getCanonicalSignature(getName()); + return FunctionType(*this).externalTypes(getName()); } bool VariableDeclaration::isLValue() const diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 335b9a880..c5cd2e5b1 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -424,7 +424,7 @@ public: /// @returns the canonical signature of the function /// That consists of the name of the function followed by the types of the /// arguments separated by commas all enclosed in parentheses without any spaces. - std::string getCanonicalSignature() const; + std::string externalTypes() const; private: bool m_isConstructor; diff --git a/libsolidity/ExpressionCompiler.cpp b/libsolidity/ExpressionCompiler.cpp index da762147a..288af3983 100644 --- a/libsolidity/ExpressionCompiler.cpp +++ b/libsolidity/ExpressionCompiler.cpp @@ -544,7 +544,7 @@ bool ExpressionCompiler::visit(FunctionCall const& _functionCall) } if (!event.isAnonymous()) { - m_context << u256(h256::Arith(dev::sha3(function.getCanonicalSignature(event.getName())))); + m_context << u256(h256::Arith(dev::sha3(function.externalTypes(event.getName())))); ++numIndexed; } solAssert(numIndexed <= 4, "Too many indexed arguments."); diff --git a/libsolidity/InterfaceHandler.cpp b/libsolidity/InterfaceHandler.cpp index 406d1e24a..e09e55cbc 100644 --- a/libsolidity/InterfaceHandler.cpp +++ b/libsolidity/InterfaceHandler.cpp @@ -129,7 +129,7 @@ std::unique_ptr InterfaceHandler::getUserDocumentation(ContractDefi if (!m_notice.empty()) {// since @notice is the only user tag if missing function should not appear user["notice"] = Json::Value(m_notice); - methods[it.second->getCanonicalSignature()] = user; + methods[it.second->externalTypes()] = user; } } } @@ -185,7 +185,7 @@ std::unique_ptr InterfaceHandler::getDevDocumentation(ContractDefin method["return"] = m_return; if (!method.empty()) // add the function, only if we have any documentation to add - methods[it.second->getCanonicalSignature()] = method; + methods[it.second->externalTypes()] = method; } } doc["methods"] = methods; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index 7b4d1de26..28a3af33a 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -1127,7 +1127,7 @@ MemberList const& FunctionType::getMembers() const } } -string FunctionType::getCanonicalSignature(std::string const& _name) const +string FunctionType::externalTypes(std::string const& _name) const { std::string funcName = _name; if (_name == "") @@ -1138,8 +1138,10 @@ string FunctionType::getCanonicalSignature(std::string const& _name) const string ret = funcName + "("; for (auto it = m_parameterTypes.cbegin(); it != m_parameterTypes.cend(); ++it) - ret += (*it)->toString() + (it + 1 == m_parameterTypes.cend() ? "" : ","); - + { + solAssert(!!(*it)->externalType(), "Parameter should have external type"); + ret += (*it)->externalType()->toString() + (it + 1 == m_parameterTypes.cend() ? "" : ","); + } return ret + ")"; } diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 17264dc59..599d80cc6 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -550,10 +550,10 @@ public: virtual MemberList const& getMembers() const override; Location const& getLocation() const { return m_location; } - /// @returns the canonical signature of this function type given the function name + /// @returns the external type 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 getCanonicalSignature(std::string const& _name = "") const; + std::string externalTypes(std::string const& _name = "") const; Declaration const& getDeclaration() const { solAssert(m_declaration, "Requested declaration from a FunctionType that has none"); diff --git a/mix/QFunctionDefinition.cpp b/mix/QFunctionDefinition.cpp index fed4e8add..d8cc63dee 100644 --- a/mix/QFunctionDefinition.cpp +++ b/mix/QFunctionDefinition.cpp @@ -28,7 +28,7 @@ using namespace dev::solidity; using namespace dev::mix; -QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(_parent, &_f->getDeclaration()), m_hash(dev::sha3(_f->getCanonicalSignature())) +QFunctionDefinition::QFunctionDefinition(QObject* _parent, dev::solidity::FunctionTypePointer const& _f): QBasicNodeDefinition(_parent, &_f->getDeclaration()), m_hash(dev::sha3(_f->externalTypes())) { auto paramNames = _f->getParameterNames(); auto paramTypes = _f->getParameterTypes(); diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 591cf053a..4e8166963 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -359,7 +359,7 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature) if (ContractDefinition* contract = dynamic_cast(node.get())) { auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", functions[0]->getCanonicalSignature()); + BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", functions[0]->externalTypes()); } } @@ -376,10 +376,41 @@ BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases) if (ContractDefinition* contract = dynamic_cast(node.get())) { auto functions = contract->getDefinedFunctions(); - BOOST_CHECK_EQUAL("boo(uint256,bytes32,address)", functions[0]->getCanonicalSignature()); + BOOST_CHECK_EQUAL("boo(uint256,bytes32,address)", functions[0]->externalTypes()); } } +BOOST_AUTO_TEST_CASE(function_external_types) +{ + ASTPointer sourceUnit; + char const* text = R"( + contract Test { + function boo(uint arg2, bool arg3, bytes8 arg4) returns (uint ret) { + ret = 5; + } + })"; + ETH_TEST_REQUIRE_NO_THROW(sourceUnit = parseTextAndResolveNames(text), "Parsing and name Resolving failed"); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_EQUAL("boo(uint256,bool,bytes8)", functions[0]->externalTypes()); + } +} + +//todo should check arrays and contract. also event +//BOOST_AUTO_TEST_CASE(function_external_types_throw) +//{ +// ASTPointer sourceUnit; +// char const* text = R"( +// contract Test { +// function boo(uint32[] arg5) returns (uint ret) { +// ret = 5; +// } +// })"; +// BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +//} + BOOST_AUTO_TEST_CASE(hash_collision_in_interface) { char const* text = "contract test {\n" @@ -635,7 +666,6 @@ BOOST_AUTO_TEST_CASE(state_variable_accessors) "mapping(uint=>bytes4) public map;\n" "mapping(uint=>mapping(uint=>bytes4)) public multiple_map;\n" "}\n"; - ASTPointer source; ContractDefinition const* contract; ETH_TEST_CHECK_NO_THROW(source = parseTextAndResolveNames(text), "Parsing and Resolving names failed"); diff --git a/test/SolidityTypes.cpp b/test/SolidityTypes.cpp index 6b6306479..4133ce7b7 100644 --- a/test/SolidityTypes.cpp +++ b/test/SolidityTypes.cpp @@ -86,6 +86,7 @@ BOOST_AUTO_TEST_CASE(storage_layout_arrays) BOOST_CHECK(ArrayType(ArrayType::Location::Storage, make_shared(32), 9).getStorageSize() == 9); } + BOOST_AUTO_TEST_SUITE_END() }