summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp34
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd29
-rw-r--r--modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out8
3 files changed, 63 insertions, 8 deletions
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 6af6460b31..a5b40dacff 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3113,6 +3113,26 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
push_error(vformat(R"(No constructor of "%s" matches the signature "%s".)", Variant::get_type_name(builtin_type), signature), p_call);
}
}
+
+#ifdef DEBUG_ENABLED
+ // Consider `Signal(self, "my_signal")` as an implicit use of the signal.
+ if (builtin_type == Variant::SIGNAL && p_call->arguments.size() >= 2) {
+ const GDScriptParser::ExpressionNode *object_arg = p_call->arguments[0];
+ if (object_arg && object_arg->type == GDScriptParser::Node::SELF) {
+ const GDScriptParser::ExpressionNode *signal_arg = p_call->arguments[1];
+ if (signal_arg && signal_arg->is_constant) {
+ const StringName &signal_name = signal_arg->reduced_value;
+ if (parser->current_class->has_member(signal_name)) {
+ const GDScriptParser::ClassNode::Member &member = parser->current_class->get_member(signal_name);
+ if (member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
+ member.signal->usages++;
+ }
+ }
+ }
+ }
+ }
+#endif
+
p_call->set_datatype(call_type);
return;
} else if (GDScriptUtilityFunctions::function_exists(function_name)) {
@@ -3345,6 +3365,20 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
parser->push_warning(p_call, GDScriptWarning::STATIC_CALLED_ON_INSTANCE, p_call->function_name, caller_type);
}
+
+ // Consider `emit_signal()`, `connect()`, and `disconnect()` as implicit uses of the signal.
+ if (is_self && (p_call->function_name == SNAME("emit_signal") || p_call->function_name == SNAME("connect") || p_call->function_name == SNAME("disconnect")) && !p_call->arguments.is_empty()) {
+ const GDScriptParser::ExpressionNode *signal_arg = p_call->arguments[0];
+ if (signal_arg && signal_arg->is_constant) {
+ const StringName &signal_name = signal_arg->reduced_value;
+ if (parser->current_class->has_member(signal_name)) {
+ const GDScriptParser::ClassNode::Member &member = parser->current_class->get_member(signal_name);
+ if (member.type == GDScriptParser::ClassNode::Member::SIGNAL) {
+ member.signal->usages++;
+ }
+ }
+ }
+ }
#endif // DEBUG_ENABLED
call_type = return_type;
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd
index d937dfdcfe..37f118dc5d 100644
--- a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.gd
@@ -1,12 +1,29 @@
-signal s1()
-signal s2()
-signal s3()
+# Doesn't produce the warning:
+signal used_as_first_class_signal()
+signal used_with_signal_constructor()
+signal used_with_signal_emit()
+signal used_with_object_emit_signal()
+signal used_with_object_connect()
+signal used_with_object_disconnect()
+signal used_with_self_prefix()
+
+# Produce the warning:
+signal used_with_dynamic_name()
+signal just_unused()
@warning_ignore("unused_signal")
-signal s4()
+signal unused_but_ignored()
func no_exec():
- s1.emit()
- print(s2)
+ print(used_as_first_class_signal)
+ print(Signal(self, "used_with_signal_constructor"))
+ used_with_signal_emit.emit()
+ print(emit_signal("used_with_object_emit_signal"))
+ print(connect("used_with_object_connect", Callable()))
+ disconnect("used_with_object_disconnect", Callable())
+ print(self.emit_signal("used_with_self_prefix"))
+
+ var dynamic_name := "used_with_dynamic_name"
+ print(emit_signal(dynamic_name))
func test():
pass
diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out
index ff57017830..39ddf91c76 100644
--- a/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out
+++ b/modules/gdscript/tests/scripts/analyzer/warnings/unused_signal.out
@@ -1,5 +1,9 @@
GDTEST_OK
>> WARNING
->> Line: 3
+>> Line: 11
>> UNUSED_SIGNAL
->> The signal "s3" is declared but never explicitly used in the class.
+>> The signal "used_with_dynamic_name" is declared but never explicitly used in the class.
+>> WARNING
+>> Line: 12
+>> UNUSED_SIGNAL
+>> The signal "just_unused" is declared but never explicitly used in the class.