1
0
mirror of https://github.com/godotengine/godot.git synced 2025-11-21 14:57:09 +00:00

GDScript: Add debug/gdscript/warnings/directory_rules project setting

This commit is contained in:
Danil Alexeev
2025-11-01 16:08:07 +03:00
parent 8327dfa215
commit 1bd7b99182
10 changed files with 222 additions and 96 deletions

View File

@@ -530,151 +530,154 @@
If the [code]--log-file <file>[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url] is used, log rotation is always disabled. If the [code]--log-file <file>[/code] [url=$DOCS_URL/tutorials/editor/command_line_tutorial.html]command line argument[/url] is used, log rotation is always disabled.
</member> </member>
<member name="debug/gdscript/warnings/assert_always_false" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/assert_always_false" 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 [code]false[/code]. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to [code]false[/code].
</member> </member>
<member name="debug/gdscript/warnings/assert_always_true" type="int" setter="" getter="" default="1"> <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 [code]true[/code]. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when an [code]assert[/code] call always evaluates to [code]true[/code].
</member> </member>
<member name="debug/gdscript/warnings/confusable_capture_reassignment" type="int" setter="" getter="" default="1"> <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. When set to [b]Warn[/b] or [b]Error[/b], 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>
<member name="debug/gdscript/warnings/confusable_identifier" type="int" setter="" getter="" default="1"> <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. When set to [b]Warn[/b] or [b]Error[/b], 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> </member>
<member name="debug/gdscript/warnings/confusable_local_declaration" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/confusable_local_declaration" 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 declared in the nested block has the same name as an identifier declared below in the parent block. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when an identifier declared in the nested block has the same name as an identifier declared below in the parent block.
</member> </member>
<member name="debug/gdscript/warnings/confusable_local_usage" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/confusable_local_usage" 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 that will be shadowed below in the block is used. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when an identifier that will be shadowed below in the block is used.
</member> </member>
<member name="debug/gdscript/warnings/deprecated_keyword" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/deprecated_keyword" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when deprecated keywords are used. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when deprecated keywords are used.
[b]Note:[/b] There are currently no deprecated keywords, so this warning is never produced. [b]Note:[/b] There are currently no deprecated keywords, so this warning is never produced.
</member> </member>
<member name="debug/gdscript/warnings/directory_rules" type="Dictionary" setter="" getter="" default="{ &quot;res://addons&quot;: 0 }">
The rules for including or excluding scripts when generating warnings, as a dictionary. Each rule is an entry consisting of a directory path (key) and a decision (value). When trying to generate a warning, the GDScript parser chooses the most specific rule, i.e. the most nested directory containing the script. If the decision is [b]Exclude[/b], warnings are not generated for this script. If the decision is [b]Include[/b] or the script doesn't satisfy any of the rules, the warning configuration specified in the Project Settings is applied.
It is recommended to include your own addons/libraries, either project-specific or actively being developed at the moment. Third-party or project-agnostic addons/libraries should be excluded, as they may be incompatible with the project's warning configuration.
[b]Note:[/b] It is not recommended to remove or change the rule for [code]"res://addons"[/code] as the project's warning configuration may break third-party addons. Instead, consider including individual addons, if necessary.
[b]Note:[/b] The editor does not check whether the specified paths are existing directories. It also does not automatically update these paths when directories are moved.
</member>
<member name="debug/gdscript/warnings/empty_file" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/empty_file" 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 empty file is parsed. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when an empty file is parsed.
</member> </member>
<member name="debug/gdscript/warnings/enable" type="bool" setter="" getter="" default="true"> <member name="debug/gdscript/warnings/enable" type="bool" setter="" getter="" default="true">
If [code]true[/code], enables specific GDScript warnings (see [code]debug/gdscript/warnings/*[/code] settings). If [code]false[/code], disables all GDScript warnings. If [code]true[/code], enables specific GDScript warnings (see [code]debug/gdscript/warnings/*[/code] settings). If [code]false[/code], disables all GDScript warnings.
</member> </member>
<member name="debug/gdscript/warnings/enum_variable_without_default" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/enum_variable_without_default" 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 variable has an enum type but no explicit default value, but only if the enum does not contain [code]0[/code] as a valid value. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a variable has an enum type but no explicit default value, but only if the enum does not contain [code]0[/code] as a valid value.
</member>
<member name="debug/gdscript/warnings/exclude_addons" type="bool" setter="" getter="" default="true">
If [code]true[/code], scripts in the [code]res://addons[/code] folder will not generate warnings.
</member> </member>
<member name="debug/gdscript/warnings/get_node_default_without_onready" type="int" setter="" getter="" default="2"> <member name="debug/gdscript/warnings/get_node_default_without_onready" type="int" setter="" getter="" default="2">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when [method Node.get_node] (or the shorthand [code]$[/code]) is used as default value of a class variable without the [code]@onready[/code] annotation. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when [method Node.get_node] (or the shorthand [code]$[/code]) is used as default value of a class variable without the [code]@onready[/code] annotation.
</member> </member>
<member name="debug/gdscript/warnings/incompatible_ternary" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/incompatible_ternary" 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 ternary operator may emit values with incompatible types. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a ternary operator may emit values with incompatible types.
</member> </member>
<member name="debug/gdscript/warnings/inference_on_variant" type="int" setter="" getter="" default="2"> <member name="debug/gdscript/warnings/inference_on_variant" type="int" setter="" getter="" default="2">
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 [b]Warn[/b] or [b]Error[/b], 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.
</member> </member>
<member name="debug/gdscript/warnings/inferred_declaration" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/inferred_declaration" type="int" setter="" getter="" default="0">
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. In GDScript, type inference is performed by declaring a variable with [code]:=[/code] instead of [code]=[/code] and leaving out the type specifier. For example, [code]var x := 1[/code] will [i]infer[/i] the [int] type, while [code]var x: int = 1[/code] explicitly declares the variable as [int]. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a variable, constant, or parameter has an implicitly inferred static type. In GDScript, type inference is performed by declaring a variable with [code]:=[/code] instead of [code]=[/code] and leaving out the type specifier. For example, [code]var x := 1[/code] will [i]infer[/i] the [int] type, while [code]var x: int = 1[/code] explicitly declares the variable as [int].
[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. [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.
</member> </member>
<member name="debug/gdscript/warnings/int_as_enum_without_cast" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/int_as_enum_without_cast" type="int" setter="" getter="" default="1">
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. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when trying to use an integer as an enum without an explicit cast.
</member> </member>
<member name="debug/gdscript/warnings/int_as_enum_without_match" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/int_as_enum_without_match" type="int" setter="" getter="" default="1">
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 when there is no matching enum member for that numeric value. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when trying to use an integer as an enum when there is no matching enum member for that numeric value.
</member> </member>
<member name="debug/gdscript/warnings/integer_division" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/integer_division" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when dividing an integer by another integer (the decimal part will be discarded). When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when dividing an integer by another integer (the decimal part will be discarded).
</member> </member>
<member name="debug/gdscript/warnings/missing_await" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/missing_await" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a coroutine without [code]await[/code]. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when calling a coroutine without [code]await[/code].
</member> </member>
<member name="debug/gdscript/warnings/missing_tool" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/missing_tool" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the base class script has the [code]@tool[/code] annotation, but the current class script does not have it. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when the base class script has the [code]@tool[/code] annotation, but the current class script does not have it.
</member> </member>
<member name="debug/gdscript/warnings/narrowing_conversion" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/narrowing_conversion" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when passing a floating-point value to a function that expects an integer (it will be converted and lose precision). When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when passing a floating-point value to a function that expects an integer (it will be converted and lose precision).
</member> </member>
<member name="debug/gdscript/warnings/native_method_override" type="int" setter="" getter="" default="2"> <member name="debug/gdscript/warnings/native_method_override" type="int" setter="" getter="" default="2">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a method in the script overrides a native method, because it may not behave as expected. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a method in the script overrides a native method, because it may not behave as expected.
</member> </member>
<member name="debug/gdscript/warnings/onready_with_export" type="int" setter="" getter="" default="2"> <member name="debug/gdscript/warnings/onready_with_export" type="int" setter="" getter="" default="2">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the [code]@onready[/code] annotation is used together with the [code]@export[/code] annotation, since it may not behave as expected. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when the [code]@onready[/code] annotation is used together with the [code]@export[/code] annotation, since it may not behave as expected.
</member> </member>
<member name="debug/gdscript/warnings/redundant_await" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/redundant_await" 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 function that is not a coroutine is called with await. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a function that is not a coroutine is called with await.
</member> </member>
<member name="debug/gdscript/warnings/redundant_static_unload" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/redundant_static_unload" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when the [code]@static_unload[/code] annotation is used in a script without any static variables. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when the [code]@static_unload[/code] annotation is used in a script without any static variables.
</member> </member>
<member name="debug/gdscript/warnings/renamed_in_godot_4_hint" type="bool" setter="" getter="" default="true"> <member name="debug/gdscript/warnings/renamed_in_godot_4_hint" type="bool" setter="" getter="" default="true">
When enabled, using a property, enum, or function that was renamed since Godot 3 will produce a hint if an error occurs. When enabled, using a property, enum, or function that was renamed since Godot 3 will produce a hint if an error occurs.
</member> </member>
<member name="debug/gdscript/warnings/return_value_discarded" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/return_value_discarded" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a function without using its return value (by assigning it to a variable or using it as a function argument). These return values are sometimes used to indicate possible errors using the [enum Error] enum. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when calling a function without using its return value (by assigning it to a variable or using it as a function argument). These return values are sometimes used to indicate possible errors using the [enum Error] enum.
</member> </member>
<member name="debug/gdscript/warnings/shadowed_global_identifier" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/shadowed_global_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 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 [b]Warn[/b] or [b]Error[/b], 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 a local variable or local constant shadows a member declared in the current class. When set to [b]Warn[/b] or [b]Error[/b], 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 a local variable or local constant shadows a member declared in a base class. When set to [b]Warn[/b] or [b]Error[/b], 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 [b]Warn[/b] or [b]Error[/b], 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.
</member> </member>
<member name="debug/gdscript/warnings/standalone_ternary" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/standalone_ternary" 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 a ternary expression that may have no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when calling a ternary expression that may have no effect on the surrounding code, such as writing [code]42 if active else 0[/code] as a statement.
</member> </member>
<member name="debug/gdscript/warnings/static_called_on_instance" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/static_called_on_instance" 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 a static method from an instance of a class instead of from the class directly. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when calling a static method from an instance of a class instead of from the class directly.
</member> </member>
<member name="debug/gdscript/warnings/unassigned_variable" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unassigned_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 using a variable that wasn't previously assigned. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when using a variable that wasn't previously assigned.
</member> </member>
<member name="debug/gdscript/warnings/unassigned_variable_op_assign" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unassigned_variable_op_assign" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when assigning a variable using an assignment operator like [code]+=[/code] if the variable wasn't previously assigned. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when assigning a variable using an assignment operator like [code]+=[/code] if the variable wasn't previously assigned.
</member> </member>
<member name="debug/gdscript/warnings/unreachable_code" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unreachable_code" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when unreachable code is detected (such as after a [code]return[/code] statement that will always be executed). When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when unreachable code is detected (such as after a [code]return[/code] statement that will always be executed).
</member> </member>
<member name="debug/gdscript/warnings/unreachable_pattern" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unreachable_pattern" 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 unreachable [code]match[/code] pattern is detected. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when an unreachable [code]match[/code] pattern is detected.
</member> </member>
<member name="debug/gdscript/warnings/unsafe_call_argument" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/unsafe_call_argument" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when using an expression whose type may not be compatible with the function parameter expected. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when using an expression whose type may not be compatible with the function parameter expected.
</member> </member>
<member name="debug/gdscript/warnings/unsafe_cast" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/unsafe_cast" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a [Variant] value is cast to a non-Variant. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a [Variant] value is cast to a non-Variant.
</member> </member>
<member name="debug/gdscript/warnings/unsafe_method_access" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/unsafe_method_access" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when calling a method whose presence is not guaranteed at compile-time in the class. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when calling a method whose presence is not guaranteed at compile-time in the class.
</member> </member>
<member name="debug/gdscript/warnings/unsafe_property_access" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/unsafe_property_access" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when accessing a property whose presence is not guaranteed at compile-time in the class. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when accessing a property whose presence is not guaranteed at compile-time in the class.
</member> </member>
<member name="debug/gdscript/warnings/unsafe_void_return" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unsafe_void_return" type="int" setter="" getter="" default="1">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when returning a call from a [code]void[/code] function when such call cannot be guaranteed to be also [code]void[/code]. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when returning a call from a [code]void[/code] function when such call cannot be guaranteed to be also [code]void[/code].
</member> </member>
<member name="debug/gdscript/warnings/untyped_declaration" type="int" setter="" getter="" default="0"> <member name="debug/gdscript/warnings/untyped_declaration" type="int" setter="" getter="" default="0">
When set to [code]warn[/code] or [code]error[/code], produces a warning or an error respectively when a variable or parameter has no static type, or if a function has no static return type. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a variable or parameter has no static type, or if a function has no static return type.
[b]Note:[/b] This warning is recommended together with [member EditorSettings.text_editor/completion/add_type_hints] to help achieve type safety. [b]Note:[/b] This warning is recommended together with [member EditorSettings.text_editor/completion/add_type_hints] to help achieve type safety.
</member> </member>
<member name="debug/gdscript/warnings/unused_local_constant" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unused_local_constant" 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 constant is never used. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a local constant is never used.
</member> </member>
<member name="debug/gdscript/warnings/unused_parameter" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unused_parameter" 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 function parameter is never used. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a function parameter is never used.
</member> </member>
<member name="debug/gdscript/warnings/unused_private_class_variable" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unused_private_class_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 a private member variable is never used. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a private member variable is never used.
</member> </member>
<member name="debug/gdscript/warnings/unused_signal" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unused_signal" 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 signal is declared but never explicitly used in the class. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a signal is declared but never explicitly used in the class.
</member> </member>
<member name="debug/gdscript/warnings/unused_variable" type="int" setter="" getter="" default="1"> <member name="debug/gdscript/warnings/unused_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 a local variable is unused. When set to [b]Warn[/b] or [b]Error[/b], produces a warning or an error respectively when a local variable is unused.
</member> </member>
<member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default="&quot;Please include this when reporting the bug to the project developer.&quot;"> <member name="debug/settings/crash_handler/message" type="String" setter="" getter="" default="&quot;Please include this when reporting the bug to the project developer.&quot;">
Message to be displayed before the backtrace when the engine crashes. By default, this message is only used in exported projects due to the editor-only override applied to this setting. Message to be displayed before the backtrace when the engine crashes. By default, this message is only used in exported projects due to the editor-only override applied to this setting.

View File

@@ -131,6 +131,9 @@ void PluginConfigDialog::_on_required_text_changed() {
if ((!script_edit->get_text().get_extension().is_empty() && script_edit->get_text().get_extension() != ext) || script_edit->get_text().ends_with(".")) { if ((!script_edit->get_text().get_extension().is_empty() && script_edit->get_text().get_extension() != ext) || script_edit->get_text().ends_with(".")) {
validation_panel->set_message(MSG_ID_SCRIPT, vformat(TTR("Script extension must match chosen language extension (.%s)."), ext), EditorValidationPanel::MSG_ERROR); validation_panel->set_message(MSG_ID_SCRIPT, vformat(TTR("Script extension must match chosen language extension (.%s)."), ext), EditorValidationPanel::MSG_ERROR);
} }
if (language->get_name() == "GDScript") {
validation_panel->set_message(MSG_ID_ENABLE_WARNINGS, TTR("Consider enabling GDScript warnings for this plugin by adding an entry for it to the project setting Debug > GDScript > Warnings > Directory Rules."), EditorValidationPanel::MSG_INFO);
}
} }
String PluginConfigDialog::_get_subfolder() { String PluginConfigDialog::_get_subfolder() {
@@ -317,6 +320,7 @@ PluginConfigDialog::PluginConfigDialog() {
validation_panel->add_line(MSG_ID_SCRIPT, TTR("Script extension is valid.")); validation_panel->add_line(MSG_ID_SCRIPT, TTR("Script extension is valid."));
validation_panel->add_line(MSG_ID_SUBFOLDER, TTR("Subfolder name is valid.")); validation_panel->add_line(MSG_ID_SUBFOLDER, TTR("Subfolder name is valid."));
validation_panel->add_line(MSG_ID_ACTIVE, ""); validation_panel->add_line(MSG_ID_ACTIVE, "");
validation_panel->add_line(MSG_ID_ENABLE_WARNINGS, "");
validation_panel->set_update_callback(callable_mp(this, &PluginConfigDialog::_on_required_text_changed)); validation_panel->set_update_callback(callable_mp(this, &PluginConfigDialog::_on_required_text_changed));
validation_panel->set_accept_button(get_ok_button()); validation_panel->set_accept_button(get_ok_button());

View File

@@ -47,6 +47,7 @@ class PluginConfigDialog : public ConfirmationDialog {
MSG_ID_SUBFOLDER, MSG_ID_SUBFOLDER,
MSG_ID_SCRIPT, MSG_ID_SCRIPT,
MSG_ID_ACTIVE, MSG_ID_ACTIVE,
MSG_ID_ENABLE_WARNINGS,
}; };
LineEdit *name_edit = nullptr; LineEdit *name_edit = nullptr;

View File

@@ -2282,11 +2282,18 @@ void GDScriptLanguage::init() {
GDExtensionManager::get_singleton()->connect("extension_loaded", callable_mp(this, &GDScriptLanguage::_extension_loaded)); GDExtensionManager::get_singleton()->connect("extension_loaded", callable_mp(this, &GDScriptLanguage::_extension_loaded));
GDExtensionManager::get_singleton()->connect("extension_unloading", callable_mp(this, &GDScriptLanguage::_extension_unloading)); GDExtensionManager::get_singleton()->connect("extension_unloading", callable_mp(this, &GDScriptLanguage::_extension_unloading));
} }
#endif #endif // TOOLS_ENABLED
#ifdef DEBUG_ENABLED
GDScriptParser::update_project_settings();
if (!ProjectSettings::get_singleton()->is_connected("settings_changed", callable_mp_static(&GDScriptParser::update_project_settings))) {
ProjectSettings::get_singleton()->connect("settings_changed", callable_mp_static(&GDScriptParser::update_project_settings));
}
#endif // DEBUG_ENABLED
#ifdef TESTS_ENABLED #ifdef TESTS_ENABLED
GDScriptTests::GDScriptTestRunner::handle_cmdline(); GDScriptTests::GDScriptTestRunner::handle_cmdline();
#endif #endif // TESTS_ENABLED
} }
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
@@ -2950,7 +2957,7 @@ GDScriptLanguage::GDScriptLanguage() {
profiling = false; profiling = false;
profile_native_calls = false; profile_native_calls = false;
script_frame_time = 0; script_frame_time = 0;
#endif #endif // DEBUG_ENABLED
_debug_max_call_stack = GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "512," + itos(GDScriptFunction::MAX_CALL_DEPTH - 1) + ",1"), 1024); _debug_max_call_stack = GLOBAL_DEF_RST(PropertyInfo(Variant::INT, "debug/settings/gdscript/max_call_stack", PROPERTY_HINT_RANGE, "512," + itos(GDScriptFunction::MAX_CALL_DEPTH - 1) + ",1"), 1024);
track_call_stack = GLOBAL_DEF_RST("debug/settings/gdscript/always_track_call_stacks", false); track_call_stack = GLOBAL_DEF_RST("debug/settings/gdscript/always_track_call_stacks", false);
@@ -2961,20 +2968,29 @@ GDScriptLanguage::GDScriptLanguage() {
track_locals = track_locals || EngineDebugger::is_active(); track_locals = track_locals || EngineDebugger::is_active();
GLOBAL_DEF("debug/gdscript/warnings/enable", true); GLOBAL_DEF("debug/gdscript/warnings/enable", true);
GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true);
GLOBAL_DEF("debug/gdscript/warnings/renamed_in_godot_4_hint", true); GLOBAL_DEF(PropertyInfo(Variant::DICTIONARY,
"debug/gdscript/warnings/directory_rules",
PROPERTY_HINT_TYPE_STRING,
vformat("%d/%d:;%d/%d:Exclude,Include", Variant::STRING, PROPERTY_HINT_DIR, Variant::INT, PROPERTY_HINT_ENUM)),
Dictionary({ { "res://addons", GDScriptParser::WarningDirectoryRule::DECISION_EXCLUDE } }));
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) { for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
GDScriptWarning::Code code = (GDScriptWarning::Code)i; const GDScriptWarning::Code code = (GDScriptWarning::Code)i;
Variant default_enabled = GDScriptWarning::get_default_value(code); const Variant default_value = GDScriptWarning::get_default_value(code);
String path = GDScriptWarning::get_settings_path_from_code(code); GLOBAL_DEF(GDScriptWarning::get_property_info(code), default_value);
GLOBAL_DEF(GDScriptWarning::get_property_info(code), default_enabled);
}
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
ProjectSettings::get_singleton()->set_as_internal("debug/gdscript/warnings/property_used_as_function", true); if (i >= GDScriptWarning::FIRST_DEPRECATED_WARNING) {
ProjectSettings::get_singleton()->set_as_internal("debug/gdscript/warnings/constant_used_as_function", true); const String setting_path = GDScriptWarning::get_setting_path_from_code(code);
ProjectSettings::get_singleton()->set_as_internal("debug/gdscript/warnings/function_used_as_property", true); ProjectSettings::get_singleton()->set_as_internal(setting_path, true);
#endif }
#endif // DISABLE_DEPRECATED
}
// TODO: This setting has nothing to do with warnings. It should be moved at the next compatibility breakage,
// if the setting is still relevant at that time.
GLOBAL_DEF("debug/gdscript/warnings/renamed_in_godot_4_hint", true);
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
} }

View File

@@ -1010,7 +1010,7 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
if (warning_code >= GDScriptWarning::FIRST_DEPRECATED_WARNING) { if (warning_code >= GDScriptWarning::FIRST_DEPRECATED_WARNING) {
break; // Don't suggest deprecated warnings as they are never produced. break; // Don't suggest deprecated warnings as they are never produced.
} }
#endif #endif // DISABLE_DEPRECATED
ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT); ScriptLanguage::CodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptLanguage::CODE_COMPLETION_KIND_PLAIN_TEXT);
warning.insert_text = warning.display.quote(p_quote_style); warning.insert_text = warning.display.quote(p_quote_style);
r_result.insert(warning.display, warning); r_result.insert(warning.display, warning);

View File

@@ -68,9 +68,15 @@ Variant::Type GDScriptParser::get_builtin_type(const StringName &p_type) {
return Variant::VARIANT_MAX; return Variant::VARIANT_MAX;
} }
#ifdef DEBUG_ENABLED
bool GDScriptParser::is_project_ignoring_warnings = false;
GDScriptWarning::WarnLevel GDScriptParser::warning_levels[GDScriptWarning::WARNING_MAX];
LocalVector<GDScriptParser::WarningDirectoryRule> GDScriptParser::warning_directory_rules;
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
HashMap<String, String> GDScriptParser::theme_color_names; HashMap<String, String> GDScriptParser::theme_color_names;
#endif #endif // TOOLS_ENABLED
HashMap<StringName, GDScriptParser::AnnotationInfo> GDScriptParser::valid_annotations; HashMap<StringName, GDScriptParser::AnnotationInfo> GDScriptParser::valid_annotations;
@@ -89,6 +95,53 @@ bool GDScriptParser::annotation_exists(const String &p_annotation_name) const {
return valid_annotations.has(p_annotation_name); return valid_annotations.has(p_annotation_name);
} }
#ifdef DEBUG_ENABLED
void GDScriptParser::update_project_settings() {
is_project_ignoring_warnings = !GLOBAL_GET("debug/gdscript/warnings/enable").booleanize();
for (int i = 0; i < GDScriptWarning::WARNING_MAX; i++) {
const String setting_path = GDScriptWarning::get_setting_path_from_code((GDScriptWarning::Code)i);
warning_levels[i] = (GDScriptWarning::WarnLevel)(int)GLOBAL_GET(setting_path);
}
#ifndef DISABLE_DEPRECATED
// We do not use `GLOBAL_GET`, since we check without taking overrides into account. We leave the migration of non-trivial configurations to the user.
if (unlikely(ProjectSettings::get_singleton()->has_setting("debug/gdscript/warnings/exclude_addons"))) {
const bool is_excluding_addons = ProjectSettings::get_singleton()->get_setting("debug/gdscript/warnings/exclude_addons", true).booleanize();
ProjectSettings::get_singleton()->clear("debug/gdscript/warnings/exclude_addons");
Dictionary rules = ProjectSettings::get_singleton()->get_setting("debug/gdscript/warnings/directory_rules");
rules["res://addons"] = is_excluding_addons ? WarningDirectoryRule::DECISION_EXCLUDE : WarningDirectoryRule::DECISION_INCLUDE;
ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/directory_rules", rules);
}
#endif // DISABLE_DEPRECATED
warning_directory_rules.clear();
const Dictionary rules = GLOBAL_GET("debug/gdscript/warnings/directory_rules");
for (const KeyValue<Variant, Variant> &kv : rules) {
String dir = kv.key.operator String().simplify_path();
ERR_CONTINUE_MSG(!dir.begins_with("res://"), R"(Paths in the project setting "debug/gdscript/warnings/directory_rules" keys must start with the "res://" prefix.)");
if (!dir.ends_with("/")) {
dir += '/';
}
const int decision = kv.value;
ERR_CONTINUE(decision < 0 || decision >= WarningDirectoryRule::DECISION_MAX);
warning_directory_rules.push_back({ dir, (WarningDirectoryRule::Decision)decision });
}
struct RuleSort {
bool operator()(const WarningDirectoryRule &p_a, const WarningDirectoryRule &p_b) const {
return p_a.directory_path.count("/") > p_b.directory_path.count("/");
}
};
warning_directory_rules.sort_custom<RuleSort>();
}
#endif // DEBUG_ENABLED
GDScriptParser::GDScriptParser() { GDScriptParser::GDScriptParser() {
// Register valid annotations. // Register valid annotations.
if (unlikely(valid_annotations.is_empty())) { if (unlikely(valid_annotations.is_empty())) {
@@ -137,11 +190,10 @@ GDScriptParser::GDScriptParser() {
} }
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
is_ignoring_warnings = !(bool)GLOBAL_GET("debug/gdscript/warnings/enable");
for (int i = 0; i < GDScriptWarning::WARNING_MAX; i++) { for (int i = 0; i < GDScriptWarning::WARNING_MAX; i++) {
warning_ignore_start_lines[i] = INT_MAX; warning_ignore_start_lines[i] = INT_MAX;
} }
#endif #endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
if (unlikely(theme_color_names.is_empty())) { if (unlikely(theme_color_names.is_empty())) {
@@ -161,7 +213,7 @@ GDScriptParser::GDScriptParser() {
theme_color_names.insert("a", "axis_w_color"); theme_color_names.insert("a", "axis_w_color");
theme_color_names.insert("a8", "axis_w_color"); theme_color_names.insert("a8", "axis_w_color");
} }
#endif #endif // TOOLS_ENABLED
} }
GDScriptParser::~GDScriptParser() { GDScriptParser::~GDScriptParser() {
@@ -195,13 +247,11 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
ERR_FAIL_NULL(p_source); ERR_FAIL_NULL(p_source);
ERR_FAIL_INDEX(p_code, GDScriptWarning::WARNING_MAX); ERR_FAIL_INDEX(p_code, GDScriptWarning::WARNING_MAX);
if (is_ignoring_warnings) { if (is_project_ignoring_warnings || is_script_ignoring_warnings) {
return; return;
} }
if (GLOBAL_GET_CACHED(bool, "debug/gdscript/warnings/exclude_addons") && script_path.begins_with("res://addons/")) {
return; const GDScriptWarning::WarnLevel warn_level = warning_levels[p_code];
}
GDScriptWarning::WarnLevel warn_level = (GDScriptWarning::WarnLevel)(int)GLOBAL_GET(GDScriptWarning::get_settings_path_from_code(p_code));
if (warn_level == GDScriptWarning::IGNORE) { if (warn_level == GDScriptWarning::IGNORE) {
return; return;
} }
@@ -251,6 +301,24 @@ void GDScriptParser::apply_pending_warnings() {
pending_warnings.clear(); pending_warnings.clear();
} }
void GDScriptParser::evaluate_warning_directory_rules_for_script_path() {
is_script_ignoring_warnings = false;
for (const WarningDirectoryRule &rule : warning_directory_rules) {
if (script_path.begins_with(rule.directory_path)) {
switch (rule.decision) {
case WarningDirectoryRule::DECISION_EXCLUDE:
is_script_ignoring_warnings = true;
return; // Stop checking rules.
case WarningDirectoryRule::DECISION_INCLUDE:
is_script_ignoring_warnings = false;
return; // Stop checking rules.
case WarningDirectoryRule::DECISION_MAX:
return; // Unreachable.
}
}
}
}
#endif // DEBUG_ENABLED #endif // DEBUG_ENABLED
void GDScriptParser::override_completion_context(const Node *p_for_node, CompletionType p_type, Node *p_node, int p_argument) { void GDScriptParser::override_completion_context(const Node *p_for_node, CompletionType p_type, Node *p_node, int p_argument) {
@@ -391,9 +459,14 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
text_tokenizer->set_source_code(source); text_tokenizer->set_source_code(source);
tokenizer = text_tokenizer; tokenizer = text_tokenizer;
tokenizer->set_cursor_position(cursor_line, cursor_column); tokenizer->set_cursor_position(cursor_line, cursor_column);
script_path = p_script_path.simplify_path(); script_path = p_script_path.simplify_path();
#ifdef DEBUG_ENABLED
evaluate_warning_directory_rules_for_script_path();
#endif // DEBUG_ENABLED
current = tokenizer->scan(); current = tokenizer->scan();
// Avoid error or newline as the first token. // Avoid error or newline as the first token.
// The latter can mess with the parser when opening files filled exclusively with comments and newlines. // The latter can mess with the parser when opening files filled exclusively with comments and newlines.
@@ -414,7 +487,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
nd->end_line = 1; nd->end_line = 1;
push_warning(nd, GDScriptWarning::EMPTY_FILE); push_warning(nd, GDScriptWarning::EMPTY_FILE);
} }
#endif #endif // DEBUG_ENABLED
push_multiline(false); // Keep one for the whole parsing. push_multiline(false); // Keep one for the whole parsing.
parse_program(); parse_program();
@@ -422,7 +495,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
comment_data = tokenizer->get_comments(); comment_data = tokenizer->get_comments();
#endif #endif // TOOLS_ENABLED
memdelete(text_tokenizer); memdelete(text_tokenizer);
tokenizer = nullptr; tokenizer = nullptr;
@@ -431,7 +504,7 @@ Error GDScriptParser::parse(const String &p_source_code, const String &p_script_
if (multiline_stack.size() > 0) { if (multiline_stack.size() > 0) {
ERR_PRINT("Parser bug: Imbalanced multiline stack."); ERR_PRINT("Parser bug: Imbalanced multiline stack.");
} }
#endif #endif // DEBUG_ENABLED
if (errors.is_empty()) { if (errors.is_empty()) {
return OK; return OK;
@@ -450,7 +523,13 @@ Error GDScriptParser::parse_binary(const Vector<uint8_t> &p_binary, const String
} }
tokenizer = buffer_tokenizer; tokenizer = buffer_tokenizer;
script_path = p_script_path.simplify_path(); script_path = p_script_path.simplify_path();
#ifdef DEBUG_ENABLED
evaluate_warning_directory_rules_for_script_path();
#endif // DEBUG_ENABLED
current = tokenizer->scan(); current = tokenizer->scan();
// Avoid error or newline as the first token. // Avoid error or newline as the first token.
// The latter can mess with the parser when opening files filled exclusively with comments and newlines. // The latter can mess with the parser when opening files filled exclusively with comments and newlines.
@@ -4997,10 +5076,6 @@ bool GDScriptParser::export_group_annotations(AnnotationNode *p_annotation, Node
bool GDScriptParser::warning_ignore_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) { bool GDScriptParser::warning_ignore_annotation(AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
if (is_ignoring_warnings) {
return true; // We already ignore all warnings, let's optimize it.
}
bool has_error = false; bool has_error = false;
for (const Variant &warning_name : p_annotation->resolved_arguments) { for (const Variant &warning_name : p_annotation->resolved_arguments) {
GDScriptWarning::Code warning_code = GDScriptWarning::get_code_from_name(String(warning_name).to_upper()); GDScriptWarning::Code warning_code = GDScriptWarning::get_code_from_name(String(warning_name).to_upper());

View File

@@ -1349,6 +1349,19 @@ private:
List<ParserError> errors; List<ParserError> errors;
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
public:
struct WarningDirectoryRule {
enum Decision {
DECISION_EXCLUDE,
DECISION_INCLUDE,
DECISION_MAX,
};
String directory_path; // With a trailing slash.
Decision decision = DECISION_EXCLUDE;
};
private:
struct PendingWarning { struct PendingWarning {
const Node *source = nullptr; const Node *source = nullptr;
GDScriptWarning::Code code = GDScriptWarning::WARNING_MAX; GDScriptWarning::Code code = GDScriptWarning::WARNING_MAX;
@@ -1356,13 +1369,17 @@ private:
Vector<String> symbols; Vector<String> symbols;
}; };
bool is_ignoring_warnings = false; static bool is_project_ignoring_warnings;
static GDScriptWarning::WarnLevel warning_levels[GDScriptWarning::WARNING_MAX];
static LocalVector<WarningDirectoryRule> warning_directory_rules;
List<GDScriptWarning> warnings; List<GDScriptWarning> warnings;
List<PendingWarning> pending_warnings; List<PendingWarning> pending_warnings;
bool is_script_ignoring_warnings = false;
HashSet<int> warning_ignored_lines[GDScriptWarning::WARNING_MAX]; HashSet<int> warning_ignored_lines[GDScriptWarning::WARNING_MAX];
int warning_ignore_start_lines[GDScriptWarning::WARNING_MAX]; int warning_ignore_start_lines[GDScriptWarning::WARNING_MAX];
HashSet<int> unsafe_lines; HashSet<int> unsafe_lines;
#endif #endif // DEBUG_ENABLED
GDScriptTokenizer *tokenizer = nullptr; GDScriptTokenizer *tokenizer = nullptr;
GDScriptTokenizer::Token previous; GDScriptTokenizer::Token previous;
@@ -1473,6 +1490,7 @@ private:
} }
void clear(); void clear();
void push_error(const String &p_message, const Node *p_origin = nullptr); void push_error(const String &p_message, const Node *p_origin = nullptr);
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols); void push_warning(const Node *p_source, GDScriptWarning::Code p_code, const Vector<String> &p_symbols);
@@ -1481,7 +1499,9 @@ private:
push_warning(p_source, p_code, Vector<String>{ p_symbols... }); push_warning(p_source, p_code, Vector<String>{ p_symbols... });
} }
void apply_pending_warnings(); void apply_pending_warnings();
#endif void evaluate_warning_directory_rules_for_script_path();
#endif // DEBUG_ENABLED
// Setting p_force to false will prevent the completion context from being update if a context was already set before. // Setting p_force to false will prevent the completion context from being update if a context was already set before.
// This should only be done when we push context before we consumed any tokens for the corresponding structure. // This should only be done when we push context before we consumed any tokens for the corresponding structure.
// See parse_precedence for an example. // See parse_precedence for an example.
@@ -1615,11 +1635,13 @@ public:
// TODO: Keep track of deps. // TODO: Keep track of deps.
return List<String>(); return List<String>();
} }
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
static void update_project_settings();
const List<GDScriptWarning> &get_warnings() const { return warnings; } const List<GDScriptWarning> &get_warnings() const { return warnings; }
const HashSet<int> &get_unsafe_lines() const { return unsafe_lines; } const HashSet<int> &get_unsafe_lines() const { return unsafe_lines; }
int get_last_line_number() const { return current.end_line; } int get_last_line_number() const { return current.end_line; }
#endif #endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED #ifdef TOOLS_ENABLED
static HashMap<String, String> theme_color_names; static HashMap<String, String> theme_color_names;

View File

@@ -170,7 +170,7 @@ String GDScriptWarning::get_message() const {
case CONSTANT_USED_AS_FUNCTION: // There is already an error. case CONSTANT_USED_AS_FUNCTION: // There is already an error.
case FUNCTION_USED_AS_PROPERTY: // This is valid, returns `Callable`. case FUNCTION_USED_AS_PROPERTY: // This is valid, returns `Callable`.
break; break;
#endif #endif // DISABLE_DEPRECATED
case WARNING_MAX: case WARNING_MAX:
break; // Can't happen, but silences warning. break; // Can't happen, but silences warning.
} }
@@ -185,7 +185,7 @@ int GDScriptWarning::get_default_value(Code p_code) {
} }
PropertyInfo GDScriptWarning::get_property_info(Code p_code) { PropertyInfo GDScriptWarning::get_property_info(Code p_code) {
return PropertyInfo(Variant::INT, get_settings_path_from_code(p_code), PROPERTY_HINT_ENUM, "Ignore,Warn,Error"); return PropertyInfo(Variant::INT, get_setting_path_from_code(p_code), PROPERTY_HINT_ENUM, "Ignore,Warn,Error");
} }
String GDScriptWarning::get_name() const { String GDScriptWarning::get_name() const {
@@ -245,7 +245,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"PROPERTY_USED_AS_FUNCTION", "PROPERTY_USED_AS_FUNCTION",
"CONSTANT_USED_AS_FUNCTION", "CONSTANT_USED_AS_FUNCTION",
"FUNCTION_USED_AS_PROPERTY", "FUNCTION_USED_AS_PROPERTY",
#endif #endif // DISABLE_DEPRECATED
}; };
static_assert(std_size(names) == WARNING_MAX, "Amount of warning types don't match the amount of warning names."); static_assert(std_size(names) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
@@ -253,7 +253,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
return names[(int)p_code]; return names[(int)p_code];
} }
String GDScriptWarning::get_settings_path_from_code(Code p_code) { String GDScriptWarning::get_setting_path_from_code(Code p_code) {
return "debug/gdscript/warnings/" + get_name_from_code(p_code).to_lower(); return "debug/gdscript/warnings/" + get_name_from_code(p_code).to_lower();
} }

View File

@@ -94,13 +94,13 @@ public:
PROPERTY_USED_AS_FUNCTION, // Function not found, but there's a property with the same name. 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. 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. FUNCTION_USED_AS_PROPERTY, // Property not found, but there's a function with the same name.
#endif #endif // DISABLE_DEPRECATED
WARNING_MAX, WARNING_MAX,
}; };
#ifndef DISABLE_DEPRECATED #ifndef DISABLE_DEPRECATED
static constexpr int FIRST_DEPRECATED_WARNING = PROPERTY_USED_AS_FUNCTION; static constexpr int FIRST_DEPRECATED_WARNING = PROPERTY_USED_AS_FUNCTION;
#endif #endif // DISABLE_DEPRECATED
constexpr static WarnLevel default_warning_levels[] = { constexpr static WarnLevel default_warning_levels[] = {
WARN, // UNASSIGNED_VARIABLE WARN, // UNASSIGNED_VARIABLE
@@ -152,7 +152,7 @@ public:
WARN, // PROPERTY_USED_AS_FUNCTION WARN, // PROPERTY_USED_AS_FUNCTION
WARN, // CONSTANT_USED_AS_FUNCTION WARN, // CONSTANT_USED_AS_FUNCTION
WARN, // FUNCTION_USED_AS_PROPERTY WARN, // FUNCTION_USED_AS_PROPERTY
#endif #endif // DISABLE_DEPRECATED
}; };
static_assert(std_size(default_warning_levels) == WARNING_MAX, "Amount of default levels does not match the amount of warnings."); static_assert(std_size(default_warning_levels) == WARNING_MAX, "Amount of default levels does not match the amount of warnings.");
@@ -166,7 +166,7 @@ public:
static int get_default_value(Code p_code); static int get_default_value(Code p_code);
static PropertyInfo get_property_info(Code p_code); static PropertyInfo get_property_info(Code p_code);
static String get_name_from_code(Code p_code); static String get_name_from_code(Code p_code);
static String get_settings_path_from_code(Code p_code); static String get_setting_path_from_code(Code p_code);
static Code get_code_from_name(const String &p_name); static Code get_code_from_name(const String &p_name);
}; };

View File

@@ -145,6 +145,7 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l
if (do_init_languages) { if (do_init_languages) {
init_language(p_source_dir); init_language(p_source_dir);
} }
#ifdef DEBUG_ENABLED #ifdef DEBUG_ENABLED
// Set all warning levels to "Warn" in order to test them properly, even the ones that default to error. // 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); ProjectSettings::get_singleton()->set_setting("debug/gdscript/warnings/enable", true);
@@ -153,12 +154,16 @@ GDScriptTestRunner::GDScriptTestRunner(const String &p_source_dir, bool p_init_l
// TODO: Add ability for test scripts to specify which warnings to enable/disable for testing. // TODO: Add ability for test scripts to specify which warnings to enable/disable for testing.
continue; continue;
} }
String warning_setting = GDScriptWarning::get_settings_path_from_code((GDScriptWarning::Code)i); const String setting_path = GDScriptWarning::get_setting_path_from_code((GDScriptWarning::Code)i);
ProjectSettings::get_singleton()->set_setting(warning_setting, (int)GDScriptWarning::WARN); ProjectSettings::get_singleton()->set_setting(setting_path, (int)GDScriptWarning::WARN);
} }
#endif
// Enable printing to show results // Force the call, since the language is initialized **before** applying project settings
// and the `settings_changed` signal is emitted with `call_deferred()`.
GDScriptParser::update_project_settings();
#endif // DEBUG_ENABLED
// Enable printing to show results.
CoreGlobals::print_line_enabled = true; CoreGlobals::print_line_enabled = true;
CoreGlobals::print_error_enabled = true; CoreGlobals::print_error_enabled = true;
} }