mirror of
https://github.com/ethereum/solidity
synced 2023-10-03 13:03:40 +00:00
Disallows old constructor syntax.
This commit is contained in:
parent
b909df4573
commit
182a0a9551
@ -24,7 +24,7 @@ Breaking Changes:
|
|||||||
* General: Disallow the ``throw`` statement. This was already the case in the experimental 0.5.0 mode.
|
* General: Disallow the ``throw`` statement. This was already the case in the experimental 0.5.0 mode.
|
||||||
* General: Disallow the ``years`` unit denomination (was already deprecated in 0.4.24)
|
* General: Disallow the ``years`` unit denomination (was already deprecated in 0.4.24)
|
||||||
* General: Introduce ``emit`` as a keyword instead of parsing it as identifier.
|
* General: Introduce ``emit`` as a keyword instead of parsing it as identifier.
|
||||||
* General: New keywords: ``calldata``
|
* General: New keywords: ``calldata`` and ``constructor``
|
||||||
* General: New reserved keywords: ``alias``, ``apply``, ``auto``, ``copyof``, ``define``, ``immutable``,
|
* General: New reserved keywords: ``alias``, ``apply``, ``auto``, ``copyof``, ``define``, ``immutable``,
|
||||||
``implements``, ``macro``, ``mutable``, ``override``, ``partial``, ``promise``, ``reference``, ``sealed``,
|
``implements``, ``macro``, ``mutable``, ``override``, ``partial``, ``promise``, ``reference``, ``sealed``,
|
||||||
``sizeof``, ``supports``, ``typedef`` and ``unchecked``.
|
``sizeof``, ``supports``, ``typedef`` and ``unchecked``.
|
||||||
|
@ -482,6 +482,14 @@ bool DeclarationRegistrationHelper::registerDeclaration(
|
|||||||
Declaration const* shadowedDeclaration = nullptr;
|
Declaration const* shadowedDeclaration = nullptr;
|
||||||
if (_warnOnShadow && !name.empty() && _container.enclosingContainer())
|
if (_warnOnShadow && !name.empty() && _container.enclosingContainer())
|
||||||
for (auto const* decl: _container.enclosingContainer()->resolveName(name, true, true))
|
for (auto const* decl: _container.enclosingContainer()->resolveName(name, true, true))
|
||||||
|
// Do not warn about functions shadowing a contract.
|
||||||
|
if (
|
||||||
|
!(
|
||||||
|
dynamic_cast<ContractDefinition const*>(decl) &&
|
||||||
|
dynamic_cast<FunctionDefinition const*>(&_declaration) &&
|
||||||
|
name == decl->name()
|
||||||
|
)
|
||||||
|
)
|
||||||
shadowedDeclaration = decl;
|
shadowedDeclaration = decl;
|
||||||
|
|
||||||
// We use "invisible" for both inactive variables in blocks and for members invisible in contracts.
|
// We use "invisible" for both inactive variables in blocks and for members invisible in contracts.
|
||||||
@ -710,10 +718,6 @@ void DeclarationRegistrationHelper::registerDeclaration(Declaration& _declaratio
|
|||||||
dynamic_cast<EventDefinition const*>(m_currentScope)
|
dynamic_cast<EventDefinition const*>(m_currentScope)
|
||||||
)
|
)
|
||||||
warnAboutShadowing = false;
|
warnAboutShadowing = false;
|
||||||
// Do not warn about the constructor shadowing the contract.
|
|
||||||
if (auto fun = dynamic_cast<FunctionDefinition const*>(&_declaration))
|
|
||||||
if (fun->isConstructor())
|
|
||||||
warnAboutShadowing = false;
|
|
||||||
|
|
||||||
// Register declaration as inactive if we are in block scope.
|
// Register declaration as inactive if we are in block scope.
|
||||||
bool inactive =
|
bool inactive =
|
||||||
|
@ -200,6 +200,14 @@ bool SyntaxChecker::visit(PlaceholderStatement const&)
|
|||||||
bool SyntaxChecker::visit(ContractDefinition const& _contract)
|
bool SyntaxChecker::visit(ContractDefinition const& _contract)
|
||||||
{
|
{
|
||||||
m_isInterface = _contract.contractKind() == ContractDefinition::ContractKind::Interface;
|
m_isInterface = _contract.contractKind() == ContractDefinition::ContractKind::Interface;
|
||||||
|
|
||||||
|
ASTString const& contractName = _contract.name();
|
||||||
|
for (FunctionDefinition const* function: _contract.definedFunctions())
|
||||||
|
if (function->name() == contractName)
|
||||||
|
m_errorReporter.syntaxError(function->location(),
|
||||||
|
"Functions are not allowed to have the same name as the contract. "
|
||||||
|
"If you intend this to be a constructor, use \"constructor(...) { ... }\" to define it."
|
||||||
|
);
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -216,21 +224,6 @@ bool SyntaxChecker::visit(FunctionDefinition const& _function)
|
|||||||
);
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
if (_function.isOldStyleConstructor())
|
|
||||||
{
|
|
||||||
if (v050)
|
|
||||||
m_errorReporter.syntaxError(
|
|
||||||
_function.location(),
|
|
||||||
"Functions are not allowed to have the same name as the contract. "
|
|
||||||
"If you intend this to be a constructor, use \"constructor(...) { ... }\" to define it."
|
|
||||||
);
|
|
||||||
else
|
|
||||||
m_errorReporter.warning(
|
|
||||||
_function.location(),
|
|
||||||
"Defining constructors as functions with the same name as the contract is deprecated. "
|
|
||||||
"Use \"constructor(...) { ... }\" instead."
|
|
||||||
);
|
|
||||||
}
|
|
||||||
if (!_function.isImplemented() && !_function.modifiers().empty())
|
if (!_function.isImplemented() && !_function.modifiers().empty())
|
||||||
{
|
{
|
||||||
if (v050)
|
if (v050)
|
||||||
@ -238,11 +231,6 @@ bool SyntaxChecker::visit(FunctionDefinition const& _function)
|
|||||||
else
|
else
|
||||||
m_errorReporter.warning(_function.location(), "Modifiers of functions without implementation are ignored." );
|
m_errorReporter.warning(_function.location(), "Modifiers of functions without implementation are ignored." );
|
||||||
}
|
}
|
||||||
if (_function.name() == "constructor")
|
|
||||||
m_errorReporter.warning(_function.location(),
|
|
||||||
"This function is named \"constructor\" but is not the constructor of the contract. "
|
|
||||||
"If you intend this to be a constructor, use \"constructor(...) { ... }\" without the \"function\" keyword to define it."
|
|
||||||
);
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -614,7 +614,6 @@ public:
|
|||||||
|
|
||||||
StateMutability stateMutability() const { return m_stateMutability; }
|
StateMutability stateMutability() const { return m_stateMutability; }
|
||||||
bool isConstructor() const { return m_isConstructor; }
|
bool isConstructor() const { return m_isConstructor; }
|
||||||
bool isOldStyleConstructor() const { return m_isConstructor && !name().empty(); }
|
|
||||||
bool isFallback() const { return !m_isConstructor && name().empty(); }
|
bool isFallback() const { return !m_isConstructor && name().empty(); }
|
||||||
bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
|
bool isPayable() const { return m_stateMutability == StateMutability::Payable; }
|
||||||
std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
|
std::vector<ASTPointer<ModifierInvocation>> const& modifiers() const { return m_functionModifiers; }
|
||||||
|
@ -239,13 +239,10 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition(Token::Value _exp
|
|||||||
Token::Value currentTokenValue = m_scanner->currentToken();
|
Token::Value currentTokenValue = m_scanner->currentToken();
|
||||||
if (currentTokenValue == Token::RBrace)
|
if (currentTokenValue == Token::RBrace)
|
||||||
break;
|
break;
|
||||||
else if (
|
else if (currentTokenValue == Token::Function || currentTokenValue == Token::Constructor)
|
||||||
currentTokenValue == Token::Function ||
|
|
||||||
(currentTokenValue == Token::Identifier && m_scanner->currentLiteral() == "constructor")
|
|
||||||
)
|
|
||||||
// This can be a function or a state variable of function type (especially
|
// This can be a function or a state variable of function type (especially
|
||||||
// complicated to distinguish fallback function from function type state variable)
|
// complicated to distinguish fallback function from function type state variable)
|
||||||
subNodes.push_back(parseFunctionDefinitionOrFunctionTypeStateVariable(name.get()));
|
subNodes.push_back(parseFunctionDefinitionOrFunctionTypeStateVariable());
|
||||||
else if (currentTokenValue == Token::Struct)
|
else if (currentTokenValue == Token::Struct)
|
||||||
subNodes.push_back(parseStructDefinition());
|
subNodes.push_back(parseStructDefinition());
|
||||||
else if (currentTokenValue == Token::Enum)
|
else if (currentTokenValue == Token::Enum)
|
||||||
@ -340,30 +337,31 @@ StateMutability Parser::parseStateMutability(Token::Value _token)
|
|||||||
return stateMutability;
|
return stateMutability;
|
||||||
}
|
}
|
||||||
|
|
||||||
Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(
|
Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers)
|
||||||
bool _forceEmptyName,
|
|
||||||
bool _allowModifiers,
|
|
||||||
ASTString const* _contractName
|
|
||||||
)
|
|
||||||
{
|
{
|
||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
FunctionHeaderParserResult result;
|
FunctionHeaderParserResult result;
|
||||||
|
|
||||||
result.isConstructor = false;
|
result.isConstructor = false;
|
||||||
|
|
||||||
if (m_scanner->currentToken() == Token::Identifier && m_scanner->currentLiteral() == "constructor")
|
if (m_scanner->currentToken() == Token::Constructor)
|
||||||
result.isConstructor = true;
|
result.isConstructor = true;
|
||||||
else if (m_scanner->currentToken() != Token::Function)
|
else if (m_scanner->currentToken() != Token::Function)
|
||||||
solAssert(false, "Function or constructor expected.");
|
solAssert(false, "Function or constructor expected.");
|
||||||
m_scanner->next();
|
m_scanner->next();
|
||||||
|
|
||||||
if (result.isConstructor || _forceEmptyName || m_scanner->currentToken() == Token::LParen)
|
if (result.isConstructor)
|
||||||
result.name = make_shared<ASTString>();
|
result.name = make_shared<ASTString>();
|
||||||
|
else if (_forceEmptyName || m_scanner->currentToken() == Token::LParen)
|
||||||
|
result.name = make_shared<ASTString>();
|
||||||
|
else if (m_scanner->currentToken() == Token::Constructor)
|
||||||
|
fatalParserError(string(
|
||||||
|
"This function is named \"constructor\" but is not the constructor of the contract. "
|
||||||
|
"If you intend this to be a constructor, use \"constructor(...) { ... }\" without the \"function\" keyword to define it."
|
||||||
|
));
|
||||||
else
|
else
|
||||||
result.name = expectIdentifierToken();
|
result.name = expectIdentifierToken();
|
||||||
|
|
||||||
if (!result.name->empty() && _contractName && *result.name == *_contractName)
|
|
||||||
result.isConstructor = true;
|
|
||||||
|
|
||||||
VarDeclParserOptions options;
|
VarDeclParserOptions options;
|
||||||
options.allowLocationSpecifier = true;
|
options.allowLocationSpecifier = true;
|
||||||
@ -435,7 +433,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(
|
|||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName)
|
ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable()
|
||||||
{
|
{
|
||||||
RecursionGuard recursionGuard(*this);
|
RecursionGuard recursionGuard(*this);
|
||||||
ASTNodeFactory nodeFactory(*this);
|
ASTNodeFactory nodeFactory(*this);
|
||||||
@ -443,7 +441,7 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinitionOrFunctionTypeStateVariable(A
|
|||||||
if (m_scanner->currentCommentLiteral() != "")
|
if (m_scanner->currentCommentLiteral() != "")
|
||||||
docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral());
|
docstring = make_shared<ASTString>(m_scanner->currentCommentLiteral());
|
||||||
|
|
||||||
FunctionHeaderParserResult header = parseFunctionHeader(false, true, _contractName);
|
FunctionHeaderParserResult header = parseFunctionHeader(false, true);
|
||||||
|
|
||||||
if (
|
if (
|
||||||
header.isConstructor ||
|
header.isConstructor ||
|
||||||
|
@ -74,12 +74,8 @@ private:
|
|||||||
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
ASTPointer<InheritanceSpecifier> parseInheritanceSpecifier();
|
||||||
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
Declaration::Visibility parseVisibilitySpecifier(Token::Value _token);
|
||||||
StateMutability parseStateMutability(Token::Value _token);
|
StateMutability parseStateMutability(Token::Value _token);
|
||||||
FunctionHeaderParserResult parseFunctionHeader(
|
FunctionHeaderParserResult parseFunctionHeader(bool _forceEmptyName, bool _allowModifiers);
|
||||||
bool _forceEmptyName,
|
ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable();
|
||||||
bool _allowModifiers,
|
|
||||||
ASTString const* _contractName = nullptr
|
|
||||||
);
|
|
||||||
ASTPointer<ASTNode> parseFunctionDefinitionOrFunctionTypeStateVariable(ASTString const* _contractName);
|
|
||||||
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
ASTPointer<FunctionDefinition> parseFunctionDefinition(ASTString const* _contractName);
|
||||||
ASTPointer<StructDefinition> parseStructDefinition();
|
ASTPointer<StructDefinition> parseStructDefinition();
|
||||||
ASTPointer<EnumDefinition> parseEnumDefinition();
|
ASTPointer<EnumDefinition> parseEnumDefinition();
|
||||||
|
@ -144,6 +144,7 @@ namespace solidity
|
|||||||
K(Assembly, "assembly", 0) \
|
K(Assembly, "assembly", 0) \
|
||||||
K(Break, "break", 0) \
|
K(Break, "break", 0) \
|
||||||
K(Constant, "constant", 0) \
|
K(Constant, "constant", 0) \
|
||||||
|
K(Constructor, "constructor", 0) \
|
||||||
K(Continue, "continue", 0) \
|
K(Continue, "continue", 0) \
|
||||||
K(Contract, "contract", 0) \
|
K(Contract, "contract", 0) \
|
||||||
K(Do, "do", 0) \
|
K(Do, "do", 0) \
|
||||||
|
Loading…
Reference in New Issue
Block a user