Fix #10155 - remove warning about free fucntion shadowing of interface function

This commit is contained in:
David Bar-On 2023-06-20 15:29:45 +03:00
parent dc7cda18f0
commit 35fb4990dd
11 changed files with 758 additions and 20 deletions

View File

@ -123,7 +123,11 @@ bool DeclarationContainer::registerDeclaration(
if (conflictingDeclaration(_declaration, _name))
return false;
if (m_enclosingContainer && _declaration.isVisibleAsUnqualifiedName())
if (
m_enclosingContainer &&
_declaration.isVisibleAsUnqualifiedName() &&
!_declaration.isParentInterface()
)
m_homonymCandidates.emplace_back(*_name, _location ? _location : &_declaration.location());
}

View File

@ -114,6 +114,9 @@ public:
///@todo make this const-safe by providing a different way to access the annotation
virtual ASTAnnotation& annotation() const;
/// Whether this node is a child of Interface contract.
virtual bool isParentInterface() const { return false; }
///@{
///@name equality operators
/// Equality relies on the fact that nodes cannot be copied.
@ -956,7 +959,8 @@ public:
ASTPointer<ParameterList> const& _parameters,
std::vector<ASTPointer<ModifierInvocation>> _modifiers,
ASTPointer<ParameterList> const& _returnParameters,
ASTPointer<Block> const& _body
ASTPointer<Block> const& _body,
bool _isParentInterface
):
CallableDeclaration(_id, _location, _name, _nameLocation, _visibility, _parameters, _isVirtual, _overrides, _returnParameters),
StructurallyDocumented(_documentation),
@ -965,7 +969,8 @@ public:
m_free(_free),
m_kind(_kind),
m_functionModifiers(std::move(_modifiers)),
m_body(_body)
m_body(_body),
m_isParentInterface(_isParentInterface)
{
solAssert(_kind == Token::Constructor || _kind == Token::Function || _kind == Token::Fallback || _kind == Token::Receive, "");
solAssert(isOrdinary() == !name().empty(), "");
@ -1026,12 +1031,16 @@ public:
ContractDefinition const* _searchStart = nullptr
) const override;
/// Whether this node is a child of Interface contract.
bool isParentInterface() const override { return m_isParentInterface; }
private:
StateMutability m_stateMutability;
bool m_free;
Token const m_kind;
std::vector<ASTPointer<ModifierInvocation>> m_functionModifiers;
ASTPointer<Block> m_body;
bool m_isParentInterface;
};
/**

View File

@ -132,16 +132,17 @@ SourceLocation ASTJsonImporter::createValueNameSourceLocation(Json::Value const&
}
template<class T>
ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node)
ASTPointer<T> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _node, bool _isParentInterface)
{
ASTPointer<T> ret = dynamic_pointer_cast<T>(convertJsonToASTNode(_node));
ASTPointer<T> ret = dynamic_pointer_cast<T>(convertJsonToASTNode(_node, _isParentInterface));
astAssert(ret, "cast of converted json-node must not be nullptr");
return ret;
}
ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _json)
{
ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(
Json::Value const& _json,
bool _isParentInterface
) {
astAssert(_json["nodeType"].isString() && _json.isMember("id"), "JSON-Node needs to have 'nodeType' and 'id' fields.");
string nodeType = _json["nodeType"].asString();
if (nodeType == "PragmaDirective")
@ -169,7 +170,7 @@ ASTPointer<ASTNode> ASTJsonImporter::convertJsonToASTNode(Json::Value const& _js
if (nodeType == "OverrideSpecifier")
return createOverrideSpecifier(_json);
if (nodeType == "FunctionDefinition")
return createFunctionDefinition(_json);
return createFunctionDefinition(_json, _isParentInterface);
if (nodeType == "VariableDeclaration")
return createVariableDeclaration(_json);
if (nodeType == "ModifierDefinition")
@ -337,9 +338,10 @@ ASTPointer<ContractDefinition> ASTJsonImporter::createContractDefinition(Json::V
baseContracts.push_back(createInheritanceSpecifier(base));
std::vector<ASTPointer<ASTNode>> subNodes;
bool isInterface = (contractKind(_node) == ContractKind::Interface);
for (auto& subnode: _node["nodes"])
subNodes.push_back(convertJsonToASTNode(subnode));
subNodes.push_back(convertJsonToASTNode(subnode, isInterface));
return createASTNode<ContractDefinition>(
_node,
@ -514,8 +516,10 @@ ASTPointer<OverrideSpecifier> ASTJsonImporter::createOverrideSpecifier(Json::Val
);
}
ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(Json::Value const& _node)
{
ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(
Json::Value const& _node,
bool _isParentInterface
) {
astAssert(_node["kind"].isString(), "Expected 'kind' to be a string!");
Token kind;
@ -562,7 +566,8 @@ ASTPointer<FunctionDefinition> ASTJsonImporter::createFunctionDefinition(Json::V
createParameterList(member(_node, "parameters")),
modifiers,
createParameterList(member(_node, "returnParameters")),
memberAsBool(_node, "implemented") ? createBlock(member(_node, "body"), false) : nullptr
memberAsBool(_node, "implemented") ? createBlock(member(_node, "body"), false) : nullptr,
_isParentInterface
);
}

View File

@ -62,11 +62,11 @@ private:
std::optional<std::vector<langutil::SourceLocation>> createSourceLocations(Json::Value const& _node) const;
/// Creates an ASTNode for a given JSON-ast of unknown type
/// @returns Pointer to a new created ASTNode
ASTPointer<ASTNode> convertJsonToASTNode(Json::Value const& _ast);
ASTPointer<ASTNode> convertJsonToASTNode(Json::Value const& _ast, bool _isParentInterface = false);
/// @returns a pointer to the more specific subclass of ASTNode
/// as indicated by the nodeType field of the json
template<class T>
ASTPointer<T> convertJsonToASTNode(Json::Value const& _node);
ASTPointer<T> convertJsonToASTNode(Json::Value const& _node, bool _isParentInterface = false);
langutil::SourceLocation createNameSourceLocation(Json::Value const& _node);
/// @returns source location of a mapping key name
@ -89,7 +89,7 @@ private:
ASTPointer<UserDefinedValueTypeDefinition> createUserDefinedValueTypeDefinition(Json::Value const& _node);
ASTPointer<ParameterList> createParameterList(Json::Value const& _node);
ASTPointer<OverrideSpecifier> createOverrideSpecifier(Json::Value const& _node);
ASTPointer<FunctionDefinition> createFunctionDefinition(Json::Value const& _node);
ASTPointer<FunctionDefinition> createFunctionDefinition(Json::Value const& _node, bool _isParentInterface);
ASTPointer<VariableDeclaration> createVariableDeclaration(Json::Value const& _node);
ASTPointer<ModifierDefinition> createModifierDefinition(Json::Value const& _node);
ASTPointer<ModifierInvocation> createModifierInvocation(Json::Value const& _node);

View File

@ -368,6 +368,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
{
documentation = parseStructuredDocumentation();
contractKind = parseContractKind();
bool isInterfaceContract = (contractKind.first == ContractKind::Interface);
tie(name, nameLocation) = expectIdentifierWithLocation();
if (m_scanner->currentToken() == Token::Is)
do
@ -388,7 +389,7 @@ ASTPointer<ContractDefinition> Parser::parseContractDefinition()
currentTokenValue == Token::Receive ||
currentTokenValue == Token::Fallback
)
subNodes.push_back(parseFunctionDefinition());
subNodes.push_back(parseFunctionDefinition(false, isInterfaceContract));
else if (currentTokenValue == Token::Struct)
subNodes.push_back(parseStructDefinition());
else if (currentTokenValue == Token::Enum)
@ -618,7 +619,7 @@ Parser::FunctionHeaderParserResult Parser::parseFunctionHeader(bool _isStateVari
return result;
}
ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction)
ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction, bool _isParentInterface)
{
RecursionGuard recursionGuard(*this);
ASTNodeFactory nodeFactory(*this);
@ -688,7 +689,8 @@ ASTPointer<ASTNode> Parser::parseFunctionDefinition(bool _freeFunction)
header.parameters,
header.modifiers,
header.returnParameters,
block
block,
_isParentInterface
);
}

View File

@ -100,7 +100,7 @@ private:
ASTPointer<OverrideSpecifier> parseOverrideSpecifier();
StateMutability parseStateMutability();
FunctionHeaderParserResult parseFunctionHeader(bool _isStateVariable);
ASTPointer<ASTNode> parseFunctionDefinition(bool _freeFunction = false);
ASTPointer<ASTNode> parseFunctionDefinition(bool _freeFunction = false, bool isParentInterface = false);
ASTPointer<StructDefinition> parseStructDefinition();
ASTPointer<EnumDefinition> parseEnumDefinition();
ASTPointer<UserDefinedValueTypeDefinition> parseUserDefinedValueTypeDefinition();

View File

@ -0,0 +1 @@
--import-ast

View File

@ -0,0 +1,7 @@
Warning: Source file does not specify required compiler version!
--> A
Warning: This declaration shadows an existing declaration.
--> A:1:481:
Note: The shadowed declaration is here:
--> A:1:335:

View File

@ -0,0 +1,694 @@
{
"language": "SolidityAST",
"sources": {
"A": {
"ast": {
"absolutePath": "<stdin>",
"exportedSymbols":
{
"C":
[
51
],
"I":
[
22
],
"f":
[
30
],
"h":
[
38
]
},
"id": 52,
"nodeType": "SourceUnit",
"nodes":
[
{
"abstract": false,
"baseContracts": [],
"canonicalName": "I",
"contractDependencies": [],
"contractKind": "interface",
"fullyImplemented": false,
"id": 22,
"linearizedBaseContracts":
[
22
],
"name": "I",
"nameLocation": "10:1:0",
"nodeType": "ContractDefinition",
"nodes":
[
{
"functionSelector": "b3de648b",
"id": 7,
"implemented": false,
"kind": "function",
"modifiers": [],
"name": "f",
"nameLocation": "27:1:0",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 3,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 2,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 7,
"src": "29:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 1,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "29:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "28:6:0"
},
"returnParameters":
{
"id": 6,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 5,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 7,
"src": "53:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 4,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "53:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "52:6:0"
},
"scope": 22,
"src": "18:41:0",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "external"
},
{
"functionSelector": "e420264a",
"id": 14,
"implemented": false,
"kind": "function",
"modifiers": [],
"name": "g",
"nameLocation": "109:1:0",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 10,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 9,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 14,
"src": "111:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 8,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "111:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "110:6:0"
},
"returnParameters":
{
"id": 13,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 12,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 14,
"src": "135:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 11,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "135:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "134:6:0"
},
"scope": 22,
"src": "100:41:0",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "external"
},
{
"functionSelector": "cb97492a",
"id": 21,
"implemented": false,
"kind": "function",
"modifiers": [],
"name": "h",
"nameLocation": "191:1:0",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 17,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 16,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 21,
"src": "193:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 15,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "193:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "192:6:0"
},
"returnParameters":
{
"id": 20,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 19,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 21,
"src": "217:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 18,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "217:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "216:6:0"
},
"scope": 22,
"src": "182:41:0",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "external"
}
],
"scope": 52,
"src": "0:261:0",
"usedErrors": [],
"usedEvents": []
},
{
"body":
{
"id": 29,
"nodeType": "Block",
"src": "295:2:0",
"statements": []
},
"id": 30,
"implemented": true,
"kind": "freeFunction",
"modifiers": [],
"name": "f",
"nameLocation": "272:1:0",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 25,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 24,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 30,
"src": "274:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 23,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "274:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "273:6:0"
},
"returnParameters":
{
"id": 28,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 27,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 30,
"src": "289:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 26,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "289:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "288:6:0"
},
"scope": 52,
"src": "263:34:0",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "internal"
},
{
"body":
{
"id": 37,
"nodeType": "Block",
"src": "366:2:0",
"statements": []
},
"id": 38,
"implemented": true,
"kind": "freeFunction",
"modifiers": [],
"name": "h",
"nameLocation": "343:1:0",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 33,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 32,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 38,
"src": "345:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 31,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "345:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "344:6:0"
},
"returnParameters":
{
"id": 36,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 35,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 38,
"src": "360:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 34,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "360:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "359:6:0"
},
"scope": 52,
"src": "334:34:0",
"stateMutability": "nonpayable",
"virtual": false,
"visibility": "internal"
},
{
"abstract": false,
"baseContracts": [],
"canonicalName": "C",
"contractDependencies": [],
"contractKind": "contract",
"fullyImplemented": true,
"id": 51,
"linearizedBaseContracts":
[
51
],
"name": "C",
"nameLocation": "400:1:0",
"nodeType": "ContractDefinition",
"nodes":
[
{
"body":
{
"id": 43,
"nodeType": "Block",
"src": "437:2:0",
"statements": []
},
"functionSelector": "e420264a",
"id": 44,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "g",
"nameLocation": "417:1:0",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 41,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 40,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 44,
"src": "419:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 39,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "419:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "418:6:0"
},
"returnParameters":
{
"id": 42,
"nodeType": "ParameterList",
"parameters": [],
"src": "437:0:0"
},
"scope": 51,
"src": "408:31:0",
"stateMutability": "pure",
"virtual": false,
"visibility": "public"
},
{
"body":
{
"id": 49,
"nodeType": "Block",
"src": "509:2:0",
"statements": []
},
"functionSelector": "cb97492a",
"id": 50,
"implemented": true,
"kind": "function",
"modifiers": [],
"name": "h",
"nameLocation": "489:1:0",
"nodeType": "FunctionDefinition",
"parameters":
{
"id": 47,
"nodeType": "ParameterList",
"parameters":
[
{
"constant": false,
"id": 46,
"mutability": "mutable",
"name": "",
"nameLocation": "-1:-1:-1",
"nodeType": "VariableDeclaration",
"scope": 50,
"src": "491:4:0",
"stateVariable": false,
"storageLocation": "default",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
},
"typeName":
{
"id": 45,
"name": "uint",
"nodeType": "ElementaryTypeName",
"src": "491:4:0",
"typeDescriptions":
{
"typeIdentifier": "t_uint256",
"typeString": "uint256"
}
},
"visibility": "internal"
}
],
"src": "490:6:0"
},
"returnParameters":
{
"id": 48,
"nodeType": "ParameterList",
"parameters": [],
"src": "509:0:0"
},
"scope": 51,
"src": "480:31:0",
"stateMutability": "pure",
"virtual": false,
"visibility": "public"
}
],
"scope": 52,
"src": "391:146:0",
"usedErrors": [],
"usedEvents": []
}
],
"src": "0:538:0"
}
}
}
}

View File

@ -0,0 +1,15 @@
interface I {
function f(uint) external returns (uint); // Should not shadow or be shadowed
function g(uint) external returns (uint); // Should not shadow or be shadowed
function h(uint) external returns (uint); // Should not shadow or be shadowed
}
function f(uint) returns (uint) {} // Should not shadow or be shadowed
function h(uint) returns (uint) {} // Shadowed by C.h()
contract C {
function g(uint) public pure {} // Should not shadow or be shadowed
function h(uint) public pure {} // Shadows the free h()
}
// ----
// Warning 2519: (480-511): This declaration shadows an existing declaration.