summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanil Alexeev <danil@alexeev.xyz>2024-06-28 09:35:04 +0300
committerDanil Alexeev <danil@alexeev.xyz>2024-06-28 11:12:01 +0300
commit68898dbcc9444dcbb45a5261aa8f9d4a2dd7390d (patch)
tree3a2f49743bff016b8e6069842b053508cdd624b7
parentcae2f853dcd1ecc26ca68de08cec62089dee1f26 (diff)
downloadredot-engine-68898dbcc9444dcbb45a5261aa8f9d4a2dd7390d.tar.gz
GDScript: Add `CONFUSABLE_CAPTURE_REASSIGNMENT` warning
-rw-r--r--doc/classes/ProjectSettings.xml3
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp15
-rw-r--r--modules/gdscript/gdscript_warning.cpp4
-rw-r--r--modules/gdscript/gdscript_warning.h2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd27
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out36
-rw-r--r--modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd1
7 files changed, 88 insertions, 0 deletions
diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml
index 8085b20730..a446f3c928 100644
--- a/doc/classes/ProjectSettings.xml
+++ b/doc/classes/ProjectSettings.xml
@@ -477,6 +477,9 @@
<member name="debug/gdscript/warnings/assert_always_true" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to true.
</member>
+ <member name="debug/gdscript/warnings/confusable_capture_reassignment" type="int" setter="" getter="" default="1">
+ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a local variable captured by a lambda is reassigned, since this does not modify the outer local variable.
+ </member>
<member name="debug/gdscript/warnings/confusable_identifier" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when an identifier contains characters that can be confused with something else, like when mixing different alphabets.
</member>
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 76e690a083..9147204a9b 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -2663,6 +2663,21 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
reduce_expression(p_assignment->assignee);
+#ifdef DEBUG_ENABLED
+ {
+ GDScriptParser::ExpressionNode *base = p_assignment->assignee;
+ while (base && base->type == GDScriptParser::Node::SUBSCRIPT) {
+ base = static_cast<GDScriptParser::SubscriptNode *>(base)->base;
+ }
+ if (base && base->type == GDScriptParser::Node::IDENTIFIER) {
+ GDScriptParser::IdentifierNode *id = static_cast<GDScriptParser::IdentifierNode *>(base);
+ if (current_lambda && current_lambda->captures_indices.has(id->name)) {
+ parser->push_warning(p_assignment, GDScriptWarning::CONFUSABLE_CAPTURE_REASSIGNMENT, id->name);
+ }
+ }
+ }
+#endif
+
if (p_assignment->assigned_value == nullptr || p_assignment->assignee == nullptr) {
return;
}
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 611a9ad2d9..e8fb1d94b3 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -145,6 +145,9 @@ String GDScriptWarning::get_message() const {
case CONFUSABLE_LOCAL_USAGE:
CHECK_SYMBOLS(1);
return vformat(R"(The identifier "%s" will be shadowed below in the block.)", symbols[0]);
+ case CONFUSABLE_CAPTURE_REASSIGNMENT:
+ CHECK_SYMBOLS(1);
+ return vformat(R"(Reassigning lambda capture does not modify the outer local variable "%s".)", symbols[0]);
case INFERENCE_ON_VARIANT:
CHECK_SYMBOLS(1);
return vformat("The %s type is being inferred from a Variant value, so it will be typed as Variant.", symbols[0]);
@@ -231,6 +234,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"CONFUSABLE_IDENTIFIER",
"CONFUSABLE_LOCAL_DECLARATION",
"CONFUSABLE_LOCAL_USAGE",
+ "CONFUSABLE_CAPTURE_REASSIGNMENT",
"INFERENCE_ON_VARIANT",
"NATIVE_METHOD_OVERRIDE",
"GET_NODE_DEFAULT_WITHOUT_ONREADY",
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 3ad9488138..1c806bb4e2 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -85,6 +85,7 @@ public:
CONFUSABLE_IDENTIFIER, // The identifier contains misleading characters that can be confused. E.g. "usеr" (has Cyrillic "е" instead of Latin "e").
CONFUSABLE_LOCAL_DECLARATION, // The parent block declares an identifier with the same name below.
CONFUSABLE_LOCAL_USAGE, // The identifier will be shadowed below in the block.
+ CONFUSABLE_CAPTURE_REASSIGNMENT, // Reassigning lambda capture does not modify the outer local variable.
INFERENCE_ON_VARIANT, // The declaration uses type inference but the value is typed as Variant.
NATIVE_METHOD_OVERRIDE, // The script method overrides a native one, this may not work as intended.
GET_NODE_DEFAULT_WITHOUT_ONREADY, // A class variable uses `get_node()` (or the `$` notation) as its default value, but does not use the @onready annotation.
@@ -137,6 +138,7 @@ public:
WARN, // CONFUSABLE_IDENTIFIER
WARN, // CONFUSABLE_LOCAL_DECLARATION
WARN, // CONFUSABLE_LOCAL_USAGE
+ WARN, // CONFUSABLE_CAPTURE_REASSIGNMENT
ERROR, // INFERENCE_ON_VARIANT // Most likely done by accident, usually inference is trying for a particular type.
ERROR, // NATIVE_METHOD_OVERRIDE // May not work as expected.
ERROR, // GET_NODE_DEFAULT_WITHOUT_ONREADY // May not work as expected.
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd
new file mode 100644
index 0000000000..b1accbe628
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.gd
@@ -0,0 +1,27 @@
+var member := 1
+
+func test():
+ var number := 1
+ var string := "1"
+ var vector := Vector2i(1, 0)
+ var array_assign := [1]
+ var array_append := [1]
+ var f := func ():
+ member = 2
+ number = 2
+ string += "2"
+ vector.x = 2
+ array_assign = [2]
+ array_append.append(2)
+ var g := func ():
+ member = 3
+ number = 3
+ string += "3"
+ vector.x = 3
+ array_assign = [3]
+ array_append.append(3)
+ prints("g", member, number, string, vector, array_assign, array_append)
+ g.call()
+ prints("f", member, number, string, vector, array_assign, array_append)
+ f.call()
+ prints("test", member, number, string, vector, array_assign, array_append)
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out
new file mode 100644
index 0000000000..b335a04a02
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_capture_reassignment.out
@@ -0,0 +1,36 @@
+GDTEST_OK
+>> WARNING
+>> Line: 11
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "number".
+>> WARNING
+>> Line: 12
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "string".
+>> WARNING
+>> Line: 13
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "vector".
+>> WARNING
+>> Line: 14
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "array_assign".
+>> WARNING
+>> Line: 18
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "number".
+>> WARNING
+>> Line: 19
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "string".
+>> WARNING
+>> Line: 20
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "vector".
+>> WARNING
+>> Line: 21
+>> CONFUSABLE_CAPTURE_REASSIGNMENT
+>> Reassigning lambda capture does not modify the outer local variable "array_assign".
+g 3 3 123 (3, 0) [3] [1, 2, 3]
+f 3 2 12 (2, 0) [2] [1, 2, 3]
+test 3 1 1 (1, 0) [1] [1, 2, 3]
diff --git a/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd b/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
index 46b6856d22..c3a42288c7 100644
--- a/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
+++ b/modules/gdscript/tests/scripts/parser/features/lambda_ends_with_new_line.gd
@@ -9,6 +9,7 @@ func four_parameters(_a, callable : Callable, b=func(): print(10)):
func test():
var v
+ @warning_ignore("confusable_capture_reassignment")
v=func():v=1
if true: v=1
print(v)