Merge pull request #89675 from dalexeev/gds-correct-unused-signal-warning

GDScript: Do not produce `UNUSED_SIGNAL` warning for common implicit uses
This commit is contained in:
Rémi Verschelde 2024-09-05 18:34:45 +02:00
commit d3be91e6ab
No known key found for this signature in database
GPG key ID: C3336907360768E1
3 changed files with 63 additions and 8 deletions

View file

@ -3245,6 +3245,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)) {
@ -3479,6 +3499,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;

View file

@ -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

View file

@ -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.