diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index c7d617b4f..047711067 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -110,6 +110,11 @@ void FunctionDefinition::checkTypeRequirements() m_body->checkTypeRequirements(); } +string FunctionDefinition::getCanonicalSignature() const +{ + return getName() + FunctionType(*this).getCanonicalSignature(); +} + void Block::checkTypeRequirements() { for (shared_ptr const& statement: m_statements) diff --git a/libsolidity/AST.h b/libsolidity/AST.h index b7c3dc6c0..8493d4323 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -277,6 +277,11 @@ public: /// Checks that all parameters have allowed types and calls checkTypeRequirements on the body. void checkTypeRequirements(); + /// @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; + private: bool m_isPublic; ASTPointer m_parameters; diff --git a/libsolidity/Types.cpp b/libsolidity/Types.cpp index c87ce2e60..7a81b65f6 100644 --- a/libsolidity/Types.cpp +++ b/libsolidity/Types.cpp @@ -484,6 +484,16 @@ unsigned FunctionType::getSizeOnStack() const } } +string FunctionType::getCanonicalSignature() const +{ + string ret = "("; + + for (auto it = m_parameterTypes.cbegin(); it != m_parameterTypes.cend(); ++it) + ret += (*it)->toString() + (it + 1 == m_parameterTypes.cend() ? "" : ","); + + return ret + ")"; +} + bool MappingType::operator==(Type const& _other) const { if (_other.getCategory() != getCategory()) diff --git a/libsolidity/Types.h b/libsolidity/Types.h index 0afa0ccd3..ff8a48877 100644 --- a/libsolidity/Types.h +++ b/libsolidity/Types.h @@ -338,6 +338,7 @@ public: virtual unsigned getSizeOnStack() const override; Location const& getLocation() const { return m_location; } + std::string getCanonicalSignature() const; private: TypePointers m_parameterTypes; diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 25bff71f7..94271b1f7 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -38,7 +38,7 @@ namespace test namespace { -void parseTextAndResolveNames(std::string const& _source) +ASTPointer parseTextAndResolveNames(std::string const& _source) { Parser parser; ASTPointer sourceUnit = parser.parse(std::make_shared(CharStream(_source))); @@ -50,6 +50,8 @@ void parseTextAndResolveNames(std::string const& _source) for (ASTPointer const& node: sourceUnit->getNodes()) if (ContractDefinition* contract = dynamic_cast(node.get())) resolver.checkTypeRequirements(*contract); + + return sourceUnit; } } @@ -321,6 +323,40 @@ BOOST_AUTO_TEST_CASE(comparison_bitop_precedence) BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); } +BOOST_AUTO_TEST_CASE(function_canonical_signature) +{ + ASTPointer sourceUnit; + char const* text = "contract Test {\n" + " function foo(uint256 arg1, uint64 arg2, bool arg3) returns (uint256 ret) {\n" + " ret = arg1 + arg2;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(sourceUnit = parseTextAndResolveNames(text)); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_EQUAL("foo(uint256,uint64,bool)", functions[0]->getCanonicalSignature()); + } +} + +BOOST_AUTO_TEST_CASE(function_canonical_signature_type_aliases) +{ + ASTPointer sourceUnit; + char const* text = "contract Test {\n" + " function boo(uint arg1, hash arg2, address arg3) returns (uint ret) {\n" + " ret = 5;\n" + " }\n" + "}\n"; + BOOST_CHECK_NO_THROW(sourceUnit = parseTextAndResolveNames(text)); + for (ASTPointer const& node: sourceUnit->getNodes()) + if (ContractDefinition* contract = dynamic_cast(node.get())) + { + auto functions = contract->getDefinedFunctions(); + BOOST_CHECK_EQUAL("boo(uint256,hash256,address)", functions[0]->getCanonicalSignature()); + } +} + BOOST_AUTO_TEST_SUITE_END() }