diff --git a/doc/classes/ProjectSettings.xml b/doc/classes/ProjectSettings.xml index 16d4bbd5c29..11578367797 100644 --- a/doc/classes/ProjectSettings.xml +++ b/doc/classes/ProjectSettings.xml @@ -472,6 +472,10 @@ When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a static inferred type uses a [Variant] as initial value, which makes the static type to also be Variant. + + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a variable, constant, or parameter has an implicitly inferred static type. + [b]Note:[/b] This warning is recommended [i]in addition[/i] to [member debug/gdscript/warnings/untyped_declaration] if you want to always specify the type explicitly. Having [code]INFERRED_DECLARATION[/code] warning level higher than [code]UNTYPED_DECLARATION[/code] warning level makes little sense and is not recommended. + When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when trying to use an integer as an enum without an explicit cast. diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 469c52dc9d6..5b47ed1a465 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1936,9 +1936,14 @@ void GDScriptAnalyzer::resolve_assignable(GDScriptParser::AssignableNode *p_assi } #ifdef DEBUG_ENABLED - if (!has_specified_type && !p_assignable->infer_datatype && !is_constant) { + if (!has_specified_type) { const bool is_parameter = p_assignable->type == GDScriptParser::Node::PARAMETER; - parser->push_warning(p_assignable, GDScriptWarning::UNTYPED_DECLARATION, is_parameter ? "Parameter" : "Variable", p_assignable->identifier->name); + const String declaration_type = is_constant ? "Constant" : (is_parameter ? "Parameter" : "Variable"); + if (p_assignable->infer_datatype || is_constant) { + parser->push_warning(p_assignable, GDScriptWarning::INFERRED_DECLARATION, declaration_type, p_assignable->identifier->name); + } else { + parser->push_warning(p_assignable, GDScriptWarning::UNTYPED_DECLARATION, declaration_type, p_assignable->identifier->name); + } } #endif @@ -2152,7 +2157,9 @@ void GDScriptAnalyzer::resolve_for(GDScriptParser::ForNode *p_for) { } else { p_for->variable->set_datatype(variable_type); #ifdef DEBUG_ENABLED - if (!variable_type.is_hard_type()) { + if (variable_type.is_hard_type()) { + parser->push_warning(p_for->variable, GDScriptWarning::INFERRED_DECLARATION, R"("for" iterator variable)", p_for->variable->name); + } else { parser->push_warning(p_for->variable, GDScriptWarning::UNTYPED_DECLARATION, R"("for" iterator variable)", p_for->variable->name); } #endif diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index ef2913926cb..a0078f84d6a 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -94,6 +94,9 @@ String GDScriptWarning::get_message() const { return vformat(R"*(%s "%s()" has no static return type.)*", symbols[0], symbols[1]); } return vformat(R"(%s "%s" has no static type.)", symbols[0], symbols[1]); + case INFERRED_DECLARATION: + CHECK_SYMBOLS(2); + return vformat(R"(%s "%s" has an implicitly inferred static type.)", symbols[0], symbols[1]); case UNSAFE_PROPERTY_ACCESS: CHECK_SYMBOLS(2); return vformat(R"(The property "%s" is not present on the inferred type "%s" (but may be present on a subtype).)", symbols[0], symbols[1]); @@ -207,6 +210,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) { "CONSTANT_USED_AS_FUNCTION", "FUNCTION_USED_AS_PROPERTY", "UNTYPED_DECLARATION", + "INFERRED_DECLARATION", "UNSAFE_PROPERTY_ACCESS", "UNSAFE_METHOD_ACCESS", "UNSAFE_CAST", diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index 2b177093388..1aef6fa81bb 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -64,7 +64,8 @@ public: PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name. CONSTANT_USED_AS_FUNCTION, // Function not found, but there's a constant with the same name. FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name. - UNTYPED_DECLARATION, // Variable/parameter/function has no static type, explicitly specified or inferred (`:=`). + UNTYPED_DECLARATION, // Variable/parameter/function has no static type, explicitly specified or implicitly inferred. + INFERRED_DECLARATION, // Variable/constant/parameter has an implicitly inferred static type. UNSAFE_PROPERTY_ACCESS, // Property not found in the detected type (but can be in subtypes). UNSAFE_METHOD_ACCESS, // Function not found in the detected type (but can be in subtypes). UNSAFE_CAST, // Cast used in an unknown type. @@ -113,6 +114,7 @@ public: WARN, // CONSTANT_USED_AS_FUNCTION WARN, // FUNCTION_USED_AS_PROPERTY IGNORE, // UNTYPED_DECLARATION // Static typing is optional, we don't want to spam warnings. + IGNORE, // INFERRED_DECLARATION // Static typing is optional, we don't want to spam warnings. IGNORE, // UNSAFE_PROPERTY_ACCESS // Too common in untyped scenarios. IGNORE, // UNSAFE_METHOD_ACCESS // Too common in untyped scenarios. IGNORE, // UNSAFE_CAST // Too common in untyped scenarios. diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp index 01772a2e38f..f91dc83f2cc 100644 --- a/modules/gdscript/tests/gdscript_test_runner.cpp +++ b/modules/gdscript/tests/gdscript_test_runner.cpp @@ -149,7 +149,7 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l // Set all warning levels to "Warn" in order to test them properly, even the ones that default to error. ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true); for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { - if (i == GDScriptWarning::UNTYPED_DECLARATION) { + if (i == GDScriptWarning::UNTYPED_DECLARATION || i == GDScriptWarning::INFERRED_DECLARATION) { // TODO: Add ability for test scripts to specify which warnings to enable/disable for testing. continue; }