summaryrefslogtreecommitdiffstats
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml59
-rw-r--r--modules/gdscript/editor/script_templates/SCsub2
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp8
-rw-r--r--modules/gdscript/gdscript_editor.cpp18
-rw-r--r--modules/gdscript/gdscript_parser.cpp168
-rw-r--r--modules/gdscript/gdscript_parser.h1
-rw-r--r--modules/gdscript/tests/scripts/completion/class_a.notest.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/get_node.tscn19
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd4
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local/local.cfg7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local/local.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.cfg7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg20
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg20
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd5
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member/member.cfg7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member/member.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.cfg7
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg12
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd (renamed from modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd)2
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd8
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg14
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg16
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg16
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg20
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd6
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg20
-rw-r--r--modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd6
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.gd (renamed from modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.out (renamed from modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out)0
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.gd4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_arrays.gd86
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_arrays.out137
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_enum.gd23
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_enum.out32
-rw-r--r--modules/gdscript/tests/scripts/parser/features/export_variable.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd28
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out10
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd (renamed from modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out (renamed from modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd (renamed from modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out (renamed from modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd (renamed from modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out (renamed from modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd (renamed from modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out (renamed from modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd (renamed from modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.gd)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out (renamed from modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.out)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.gd (renamed from modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd)0
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.out (renamed from modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out)0
-rw-r--r--modules/gdscript/tests/scripts/utils.notest.gd37
-rw-r--r--modules/gdscript/tests/test_completion.h2
104 files changed, 1206 insertions, 88 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 7ececce613..a68d65e8d3 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -333,20 +333,34 @@
<annotation name="@export_color_no_alpha">
<return type="void" />
<description>
- Export a [Color] property without allowing its transparency ([member Color.a]) to be edited.
+ Export a [Color], [Array][lb][Color][rb], or [PackedColorArray] property without allowing its transparency ([member Color.a]) to be edited.
See also [constant PROPERTY_HINT_COLOR_NO_ALPHA].
[codeblock]
@export_color_no_alpha var dye_color: Color
+ @export_color_no_alpha var dye_colors: Array[Color]
+ [/codeblock]
+ </description>
+ </annotation>
+ <annotation name="@export_custom">
+ <return type="void" />
+ <param index="0" name="hint" type="int" enum="PropertyHint" />
+ <param index="1" name="hint_string" type="String" />
+ <param index="2" name="usage" type="int" enum="PropertyUsageFlags" is_bitfield="true" default="6" />
+ <description>
+ Allows you to set a custom hint, hint string, and usage flags for the exported property. Note that there's no validation done in GDScript, it will just pass the hint along to the editor.
+ [codeblock]
+ @export_custom(PROPERTY_HINT_NONE, "suffix:m") var suffix: Vector3
[/codeblock]
</description>
</annotation>
<annotation name="@export_dir">
<return type="void" />
<description>
- Export a [String] property as a path to a directory. The path will be limited to the project folder and its subfolders. See [annotation @export_global_dir] to allow picking from the entire filesystem.
+ Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as a path to a directory. The path will be limited to the project folder and its subfolders. See [annotation @export_global_dir] to allow picking from the entire filesystem.
See also [constant PROPERTY_HINT_DIR].
[codeblock]
@export_dir var sprite_folder_path: String
+ @export_dir var sprite_folder_paths: Array[String]
[/codeblock]
</description>
</annotation>
@@ -354,12 +368,15 @@
<return type="void" />
<param index="0" name="names" type="String" />
<description>
- Export an [int] or [String] property as an enumerated list of options. If the property is an [int], then the index of the value is stored, in the same order the values are provided. You can add explicit values using a colon. If the property is a [String], then the value is stored.
+ Export an [int], [String], [Array][lb][int][rb], [Array][lb][String][rb], [PackedByteArray], [PackedInt32Array], [PackedInt64Array], or [PackedStringArray] property as an enumerated list of options (or an array of options). If the property is an [int], then the index of the value is stored, in the same order the values are provided. You can add explicit values using a colon. If the property is a [String], then the value is stored.
See also [constant PROPERTY_HINT_ENUM].
[codeblock]
@export_enum("Warrior", "Magician", "Thief") var character_class: int
@export_enum("Slow:30", "Average:60", "Very Fast:200") var character_speed: int
@export_enum("Rebecca", "Mary", "Leah") var character_name: String
+
+ @export_enum("Sword", "Spear", "Mace") var character_items: Array[int]
+ @export_enum("double_jump", "climb", "dash") var character_skills: Array[String]
[/codeblock]
If you want to set an initial value, you must specify it explicitly:
[codeblock]
@@ -369,6 +386,9 @@
[codeblock]
enum CharacterName {REBECCA, MARY, LEAH}
@export var character_name: CharacterName
+
+ enum CharacterItem {SWORD, SPEAR, MACE}
+ @export var character_items: Array[CharacterItem]
[/codeblock]
</description>
</annotation>
@@ -382,6 +402,7 @@
@export_exp_easing var transition_speed
@export_exp_easing("attenuation") var fading_attenuation
@export_exp_easing("positive_only") var effect_power
+ @export_exp_easing var speeds: Array[float]
[/codeblock]
</description>
</annotation>
@@ -389,12 +410,13 @@
<return type="void" />
<param index="0" name="filter" type="String" default="&quot;&quot;" />
<description>
- Export a [String] property as a path to a file. The path will be limited to the project folder and its subfolders. See [annotation @export_global_file] to allow picking from the entire filesystem.
+ Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as a path to a file. The path will be limited to the project folder and its subfolders. See [annotation @export_global_file] to allow picking from the entire filesystem.
If [param filter] is provided, only matching files will be available for picking.
See also [constant PROPERTY_HINT_FILE].
[codeblock]
@export_file var sound_effect_path: String
@export_file("*.txt") var notes_path: String
+ @export_file var level_paths: Array[String]
[/codeblock]
</description>
</annotation>
@@ -421,6 +443,10 @@
[codeblock]
@export_flags("A:16", "B", "C") var x
[/codeblock]
+ You can also use the annotation on [Array][lb][int][rb], [PackedByteArray], [PackedInt32Array], and [PackedInt64Array]
+ [codeblock]
+ @export_flags("Fire", "Water", "Earth", "Wind") var phase_elements: Array[int]
+ [/codeblock]
</description>
</annotation>
<annotation name="@export_flags_2d_navigation">
@@ -430,6 +456,7 @@
See also [constant PROPERTY_HINT_LAYERS_2D_NAVIGATION].
[codeblock]
@export_flags_2d_navigation var navigation_layers: int
+ @export_flags_2d_navigation var navigation_layers_array: Array[int]
[/codeblock]
</description>
</annotation>
@@ -440,6 +467,7 @@
See also [constant PROPERTY_HINT_LAYERS_2D_PHYSICS].
[codeblock]
@export_flags_2d_physics var physics_layers: int
+ @export_flags_2d_physics var physics_layers_array: Array[int]
[/codeblock]
</description>
</annotation>
@@ -450,6 +478,7 @@
See also [constant PROPERTY_HINT_LAYERS_2D_RENDER].
[codeblock]
@export_flags_2d_render var render_layers: int
+ @export_flags_2d_render var render_layers_array: Array[int]
[/codeblock]
</description>
</annotation>
@@ -460,6 +489,7 @@
See also [constant PROPERTY_HINT_LAYERS_3D_NAVIGATION].
[codeblock]
@export_flags_3d_navigation var navigation_layers: int
+ @export_flags_3d_navigation var navigation_layers_array: Array[int]
[/codeblock]
</description>
</annotation>
@@ -470,6 +500,7 @@
See also [constant PROPERTY_HINT_LAYERS_3D_PHYSICS].
[codeblock]
@export_flags_3d_physics var physics_layers: int
+ @export_flags_3d_physics var physics_layers_array: Array[int]
[/codeblock]
</description>
</annotation>
@@ -480,6 +511,7 @@
See also [constant PROPERTY_HINT_LAYERS_3D_RENDER].
[codeblock]
@export_flags_3d_render var render_layers: int
+ @export_flags_3d_render var render_layers_array: Array[int]
[/codeblock]
</description>
</annotation>
@@ -490,16 +522,18 @@
See also [constant PROPERTY_HINT_LAYERS_AVOIDANCE].
[codeblock]
@export_flags_avoidance var avoidance_layers: int
+ @export_flags_avoidance var avoidance_layers_array: Array[int]
[/codeblock]
</description>
</annotation>
<annotation name="@export_global_dir">
<return type="void" />
<description>
- Export a [String] property as an absolute path to a directory. The path can be picked from the entire filesystem. See [annotation @export_dir] to limit it to the project folder and its subfolders.
+ Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as an absolute path to a directory. The path can be picked from the entire filesystem. See [annotation @export_dir] to limit it to the project folder and its subfolders.
See also [constant PROPERTY_HINT_GLOBAL_DIR].
[codeblock]
@export_global_dir var sprite_folder_path: String
+ @export_global_dir var sprite_folder_paths: Array[String]
[/codeblock]
</description>
</annotation>
@@ -507,12 +541,13 @@
<return type="void" />
<param index="0" name="filter" type="String" default="&quot;&quot;" />
<description>
- Export a [String] property as an absolute path to a file. The path can be picked from the entire filesystem. See [annotation @export_file] to limit it to the project folder and its subfolders.
+ Export a [String], [Array][lb][String][rb], or [PackedStringArray] property as an absolute path to a file. The path can be picked from the entire filesystem. See [annotation @export_file] to limit it to the project folder and its subfolders.
If [param filter] is provided, only matching files will be available for picking.
See also [constant PROPERTY_HINT_GLOBAL_FILE].
[codeblock]
@export_global_file var sound_effect_path: String
@export_global_file("*.txt") var notes_path: String
+ @export_global_file var multiple_paths: Array[String]
[/codeblock]
</description>
</annotation>
@@ -542,10 +577,11 @@
<annotation name="@export_multiline">
<return type="void" />
<description>
- Export a [String] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property.
+ Export a [String], [Array][lb][String][rb], [PackedStringArray], [Dictionary] or [Array][lb][Dictionary][rb] property with a large [TextEdit] widget instead of a [LineEdit]. This adds support for multiline content and makes it easier to edit large amount of text stored in the property.
See also [constant PROPERTY_HINT_MULTILINE_TEXT].
[codeblock]
@export_multiline var character_biography
+ @export_multiline var npc_dialogs: Array[String]
[/codeblock]
</description>
</annotation>
@@ -553,10 +589,11 @@
<return type="void" />
<param index="0" name="type" type="String" default="&quot;&quot;" />
<description>
- Export a [NodePath] property with a filter for allowed node types.
+ Export a [NodePath] or [Array][lb][NodePath][rb] property with a filter for allowed node types.
See also [constant PROPERTY_HINT_NODE_PATH_VALID_TYPES].
[codeblock]
@export_node_path("Button", "TouchScreenButton") var some_button
+ @export_node_path("Button", "TouchScreenButton") var many_buttons: Array[NodePath]
[/codeblock]
[b]Note:[/b] The type must be a native class or a globally registered script (using the [code]class_name[/code] keyword) that inherits [Node].
</description>
@@ -565,10 +602,11 @@
<return type="void" />
<param index="0" name="placeholder" type="String" />
<description>
- Export a [String] property with a placeholder text displayed in the editor widget when no value is present.
+ Export a [String], [Array][lb][String][rb], or [PackedStringArray] property with a placeholder text displayed in the editor widget when no value is present.
See also [constant PROPERTY_HINT_PLACEHOLDER_TEXT].
[codeblock]
@export_placeholder("Name in lowercase") var character_id: String
+ @export_placeholder("Name in lowercase") var friend_ids: Array[String]
[/codeblock]
</description>
</annotation>
@@ -579,7 +617,7 @@
<param index="2" name="step" type="float" default="1.0" />
<param index="3" name="extra_hints" type="String" default="&quot;&quot;" />
<description>
- Export an [int] or [float] property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [member EditorSettings.interface/inspector/default_float_step] setting.
+ Export an [int], [float], [Array][lb][int][rb], [Array][lb][float][rb], [PackedByteArray], [PackedInt32Array], [PackedInt64Array], [PackedFloat32Array], or [PackedFloat64Array] property as a range value. The range must be defined by [param min] and [param max], as well as an optional [param step] and a variety of extra hints. The [param step] defaults to [code]1[/code] for integer properties. For floating-point numbers this value depends on your [member EditorSettings.interface/inspector/default_float_step] setting.
If hints [code]"or_greater"[/code] and [code]"or_less"[/code] are provided, the editor widget will not cap the value at range boundaries. The [code]"exp"[/code] hint will make the edited values on range to change exponentially. The [code]"hide_slider"[/code] hint will hide the slider element of the editor widget.
Hints also allow to indicate the units for the edited value. Using [code]"radians_as_degrees"[/code] you can specify that the actual value is in radians, but should be displayed in degrees in the Inspector dock (the range values are also in degrees). [code]"degrees"[/code] allows to add a degree sign as a unit suffix (the value is unchanged). Finally, a custom suffix can be provided using [code]"suffix:unit"[/code], where "unit" can be any string.
See also [constant PROPERTY_HINT_RANGE].
@@ -587,6 +625,7 @@
@export_range(0, 20) var number
@export_range(-10, 20) var number
@export_range(-10, 20, 0.2) var number: float
+ @export_range(0, 20) var numbers: Array[float]
@export_range(0, 100, 1, "or_greater") var power_percent
@export_range(0, 100, 1, "or_greater", "or_less") var health_delta
diff --git a/modules/gdscript/editor/script_templates/SCsub b/modules/gdscript/editor/script_templates/SCsub
index 2266ef2d01..5db7e3fc3b 100644
--- a/modules/gdscript/editor/script_templates/SCsub
+++ b/modules/gdscript/editor/script_templates/SCsub
@@ -5,7 +5,7 @@ Import("env")
import editor.template_builders as build_template_gd
env["BUILDERS"]["MakeGDTemplateBuilder"] = Builder(
- action=env.Run(build_template_gd.make_templates, "Generating GDScript templates header."),
+ action=env.Run(build_template_gd.make_templates),
suffix=".h",
src_suffix=".gd",
)
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index 98d4a19a87..3ec5098c21 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -3360,12 +3360,8 @@ void GDScriptAnalyzer::reduce_call(GDScriptParser::CallNode *p_call, bool p_is_a
parser->push_warning(p_call, GDScriptWarning::RETURN_VALUE_DISCARDED, p_call->function_name);
}
- if (method_flags.has_flag(METHOD_FLAG_STATIC) && !is_constructor && !base_type.is_meta_type && !(is_self && static_context)) {
- String caller_type = String(base_type.native_type);
-
- if (caller_type.is_empty()) {
- caller_type = base_type.to_string();
- }
+ if (method_flags.has_flag(METHOD_FLAG_STATIC) && !is_constructor && !base_type.is_meta_type && !is_self) {
+ String caller_type = base_type.to_string();
parser->push_warning(p_call, GDScriptWarning::STATIC_CALLED_ON_INSTANCE, p_call->function_name, caller_type);
}
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index babd2c1772..12ff22c878 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -828,17 +828,21 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
return arghint;
}
-static void _get_directory_contents(EditorFileSystemDirectory *p_dir, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_list) {
+static void _get_directory_contents(EditorFileSystemDirectory *p_dir, HashMap<String, ScriptLanguage::CodeCompletionOption> &r_list, const StringName &p_required_type = StringName()) {
const String quote_style = EDITOR_GET("text_editor/completion/use_single_quotes") ? "'" : "\"";
+ const bool requires_type = p_required_type;
for (int i = 0; i < p_dir->get_file_count(); i++) {
+ if (requires_type && !ClassDB::is_parent_class(p_dir->get_file_type(i), p_required_type)) {
+ continue;
+ }
ScriptLanguage::CodeCompletionOption option(p_dir->get_file_path(i), ScriptLanguage::CODE_COMPLETION_KIND_FILE_PATH);
option.insert_text = option.display.quote(quote_style);
r_list.insert(option.display, option);
}
for (int i = 0; i < p_dir->get_subdir_count(); i++) {
- _get_directory_contents(p_dir->get_subdir(i), r_list);
+ _get_directory_contents(p_dir->get_subdir(i), r_list, p_required_type);
}
}
@@ -2803,6 +2807,16 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c
r_result.insert(option.display, option);
}
}
+ if (EDITOR_GET("text_editor/completion/complete_file_paths")) {
+ if (p_argidx == 0 && p_method == SNAME("change_scene_to_file") && ClassDB::is_parent_class(class_name, SNAME("SceneTree"))) {
+ HashMap<String, ScriptLanguage::CodeCompletionOption> list;
+ _get_directory_contents(EditorFileSystem::get_singleton()->get_filesystem(), list, SNAME("PackedScene"));
+ for (const KeyValue<String, ScriptLanguage::CodeCompletionOption> &key_value_pair : list) {
+ ScriptLanguage::CodeCompletionOption option = key_value_pair.value;
+ r_result.insert(option.display, option);
+ }
+ }
+ }
base_type.kind = GDScriptParser::DataType::UNRESOLVED;
} break;
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 4d4eadf0fa..aae45274e0 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -121,6 +121,7 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_flags_3d_physics"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_PHYSICS, Variant::INT>);
register_annotation(MethodInfo("@export_flags_3d_navigation"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_NAVIGATION, Variant::INT>);
register_annotation(MethodInfo("@export_flags_avoidance"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_AVOIDANCE, Variant::INT>);
+ register_annotation(MethodInfo("@export_custom", PropertyInfo(Variant::INT, "hint", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_ENUM, "PropertyHint"), PropertyInfo(Variant::STRING, "hint_string"), PropertyInfo(Variant::INT, "usage", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_BITFIELD, "PropertyUsageFlags")), AnnotationInfo::VARIABLE, &GDScriptParser::export_custom_annotation, varray(PROPERTY_USAGE_DEFAULT));
// Export grouping annotations.
register_annotation(MethodInfo("@export_category", PropertyInfo(Variant::STRING, "name")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_CATEGORY>);
register_annotation(MethodInfo("@export_group", PropertyInfo(Variant::STRING, "name"), PropertyInfo(Variant::STRING, "prefix")), AnnotationInfo::STANDALONE, &GDScriptParser::export_group_annotations<PROPERTY_USAGE_GROUP>, varray(""));
@@ -4006,6 +4007,55 @@ bool GDScriptParser::onready_annotation(const AnnotationNode *p_annotation, Node
return true;
}
+static String _get_annotation_error_string(const StringName &p_annotation_name, const Vector<Variant::Type> &p_expected_types, const GDScriptParser::DataType &p_provided_type) {
+ Vector<String> types;
+ for (int i = 0; i < p_expected_types.size(); i++) {
+ const Variant::Type &type = p_expected_types[i];
+ types.push_back(Variant::get_type_name(type));
+ types.push_back("Array[" + Variant::get_type_name(type) + "]");
+ switch (type) {
+ case Variant::INT:
+ types.push_back("PackedByteArray");
+ types.push_back("PackedInt32Array");
+ types.push_back("PackedInt64Array");
+ break;
+ case Variant::FLOAT:
+ types.push_back("PackedFloat32Array");
+ types.push_back("PackedFloat64Array");
+ break;
+ case Variant::STRING:
+ types.push_back("PackedStringArray");
+ break;
+ case Variant::VECTOR2:
+ types.push_back("PackedVector2Array");
+ break;
+ case Variant::VECTOR3:
+ types.push_back("PackedVector3Array");
+ break;
+ case Variant::COLOR:
+ types.push_back("PackedColorArray");
+ break;
+ default:
+ break;
+ }
+ }
+
+ String string;
+ if (types.size() == 1) {
+ string = types[0].quote();
+ } else if (types.size() == 2) {
+ string = types[0].quote() + " or " + types[1].quote();
+ } else if (types.size() >= 3) {
+ string = types[0].quote();
+ for (int i = 1; i < types.size() - 1; i++) {
+ string += ", " + types[i].quote();
+ }
+ string += ", or " + types[types.size() - 1].quote();
+ }
+
+ return vformat(R"("%s" annotation requires a variable of type %s, but type "%s" was given instead.)", p_annotation_name, string, p_provided_type.to_string());
+}
+
template <PropertyHint t_hint, Variant::Type t_type>
bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class) {
ERR_FAIL_COND_V_MSG(p_target->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
@@ -4090,6 +4140,26 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
// This is called after the analyzer is done finding the type, so this should be set here.
DataType export_type = variable->get_datatype();
+
+ // Use initializer type if specified type is `Variant`.
+ if (export_type.is_variant() && variable->initializer != nullptr && variable->initializer->datatype.is_set()) {
+ export_type = variable->initializer->get_datatype();
+ export_type.type_source = DataType::INFERRED;
+ }
+
+ const Variant::Type original_export_type_builtin = export_type.builtin_type;
+
+ // Process array and packed array annotations on the element type.
+ bool is_array = false;
+ if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) {
+ is_array = true;
+ export_type = export_type.get_container_element_type(0);
+ } else if (export_type.is_typed_container_type()) {
+ is_array = true;
+ export_type = export_type.get_typed_container_type();
+ export_type.type_source = variable->datatype.type_source;
+ }
+
bool use_default_variable_type_check = true;
if (p_annotation->name == SNAME("@export_range")) {
@@ -4097,30 +4167,16 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.type = Variant::INT;
}
} else if (p_annotation->name == SNAME("@export_multiline")) {
- if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) {
- DataType inner_type = export_type.get_container_element_type(0);
- if (inner_type.builtin_type != Variant::STRING) {
- push_error(vformat(R"("%s" annotation on arrays requires a string type but type "%s" was given instead.)", p_annotation->name.operator String(), inner_type.to_string()), variable);
- return false;
- }
+ use_default_variable_type_check = false;
- String hint_prefix = itos(inner_type.builtin_type) + "/" + itos(variable->export_info.hint);
- variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
- variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
- variable->export_info.type = Variant::ARRAY;
+ if (export_type.builtin_type != Variant::STRING && export_type.builtin_type != Variant::DICTIONARY) {
+ Vector<Variant::Type> expected_types = { Variant::STRING, Variant::DICTIONARY };
+ push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation);
+ return false;
+ }
- return true;
- } else if (export_type.builtin_type == Variant::DICTIONARY) {
+ if (export_type.builtin_type == Variant::DICTIONARY) {
variable->export_info.type = Variant::DICTIONARY;
-
- return true;
- } else if (export_type.builtin_type == Variant::PACKED_STRING_ARRAY) {
- String hint_prefix = itos(Variant::STRING) + "/" + itos(variable->export_info.hint);
- variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
- variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
- variable->export_info.type = Variant::PACKED_STRING_ARRAY;
-
- return true;
}
} else if (p_annotation->name == SNAME("@export")) {
use_default_variable_type_check = false;
@@ -4130,13 +4186,6 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
return false;
}
- bool is_array = false;
-
- if (export_type.builtin_type == Variant::ARRAY && export_type.has_container_element_type(0)) {
- export_type = export_type.get_container_element_type(0); // Use inner type for.
- is_array = true;
- }
-
if (export_type.is_variant() || export_type.has_no_type()) {
push_error(R"(Cannot use simple "@export" annotation because the type of the initialized value can't be inferred.)", p_annotation);
return false;
@@ -4158,7 +4207,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint = PROPERTY_HINT_NODE_TYPE;
variable->export_info.hint_string = export_type.native_type;
} else {
- push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable);
+ push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation);
return false;
}
break;
@@ -4172,7 +4221,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint = PROPERTY_HINT_NODE_TYPE;
variable->export_info.hint_string = export_type.to_string();
} else {
- push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable);
+ push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation);
return false;
}
@@ -4223,24 +4272,14 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
}
} break;
default:
- push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable);
+ push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", p_annotation);
return false;
}
if (variable->export_info.hint == PROPERTY_HINT_NODE_TYPE && !ClassDB::is_parent_class(p_class->base_type.native_type, SNAME("Node"))) {
- push_error(vformat(R"(Node export is only supported in Node-derived classes, but the current class inherits "%s".)", p_class->base_type.to_string()), variable);
+ push_error(vformat(R"(Node export is only supported in Node-derived classes, but the current class inherits "%s".)", p_class->base_type.to_string()), p_annotation);
return false;
}
-
- if (is_array) {
- String hint_prefix = itos(variable->export_info.type);
- if (variable->export_info.hint) {
- hint_prefix += "/" + itos(variable->export_info.hint);
- }
- variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
- variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
- variable->export_info.type = Variant::ARRAY;
- }
} else if (p_annotation->name == SNAME("@export_enum")) {
use_default_variable_type_check = false;
@@ -4248,17 +4287,13 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
if (export_type.kind == DataType::BUILTIN && export_type.builtin_type == Variant::STRING) {
enum_type = Variant::STRING;
- } else if (export_type.is_variant() && variable->initializer != nullptr) {
- DataType initializer_type = variable->initializer->get_datatype();
- if (initializer_type.kind == DataType::BUILTIN && initializer_type.builtin_type == Variant::STRING) {
- enum_type = Variant::STRING;
- }
}
variable->export_info.type = enum_type;
if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != enum_type)) {
- push_error(vformat(R"("@export_enum" annotation requires a variable of type "int" or "String" but type "%s" was given instead.)", export_type.to_string()), variable);
+ Vector<Variant::Type> expected_types = { Variant::INT, Variant::STRING };
+ push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation);
return false;
}
} else if (p_annotation->name == SNAME("@export_storage")) {
@@ -4274,12 +4309,47 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
if (!export_type.is_variant() && (export_type.kind != DataType::BUILTIN || export_type.builtin_type != t_type)) {
// Allow float/int conversion.
if ((t_type != Variant::FLOAT || export_type.builtin_type != Variant::INT) && (t_type != Variant::INT || export_type.builtin_type != Variant::FLOAT)) {
- push_error(vformat(R"("%s" annotation requires a variable of type "%s" but type "%s" was given instead.)", p_annotation->name.operator String(), Variant::get_type_name(t_type), export_type.to_string()), variable);
+ Vector<Variant::Type> expected_types = { t_type };
+ push_error(_get_annotation_error_string(p_annotation->name, expected_types, variable->get_datatype()), p_annotation);
return false;
}
}
}
+ if (is_array) {
+ String hint_prefix = itos(variable->export_info.type);
+ if (variable->export_info.hint) {
+ hint_prefix += "/" + itos(variable->export_info.hint);
+ }
+ variable->export_info.hint = PROPERTY_HINT_TYPE_STRING;
+ variable->export_info.hint_string = hint_prefix + ":" + variable->export_info.hint_string;
+ variable->export_info.type = original_export_type_builtin;
+ }
+
+ return true;
+}
+
+bool GDScriptParser::export_custom_annotation(const AnnotationNode *p_annotation, Node *p_node, ClassNode *p_class) {
+ ERR_FAIL_COND_V_MSG(p_node->type != Node::VARIABLE, false, vformat(R"("%s" annotation can only be applied to variables.)", p_annotation->name));
+ ERR_FAIL_COND_V_MSG(p_annotation->resolved_arguments.size() < 2, false, R"(Annotation "@export_custom" requires 2 arguments.)");
+
+ VariableNode *variable = static_cast<VariableNode *>(p_node);
+ if (variable->exported) {
+ push_error(vformat(R"(Annotation "%s" cannot be used with another "@export" annotation.)", p_annotation->name), p_annotation);
+ return false;
+ }
+
+ variable->exported = true;
+
+ DataType export_type = variable->get_datatype();
+
+ variable->export_info.type = export_type.builtin_type;
+ variable->export_info.hint = static_cast<PropertyHint>(p_annotation->resolved_arguments[0].operator int64_t());
+ variable->export_info.hint_string = p_annotation->resolved_arguments[1];
+
+ if (p_annotation->resolved_arguments.size() >= 3) {
+ variable->export_info.usage = p_annotation->resolved_arguments[2].operator int64_t();
+ }
return true;
}
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index 6664e6df04..45ab3f3e38 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -1482,6 +1482,7 @@ private:
bool onready_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
template <PropertyHint t_hint, Variant::Type t_type>
bool export_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
+ bool export_custom_annotation(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
template <PropertyUsageFlags t_usage>
bool export_group_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
bool warning_annotations(const AnnotationNode *p_annotation, Node *p_target, ClassNode *p_class);
diff --git a/modules/gdscript/tests/scripts/completion/class_a.notest.gd b/modules/gdscript/tests/scripts/completion/class_a.notest.gd
new file mode 100644
index 0000000000..47c64dc674
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/class_a.notest.gd
@@ -0,0 +1,8 @@
+extends Node
+
+signal signal_of_a
+
+var property_of_a
+
+func func_of_a():
+ pass
diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node.tscn b/modules/gdscript/tests/scripts/completion/get_node/get_node.tscn
new file mode 100644
index 0000000000..35ac666941
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/get_node.tscn
@@ -0,0 +1,19 @@
+[gd_scene load_steps=2 format=3 uid="uid://c8wekfd5ql7bc"]
+
+[ext_resource type="Script" path="res://completion/class_a.notest.gd" id="1_ldc4g"]
+
+[node name="GetNode" type="Node"]
+
+[node name="AnimationPlayer" type="AnimationPlayer" parent="."]
+
+[node name="UniqueNames" type="Node" parent="."]
+
+[node name="UniqueAnimationPlayer" type="AnimationPlayer" parent="UniqueNames"]
+unique_name_in_owner = true
+
+[node name="UniqueA" type="Node" parent="UniqueNames"]
+unique_name_in_owner = true
+script = ExtResource("1_ldc4g")
+
+[node name="A" type="Node" parent="."]
+script = ExtResource("1_ldc4g")
diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg b/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg
deleted file mode 100644
index 27e695d245..0000000000
--- a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.cfg
+++ /dev/null
@@ -1,4 +0,0 @@
-[output]
-include=[
- {"display": "autoplay"},
-]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
new file mode 100644
index 0000000000..ae7d34d87d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.cfg
@@ -0,0 +1,7 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd
new file mode 100644
index 0000000000..df458a9435
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/dollar.gd
@@ -0,0 +1,4 @@
+extends Node
+
+func a():
+ %AnimationPlayer.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
new file mode 100644
index 0000000000..ae7d34d87d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.cfg
@@ -0,0 +1,7 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd
new file mode 100644
index 0000000000..7050761b86
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal/percent.gd
@@ -0,0 +1,4 @@
+extends Node
+
+func a():
+ $UniqueAnimationPlayer.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
new file mode 100644
index 0000000000..009ab9f9ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd
new file mode 100644
index 0000000000..a84283a1de
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_class_scene.gd
@@ -0,0 +1,4 @@
+extends Node
+
+func a():
+ $A.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
new file mode 100644
index 0000000000..0fb46a4704
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd
new file mode 100644
index 0000000000..6e3fee1696
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/dollar_native_scene.gd
@@ -0,0 +1,4 @@
+extends Node
+
+func a():
+ $AnimationPlayer.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
new file mode 100644
index 0000000000..009ab9f9ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd
new file mode 100644
index 0000000000..27f059c944
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_class_scene.gd
@@ -0,0 +1,4 @@
+extends Node
+
+func a():
+ %UniqueA.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
new file mode 100644
index 0000000000..0fb46a4704
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd
new file mode 100644
index 0000000000..07068fc5a4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/literal_scene/percent_native_scene.gd
@@ -0,0 +1,4 @@
+extends Node
+
+func a():
+ %UniqueAnimationPlayer.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
new file mode 100644
index 0000000000..ae7d34d87d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.cfg
@@ -0,0 +1,7 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local/local.gd b/modules/gdscript/tests/scripts/completion/get_node/local/local.gd
new file mode 100644
index 0000000000..596ad80ef2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local/local.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test = $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.cfg
new file mode 100644
index 0000000000..ae7d34d87d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.cfg
@@ -0,0 +1,7 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd
new file mode 100644
index 0000000000..6f87af3c85
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered/local_interfered.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test := $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg
new file mode 100644
index 0000000000..009ab9f9ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd
new file mode 100644
index 0000000000..a710c8bbd7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/class_local_interfered_scene.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test := $A
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg
new file mode 100644
index 0000000000..0fb46a4704
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd
new file mode 100644
index 0000000000..6f87af3c85
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_interfered_scene/native_local_interfered_scene.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test := $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
new file mode 100644
index 0000000000..009ab9f9ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd
new file mode 100644
index 0000000000..2fc88f93dd
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/class_local_scene.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test = $A
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
new file mode 100644
index 0000000000..0fb46a4704
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd
new file mode 100644
index 0000000000..596ad80ef2
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_scene/native_local_scene.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test = $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
new file mode 100644
index 0000000000..a72b489be6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd
new file mode 100644
index 0000000000..b6d2074939
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/class_local_typehint.gd
@@ -0,0 +1,7 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+func a():
+ var test: A = $A
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
new file mode 100644
index 0000000000..adf06c8707
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd
new file mode 100644
index 0000000000..13b541a35d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint/native_local_typehint.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test: AnimationPlayer = $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
new file mode 100644
index 0000000000..9c580b711d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd
new file mode 100644
index 0000000000..b6d2074939
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/class_local_typehint_scene.gd
@@ -0,0 +1,7 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+func a():
+ var test: A = $A
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
new file mode 100644
index 0000000000..446198dd35
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd
new file mode 100644
index 0000000000..13b541a35d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene/native_local_typehint_scene.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test: AnimationPlayer = $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
new file mode 100644
index 0000000000..9c580b711d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd
new file mode 100644
index 0000000000..5c785b3ddc
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/class_local_typehint_scene_broad.notest.gd
@@ -0,0 +1,6 @@
+# TODO
+extends Node
+
+func a():
+ var test: Node = $A
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
new file mode 100644
index 0000000000..446198dd35
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd
new file mode 100644
index 0000000000..57f4e16e3c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_broad/native_local_typehint_scene_broad.notest.gd
@@ -0,0 +1,6 @@
+# TODO
+extends Node
+
+func a():
+ var test: Node = $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
new file mode 100644
index 0000000000..1894e72c65
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.cfg
@@ -0,0 +1,20 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; Area2D
+ {"display": "get_overlapping_areas"},
+ {"display": "linear_damp"},
+ {"display": "area_entered"},
+]
+exclude=[
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd
new file mode 100644
index 0000000000..c6adfe0dd3
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/class_local_typehint_scene_incompatible.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test: Area2D = $A
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
new file mode 100644
index 0000000000..c8ab63f6d6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.cfg
@@ -0,0 +1,20 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; Area2D
+ {"display": "get_overlapping_areas"},
+ {"display": "linear_damp"},
+ {"display": "area_entered"},
+]
+exclude=[
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd
new file mode 100644
index 0000000000..f53fce9bfe
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/local_typehint_scene_incompatible/native_local_typehint_scene_incompatible.gd
@@ -0,0 +1,5 @@
+extends Node
+
+func a():
+ var test: Area2D = $AnimationPlayer
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
new file mode 100644
index 0000000000..ae7d34d87d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.cfg
@@ -0,0 +1,7 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member/member.gd b/modules/gdscript/tests/scripts/completion/get_node/member/member.gd
new file mode 100644
index 0000000000..6bcc0a0298
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member/member.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test = $AnimationPlayer
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.cfg
new file mode 100644
index 0000000000..ae7d34d87d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.cfg
@@ -0,0 +1,7 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd
new file mode 100644
index 0000000000..542197e643
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered/member_interfered.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test := $AnimationPlayer
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg
new file mode 100644
index 0000000000..009ab9f9ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd
new file mode 100644
index 0000000000..da0b1b11d4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/class_member_interfered_scene.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test := $A
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg
new file mode 100644
index 0000000000..0fb46a4704
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd
new file mode 100644
index 0000000000..542197e643
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_interfered_scene/native_member_interfered_scene.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test := $AnimationPlayer
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
new file mode 100644
index 0000000000..009ab9f9ce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd
new file mode 100644
index 0000000000..4a35661e94
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/class_member_scene.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test = $A
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
new file mode 100644
index 0000000000..0fb46a4704
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd
new file mode 100644
index 0000000000..6bcc0a0298
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_scene/native_member_scene.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test = $AnimationPlayer
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
new file mode 100644
index 0000000000..a72b489be6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd
new file mode 100644
index 0000000000..e4edc3a4e4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/class_member_typehint.gd
@@ -0,0 +1,8 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+var test: A = $A
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
new file mode 100644
index 0000000000..adf06c8707
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.cfg
@@ -0,0 +1,12 @@
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd
index d41bbb970c..eda94ae34d 100644
--- a/modules/gdscript/tests/scripts/completion/get_node/get_node_member_annotated.gd
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint/native_member_typehint.gd
@@ -2,5 +2,5 @@ extends Node
var test: AnimationPlayer = $AnimationPlayer
-func _ready():
+func a():
test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
new file mode 100644
index 0000000000..9c580b711d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd
new file mode 100644
index 0000000000..8f68f54072
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/class_member_typehint_scene.gd
@@ -0,0 +1,8 @@
+extends Node
+
+const A := preload("res://completion/class_a.notest.gd")
+
+@onready var test: A = $A
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
new file mode 100644
index 0000000000..446198dd35
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.cfg
@@ -0,0 +1,14 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd
new file mode 100644
index 0000000000..eda94ae34d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene/native_member_typehint_scene.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test: AnimationPlayer = $AnimationPlayer
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
new file mode 100644
index 0000000000..502038bef7
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.cfg
@@ -0,0 +1,16 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+]
+exclude=[
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd
new file mode 100644
index 0000000000..7b0ed4ecd8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/class_member_typehint_scene_broad.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test: Node = $A
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
new file mode 100644
index 0000000000..1810e9fe5f
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.cfg
@@ -0,0 +1,16 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+]
+exclude=[
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd
new file mode 100644
index 0000000000..87342f9a21
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_broad/native_member_typehint_scene_broad.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test: Node = $AnimationPlayer
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
new file mode 100644
index 0000000000..1894e72c65
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.cfg
@@ -0,0 +1,20 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; Area2D
+ {"display": "get_overlapping_areas"},
+ {"display": "linear_damp"},
+ {"display": "area_entered"},
+]
+exclude=[
+ ; GDScript: class_a.notest.gd
+ {"display": "property_of_a"},
+ {"display": "func_of_a"},
+ {"display": "signal_of_a"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd
new file mode 100644
index 0000000000..5f78bcdf04
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/class_member_typehint_scene_incompatible.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test: Area2D = $A
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
new file mode 100644
index 0000000000..c8ab63f6d6
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.cfg
@@ -0,0 +1,20 @@
+[input]
+scene="res://completion/get_node/get_node.tscn"
+[output]
+include=[
+ ; Node
+ {"display": "add_child"},
+ {"display": "owner"},
+ {"display": "child_entered_tree"},
+
+ ; Area2D
+ {"display": "get_overlapping_areas"},
+ {"display": "linear_damp"},
+ {"display": "area_entered"},
+]
+exclude=[
+ ; AnimationPlayer
+ {"display": "autoplay"},
+ {"display": "play"},
+ {"display": "animation_changed"},
+]
diff --git a/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd
new file mode 100644
index 0000000000..c14df5cd1b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/completion/get_node/member_typehint_scene_incompatible/native_member_typehint_scene_incompatible.gd
@@ -0,0 +1,6 @@
+extends Node
+
+var test: Area2D = $AnimationPlayer
+
+func a():
+ test.➡
diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.gd
index e9690ee93d..e9690ee93d 100644
--- a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.gd
+++ b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.gd
diff --git a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.out
index 9fafcb5a64..9fafcb5a64 100644
--- a/modules/gdscript/tests/scripts/parser/errors/dollar-assignment-bug-53696.out
+++ b/modules/gdscript/tests/scripts/parser/errors/dollar_assignment_bug_53696.out
diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.gd b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.gd
new file mode 100644
index 0000000000..9f1a52856d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.gd
@@ -0,0 +1,4 @@
+@export_enum("A", "B", "C") var x: Array[Color]
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.out b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.out
new file mode 100644
index 0000000000..1e0455b96d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_array_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+"@export_enum" annotation requires a variable of type "int", "Array[int]", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "String", "Array[String]", or "PackedStringArray", but type "Array[Color]" was given instead.
diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.gd b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.gd
new file mode 100644
index 0000000000..5fe66e7cce
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.gd
@@ -0,0 +1,4 @@
+@export_enum("A", "B", "C") var x: Color
+
+func test():
+ pass
diff --git a/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.out b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.out
new file mode 100644
index 0000000000..43a08acc0a
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/errors/export_enum_wrong_type.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+"@export_enum" annotation requires a variable of type "int", "Array[int]", "PackedByteArray", "PackedInt32Array", "PackedInt64Array", "String", "Array[String]", or "PackedStringArray", but type "Color" was given instead.
diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.gd b/modules/gdscript/tests/scripts/parser/features/export_arrays.gd
new file mode 100644
index 0000000000..ddfb186aa4
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.gd
@@ -0,0 +1,86 @@
+const Utils = preload("../../utils.notest.gd")
+
+@export_dir var test_dir: Array[String]
+@export_dir var test_dir_packed: PackedStringArray
+@export_file var test_file: Array[String]
+@export_file var test_file_packed: PackedStringArray
+@export_global_dir var test_global_dir: Array[String]
+@export_global_dir var test_global_dir_packed: PackedStringArray
+@export_global_file var test_global_file: Array[String]
+@export_global_file var test_global_file_packed: PackedStringArray
+@export_flags("A", "B", "C") var test_bit_flag: Array[int]
+@export_flags("A", "B", "C") var test_bit_flag_packed_byte: PackedByteArray
+@export_flags("A", "B", "C") var test_bit_flag_packed32: PackedInt32Array
+@export_flags("A", "B", "C") var test_bit_flag_packed64: PackedInt64Array
+@export_flags_2d_navigation var test_bit_flag_2d_nav: Array[int]
+@export_flags_2d_navigation var test_bit_flag_2d_nav_packed_byte: PackedByteArray
+@export_flags_2d_navigation var test_bit_flag_2d_nav_packed32: PackedInt32Array
+@export_flags_2d_navigation var test_bit_flag_2d_nav_packed64: PackedInt64Array
+@export_flags_2d_physics var test_bit_flag_2d_phys: Array[int]
+@export_flags_2d_physics var test_bit_flag_2d_phys_packed_byte: PackedByteArray
+@export_flags_2d_physics var test_bit_flag_2d_phys_packed32: PackedInt32Array
+@export_flags_2d_physics var test_bit_flag_2d_phys_packed64: PackedInt64Array
+@export_flags_2d_render var test_bit_flag_2d_render: Array[int]
+@export_flags_2d_render var test_bit_flag_2d_render_packed_byte: PackedByteArray
+@export_flags_2d_render var test_bit_flag_2d_render_packed32: PackedInt32Array
+@export_flags_2d_render var test_bit_flag_2d_render_packed64: PackedInt64Array
+@export_flags_3d_navigation var test_bit_flag_3d_nav: Array[int]
+@export_flags_3d_navigation var test_bit_flag_3d_nav_packed_byte: PackedByteArray
+@export_flags_3d_navigation var test_bit_flag_3d_nav_packed32: PackedInt32Array
+@export_flags_3d_navigation var test_bit_flag_3d_nav_packed64: PackedInt64Array
+@export_flags_3d_physics var test_bit_flag_3d_phys: Array[int]
+@export_flags_3d_physics var test_bit_flag_3d_phys_packed_byte: PackedByteArray
+@export_flags_3d_physics var test_bit_flag_3d_phys_packed32: PackedInt32Array
+@export_flags_3d_physics var test_bit_flag_3d_phys_packed64: PackedInt64Array
+@export_flags_3d_render var test_bit_flag_3d_render: Array[int]
+@export_flags_3d_render var test_bit_flag_3d_render_packed_byte: PackedByteArray
+@export_flags_3d_render var test_bit_flag_3d_render_packed32: PackedInt32Array
+@export_flags_3d_render var test_bit_flag_3d_render_packed64: PackedInt64Array
+@export_multiline var test_multiline: Array[String]
+@export_multiline var test_multiline_packed: PackedStringArray
+@export_placeholder("Placeholder") var test_placeholder: Array[String]
+@export_placeholder("Placeholder") var test_placeholder_packed: PackedStringArray
+@export_range(1, 10) var test_range_int: Array[int]
+@export_range(1, 10) var test_range_int_packed_byte: PackedByteArray
+@export_range(1, 10) var test_range_int_packed32: PackedInt32Array
+@export_range(1, 10) var test_range_int_packed64: PackedInt64Array
+@export_range(1, 10, 0.01) var test_range_int_float_step: Array[int]
+@export_range(1.0, 10.0) var test_range_float: Array[float]
+@export_range(1.0, 10.0) var test_range_float_packed32: PackedFloat32Array
+@export_range(1.0, 10.0) var test_range_float_packed64: PackedFloat64Array
+@export_exp_easing var test_exp_easing: Array[float]
+@export_exp_easing var test_exp_easing_packed32: PackedFloat32Array
+@export_exp_easing var test_exp_easing_packed64: PackedFloat64Array
+@export_node_path var test_node_path: Array[NodePath]
+@export_color_no_alpha var test_color: Array[Color]
+@export_color_no_alpha var test_color_packed: PackedColorArray
+
+var temp_packed_byte_array: PackedByteArray
+var temp_packed_int32_array: PackedInt32Array
+var temp_packed_int64_array: PackedInt64Array
+var temp_packed_float32_array: PackedFloat32Array
+var temp_packed_float64_array: PackedFloat64Array
+var temp_packed_color_array: PackedColorArray
+var temp_packed_vector2_array: PackedVector2Array
+var temp_packed_vector3_array: PackedVector3Array
+
+@export var test_weak_packed_byte_array = temp_packed_byte_array
+@export var test_weak_packed_int32_array = temp_packed_int32_array
+@export var test_weak_packed_int64_array = temp_packed_int64_array
+@export var test_weak_packed_float32_array = temp_packed_float32_array
+@export var test_weak_packed_float64_array = temp_packed_float64_array
+@export var test_weak_packed_color_array = temp_packed_color_array
+@export var test_weak_packed_vector2_array = temp_packed_vector2_array
+@export var test_weak_packed_vector3_array = temp_packed_vector3_array
+
+@export_range(1, 10) var test_range_weak_packed_byte_array = temp_packed_byte_array
+@export_range(1, 10) var test_range_weak_packed_int32_array = temp_packed_int32_array
+@export_range(1, 10) var test_range_weak_packed_int64_array = temp_packed_int64_array
+@export_range(1, 10) var test_range_weak_packed_float32_array = temp_packed_float32_array
+@export_range(1, 10) var test_range_weak_packed_float64_array = temp_packed_float64_array
+@export_color_no_alpha var test_noalpha_weak_packed_color_array = temp_packed_color_array
+
+func test():
+ for property in get_property_list():
+ if str(property.name).begins_with("test_"):
+ Utils.print_property_extended_info(property)
diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.out b/modules/gdscript/tests/scripts/parser/features/export_arrays.out
new file mode 100644
index 0000000000..00e75fcc43
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.out
@@ -0,0 +1,137 @@
+GDTEST_OK
+var test_dir: Array
+ hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_dir_packed: PackedStringArray
+ hint=TYPE_STRING hint_string="String/DIR:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_file: Array
+ hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_file_packed: PackedStringArray
+ hint=TYPE_STRING hint_string="String/FILE:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_global_dir: Array
+ hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_global_dir_packed: PackedStringArray
+ hint=TYPE_STRING hint_string="String/GLOBAL_DIR:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_global_file: Array
+ hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_global_file_packed: PackedStringArray
+ hint=TYPE_STRING hint_string="String/GLOBAL_FILE:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag: Array
+ hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/FLAGS:A,B,C" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_nav: Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_nav_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_nav_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_nav_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_phys: Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_phys_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_phys_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_phys_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_render: Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_render_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_render_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_2d_render_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/LAYERS_2D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_nav: Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_nav_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_nav_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_nav_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_NAVIGATION:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_phys: Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_phys_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_phys_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_phys_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_PHYSICS:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_render: Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_render_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_render_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_bit_flag_3d_render_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/LAYERS_3D_RENDER:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_multiline: Array
+ hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_multiline_packed: PackedStringArray
+ hint=TYPE_STRING hint_string="String/MULTILINE_TEXT:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_placeholder: Array
+ hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE
+var test_placeholder_packed: PackedStringArray
+ hint=TYPE_STRING hint_string="String/PLACEHOLDER_TEXT:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_int: Array
+ hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_int_packed_byte: PackedByteArray
+ hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_int_packed32: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_int_packed64: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_int_float_step: Array
+ hint=TYPE_STRING hint_string="int/RANGE:1,10,0.01" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_float: Array
+ hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_float_packed32: PackedFloat32Array
+ hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_float_packed64: PackedFloat64Array
+ hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_exp_easing: Array
+ hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_exp_easing_packed32: PackedFloat32Array
+ hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_exp_easing_packed64: PackedFloat64Array
+ hint=TYPE_STRING hint_string="float/EXP_EASING:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_node_path: Array
+ hint=TYPE_STRING hint_string="NodePath/NODE_PATH_VALID_TYPES:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_color: Array
+ hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_color_packed: PackedColorArray
+ hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_byte_array: PackedByteArray
+ hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_int32_array: PackedInt32Array
+ hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_int64_array: PackedInt64Array
+ hint=TYPE_STRING hint_string="int:int" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_float32_array: PackedFloat32Array
+ hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_float64_array: PackedFloat64Array
+ hint=TYPE_STRING hint_string="float:float" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_color_array: PackedColorArray
+ hint=TYPE_STRING hint_string="Color:Color" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_vector2_array: PackedVector2Array
+ hint=TYPE_STRING hint_string="Vector2:Vector2" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_vector3_array: PackedVector3Array
+ hint=TYPE_STRING hint_string="Vector3:Vector3" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_weak_packed_byte_array: PackedByteArray
+ hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_weak_packed_int32_array: PackedInt32Array
+ hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_weak_packed_int64_array: PackedInt64Array
+ hint=TYPE_STRING hint_string="int/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_weak_packed_float32_array: PackedFloat32Array
+ hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_range_weak_packed_float64_array: PackedFloat64Array
+ hint=TYPE_STRING hint_string="float/RANGE:1,10" usage=DEFAULT|SCRIPT_VARIABLE
+var test_noalpha_weak_packed_color_array: PackedColorArray
+ hint=TYPE_STRING hint_string="Color/COLOR_NO_ALPHA:" usage=DEFAULT|SCRIPT_VARIABLE
diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.gd b/modules/gdscript/tests/scripts/parser/features/export_enum.gd
index 4f2a43f4fe..7f0737f4db 100644
--- a/modules/gdscript/tests/scripts/parser/features/export_enum.gd
+++ b/modules/gdscript/tests/scripts/parser/features/export_enum.gd
@@ -1,14 +1,35 @@
const Utils = preload("../../utils.notest.gd")
@export_enum("Red", "Green", "Blue") var test_untyped
+@export_enum("Red:10", "Green:20", "Blue:30") var test_with_values
+
+var temp_array_int: Array[int]
+var temp_array_string: Array[String]
+var temp_packed_byte_array: PackedByteArray
+var temp_packed_int32_array: PackedInt32Array
+var temp_packed_int64_array: PackedInt64Array
+var temp_packed_string_array: PackedStringArray
+@export_enum("Red", "Green", "Blue") var test_weak_variant
@export_enum("Red", "Green", "Blue") var test_weak_int = 0
@export_enum("Red", "Green", "Blue") var test_weak_string = ""
+@export_enum("Red", "Green", "Blue") var test_weak_array_int = temp_array_int
+@export_enum("Red", "Green", "Blue") var test_weak_array_string = temp_array_string
+@export_enum("Red", "Green", "Blue") var test_weak_packed_byte_array = temp_packed_byte_array
+@export_enum("Red", "Green", "Blue") var test_weak_packed_int32_array = temp_packed_int32_array
+@export_enum("Red", "Green", "Blue") var test_weak_packed_int64_array = temp_packed_int64_array
+@export_enum("Red", "Green", "Blue") var test_weak_packed_string_array = temp_packed_string_array
+@export_enum("Red", "Green", "Blue") var test_hard_variant: Variant
@export_enum("Red", "Green", "Blue") var test_hard_int: int
@export_enum("Red", "Green", "Blue") var test_hard_string: String
+@export_enum("Red", "Green", "Blue") var test_hard_array_int: Array[int]
+@export_enum("Red", "Green", "Blue") var test_hard_array_string: Array[String]
-@export_enum("Red:10", "Green:20", "Blue:30") var test_with_values
+@export_enum("Red", "Green", "Blue") var test_variant_array_int: Variant = temp_array_int
+@export_enum("Red", "Green", "Blue") var test_variant_packed_int32_array: Variant = temp_packed_int32_array
+@export_enum("Red", "Green", "Blue") var test_variant_array_string: Variant = temp_array_string
+@export_enum("Red", "Green", "Blue") var test_variant_packed_string_array: Variant = temp_packed_string_array
func test():
for property in get_property_list():
diff --git a/modules/gdscript/tests/scripts/parser/features/export_enum.out b/modules/gdscript/tests/scripts/parser/features/export_enum.out
index 43f5e197ad..c87f9b17f0 100644
--- a/modules/gdscript/tests/scripts/parser/features/export_enum.out
+++ b/modules/gdscript/tests/scripts/parser/features/export_enum.out
@@ -1,13 +1,41 @@
GDTEST_OK
var test_untyped: int = null
hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_with_values: int = null
+ hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_variant: int = null
+ hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
var test_weak_int: int = 0
hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
var test_weak_string: String = ""
hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_array_int: Array = Array[int]([])
+ hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_array_string: Array = Array[String]([])
+ hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_byte_array: PackedByteArray = PackedByteArray()
+ hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_int32_array: PackedInt32Array = PackedInt32Array()
+ hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_int64_array: PackedInt64Array = PackedInt64Array()
+ hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_weak_packed_string_array: PackedStringArray = PackedStringArray()
+ hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_hard_variant: int = null
+ hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
var test_hard_int: int = 0
hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
var test_hard_string: String = ""
hint=ENUM hint_string="Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
-var test_with_values: int = null
- hint=ENUM hint_string="Red:10,Green:20,Blue:30" usage=DEFAULT|SCRIPT_VARIABLE
+var test_hard_array_int: Array = Array[int]([])
+ hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_hard_array_string: Array = Array[String]([])
+ hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_variant_array_int: Array = Array[int]([])
+ hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_variant_packed_int32_array: PackedInt32Array = PackedInt32Array()
+ hint=TYPE_STRING hint_string="int/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_variant_array_string: Array = Array[String]([])
+ hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
+var test_variant_packed_string_array: PackedStringArray = PackedStringArray()
+ hint=TYPE_STRING hint_string="String/ENUM:Red,Green,Blue" usage=DEFAULT|SCRIPT_VARIABLE
diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out
index baadcd4ee8..b3f9d0ca9c 100644
--- a/modules/gdscript/tests/scripts/parser/features/export_variable.out
+++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out
@@ -24,4 +24,4 @@ var test_node_path: NodePath = NodePath("hello")
var test_node: Node = null
hint=NODE_TYPE hint_string="Node" usage=DEFAULT|SCRIPT_VARIABLE
var test_node_array: Array = Array[Node]([])
- hint=TYPE_STRING hint_string="24/34:Node" usage=DEFAULT|SCRIPT_VARIABLE
+ hint=TYPE_STRING hint_string="Object/NODE_TYPE:Node" usage=DEFAULT|SCRIPT_VARIABLE
diff --git a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd
index 29d8501b78..193faab5d0 100644
--- a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd
+++ b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.gd
@@ -1,11 +1,23 @@
-class Player:
- var x = 3
+class_name TestStaticCalledOnInstance
+
+class Inner:
+ static func static_func():
+ pass
+
+static func static_func():
+ pass
func test():
- # These should not emit a warning.
- var _player = Player.new()
- print(String.num_uint64(8589934592)) # 2 ^ 33
+ print(String.num_uint64(8589934592))
+ var some_string := String()
+ print(some_string.num_uint64(8589934592)) # Warning.
+
+ TestStaticCalledOnInstance.static_func()
+ static_func()
+ self.static_func()
+ var other := TestStaticCalledOnInstance.new()
+ other.static_func() # Warning.
- # This should emit a warning.
- var some_string = String()
- print(some_string.num_uint64(8589934592)) # 2 ^ 33
+ Inner.static_func()
+ var inner := Inner.new()
+ inner.static_func() # Warning.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out
index 77994ce9ba..c00f3d093a 100644
--- a/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out
+++ b/modules/gdscript/tests/scripts/parser/warnings/static_called_on_instance.out
@@ -1,7 +1,15 @@
GDTEST_OK
>> WARNING
->> Line: 11
+>> Line: 13
>> STATIC_CALLED_ON_INSTANCE
>> The function "num_uint64()" is a static function but was called from an instance. Instead, it should be directly called from the type: "String.num_uint64()".
+>> WARNING
+>> Line: 19
+>> STATIC_CALLED_ON_INSTANCE
+>> The function "static_func()" is a static function but was called from an instance. Instead, it should be directly called from the type: "TestStaticCalledOnInstance.static_func()".
+>> WARNING
+>> Line: 23
+>> STATIC_CALLED_ON_INSTANCE
+>> The function "static_func()" is a static function but was called from an instance. Instead, it should be directly called from the type: "Inner.static_func()".
8589934592
8589934592
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd
index 809d0d28a9..809d0d28a9 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.gd
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out
index 27423ab8e7..27423ab8e7 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-equals-null.out
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_equals_null.out
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd
index f46afb0f18..f46afb0f18 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.gd
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out
index a11c47854a..a11c47854a 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-builtin-not-equals-null.out
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_builtin_not_equals_null.out
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd
index 7649062fda..7649062fda 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.gd
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out
index 639f6027b9..639f6027b9 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-null-equals-builtin.out
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_equals_builtin.out
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd
index 8d5f9df1b8..8d5f9df1b8 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.gd
diff --git a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out
index d1e332afba..d1e332afba 100644
--- a/modules/gdscript/tests/scripts/runtime/features/compare-null-not-equals-builtin.out
+++ b/modules/gdscript/tests/scripts/runtime/features/compare_null_not_equals_builtin.out
diff --git a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.gd b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd
index c774ebf83c..c774ebf83c 100644
--- a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.gd
diff --git a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.out b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out
index 04b4638adf..04b4638adf 100644
--- a/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on exit_block.out
+++ b/modules/gdscript/tests/scripts/runtime/features/reset_local_var_on_exit_block.out
diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.gd
index 691b611574..691b611574 100644
--- a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.gd
diff --git a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.out
index 5bc3dcf2db..5bc3dcf2db 100644
--- a/modules/gdscript/tests/scripts/runtime/features/standalone-calls-do-not-write-to-nil.out
+++ b/modules/gdscript/tests/scripts/runtime/features/standalone_calls_do_not_write_to_nil.out
diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd
index 31818c9d01..1cf46c179e 100644
--- a/modules/gdscript/tests/scripts/utils.notest.gd
+++ b/modules/gdscript/tests/scripts/utils.notest.gd
@@ -39,11 +39,46 @@ static func get_property_signature(property: Dictionary, base: Object = null, is
return result
+static func get_human_readable_hint_string(property: Dictionary) -> String:
+ if property.type >= TYPE_ARRAY and property.hint == PROPERTY_HINT_TYPE_STRING:
+ var type_hint_prefixes: String = ""
+ var hint_string: String = property.hint_string
+
+ while true:
+ if not hint_string.contains(":"):
+ push_error("Invalid PROPERTY_HINT_TYPE_STRING format.")
+ var elem_type_hint: String = hint_string.get_slice(":", 0)
+ hint_string = hint_string.substr(elem_type_hint.length() + 1)
+
+ var elem_type: int
+ var elem_hint: int
+
+ if elem_type_hint.is_valid_int():
+ elem_type = elem_type_hint.to_int()
+ type_hint_prefixes += type_string(elem_type) + ":"
+ else:
+ if elem_type_hint.count("/") != 1:
+ push_error("Invalid PROPERTY_HINT_TYPE_STRING format.")
+ elem_type = elem_type_hint.get_slice("/", 0).to_int()
+ elem_hint = elem_type_hint.get_slice("/", 1).to_int()
+ type_hint_prefixes += "%s/%s:" % [
+ type_string(elem_type),
+ get_property_hint_name(elem_hint).trim_prefix("PROPERTY_HINT_"),
+ ]
+
+ if elem_type < TYPE_ARRAY:
+ break
+
+ return type_hint_prefixes + hint_string
+
+ return property.hint_string
+
+
static func print_property_extended_info(property: Dictionary, base: Object = null, is_static: bool = false) -> void:
print(get_property_signature(property, base, is_static))
print(' hint=%s hint_string="%s" usage=%s' % [
get_property_hint_name(property.hint).trim_prefix("PROPERTY_HINT_"),
- str(property.hint_string).c_escape(),
+ get_human_readable_hint_string(property),
get_property_usage_string(property.usage).replace("PROPERTY_USAGE_", ""),
])
diff --git a/modules/gdscript/tests/test_completion.h b/modules/gdscript/tests/test_completion.h
index fd6b5321e6..ac9ffcd915 100644
--- a/modules/gdscript/tests/test_completion.h
+++ b/modules/gdscript/tests/test_completion.h
@@ -139,7 +139,7 @@ static void test_directory(const String &p_dir) {
Node *owner = nullptr;
if (conf.has_section_key("input", "scene")) {
- Ref<PackedScene> scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene");
+ Ref<PackedScene> scene = ResourceLoader::load(conf.get_value("input", "scene"), "PackedScene", ResourceFormatLoader::CACHE_MODE_IGNORE_DEEP);
if (scene.is_valid()) {
owner = scene->instantiate();
}