diff options
-rw-r--r-- | Changelog.md | 1 | ||||
-rw-r--r-- | libsolidity/analysis/DeclarationContainer.cpp | 22 | ||||
-rw-r--r-- | libsolidity/analysis/NameAndTypeResolver.cpp | 4 | ||||
-rw-r--r-- | test/libsolidity/SolidityEndToEndTest.cpp | 99 | ||||
-rw-r--r-- | test/libsolidity/SolidityNameAndTypeResolution.cpp | 58 |
5 files changed, 177 insertions, 7 deletions
diff --git a/Changelog.md b/Changelog.md index 5e458bba..cd3e31b2 100644 --- a/Changelog.md +++ b/Changelog.md @@ -6,6 +6,7 @@ Features: * AST: Use deterministic node identifiers. * Type system: Introduce type identifier strings. * Metadata: Do not include platform in the version number. + * Type checker: Allow multiple events of the same name (but with different arities or argument types) ### 0.4.8 (2017-01-13) diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index f8c12c5b..b33c8568 100644 --- a/libsolidity/analysis/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -42,20 +42,32 @@ Declaration const* DeclarationContainer::conflictingDeclaration( if (m_invisibleDeclarations.count(*_name)) declarations += m_invisibleDeclarations.at(*_name); - if (dynamic_cast<FunctionDefinition const*>(&_declaration)) + if ( + dynamic_cast<FunctionDefinition const*>(&_declaration) || + dynamic_cast<EventDefinition const*>(&_declaration) + ) { - // check that all other declarations with the same name are functions or a public state variable + // check that all other declarations with the same name are functions or a public state variable or events. + // And then check that the signatures are different. for (Declaration const* declaration: declarations) { - if (dynamic_cast<FunctionDefinition const*>(declaration)) - continue; if (auto variableDeclaration = dynamic_cast<VariableDeclaration const*>(declaration)) { if (variableDeclaration->isStateVariable() && !variableDeclaration->isConstant() && variableDeclaration->isPublic()) continue; return declaration; } - return declaration; + if ( + dynamic_cast<FunctionDefinition const*>(&_declaration) && + !dynamic_cast<FunctionDefinition const*>(declaration) + ) + return declaration; + if ( + dynamic_cast<EventDefinition const*>(&_declaration) && + !dynamic_cast<EventDefinition const*>(declaration) + ) + return declaration; + // Or, continue. } } else if (declarations.size() == 1 && declarations.front() == &_declaration) diff --git a/libsolidity/analysis/NameAndTypeResolver.cpp b/libsolidity/analysis/NameAndTypeResolver.cpp index 08323243..b0a82715 100644 --- a/libsolidity/analysis/NameAndTypeResolver.cpp +++ b/libsolidity/analysis/NameAndTypeResolver.cpp @@ -260,8 +260,8 @@ vector<Declaration const*> NameAndTypeResolver::cleanedDeclarations( for (auto it = _declarations.begin(); it != _declarations.end(); ++it) { solAssert(*it, ""); - // the declaration is functionDefinition or a VariableDeclaration while declarations > 1 - solAssert(dynamic_cast<FunctionDefinition const*>(*it) || dynamic_cast<VariableDeclaration const*>(*it), + // the declaration is functionDefinition, eventDefinition or a VariableDeclaration while declarations > 1 + solAssert(dynamic_cast<FunctionDefinition const*>(*it) || dynamic_cast<EventDefinition const*>(*it) || dynamic_cast<VariableDeclaration const*>(*it), "Found overloading involving something not a function or a variable"); shared_ptr<FunctionType const> functionType { (*it)->functionType(false) }; diff --git a/test/libsolidity/SolidityEndToEndTest.cpp b/test/libsolidity/SolidityEndToEndTest.cpp index 63a5828e..da7adbbf 100644 --- a/test/libsolidity/SolidityEndToEndTest.cpp +++ b/test/libsolidity/SolidityEndToEndTest.cpp @@ -2771,6 +2771,7 @@ BOOST_AUTO_TEST_CASE(event_no_arguments) } } )"; + compileAndRun(sourceCode); callContractFunction("deposit()"); BOOST_REQUIRE_EQUAL(m_logs.size(), 1); @@ -2802,6 +2803,104 @@ BOOST_AUTO_TEST_CASE(event_access_through_base_name) BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("x()"))); } +BOOST_AUTO_TEST_CASE(events_with_same_name) +{ + char const* sourceCode = R"( + contract ClientReceipt { + event Deposit; + event Deposit(address _addr); + event Deposit(address _addr, uint _amount); + function deposit() returns (uint) { + Deposit(); + return 1; + } + function deposit(address _addr) returns (uint) { + Deposit(_addr); + return 1; + } + function deposit(address _addr, uint _amount) returns (uint) { + Deposit(_addr, _amount); + return 1; + } + } + )"; + u160 const c_loggedAddress = m_contractAddress; + + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("deposit()") == encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data.empty()); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()"))); + + BOOST_CHECK(callContractFunction("deposit(address)", c_loggedAddress) == encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(c_loggedAddress)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address)"))); + + BOOST_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)) == encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(c_loggedAddress, 100)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,uint256)"))); +} + +BOOST_AUTO_TEST_CASE(events_with_same_name_inherited) +{ + char const* sourceCode = R"( + contract A { + event Deposit; + } + + contract B { + event Deposit(address _addr); + } + + contract ClientReceipt is A, B { + event Deposit(address _addr, uint _amount); + function deposit() returns (uint) { + Deposit(); + return 1; + } + function deposit(address _addr) returns (uint) { + Deposit(_addr); + return 1; + } + function deposit(address _addr, uint _amount) returns (uint) { + Deposit(_addr, _amount); + return 1; + } + } + )"; + u160 const c_loggedAddress = m_contractAddress; + + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("deposit()") == encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data.empty()); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit()"))); + + BOOST_CHECK(callContractFunction("deposit(address)", c_loggedAddress) == encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(c_loggedAddress)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address)"))); + + BOOST_CHECK(callContractFunction("deposit(address,uint256)", c_loggedAddress, u256(100)) == encodeArgs(u256(1))); + BOOST_REQUIRE_EQUAL(m_logs.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].address, m_contractAddress); + BOOST_CHECK(m_logs[0].data == encodeArgs(c_loggedAddress, 100)); + BOOST_REQUIRE_EQUAL(m_logs[0].topics.size(), 1); + BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::keccak256(string("Deposit(address,uint256)"))); +} + BOOST_AUTO_TEST_CASE(event_anonymous) { char const* sourceCode = R"( diff --git a/test/libsolidity/SolidityNameAndTypeResolution.cpp b/test/libsolidity/SolidityNameAndTypeResolution.cpp index edb57b0d..ce241c78 100644 --- a/test/libsolidity/SolidityNameAndTypeResolution.cpp +++ b/test/libsolidity/SolidityNameAndTypeResolution.cpp @@ -1365,6 +1365,17 @@ BOOST_AUTO_TEST_CASE(anonymous_event_too_many_indexed) CHECK_ERROR(text, TypeError, ""); } +BOOST_AUTO_TEST_CASE(events_with_same_name) +{ + char const* text = R"( + contract TestIt { + event A(); + event A(uint i); + } + )"; + BOOST_CHECK(success(text)); +} + BOOST_AUTO_TEST_CASE(event_call) { char const* text = R"( @@ -1376,6 +1387,53 @@ BOOST_AUTO_TEST_CASE(event_call) CHECK_SUCCESS(text); } +BOOST_AUTO_TEST_CASE(event_function_inheritance_clash) +{ + char const* text = R"( + contract A { + function dup() returns (uint) { + return 1; + } + } + contract B { + event dup(); + } + contract C is A, B { + } + )"; + CHECK_ERROR(text, DeclarationError, "Identifier already declared."); +} + +BOOST_AUTO_TEST_CASE(function_event_inheritance_clash) +{ + char const* text = R"( + contract B { + event dup(); + } + contract A { + function dup() returns (uint) { + return 1; + } + } + contract C is B, A { + } + )"; + CHECK_ERROR(text, DeclarationError, "Identifier already declared."); +} + +BOOST_AUTO_TEST_CASE(function_event_in_contract_clash) +{ + char const* text = R"( + contract A { + event dup(); + function dup() returns (uint) { + return 1; + } + } + )"; + CHECK_ERROR(text, DeclarationError, "Identifier already declared."); +} + BOOST_AUTO_TEST_CASE(event_inheritance) { char const* text = R"( |