-
-
Notifications
You must be signed in to change notification settings - Fork 3.7k
Add GDScript warning pages #10635
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
base: master
Are you sure you want to change the base?
Add GDScript warning pages #10635
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
|
|
@@ -16,4 +16,5 @@ GDScript | |
| gdscript_styleguide | ||
| static_typing | ||
| warning_system | ||
| warnings/index | ||
| gdscript_format_string | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,55 @@ | ||
| GET_NODE_DEFAULT_WITHOUT_ONREADY | ||
| ================================ | ||
|
|
||
| This warning appears when a node's property is initialized to a node in the scene tree | ||
| without using the ``@onready`` annotation. | ||
|
|
||
| Depending on how you attempt to access the scene tree, the warning message will | ||
| be one of the following: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| The default value uses "get_node()" which won't return nodes in the scene tree before "_ready()" is called. Use the "@onready" annotation to solve this. | ||
|
|
||
| The default value uses "$" which won't return nodes in the scene tree before "_ready()" is called. Use the "@onready" annotation to solve this. | ||
|
|
||
| The default value uses "%" which won't return nodes in the scene tree before "_ready()" is called. Use the "@onready" annotation to solve this. | ||
|
|
||
| The default warning level for this warning is **Error**. | ||
| To modify it, set :ref:`Project Settings > Debug > GDScript > Warnings > Get Node Default Without Onready<class_ProjectSettings_property_debug/gdscript/warnings/get_node_default_without_onready>`. | ||
|
|
||
| When this warning occurs | ||
| ------------------------ | ||
|
|
||
| This warning may appear when attempting to assign the default value of a property | ||
| to a node in the scene tree, like so: | ||
|
|
||
| .. code-block:: gdscript | ||
|
|
||
| extends Area2D | ||
|
|
||
| # Will give warning GET_NODE_DEFAULT_WITHOUT_ONREADY. | ||
|
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't think "give warning" is an established terminology? Where has this been used elsewhere?
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. From what I can see in the Godot Docs, there's not generally a lot of discussion of GDScript warnings. The verb "give" is used in at least one spot, Static typing in GDScript:
Later on the same page, "produce" is used:
In the dedicated page for the GDScript warning system, "trigger" is used:
So, overall it appears that "give", "produce", and "trigger" all have precedent in the docs currently.
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Produce seems to be the most common, but I think we can leave it as is
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Alright, I will leave it for now then 🙂 |
||
| var my_collision_shape = $CollisionShape2D | ||
|
|
||
| If you want a property to refer to another node in the scene tree, you may be inclined | ||
| to reference it using :ref:`get_node() <class_Node_method_get_node>` | ||
| (or the ``$`` and ``%`` shorthand versions) when setting its default value. | ||
|
|
||
| However, properties' default values are evaluated and assigned *before* nodes are added to the scene tree. | ||
| This means that when the script tries to assign that value, it won't be able to find the node it's looking for, | ||
| because it isn't a part of the scene tree containing that node yet. | ||
| As a result, the property will be set to ``null`` instead. | ||
|
|
||
| How to fix this warning | ||
| ----------------------- | ||
|
|
||
| Add the ``@onready`` annotation before your property declaration: | ||
|
|
||
| .. code-block:: gdscript | ||
|
|
||
| extends Area2D | ||
|
|
||
| @onready var my_collision_shape = $CollisionShape2D | ||
|
|
||
| Now, the default value of the property will not be assigned until the scene tree has been initialized, | ||
| at which time the node will be present. | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,27 @@ | ||
| :allow_comments: False | ||
|
|
||
| .. _doc_gdscript_warnings: | ||
|
|
||
| GDScript warnings | ||
| ================= | ||
|
|
||
| This is a collection of warnings that GDScript can emit, and information on how to fix the code that causes them. | ||
|
|
||
| .. note:: | ||
|
|
||
| The list of warnings is currently incomplete. We hope to add pages for more warnings over time, | ||
| so that each one can be thoroughly reviewed for correctness and clarity. | ||
|
|
||
| .. rubric:: Warnings | ||
| :heading-level: 2 | ||
|
|
||
| .. toctree:: | ||
| :maxdepth: 1 | ||
| :name: toc-gdscript-warnings | ||
|
|
||
| get_node_default_without_onready | ||
| integer_division | ||
| return_value_discarded | ||
| shadowed_variable | ||
| unassigned_variable | ||
| unused_variable |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,43 @@ | ||
| INTEGER_DIVISION | ||
| ================ | ||
|
|
||
| The warning message is: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| Integer division. Decimal part will be discarded. | ||
|
|
||
| The default warning level for this warning is **Warn**. | ||
| To modify it, set :ref:`Project Settings > Debug > GDScript > Warnings > Integer Division<class_ProjectSettings_property_debug/gdscript/warnings/integer_division>`. | ||
|
|
||
| When this warning occurs | ||
| ------------------------ | ||
|
|
||
| This warning may appear when attempting to divide two integers: | ||
|
|
||
| .. code-block:: | ||
|
|
||
| var result = 5 / 3 # Will give warning INTEGER_DIVISION. | ||
|
|
||
| Because both operands are integers, the result will be an integer as well. | ||
| Integers can't store fractional parts of numbers, so the result must be a whole number. | ||
| Godot discards anything after the decimal point in the mathematical result to obtain the integer result. | ||
| **Note that the number is not rounded to the nearest whole number.** | ||
|
|
||
|
|
||
| How to fix this warning | ||
|
Meorge marked this conversation as resolved.
|
||
| ----------------------- | ||
|
|
||
| Use a floating-point number (``float``) for at least one operand of the division operation: | ||
|
|
||
| .. code-block:: | ||
|
|
||
| var result = 5.0 / 3 | ||
|
|
||
| If the integers being divided are variables, cast them to ``float``: | ||
|
|
||
| .. code-block:: | ||
|
|
||
| var a: int = 5 | ||
| var b: int = 3 | ||
| var result = float(a) / float(b) | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,42 @@ | ||
| RETURN_VALUE_DISCARDED | ||
| ====================== | ||
|
|
||
| The warning message is: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| The function "get_number()" returns a value that will be discarded if not used. | ||
|
|
||
| The default warning level for this warning is **Ignore**. | ||
| To modify it, set :ref:`Project Settings > Debug > GDScript > Warnings > Return Value Discarded<class_ProjectSettings_property_debug/gdscript/warnings/return_value_discarded>`. | ||
|
|
||
| When this warning occurs | ||
| ------------------------ | ||
|
|
||
| This warning may appear if a method returns a value, but that value is not used | ||
| in an expression or assigned to a variable: | ||
|
|
||
| .. code-block:: | ||
|
|
||
| func _ready(): | ||
| print("About to get a number...") | ||
| get_number() # Will give warning RETURN_VALUE_DISCARDED. | ||
| print("Got a number!") | ||
|
|
||
| func get_number() -> int: | ||
| return 5 | ||
|
|
||
| How to fix this warning | ||
| ----------------------- | ||
|
|
||
| Assign the returned value to a variable for use later. | ||
|
|
||
| .. code-block:: | ||
|
|
||
| func _ready(): | ||
| print("About to get a number...") | ||
| var num = get_number() | ||
| print("Got a number! It's %s" % num) | ||
|
|
||
| However, some methods in Godot's APIs return values that are not necessary to store. | ||
| As such, depending on the situation, it may make more sense to ignore this warning. | ||
|
Comment on lines
+41
to
+42
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. It may be worth mentioning that
Member
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I wouldn't go into too much detail on this. To me it's not exactly clear if that's intended in the first place, and even if it is, it's probably just to reduce false positives. Keeping this in mind:
I see no point in going into details on potential false negatives.
Contributor
Author
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm not personally familiar with the I have thought about having expandable sections that could go into more detail when necessary, but I don't recall if Godot's documentation supports such text sections, and we'd also want to have those details verified before asserting them in the documentation.
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I certainly hope But yeah, this is way out of scope for a document aimed at beginners. |
||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,40 @@ | ||
| SHADOWED_VARIABLE | ||
| ================= | ||
|
|
||
| The warning message is: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| The local variable "level" is shadowing an already-declared variable at line 3 in the current class. | ||
|
|
||
| The default warning level for this warning is **Warn**. | ||
| To modify it, set :ref:`Project Settings > Debug > GDScript > Warnings > Shadowed Variable<class_ProjectSettings_property_debug/gdscript/warnings/shadowed_variable>`. | ||
|
|
||
| When this warning occurs | ||
| ------------------------ | ||
|
|
||
| This warning may appear when giving something the same name as a variable previously | ||
| defined in the class. | ||
|
|
||
| .. code-block:: | ||
|
|
||
| extends Node | ||
|
|
||
| var level = 3 | ||
|
|
||
| func _ready(): | ||
| # Will give warning SHADOWED_VARIABLE. | ||
| var level = 1 | ||
| print("Time for level %s" % level) | ||
|
|
||
| In this example, the script class has a property ``level`` which can be accessed from its functions. | ||
| However, at the first line of ``_ready()``, a new ``level`` variable is declared for that function specifically. | ||
| After this declaration, any references to ``level`` will go to that version and not the shared variable for the class. | ||
| This is called *shadowing*. | ||
|
|
||
|
|
||
| How to fix this warning | ||
| ----------------------- | ||
|
|
||
| Change the name to something that isn't being used by the class. | ||
| For example, if receiving a warning about using the identifier ``level``, consider using something more descriptive like ``new_level``. |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,35 @@ | ||
| UNASSIGNED_VARIABLE | ||
| =================== | ||
|
|
||
| The warning message is: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| The variable "my_var" is used before being assigned a value. | ||
|
|
||
| The default warning level for this warning is **Warn**. | ||
| To modify it, set :ref:`Project Settings > Debug > GDScript > Warnings > Unassigned Variable<class_ProjectSettings_property_debug/gdscript/warnings/unassigned_variable>`. | ||
|
|
||
| When this warning occurs | ||
| ------------------------ | ||
|
|
||
| This warning may appear when attempting to use a variable that hasn't had a value | ||
| assigned to it yet. | ||
|
|
||
| .. code-block:: | ||
|
|
||
| var my_var | ||
| print(my_var) | ||
|
|
||
| By default, the variable will be ``null``. However, Godot considers this a warning | ||
| because the user did not explicitly assign the value, and as such might be unaware of it. | ||
|
|
||
| How to fix this warning | ||
| ----------------------- | ||
|
|
||
| Assign a value to the variable before including it in an expression or function call: | ||
|
|
||
| .. code-block:: | ||
|
|
||
| var my_var = 5 | ||
| print(my_var) |
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,52 @@ | ||
| UNUSED_VARIABLE | ||
| =============== | ||
|
|
||
| The warning message is: | ||
|
|
||
| .. code-block:: none | ||
|
|
||
| The local variable "counter" is declared but never used in the block. If this is intended, prefix it with an underscore: "_counter". | ||
|
|
||
| The default warning level for this warning is **Warn**. | ||
| To modify it, set :ref:`Project Settings > Debug > GDScript > Warnings > Unused Variable<class_ProjectSettings_property_debug/gdscript/warnings/unused_variable>`. | ||
|
|
||
| When this warning occurs | ||
| ------------------------ | ||
|
|
||
| This warning may appear when a variable is declared, but never used before its | ||
| function or scope ends: | ||
|
|
||
| .. code-block:: | ||
|
|
||
| extends CharacterBody2D | ||
|
|
||
| func _process(delta): | ||
| var player_speed = 5.0 # Will give warning UNUSED_VARIABLE. | ||
| velocity = Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") | ||
| move_and_slide() | ||
|
|
||
| In this example, the variable ``player_speed`` is presumably meant to control how | ||
| fast the player moves. However, ``velocity`` never actually takes into account | ||
| this speed variable; it only uses the result of ``Input.get_vector()``. | ||
| It's likely that the programmer meant to include ``player_speed`` here somehow but forgot to write it. | ||
|
|
||
| How to fix this warning | ||
| ----------------------- | ||
|
|
||
| If a variable is being marked as unused, you probably meant to use it somewhere | ||
| but forgot to include it in the relevant statement. Following the example above, | ||
| the likely solution would be to incorporate it into the calculation of ``velocity``: | ||
|
|
||
| .. code-block:: | ||
|
|
||
| velocity = player_speed * Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down") | ||
|
|
||
| If you're certain you don't need the variable for anything right now, but might | ||
| need its value later on, prefix its name with an underscore (``_``) as the warning text suggests. | ||
| Once you start referencing it elsewhere in the code, you can remove the underscore. | ||
|
|
||
| .. code-block:: | ||
|
|
||
| var _player_speed = 5.0 # Will not give warning UNUSED_VARIABLE. | ||
|
|
||
| If you know you won't ever need the variable, then simply delete it. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don't quite understand who this section is meant for. I thought this page was aimed at beginners to give them a short explanation on the common warnings.
I don't see how the default value is relevant to them.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Eventually, the hope is to have every warning documented with examples, explanations, and fixes. This initial PR just adds pages for a few warnings that might be the most common, so that the review burden isn't as great.
Can you clarify what you mean by "I don't see how the default value is relevant to [beginners for a short explanation on the common warnings]"? I'm not sure I currently follow; the
GET_NODE_DEFAULT_WITHOUT_ONREADYwarning involves setting a property's default value withget_node()(or a shorthand equivalent) which is why default values are discussed here.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
That was referring to this part:
The default value is already in the class reference, and there it's actually always up-to-date (although displaying it as int is a bit terrible I guess).
I don't think including this information here makes that much sense.
Yeah I get that. I was talking about the general structure that you used here. I feel like we might just want to strike this initial section, and start with "When this warning occurs" directly.
It seems like this is basically saying the same as the explanation you provide below.
I see no point in spelling out all variations. That's bound to get outdated, and users already know this message if they looked up the error.
(If you did that for SEO, that might be a point I guess. But we have well defined warning names, so that seems unnecessary to me 🤔.)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Ah, I see, thanks for the clarification! Thinking about it now, I agree that it might make more sense to just link to the class reference from these pages, and only specify the default value there. That way, updates to the default value won't make these pages outdated or inaccurate.
I recall there being discussion of adding links from these pages to the settings class reference; perhaps the inclusion of the default values was to make them flow more naturally? I'll see what I can find in the previous conversations, and if I can't find anything or what I find isn't especially compelling, I'll remove the default values and only link to the class reference.
I definitely see where you're coming from here; the first sentence of the page is largely retreading ("pre-treading"?) the description given in the "When this warning occurs" section. The intent here is to provide a short (one- or two-sentence) description of the warning, along with the warning messages that might be displayed to the user (and thus that they might paste into a search engine to figure it out).
The "short description" being largely repeated below has precedent in the Godot documentation. For example, in the Node3D class reference, the initial short description says
and just below, the long description starts with
Bringing it back to the warning page, I suppose we could remove the short description of the warning and put the examples of warning messages in a section named something like "What this warning looks like". But given that other areas of the manual/class reference often start with an overview/intro section that is expanded upon in the following sections, I think it might be best to keep as-is.
Yep, that was pretty much the reason. I would expect users to copy and paste the warning messages they receive into a search engine to look for help with it, so I want to make sure the messages themselves (not just the codes/codenames, like
GET_NODE_DEFAULT_WITHOUT_ONREADY) cause these pages to show up in search results.