From 2fd33d98cc5d71ad4ce8f5b2f096581e70112a07 Mon Sep 17 00:00:00 2001 From: Liana Husikyan Date: Mon, 9 Feb 2015 02:06:30 +0100 Subject: [PATCH] - implemented Empty parameter name story. Now the name of input/return parameters of function can be not specified. - added appropriate tests Conflicts: test/SolidityEndToEndTest.cpp test/SolidityNameAndTypeResolution.cpp --- libsolidity/AST.cpp | 19 +++++-- libsolidity/AST.h | 2 +- libsolidity/DeclarationContainer.cpp | 4 ++ libsolidity/DeclarationContainer.h | 4 +- libsolidity/Parser.cpp | 20 ++++++-- libsolidity/Parser.h | 1 + test/SolidityABIJSON.cpp | 71 ++++++++++++++++++++++++++ test/SolidityEndToEndTest.cpp | 27 ++++++++++ test/SolidityNameAndTypeResolution.cpp | 42 +++++++++++++++ 9 files changed, 179 insertions(+), 11 deletions(-) diff --git a/libsolidity/AST.cpp b/libsolidity/AST.cpp index 6f5b1f387..dbc326642 100644 --- a/libsolidity/AST.cpp +++ b/libsolidity/AST.cpp @@ -58,10 +58,21 @@ void ContractDefinition::checkTypeRequirements() BOOST_THROW_EXCEPTION(constructor->getReturnParameterList()->createTypeError( "Non-empty \"returns\" directive for constructor.")); - FunctionDefinition const* fallbackFunction = getFallbackFunction(); - if (fallbackFunction && fallbackFunction->getScope() == this && !fallbackFunction->getParameters().empty()) - BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError( - "Fallback function cannot take parameters.")); + FunctionDefinition const* fallbackFunction = nullptr; + for (ASTPointer const& function: getDefinedFunctions()) + { + if (function->getName().empty()) + { + if (fallbackFunction) + BOOST_THROW_EXCEPTION(DeclarationError() << errinfo_comment("Only one fallback function is allowed.")); + else + { + fallbackFunction = function.get(); + if (!fallbackFunction->getParameters().empty()) + BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError("Fallback function cannot take parameters.")); + } + } + } for (ASTPointer const& modifier: getFunctionModifiers()) modifier->checkTypeRequirements(); diff --git a/libsolidity/AST.h b/libsolidity/AST.h index 47f2a40ca..98f28afb0 100644 --- a/libsolidity/AST.h +++ b/libsolidity/AST.h @@ -250,7 +250,7 @@ public: /// Returns the constructor or nullptr if no constructor was specified. FunctionDefinition const* getConstructor() const; - /// Returns the fallback function or nullptr if no constructor was specified. + /// Returns the fallback function or nullptr if no fallback function was specified. FunctionDefinition const* getFallbackFunction() const; private: diff --git a/libsolidity/DeclarationContainer.cpp b/libsolidity/DeclarationContainer.cpp index c7081bc78..2e810a4cf 100644 --- a/libsolidity/DeclarationContainer.cpp +++ b/libsolidity/DeclarationContainer.cpp @@ -30,6 +30,9 @@ namespace solidity bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _update) { + if (_declaration.getName().empty()) + return true; + if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end()) return false; m_declarations[_declaration.getName()] = &_declaration; @@ -38,6 +41,7 @@ bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, Declaration const* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const { + solAssert(!_name.empty(), "Attempt to resolve empty name."); auto result = m_declarations.find(_name); if (result != m_declarations.end()) return result->second; diff --git a/libsolidity/DeclarationContainer.h b/libsolidity/DeclarationContainer.h index e4b793259..1216fcef2 100644 --- a/libsolidity/DeclarationContainer.h +++ b/libsolidity/DeclarationContainer.h @@ -42,8 +42,8 @@ public: 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. - /// @returns true iff it was not yet declared. + /// Registers the declaration in the scope unless its name is already declared or the name is empty. + /// @returns false if the name was already declared. bool registerDeclaration(Declaration const& _declaration, bool _update = false); Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } diff --git a/libsolidity/Parser.cpp b/libsolidity/Parser.cpp index d8c15c36d..2f5b18a04 100644 --- a/libsolidity/Parser.cpp +++ b/libsolidity/Parser.cpp @@ -268,17 +268,28 @@ ASTPointer Parser::parseVariableDeclaration(VarDeclParserOp ASTNodeFactory nodeFactory(*this); ASTPointer type = parseTypeName(_options.allowVar); bool isIndexed = false; + ASTPointer identifier; Token::Value token = m_scanner->getCurrentToken(); + Declaration::Visibility visibility(Declaration::Visibility::DEFAULT); + if (_options.isStateVariable && Token::isVisibilitySpecifier(token)) + visibility = parseVisibilitySpecifier(token); if (_options.allowIndexed && token == Token::INDEXED) { isIndexed = true; m_scanner->next(); } - Declaration::Visibility visibility(Declaration::Visibility::DEFAULT); - if (_options.isStateVariable && Token::isVisibilitySpecifier(token)) - visibility = parseVisibilitySpecifier(token); + if (_options.allowEmptyName && m_scanner->getCurrentToken() != Token::IDENTIFIER) + { + identifier = make_shared(""); + nodeFactory.setEndPositionFromNode(type); + } + else + { + nodeFactory.markEndPosition(); + identifier = expectIdentifierToken(); + } nodeFactory.markEndPosition(); - return nodeFactory.createNode(type, expectIdentifierToken(), + return nodeFactory.createNode(type, identifier, visibility, _options.isStateVariable, isIndexed); } @@ -402,6 +413,7 @@ ASTPointer Parser::parseParameterList(bool _allowEmpty, bool _all vector> parameters; VarDeclParserOptions options; options.allowIndexed = _allowIndexed; + options.allowEmptyName = true; expectToken(Token::LPAREN); if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) { diff --git a/libsolidity/Parser.h b/libsolidity/Parser.h index 19e0af1aa..5816fec40 100644 --- a/libsolidity/Parser.h +++ b/libsolidity/Parser.h @@ -50,6 +50,7 @@ private: bool allowVar = false; bool isStateVariable = false; bool allowIndexed = false; + bool allowEmptyName = false; }; ///@{ diff --git a/test/SolidityABIJSON.cpp b/test/SolidityABIJSON.cpp index 13e65761f..d600340eb 100644 --- a/test/SolidityABIJSON.cpp +++ b/test/SolidityABIJSON.cpp @@ -409,7 +409,78 @@ BOOST_AUTO_TEST_CASE(inherited) checkInterface(sourceCode, interface); } +BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) +{ + char const* sourceCode = R"( + contract test { + function f(uint, uint k) returns(uint ret_k, uint ret_g){ + uint g = 8; + ret_k = k; + ret_g = g; + } + })"; + + char const* interface = R"([ + { + "name": "f", + "constant": false, + "type": "function", + "inputs": [ + { + "name": "", + "type": "uint256" + }, + { + "name": "k", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "ret_k", + "type": "uint256" + }, + { + "name": "ret_g", + "type": "uint256" + } + ] + } + ])"; + checkInterface(sourceCode, interface); +} + +BOOST_AUTO_TEST_CASE(empty_name_return_parameter) +{ + char const* sourceCode = R"( + contract test { + function f(uint k) returns(uint){ + return k; + } + })"; + + char const* interface = R"([ + { + "name": "f", + "constant": false, + "type": "function", + "inputs": [ + { + "name": "k", + "type": "uint256" + } + ], + "outputs": [ + { + "name": "", + "type": "uint256" + } + ] + } + ])"; + checkInterface(sourceCode, interface); +} BOOST_AUTO_TEST_SUITE_END() diff --git a/test/SolidityEndToEndTest.cpp b/test/SolidityEndToEndTest.cpp index 56ee631b9..5bd1e8578 100644 --- a/test/SolidityEndToEndTest.cpp +++ b/test/SolidityEndToEndTest.cpp @@ -2113,6 +2113,33 @@ BOOST_AUTO_TEST_CASE(event_lots_of_data) BOOST_CHECK_EQUAL(m_logs[0].topics[0], dev::sha3(string("Deposit(address,hash256,uint256,bool)"))); } +BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) +{ + char const* sourceCode = R"( + contract test { + function f(uint, uint k) returns(uint ret_k, uint ret_g){ + uint g = 8; + ret_k = k; + ret_g = g; + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) != encodeArgs(5, 8)); + BOOST_CHECK(callContractFunction("f(uint256,uint256)", 5, 9) == encodeArgs(9, 8)); +} + +BOOST_AUTO_TEST_CASE(empty_name_return_parameter) +{ + char const* sourceCode = R"( + contract test { + function f(uint k) returns(uint){ + return k; + } + })"; + compileAndRun(sourceCode); + BOOST_CHECK(callContractFunction("f(uint256)", 9) == encodeArgs(9)); +} + BOOST_AUTO_TEST_CASE(sha3_multiple_arguments) { char const* sourceCode = R"( diff --git a/test/SolidityNameAndTypeResolution.cpp b/test/SolidityNameAndTypeResolution.cpp index 05ce6ed66..f4be31f4b 100644 --- a/test/SolidityNameAndTypeResolution.cpp +++ b/test/SolidityNameAndTypeResolution.cpp @@ -904,6 +904,48 @@ BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args) BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); } +BOOST_AUTO_TEST_CASE(empty_name_input_parameter) +{ + char const* text = R"( + contract test { + function f(uint){ + } + })"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(empty_name_return_parameter) +{ + char const* text = R"( + contract test { + function f() returns(bool){ + } + })"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(empty_name_input_parameter_with_named_one) +{ + char const* text = R"( + contract test { + function f(uint, uint k) returns(uint ret_k){ + return k; + } + })"; + BOOST_CHECK_NO_THROW(parseTextAndResolveNames(text)); +} + +BOOST_AUTO_TEST_CASE(empty_name_return_parameter_with_named_one) +{ + char const* text = R"( + contract test { + function f() returns(uint ret_k, uint){ + return 5; + } + })"; + BOOST_CHECK_THROW(parseTextAndResolveNames(text), TypeError); +} + BOOST_AUTO_TEST_CASE(disallow_declaration_of_void_type) { char const* sourceCode = "contract c { function f() { var x = f(); } }";