diff --git a/libsolidity/analysis/DeclarationContainer.cpp b/libsolidity/analysis/DeclarationContainer.cpp index e7b23f7dd..bb104b684 100644 --- a/libsolidity/analysis/DeclarationContainer.cpp +++ b/libsolidity/analysis/DeclarationContainer.cpp @@ -120,11 +120,7 @@ bool DeclarationContainer::registerDeclaration( if (conflictingDeclaration(_declaration, _name)) return false; - // Do not warn about shadowing for structs and enums because their members are - // not accessible without prefixes. Also do not warn about event parameters - // because they do not participate in any proper scope. - bool special = _declaration.scope() && (_declaration.isStructMember() || _declaration.isEnumValue() || _declaration.isEventOrErrorParameter()); - if (m_enclosingContainer && !special) + if (m_enclosingContainer && _declaration.isVisibleAsUnqualifiedName()) m_homonymCandidates.emplace_back(*_name, _location ? _location : &_declaration.location()); } diff --git a/libsolidity/ast/AST.cpp b/libsolidity/ast/AST.cpp index 29137c1b6..6d5e89ce2 100644 --- a/libsolidity/ast/AST.cpp +++ b/libsolidity/ast/AST.cpp @@ -606,6 +606,18 @@ bool Declaration::isEventOrErrorParameter() const return dynamic_cast(scope()) || dynamic_cast(scope()); } +bool Declaration::isVisibleAsUnqualifiedName() const +{ + if (!scope()) + return true; + if (isStructMember() || isEnumValue() || isEventOrErrorParameter()) + return false; + if (auto const* functionDefinition = dynamic_cast(scope())) + if (!functionDefinition->isImplemented()) + return false; // parameter of a function without body + return true; +} + DeclarationAnnotation& Declaration::annotation() const { return initAnnotation(); diff --git a/libsolidity/ast/AST.h b/libsolidity/ast/AST.h index 84981daae..f02e93599 100644 --- a/libsolidity/ast/AST.h +++ b/libsolidity/ast/AST.h @@ -265,6 +265,12 @@ public: /// @returns true if this is a declaration of a parameter of an event. bool isEventOrErrorParameter() const; + /// @returns false if the declaration can never be referenced without being qualified with a scope. + /// Usually the name alone can be used to refer to the corresponding entity. + /// But, for example, struct member names or enum member names always require a prefix. + /// Another example is event parameter names, which do not participate in any proper scope. + bool isVisibleAsUnqualifiedName() const; + /// @returns the type of expressions referencing this declaration. /// This can only be called once types of variable declarations have already been resolved. virtual Type const* type() const = 0; diff --git a/test/libsolidity/syntaxTests/scoping/name_shadowing_function_parameter_name_vs_contract.sol b/test/libsolidity/syntaxTests/scoping/name_shadowing_function_parameter_name_vs_contract.sol new file mode 100644 index 000000000..1ae8ed754 --- /dev/null +++ b/test/libsolidity/syntaxTests/scoping/name_shadowing_function_parameter_name_vs_contract.sol @@ -0,0 +1,20 @@ +interface I { + function f(uint I) external; // OK +} + +library L { + function f(uint L) public pure {} // warning +} + +abstract contract A { + function f(uint A) public pure {} // warning + function g(uint A) public virtual; // OK +} + +contract C { + function f(uint C) public pure {} // warning +} +// ---- +// Warning 2519: (91-97): This declaration shadows an existing declaration. +// Warning 2519: (168-174): This declaration shadows an existing declaration. +// Warning 2519: (283-289): This declaration shadows an existing declaration. diff --git a/test/libsolidity/syntaxTests/scoping/name_shadowing_function_parameter_vs_its_function.sol b/test/libsolidity/syntaxTests/scoping/name_shadowing_function_parameter_vs_its_function.sol new file mode 100644 index 000000000..a17a74353 --- /dev/null +++ b/test/libsolidity/syntaxTests/scoping/name_shadowing_function_parameter_vs_its_function.sol @@ -0,0 +1,5 @@ +contract C { + function f(uint f) pure public {} +} +// ---- +// Warning 2519: (28-34): This declaration shadows an existing declaration. diff --git a/test/libsolidity/syntaxTests/scoping/name_shadowing2.sol b/test/libsolidity/syntaxTests/scoping/name_shadowing_local_variable_vs_free_function.sol similarity index 100% rename from test/libsolidity/syntaxTests/scoping/name_shadowing2.sol rename to test/libsolidity/syntaxTests/scoping/name_shadowing_local_variable_vs_free_function.sol diff --git a/test/libsolidity/syntaxTests/scoping/name_shadowing3.sol b/test/libsolidity/syntaxTests/scoping/name_shadowing_local_variable_vs_functions.sol similarity index 100% rename from test/libsolidity/syntaxTests/scoping/name_shadowing3.sol rename to test/libsolidity/syntaxTests/scoping/name_shadowing_local_variable_vs_functions.sol diff --git a/test/libsolidity/syntaxTests/scoping/name_shadowing.sol b/test/libsolidity/syntaxTests/scoping/name_shadowing_local_variable_vs_state_variable.sol similarity index 100% rename from test/libsolidity/syntaxTests/scoping/name_shadowing.sol rename to test/libsolidity/syntaxTests/scoping/name_shadowing_local_variable_vs_state_variable.sol