mirror of
https://github.com/godotengine/godot.git
synced 2024-11-24 13:12:42 +00:00
Fix analyzer pushing SHADOWED_VARIABLE warning for members shadowed in subclasses
This fixes a bug in the analyzer where it did not push the SHADOWED_VARIABLE_BASE_CLASS warning for members shadowed by variable in subclass. It does this by comparing the class which contains the shadowed member with the class containing the variable, and pushing SHADOWED_VARIABLE only if the classes are the same. Additionally, SHADOWED_VARIABLE_BASE_CLASS can take an extra symbol which helps to specify the line for non native base class.
This commit is contained in:
parent
87318a2fb7
commit
413490c270
@ -561,10 +561,10 @@
|
|||||||
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or member variable, signal, or enum that would have the same name as a built-in function or global class name, thus shadowing it.
|
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or member variable, signal, or enum that would have the same name as a built-in function or global class name, thus shadowing it.
|
||||||
</member>
|
</member>
|
||||||
<member name="debug/gdscript/warnings/shadowed_variable" type="int" setter="" getter="" default="1">
|
<member name="debug/gdscript/warnings/shadowed_variable" type="int" setter="" getter="" default="1">
|
||||||
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or member variable that would shadow a member variable that the class defines.
|
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable or local constant shadows a member declared in the current class.
|
||||||
</member>
|
</member>
|
||||||
<member name="debug/gdscript/warnings/shadowed_variable_base_class" type="int" setter="" getter="" default="1">
|
<member name="debug/gdscript/warnings/shadowed_variable_base_class" type="int" setter="" getter="" default="1">
|
||||||
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when defining a local or subclass member variable that would shadow a variable that is inherited from a parent class.
|
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable or local constant shadows a member declared in a base class.
|
||||||
</member>
|
</member>
|
||||||
<member name="debug/gdscript/warnings/standalone_expression" type="int" setter="" getter="" default="1">
|
<member name="debug/gdscript/warnings/standalone_expression" type="int" setter="" getter="" default="1">
|
||||||
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling an expression that may have no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement.
|
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling an expression that may have no effect on the surrounding code, such as writing [code]2 + 2[/code] as a statement.
|
||||||
|
@ -5809,8 +5809,6 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
|
|||||||
#ifdef DEBUG_ENABLED
|
#ifdef DEBUG_ENABLED
|
||||||
void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope) {
|
void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope) {
|
||||||
const StringName &name = p_identifier->name;
|
const StringName &name = p_identifier->name;
|
||||||
GDScriptParser::DataType base = parser->current_class->get_datatype();
|
|
||||||
GDScriptParser::ClassNode *base_class = base.class_type;
|
|
||||||
|
|
||||||
{
|
{
|
||||||
List<MethodInfo> gdscript_funcs;
|
List<MethodInfo> gdscript_funcs;
|
||||||
@ -5838,37 +5836,53 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const GDScriptParser::DataType current_class_type = parser->current_class->get_datatype();
|
||||||
if (p_in_local_scope) {
|
if (p_in_local_scope) {
|
||||||
while (base_class != nullptr) {
|
GDScriptParser::ClassNode *base_class = current_class_type.class_type;
|
||||||
|
|
||||||
|
if (base_class != nullptr) {
|
||||||
if (base_class->has_member(name)) {
|
if (base_class->has_member(name)) {
|
||||||
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
|
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
base_class = base_class->base_type.class_type;
|
base_class = base_class->base_type.class_type;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
while (base_class != nullptr) {
|
||||||
|
if (base_class->has_member(name)) {
|
||||||
|
String base_class_name = base_class->get_global_name();
|
||||||
|
if (base_class_name.is_empty()) {
|
||||||
|
base_class_name = base_class->fqcn;
|
||||||
|
}
|
||||||
|
|
||||||
|
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()), base_class_name);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
base_class = base_class->base_type.class_type;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
StringName parent = base.native_type;
|
StringName native_base_class = current_class_type.native_type;
|
||||||
while (parent != StringName()) {
|
while (native_base_class != StringName()) {
|
||||||
ERR_FAIL_COND_MSG(!class_exists(parent), "Non-existent native base class.");
|
ERR_FAIL_COND_MSG(!class_exists(native_base_class), "Non-existent native base class.");
|
||||||
|
|
||||||
if (ClassDB::has_method(parent, name, true)) {
|
if (ClassDB::has_method(native_base_class, name, true)) {
|
||||||
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", parent);
|
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", native_base_class);
|
||||||
return;
|
return;
|
||||||
} else if (ClassDB::has_signal(parent, name, true)) {
|
} else if (ClassDB::has_signal(native_base_class, name, true)) {
|
||||||
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", parent);
|
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", native_base_class);
|
||||||
return;
|
return;
|
||||||
} else if (ClassDB::has_property(parent, name, true)) {
|
} else if (ClassDB::has_property(native_base_class, name, true)) {
|
||||||
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", parent);
|
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", native_base_class);
|
||||||
return;
|
return;
|
||||||
} else if (ClassDB::has_integer_constant(parent, name, true)) {
|
} else if (ClassDB::has_integer_constant(native_base_class, name, true)) {
|
||||||
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", parent);
|
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", native_base_class);
|
||||||
return;
|
return;
|
||||||
} else if (ClassDB::has_enum(parent, name, true)) {
|
} else if (ClassDB::has_enum(native_base_class, name, true)) {
|
||||||
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", parent);
|
parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", native_base_class);
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
parent = ClassDB::get_parent_class(parent);
|
native_base_class = ClassDB::get_parent_class(native_base_class);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
#endif // DEBUG_ENABLED
|
#endif // DEBUG_ENABLED
|
||||||
|
@ -61,10 +61,13 @@ String GDScriptWarning::get_message() const {
|
|||||||
return vformat(R"(The signal "%s" is declared but never explicitly used in the class.)", symbols[0]);
|
return vformat(R"(The signal "%s" is declared but never explicitly used in the class.)", symbols[0]);
|
||||||
case SHADOWED_VARIABLE:
|
case SHADOWED_VARIABLE:
|
||||||
CHECK_SYMBOLS(4);
|
CHECK_SYMBOLS(4);
|
||||||
return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s.)", symbols[0], symbols[1], symbols[2], symbols[3]);
|
return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s in the current class.)", symbols[0], symbols[1], symbols[2], symbols[3]);
|
||||||
case SHADOWED_VARIABLE_BASE_CLASS:
|
case SHADOWED_VARIABLE_BASE_CLASS:
|
||||||
CHECK_SYMBOLS(4);
|
CHECK_SYMBOLS(4);
|
||||||
return vformat(R"(The local %s "%s" is shadowing an already-declared %s at the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3]);
|
if (symbols.size() > 4) {
|
||||||
|
return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s in the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3], symbols[4]);
|
||||||
|
}
|
||||||
|
return vformat(R"(The local %s "%s" is shadowing an already-declared %s in the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3]);
|
||||||
case SHADOWED_GLOBAL_IDENTIFIER:
|
case SHADOWED_GLOBAL_IDENTIFIER:
|
||||||
CHECK_SYMBOLS(3);
|
CHECK_SYMBOLS(3);
|
||||||
return vformat(R"(The %s "%s" has the same name as a %s.)", symbols[0], symbols[1], symbols[2]);
|
return vformat(R"(The %s "%s" has the same name as a %s.)", symbols[0], symbols[1], symbols[2]);
|
||||||
|
@ -53,8 +53,8 @@ public:
|
|||||||
UNUSED_PRIVATE_CLASS_VARIABLE, // Class variable is declared private ("_" prefix) but never used in the class.
|
UNUSED_PRIVATE_CLASS_VARIABLE, // Class variable is declared private ("_" prefix) but never used in the class.
|
||||||
UNUSED_PARAMETER, // Function parameter is never used.
|
UNUSED_PARAMETER, // Function parameter is never used.
|
||||||
UNUSED_SIGNAL, // Signal is defined but never explicitly used in the class.
|
UNUSED_SIGNAL, // Signal is defined but never explicitly used in the class.
|
||||||
SHADOWED_VARIABLE, // Variable name shadowed by other variable in same class.
|
SHADOWED_VARIABLE, // A local variable/constant shadows a current class member.
|
||||||
SHADOWED_VARIABLE_BASE_CLASS, // Variable name shadowed by other variable in some base class.
|
SHADOWED_VARIABLE_BASE_CLASS, // A local variable/constant shadows a base class member.
|
||||||
SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
|
SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
|
||||||
UNREACHABLE_CODE, // Code after a return statement.
|
UNREACHABLE_CODE, // Code after a return statement.
|
||||||
UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind).
|
UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind).
|
||||||
|
@ -6,6 +6,6 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 5
|
>> Line: 5
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local variable "a" is shadowing an already-declared variable at line 1.
|
>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class.
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
|
@ -10,6 +10,6 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 5
|
>> Line: 5
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local variable "a" is shadowing an already-declared variable at line 1.
|
>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class.
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
|
@ -6,7 +6,7 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 6
|
>> Line: 6
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local variable "a" is shadowing an already-declared variable at line 1.
|
>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class.
|
||||||
1
|
1
|
||||||
2
|
2
|
||||||
1
|
1
|
||||||
|
@ -2,5 +2,5 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 4
|
>> Line: 4
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local function parameter "shadow" is shadowing an already-declared variable at line 1.
|
>> The local function parameter "shadow" is shadowing an already-declared variable at line 1 in the current class.
|
||||||
shadow
|
shadow
|
||||||
|
@ -0,0 +1,7 @@
|
|||||||
|
class_name ShadowingBase
|
||||||
|
|
||||||
|
const base_const_member = 1
|
||||||
|
var base_variable_member
|
||||||
|
|
||||||
|
func base_function_member():
|
||||||
|
pass
|
@ -1,4 +1,5 @@
|
|||||||
class_name ShadowedClass
|
class_name ShadowedClass
|
||||||
|
extends ShadowingBase
|
||||||
|
|
||||||
var member: int = 0
|
var member: int = 0
|
||||||
|
|
||||||
@ -7,6 +8,7 @@ var print_debug := 'print_debug'
|
|||||||
var print := 'print'
|
var print := 'print'
|
||||||
|
|
||||||
@warning_ignore("unused_variable")
|
@warning_ignore("unused_variable")
|
||||||
|
@warning_ignore("unused_local_constant")
|
||||||
func test():
|
func test():
|
||||||
var Array := 'Array'
|
var Array := 'Array'
|
||||||
var Node := 'Node'
|
var Node := 'Node'
|
||||||
@ -15,5 +17,8 @@ func test():
|
|||||||
var member := 'member'
|
var member := 'member'
|
||||||
var reference := 'reference'
|
var reference := 'reference'
|
||||||
var ShadowedClass := 'ShadowedClass'
|
var ShadowedClass := 'ShadowedClass'
|
||||||
|
var base_variable_member
|
||||||
|
const base_function_member = 1
|
||||||
|
var base_const_member
|
||||||
|
|
||||||
print('warn')
|
print('warn')
|
||||||
|
@ -1,34 +1,46 @@
|
|||||||
GDTEST_OK
|
GDTEST_OK
|
||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 5
|
>> Line: 6
|
||||||
>> SHADOWED_GLOBAL_IDENTIFIER
|
>> SHADOWED_GLOBAL_IDENTIFIER
|
||||||
>> The variable "print_debug" has the same name as a built-in function.
|
>> The variable "print_debug" has the same name as a built-in function.
|
||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 11
|
>> Line: 13
|
||||||
>> SHADOWED_GLOBAL_IDENTIFIER
|
>> SHADOWED_GLOBAL_IDENTIFIER
|
||||||
>> The variable "Array" has the same name as a built-in type.
|
>> The variable "Array" has the same name as a built-in type.
|
||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 12
|
>> Line: 14
|
||||||
>> SHADOWED_GLOBAL_IDENTIFIER
|
>> SHADOWED_GLOBAL_IDENTIFIER
|
||||||
>> The variable "Node" has the same name as a native class.
|
>> The variable "Node" has the same name as a native class.
|
||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 13
|
>> Line: 15
|
||||||
>> SHADOWED_GLOBAL_IDENTIFIER
|
>> SHADOWED_GLOBAL_IDENTIFIER
|
||||||
>> The variable "is_same" has the same name as a built-in function.
|
>> The variable "is_same" has the same name as a built-in function.
|
||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 14
|
>> Line: 16
|
||||||
>> SHADOWED_GLOBAL_IDENTIFIER
|
>> SHADOWED_GLOBAL_IDENTIFIER
|
||||||
>> The variable "sqrt" has the same name as a built-in function.
|
>> The variable "sqrt" has the same name as a built-in function.
|
||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 15
|
|
||||||
>> SHADOWED_VARIABLE
|
|
||||||
>> The local variable "member" is shadowing an already-declared variable at line 3.
|
|
||||||
>> WARNING
|
|
||||||
>> Line: 16
|
|
||||||
>> SHADOWED_VARIABLE_BASE_CLASS
|
|
||||||
>> The local variable "reference" is shadowing an already-declared method at the base class "RefCounted".
|
|
||||||
>> WARNING
|
|
||||||
>> Line: 17
|
>> Line: 17
|
||||||
|
>> SHADOWED_VARIABLE
|
||||||
|
>> The local variable "member" is shadowing an already-declared variable at line 4 in the current class.
|
||||||
|
>> WARNING
|
||||||
|
>> Line: 18
|
||||||
|
>> SHADOWED_VARIABLE_BASE_CLASS
|
||||||
|
>> The local variable "reference" is shadowing an already-declared method in the base class "RefCounted".
|
||||||
|
>> WARNING
|
||||||
|
>> Line: 19
|
||||||
>> SHADOWED_GLOBAL_IDENTIFIER
|
>> SHADOWED_GLOBAL_IDENTIFIER
|
||||||
>> The variable "ShadowedClass" has the same name as a global class defined in "shadowning.gd".
|
>> The variable "ShadowedClass" has the same name as a global class defined in "shadowning.gd".
|
||||||
|
>> WARNING
|
||||||
|
>> Line: 20
|
||||||
|
>> SHADOWED_VARIABLE_BASE_CLASS
|
||||||
|
>> The local variable "base_variable_member" is shadowing an already-declared variable at line 4 in the base class "ShadowingBase".
|
||||||
|
>> WARNING
|
||||||
|
>> Line: 21
|
||||||
|
>> SHADOWED_VARIABLE_BASE_CLASS
|
||||||
|
>> The local constant "base_function_member" is shadowing an already-declared function at line 6 in the base class "ShadowingBase".
|
||||||
|
>> WARNING
|
||||||
|
>> Line: 22
|
||||||
|
>> SHADOWED_VARIABLE_BASE_CLASS
|
||||||
|
>> The local variable "base_const_member" is shadowing an already-declared constant at line 3 in the base class "ShadowingBase".
|
||||||
warn
|
warn
|
||||||
|
@ -6,4 +6,4 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 8
|
>> Line: 8
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local constant "TEST" is shadowing an already-declared constant at line 2.
|
>> The local constant "TEST" is shadowing an already-declared constant at line 2 in the current class.
|
||||||
|
@ -6,4 +6,4 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 8
|
>> Line: 8
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local variable "foo" is shadowing an already-declared variable at line 1.
|
>> The local variable "foo" is shadowing an already-declared variable at line 1 in the current class.
|
||||||
|
@ -6,4 +6,4 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 2
|
>> Line: 2
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local variable "test" is shadowing an already-declared function at line 1.
|
>> The local variable "test" is shadowing an already-declared function at line 1 in the current class.
|
||||||
|
@ -2,11 +2,11 @@ GDTEST_OK
|
|||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 5
|
>> Line: 5
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local function parameter "a" is shadowing an already-declared variable at line 3.
|
>> The local function parameter "a" is shadowing an already-declared variable at line 3 in the current class.
|
||||||
>> WARNING
|
>> WARNING
|
||||||
>> Line: 15
|
>> Line: 15
|
||||||
>> SHADOWED_VARIABLE
|
>> SHADOWED_VARIABLE
|
||||||
>> The local function parameter "v" is shadowing an already-declared variable at line 13.
|
>> The local function parameter "v" is shadowing an already-declared variable at line 13 in the current class.
|
||||||
a
|
a
|
||||||
1
|
1
|
||||||
b
|
b
|
||||||
|
Loading…
Reference in New Issue
Block a user