Browse Source

- 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
cl-refactor
Liana Husikyan 10 years ago
parent
commit
2fd33d98cc
  1. 19
      libsolidity/AST.cpp
  2. 2
      libsolidity/AST.h
  3. 4
      libsolidity/DeclarationContainer.cpp
  4. 4
      libsolidity/DeclarationContainer.h
  5. 20
      libsolidity/Parser.cpp
  6. 1
      libsolidity/Parser.h
  7. 71
      test/SolidityABIJSON.cpp
  8. 27
      test/SolidityEndToEndTest.cpp
  9. 42
      test/SolidityNameAndTypeResolution.cpp

19
libsolidity/AST.cpp

@ -58,10 +58,21 @@ void ContractDefinition::checkTypeRequirements()
BOOST_THROW_EXCEPTION(constructor->getReturnParameterList()->createTypeError( BOOST_THROW_EXCEPTION(constructor->getReturnParameterList()->createTypeError(
"Non-empty \"returns\" directive for constructor.")); "Non-empty \"returns\" directive for constructor."));
FunctionDefinition const* fallbackFunction = getFallbackFunction(); FunctionDefinition const* fallbackFunction = nullptr;
if (fallbackFunction && fallbackFunction->getScope() == this && !fallbackFunction->getParameters().empty()) for (ASTPointer<FunctionDefinition> const& function: getDefinedFunctions())
BOOST_THROW_EXCEPTION(fallbackFunction->getParameterList().createTypeError( {
"Fallback function cannot take parameters.")); 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<ModifierDefinition> const& modifier: getFunctionModifiers()) for (ASTPointer<ModifierDefinition> const& modifier: getFunctionModifiers())
modifier->checkTypeRequirements(); modifier->checkTypeRequirements();

2
libsolidity/AST.h

@ -250,7 +250,7 @@ public:
/// Returns the constructor or nullptr if no constructor was specified. /// Returns the constructor or nullptr if no constructor was specified.
FunctionDefinition const* getConstructor() const; 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; FunctionDefinition const* getFallbackFunction() const;
private: private:

4
libsolidity/DeclarationContainer.cpp

@ -30,6 +30,9 @@ namespace solidity
bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _update) bool DeclarationContainer::registerDeclaration(Declaration const& _declaration, bool _update)
{ {
if (_declaration.getName().empty())
return true;
if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end()) if (!_update && m_declarations.find(_declaration.getName()) != m_declarations.end())
return false; return false;
m_declarations[_declaration.getName()] = &_declaration; 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 Declaration const* DeclarationContainer::resolveName(ASTString const& _name, bool _recursive) const
{ {
solAssert(!_name.empty(), "Attempt to resolve empty name.");
auto result = m_declarations.find(_name); auto result = m_declarations.find(_name);
if (result != m_declarations.end()) if (result != m_declarations.end())
return result->second; return result->second;

4
libsolidity/DeclarationContainer.h

@ -42,8 +42,8 @@ public:
explicit DeclarationContainer(Declaration const* _enclosingDeclaration = nullptr, explicit DeclarationContainer(Declaration const* _enclosingDeclaration = nullptr,
DeclarationContainer const* _enclosingContainer = nullptr): DeclarationContainer const* _enclosingContainer = nullptr):
m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {} m_enclosingDeclaration(_enclosingDeclaration), m_enclosingContainer(_enclosingContainer) {}
/// Registers the declaration in the scope unless its name is already declared. /// Registers the declaration in the scope unless its name is already declared or the name is empty.
/// @returns true iff it was not yet declared. /// @returns false if the name was already declared.
bool registerDeclaration(Declaration const& _declaration, bool _update = false); bool registerDeclaration(Declaration const& _declaration, bool _update = false);
Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const; Declaration const* resolveName(ASTString const& _name, bool _recursive = false) const;
Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; } Declaration const* getEnclosingDeclaration() const { return m_enclosingDeclaration; }

20
libsolidity/Parser.cpp

@ -268,17 +268,28 @@ ASTPointer<VariableDeclaration> Parser::parseVariableDeclaration(VarDeclParserOp
ASTNodeFactory nodeFactory(*this); ASTNodeFactory nodeFactory(*this);
ASTPointer<TypeName> type = parseTypeName(_options.allowVar); ASTPointer<TypeName> type = parseTypeName(_options.allowVar);
bool isIndexed = false; bool isIndexed = false;
ASTPointer<ASTString> identifier;
Token::Value token = m_scanner->getCurrentToken(); 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) if (_options.allowIndexed && token == Token::INDEXED)
{ {
isIndexed = true; isIndexed = true;
m_scanner->next(); m_scanner->next();
} }
Declaration::Visibility visibility(Declaration::Visibility::DEFAULT); if (_options.allowEmptyName && m_scanner->getCurrentToken() != Token::IDENTIFIER)
if (_options.isStateVariable && Token::isVisibilitySpecifier(token)) {
visibility = parseVisibilitySpecifier(token); identifier = make_shared<ASTString>("");
nodeFactory.setEndPositionFromNode(type);
}
else
{
nodeFactory.markEndPosition();
identifier = expectIdentifierToken();
}
nodeFactory.markEndPosition(); nodeFactory.markEndPosition();
return nodeFactory.createNode<VariableDeclaration>(type, expectIdentifierToken(), return nodeFactory.createNode<VariableDeclaration>(type, identifier,
visibility, _options.isStateVariable, visibility, _options.isStateVariable,
isIndexed); isIndexed);
} }
@ -402,6 +413,7 @@ ASTPointer<ParameterList> Parser::parseParameterList(bool _allowEmpty, bool _all
vector<ASTPointer<VariableDeclaration>> parameters; vector<ASTPointer<VariableDeclaration>> parameters;
VarDeclParserOptions options; VarDeclParserOptions options;
options.allowIndexed = _allowIndexed; options.allowIndexed = _allowIndexed;
options.allowEmptyName = true;
expectToken(Token::LPAREN); expectToken(Token::LPAREN);
if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN) if (!_allowEmpty || m_scanner->getCurrentToken() != Token::RPAREN)
{ {

1
libsolidity/Parser.h

@ -50,6 +50,7 @@ private:
bool allowVar = false; bool allowVar = false;
bool isStateVariable = false; bool isStateVariable = false;
bool allowIndexed = false; bool allowIndexed = false;
bool allowEmptyName = false;
}; };
///@{ ///@{

71
test/SolidityABIJSON.cpp

@ -409,7 +409,78 @@ BOOST_AUTO_TEST_CASE(inherited)
checkInterface(sourceCode, interface); 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() BOOST_AUTO_TEST_SUITE_END()

27
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_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) BOOST_AUTO_TEST_CASE(sha3_multiple_arguments)
{ {
char const* sourceCode = R"( char const* sourceCode = R"(

42
test/SolidityNameAndTypeResolution.cpp

@ -904,6 +904,48 @@ BOOST_AUTO_TEST_CASE(invalid_parameter_names_in_named_args)
BOOST_CHECK_THROW(parseTextAndResolveNames(sourceCode), TypeError); 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) BOOST_AUTO_TEST_CASE(disallow_declaration_of_void_type)
{ {
char const* sourceCode = "contract c { function f() { var x = f(); } }"; char const* sourceCode = "contract c { function f() { var x = f(); } }";

Loading…
Cancel
Save