summaryrefslogtreecommitdiff
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/SCsub2
-rw-r--r--modules/gdscript/doc_classes/@GDScript.xml16
-rw-r--r--modules/gdscript/doc_classes/GDScript.xml2
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.cpp106
-rw-r--r--modules/gdscript/editor/gdscript_highlighter.h5
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.cpp4
-rw-r--r--modules/gdscript/editor/gdscript_translation_parser_plugin.h4
-rw-r--r--modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd29
-rw-r--r--modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd32
-rw-r--r--modules/gdscript/editor_templates/EditorPlugin/plugin.gd11
-rw-r--r--modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd7
-rw-r--r--modules/gdscript/editor_templates/Node/default.gd11
-rw-r--r--modules/gdscript/editor_templates/Object/empty.gd3
-rw-r--r--modules/gdscript/editor_templates/SCsub16
-rw-r--r--modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd41
-rw-r--r--modules/gdscript/gdscript.cpp91
-rw-r--r--modules/gdscript/gdscript.h106
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp118
-rw-r--r--modules/gdscript/gdscript_analyzer.h4
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp5
-rw-r--r--modules/gdscript/gdscript_byte_codegen.h4
-rw-r--r--modules/gdscript/gdscript_cache.cpp10
-rw-r--r--modules/gdscript/gdscript_cache.h4
-rw-r--r--modules/gdscript/gdscript_codegen.h4
-rw-r--r--modules/gdscript/gdscript_compiler.cpp100
-rw-r--r--modules/gdscript/gdscript_compiler.h4
-rw-r--r--modules/gdscript/gdscript_disassembler.cpp4
-rw-r--r--modules/gdscript/gdscript_editor.cpp162
-rw-r--r--modules/gdscript/gdscript_function.cpp4
-rw-r--r--modules/gdscript/gdscript_function.h7
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp4
-rw-r--r--modules/gdscript/gdscript_lambda_callable.h4
-rw-r--r--modules/gdscript/gdscript_parser.cpp169
-rw-r--r--modules/gdscript/gdscript_parser.h11
-rw-r--r--modules/gdscript/gdscript_tokenizer.cpp22
-rw-r--r--modules/gdscript/gdscript_tokenizer.h5
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp23
-rw-r--r--modules/gdscript/gdscript_utility_functions.h4
-rw-r--r--modules/gdscript/gdscript_vm.cpp47
-rw-r--r--modules/gdscript/gdscript_warning.cpp11
-rw-r--r--modules/gdscript/gdscript_warning.h5
-rw-r--r--modules/gdscript/icons/GDScriptInternal.svg1
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.cpp6
-rw-r--r--modules/gdscript/language_server/gdscript_extend_parser.h4
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.cpp6
-rw-r--r--modules/gdscript/language_server/gdscript_language_protocol.h6
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.cpp4
-rw-r--r--modules/gdscript/language_server/gdscript_language_server.h8
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp7
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.h4
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.cpp12
-rw-r--r--modules/gdscript/language_server/gdscript_workspace.h4
-rw-r--r--modules/gdscript/language_server/lsp.hpp90
-rw-r--r--modules/gdscript/register_types.cpp4
-rw-r--r--modules/gdscript/register_types.h4
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.cpp16
-rw-r--r--modules/gdscript/tests/gdscript_test_runner.h6
-rw-r--r--modules/gdscript/tests/gdscript_test_runner_suite.h4
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd9
-rw-r--r--modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out2
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd15
-rw-r--r--modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out4
-rw-r--r--modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out2
-rw-r--r--modules/gdscript/tests/scripts/parser/features/signal_declaration.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd2
-rw-r--r--modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out9
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/params_default_values.gd35
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/params_default_values.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/stringify.gd2
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp4
-rw-r--r--modules/gdscript/tests/test_gdscript.h4
71 files changed, 1038 insertions, 465 deletions
diff --git a/modules/gdscript/SCsub b/modules/gdscript/SCsub
index 5c8cbdf869..c6121ec7fe 100644
--- a/modules/gdscript/SCsub
+++ b/modules/gdscript/SCsub
@@ -21,3 +21,5 @@ if env["tools"]:
if env["tests"]:
env_gdscript.Append(CPPDEFINES=["TESTS_ENABLED"])
env_gdscript.add_source_files(env.modules_sources, "./tests/*.cpp")
+
+SConscript("editor_templates/SCsub")
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml
index 631ee4d895..33f4198ac1 100644
--- a/modules/gdscript/doc_classes/@GDScript.xml
+++ b/modules/gdscript/doc_classes/@GDScript.xml
@@ -4,10 +4,10 @@
Built-in GDScript functions.
</brief_description>
<description>
- List of core built-in GDScript functions. Math functions and other utilities. Everything else is provided by objects. (Keywords: builtin, built in, global functions.)
+ A list of GDScript-specific utility functions accessed in any script.
+ For the list of the global functions and constants see [@GlobalScope].
</description>
<tutorials>
- <link title="Random number generation">https://docs.godotengine.org/en/latest/tutorials/math/random_number_generation.html</link>
</tutorials>
<methods>
<method name="Color8">
@@ -98,6 +98,7 @@
[codeblock]
[{function:bar, line:12, source:res://script.gd}, {function:foo, line:9, source:res://script.gd}, {function:_ready, line:6, source:res://script.gd}]
[/codeblock]
+ [b]Note:[/b] Not supported for calling from threads. Instead, this will return an empty array.
</description>
</method>
<method name="inst2dict">
@@ -160,17 +161,24 @@
<method name="print_debug" qualifiers="vararg">
<return type="void" />
<description>
- Like [method @GlobalScope.print], but prints only when used in debug mode.
+ Like [method @GlobalScope.print], but includes the current stack frame when running with the debugger turned on.
+ Output in the console would look something like this:
+ [codeblock]
+ Test print
+ At: res://test.gd:15:_process()
+ [/codeblock]
+ [b]Note:[/b] Not supported for calling from threads. Instead of the stack frame, this will print the thread ID.
</description>
</method>
<method name="print_stack">
<return type="void" />
<description>
- Prints a stack track at code location, only works when running with debugger turned on.
+ Prints a stack trace at the current code location. Only works when running with debugger turned on.
Output in the console would look something like this:
[codeblock]
Frame 0 - res://test.gd:16 in function '_process'
[/codeblock]
+ [b]Note:[/b] Not supported for calling from threads. Instead of the stack trace, this will print the thread ID.
</description>
</method>
<method name="range" qualifiers="vararg">
diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml
index 0a448ed88c..5acb29e748 100644
--- a/modules/gdscript/doc_classes/GDScript.xml
+++ b/modules/gdscript/doc_classes/GDScript.xml
@@ -8,7 +8,7 @@
[method new] creates a new instance of the script. [method Object.set_script] extends an existing object, if that object's class matches one of the script's base classes.
</description>
<tutorials>
- <link title="GDScript documentation index">https://docs.godotengine.org/en/latest/tutorials/scripting/gdscript/index.html</link>
+ <link title="GDScript documentation index">$DOCS_URL/tutorials/scripting/gdscript/index.html</link>
</tutorials>
<methods>
<method name="get_as_byte_code" qualifiers="const">
diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp
index 6529154e5c..5cc295bbab 100644
--- a/modules/gdscript/editor/gdscript_highlighter.cpp
+++ b/modules/gdscript/editor/gdscript_highlighter.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -60,7 +60,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
bool in_keyword = false;
bool in_word = false;
bool in_function_name = false;
+ bool in_lambda = false;
bool in_variable_declaration = false;
+ bool in_signal_declaration = false;
bool in_function_args = false;
bool in_member_variable = false;
bool in_node_path = false;
@@ -105,12 +107,15 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
/* color regions */
if (is_a_symbol || in_region != -1) {
int from = j;
- for (; from < line_length; from++) {
- if (str[from] == '\\') {
- from++;
- continue;
+
+ if (in_region == -1) {
+ for (; from < line_length; from++) {
+ if (str[from] == '\\') {
+ from++;
+ continue;
+ }
+ break;
}
- break;
}
if (from != line_length) {
@@ -142,6 +147,12 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
/* check if it's the whole line */
if (end_key_length == 0 || color_regions[c].line_only || from + end_key_length > line_length) {
+ if (from + end_key_length > line_length) {
+ // If it's key length and there is a '\', dont skip to highlight esc chars.
+ if (str.find("\\", from) >= 0) {
+ break;
+ }
+ }
prev_color = color_regions[in_region].color;
highlighter_info["color"] = color_regions[c].color;
color_map[j] = highlighter_info;
@@ -161,13 +172,25 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
/* if we are in one find the end key */
if (in_region != -1) {
+ Color region_color = color_regions[in_region].color;
+ if (in_node_path && (color_regions[in_region].start_key == "\"" || color_regions[in_region].start_key == "\'")) {
+ region_color = node_path_color;
+ }
+
+ prev_color = region_color;
+ highlighter_info["color"] = region_color;
+ color_map[j] = highlighter_info;
+
/* search the line */
int region_end_index = -1;
int end_key_length = color_regions[in_region].end_key.length();
const char32_t *end_key = color_regions[in_region].end_key.get_data();
for (; from < line_length; from++) {
if (line_length - from < end_key_length) {
- break;
+ // Don't break if '\' to highlight esc chars.
+ if (str.find("\\", from) < 0) {
+ break;
+ }
}
if (!is_symbol(str[from])) {
@@ -175,7 +198,16 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
if (str[from] == '\\') {
+ Dictionary escape_char_highlighter_info;
+ escape_char_highlighter_info["color"] = symbol_color;
+ color_map[from] = escape_char_highlighter_info;
+
from++;
+
+ Dictionary region_continue_highlighter_info;
+ prev_color = region_color;
+ region_continue_highlighter_info["color"] = region_color;
+ color_map[from + 1] = region_continue_highlighter_info;
continue;
}
@@ -192,10 +224,6 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
}
- prev_color = color_regions[in_region].color;
- highlighter_info["color"] = color_regions[in_region].color;
- color_map[j] = highlighter_info;
-
previous_type = REGION;
previous_text = "";
previous_column = j;
@@ -289,20 +317,36 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
if (!in_function_name && in_word && !in_keyword) {
- int k = j;
- while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
- k++;
- }
+ if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::SIGNAL)) {
+ in_signal_declaration = true;
+ } else {
+ int k = j;
+ while (k < str.length() && !is_symbol(str[k]) && str[k] != '\t' && str[k] != ' ') {
+ k++;
+ }
- // check for space between name and bracket
- while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
- k++;
- }
+ // check for space between name and bracket
+ while (k < str.length() && (str[k] == '\t' || str[k] == ' ')) {
+ k++;
+ }
- if (str[k] == '(') {
- in_function_name = true;
- } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) {
- in_variable_declaration = true;
+ if (str[k] == '(') {
+ in_function_name = true;
+ } else if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::VAR)) {
+ in_variable_declaration = true;
+ }
+
+ // Check for lambda.
+ if (in_function_name && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) {
+ k = j - 1;
+ while (k > 0 && (str[k] == '\t' || str[k] == ' ')) {
+ k--;
+ }
+
+ if (str[k] == ':') {
+ in_lambda = true;
+ }
+ }
}
}
@@ -348,7 +392,9 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
}
in_variable_declaration = false;
+ in_signal_declaration = false;
in_function_name = false;
+ in_lambda = false;
in_member_variable = false;
}
@@ -376,10 +422,14 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
} else if (in_member_variable) {
next_type = MEMBER;
color = member_color;
+ } else if (in_signal_declaration) {
+ next_type = SIGNAL;
+
+ color = member_color;
} else if (in_function_name) {
next_type = FUNCTION;
- if (previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) {
+ if (!in_lambda && previous_text == GDScriptTokenizer::get_token_name(GDScriptTokenizer::Token::FUNC)) {
color = function_definition_color;
} else {
color = function_color;
@@ -413,7 +463,7 @@ Dictionary GDScriptSyntaxHighlighter::_get_line_syntax_highlighting_impl(int p_l
previous_column = j;
// ignore if just whitespace
- if (text != "") {
+ if (!text.is_empty()) {
previous_text = text;
}
}
@@ -509,7 +559,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
for (const String &comment : comments) {
String beg = comment.get_slice(" ", 0);
String end = comment.get_slice_count(" ") > 1 ? comment.get_slice(" ", 1) : String();
- add_color_region(beg, end, comment_color, end == "");
+ add_color_region(beg, end, comment_color, end.is_empty());
}
/* Strings */
@@ -519,7 +569,7 @@ void GDScriptSyntaxHighlighter::_update_cache() {
for (const String &string : strings) {
String beg = string.get_slice(" ", 0);
String end = string.get_slice_count(" ") > 1 ? string.get_slice(" ", 1) : String();
- add_color_region(beg, end, string_color, end == "");
+ add_color_region(beg, end, string_color, end.is_empty());
}
const Ref<Script> script = _get_edited_resource();
diff --git a/modules/gdscript/editor/gdscript_highlighter.h b/modules/gdscript/editor/gdscript_highlighter.h
index 07f21b34ae..1ae0d72896 100644
--- a/modules/gdscript/editor/gdscript_highlighter.h
+++ b/modules/gdscript/editor/gdscript_highlighter.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -58,6 +58,7 @@ private:
SYMBOL,
NUMBER,
FUNCTION,
+ SIGNAL,
KEYWORD,
MEMBER,
IDENTIFIER,
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
index 9d0d91162c..a8f4483cf4 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/editor/gdscript_translation_parser_plugin.h b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
index caa80fc24c..e7b40aa367 100644
--- a/modules/gdscript/editor/gdscript_translation_parser_plugin.h
+++ b/modules/gdscript/editor/gdscript_translation_parser_plugin.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd b/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd
new file mode 100644
index 0000000000..0824d894c5
--- /dev/null
+++ b/modules/gdscript/editor_templates/CharacterBody2D/basic_movement.gd
@@ -0,0 +1,29 @@
+# meta-description: Classic movement for gravity games (platformer, ...)
+
+extends _BASE_
+
+const SPEED: float = 300.0
+const JUMP_FORCE: float = -400.0
+
+# Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
+var gravity: int = ProjectSettings.get_setting("physics/2d/default_gravity")
+
+
+func _physics_process(delta: float) -> void:
+ # Add the gravity.
+ if not is_on_floor():
+ motion_velocity.y += gravity * delta
+
+ # Handle Jump.
+ if Input.is_action_just_pressed("ui_accept") and is_on_floor():
+ motion_velocity.y = JUMP_FORCE
+
+ # Get the input direction and handle the movement/deceleration.
+ # As good practice, you should replace UI actions with custom gameplay actions.
+ var direction := Input.get_axis("ui_left", "ui_right")
+ if direction:
+ motion_velocity.x = direction * SPEED
+ else:
+ motion_velocity.x = move_toward(motion_velocity.x, 0, SPEED)
+
+ move_and_slide()
diff --git a/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd b/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd
new file mode 100644
index 0000000000..ce6d67ae84
--- /dev/null
+++ b/modules/gdscript/editor_templates/CharacterBody3D/basic_movement.gd
@@ -0,0 +1,32 @@
+# meta-description: Classic movement for gravity games (FPS, TPS, ...)
+
+extends _BASE_
+
+const SPEED: float = 5.0
+const JUMP_FORCE: float = 4.5
+
+# Get the gravity from the project settings to be synced with RigidDynamicBody nodes.
+var gravity: float = ProjectSettings.get_setting("physics/3d/default_gravity")
+
+
+func _physics_process(delta: float) -> void:
+ # Add the gravity.
+ if not is_on_floor():
+ motion_velocity.y -= gravity * delta
+
+ # Handle Jump.
+ if Input.is_action_just_pressed("ui_accept") and is_on_floor():
+ motion_velocity.y = JUMP_FORCE
+
+ # Get the input direction and handle the movement/deceleration.
+ # As good practice, you should replace UI actions with custom gameplay actions.
+ var input_dir := Input.get_vector("ui_left", "ui_right", "ui_up", "ui_down")
+ var direction := (transform.basis * Vector3(input_dir.x, 0, input_dir.y)).normalized()
+ if direction:
+ motion_velocity.x = direction.x * SPEED
+ motion_velocity.z = direction.z * SPEED
+ else:
+ motion_velocity.x = move_toward(motion_velocity.x, 0, SPEED)
+ motion_velocity.z = move_toward(motion_velocity.z, 0, SPEED)
+
+ move_and_slide()
diff --git a/modules/gdscript/editor_templates/EditorPlugin/plugin.gd b/modules/gdscript/editor_templates/EditorPlugin/plugin.gd
new file mode 100644
index 0000000000..8614bb8b17
--- /dev/null
+++ b/modules/gdscript/editor_templates/EditorPlugin/plugin.gd
@@ -0,0 +1,11 @@
+# meta-description: Basic plugin template
+@tool
+extends EditorPlugin
+
+func _enter_tree() -> void:
+ # Initialization of the plugin goes here.
+ pass
+
+func _exit_tree() -> void:
+ # Clean-up of the plugin goes here.
+ pass
diff --git a/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd b/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd
new file mode 100644
index 0000000000..fdb174c7ed
--- /dev/null
+++ b/modules/gdscript/editor_templates/EditorScript/basic_editor_script.gd
@@ -0,0 +1,7 @@
+# meta-description: Basic editor script template
+@tool
+extends EditorScript
+
+func _run() -> void:
+ # Called when the script is executed (using File -> Run in Script Editor).
+ pass
diff --git a/modules/gdscript/editor_templates/Node/default.gd b/modules/gdscript/editor_templates/Node/default.gd
new file mode 100644
index 0000000000..ee5c0b99cc
--- /dev/null
+++ b/modules/gdscript/editor_templates/Node/default.gd
@@ -0,0 +1,11 @@
+# meta-description: Base template for Node with default Godot cycle methods
+
+extends _BASE_
+
+# Called when the node enters the scene tree for the first time.
+func _ready() -> void:
+ pass # Replace with function body.
+
+# Called every frame. 'delta' is the elapsed time since the previous frame.
+func _process(delta: float) -> void:
+ pass
diff --git a/modules/gdscript/editor_templates/Object/empty.gd b/modules/gdscript/editor_templates/Object/empty.gd
new file mode 100644
index 0000000000..387786b0a4
--- /dev/null
+++ b/modules/gdscript/editor_templates/Object/empty.gd
@@ -0,0 +1,3 @@
+# meta-description: Empty template suitable for all Objects
+
+extends _BASE_
diff --git a/modules/gdscript/editor_templates/SCsub b/modules/gdscript/editor_templates/SCsub
new file mode 100644
index 0000000000..2266ef2d01
--- /dev/null
+++ b/modules/gdscript/editor_templates/SCsub
@@ -0,0 +1,16 @@
+#!/usr/bin/env python
+
+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."),
+ suffix=".h",
+ src_suffix=".gd",
+)
+
+# Template files
+templates_sources = Glob("*/*.gd")
+
+env.Alias("editor_template_gd", [env.MakeGDTemplateBuilder("templates.gen.h", templates_sources)])
diff --git a/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd
new file mode 100644
index 0000000000..27383b878d
--- /dev/null
+++ b/modules/gdscript/editor_templates/VisualShaderNodeCustom/basic.gd
@@ -0,0 +1,41 @@
+# meta-description: Visual shader's node plugin template
+
+@tool
+extends _BASE_
+class_name VisualShaderNode_CLASS_
+
+func _get_name() -> String:
+ return "_CLASS_"
+
+func _get_category() -> String:
+ return ""
+
+func _get_description() -> String:
+ return ""
+
+func _get_return_icon_type() -> int:
+ return PORT_TYPE_SCALAR
+
+func _get_input_port_count() -> int:
+ return 0
+
+func _get_input_port_name(port: int) -> String:
+ return ""
+
+func _get_input_port_type(port: int) -> int:
+ return PORT_TYPE_SCALAR
+
+func _get_output_port_count() -> int:
+ return 1
+
+func _get_output_port_name(port: int) -> String:
+ return "result"
+
+func _get_output_port_type(port: int) -> int:
+ return PORT_TYPE_SCALAR
+
+func _get_global_code(mode: Shader.Mode) -> String:
+ return ""
+
+func _get_code(input_vars: Array[String], output_vars: Array[String], mode: Shader.Mode, type: VisualShader.Type) -> String:
+ return output_vars[0] + " = 0.0;"
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index e9d3749a8d..84db97625b 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -49,6 +49,10 @@
#include "tests/gdscript_test_runner.h"
#endif
+#ifdef TOOLS_ENABLED
+#include "editor/editor_settings.h"
+#endif
+
///////////////////////////
GDScriptNativeClass::GDScriptNativeClass(const StringName &p_name) {
@@ -361,7 +365,7 @@ ScriptInstance *GDScript::instance_create(Object *p_this) {
if (top->native.is_valid()) {
if (!ClassDB::is_parent_class(p_this->get_class_name(), top->native->get_name())) {
if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
+ GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), 1, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type: '" + p_this->get_class() + "'");
}
ERR_FAIL_V_MSG(nullptr, "Script inherits from native type '" + String(top->native->get_name()) + "', so it can't be instantiated in object of type '" + p_this->get_class() + "'" + ".");
}
@@ -389,7 +393,7 @@ bool GDScript::instance_has(const Object *p_this) const {
}
bool GDScript::has_source_code() const {
- return source != "";
+ return !source.is_empty();
}
String GDScript::get_source_code() const {
@@ -427,7 +431,7 @@ void GDScript::_add_doc(const DocData::ClassDoc &p_inner_class) {
} else {
for (int i = 0; i < docs.size(); i++) {
if (docs[i].name == p_inner_class.name) {
- docs.remove(i);
+ docs.remove_at(i);
break;
}
}
@@ -458,7 +462,7 @@ void GDScript::_update_doc() {
doc.is_script_doc = true;
if (base.is_valid() && base->is_valid()) {
- if (base->doc.name != String()) {
+ if (!base->doc.name.is_empty()) {
doc.inherits = base->doc.name;
} else {
doc.inherits = base->get_instance_base_type();
@@ -472,7 +476,7 @@ void GDScript::_update_doc() {
doc.tutorials = doc_tutorials;
for (const KeyValue<String, DocData::EnumDoc> &E : doc_enums) {
- if (E.value.description != "") {
+ if (!E.value.description.is_empty()) {
doc.enums[E.key] = E.value.description;
}
}
@@ -616,11 +620,11 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
String basedir = path;
- if (basedir == "") {
+ if (basedir.is_empty()) {
basedir = get_path();
}
- if (basedir != "") {
+ if (!basedir.is_empty()) {
basedir = basedir.get_base_dir();
}
@@ -642,7 +646,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
path = c->extends_path;
if (path.is_relative_path()) {
String base = get_path();
- if (base == "" || base.is_relative_path()) {
+ if (base.is_empty() || base.is_relative_path()) {
ERR_PRINT(("Could not resolve relative path for parent class: " + path).utf8().get_data());
} else {
path = base.get_base_dir().plus_file(path);
@@ -656,7 +660,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc
}
}
- if (path != "") {
+ if (!path.is_empty()) {
if (path != get_path()) {
Ref<GDScript> bf = ResourceLoader::load(path);
@@ -789,6 +793,14 @@ void GDScript::_set_subclass_path(Ref<GDScript> &p_sc, const String &p_path) {
}
}
+String GDScript::_get_debug_path() const {
+ if (is_built_in() && !get_name().is_empty()) {
+ return get_name() + " (" + get_path().get_slice("::", 0) + ")";
+ } else {
+ return get_path();
+ }
+}
+
Error GDScript::reload(bool p_keep_state) {
bool has_instances;
{
@@ -801,18 +813,24 @@ Error GDScript::reload(bool p_keep_state) {
String basedir = path;
- if (basedir == "") {
+ if (basedir.is_empty()) {
basedir = get_path();
}
- if (basedir != "") {
+ if (!basedir.is_empty()) {
basedir = basedir.get_base_dir();
}
- if (source.find("%BASE%") != -1) {
- //loading a template, don't parse
+// Loading a template, don't parse.
+#ifdef TOOLS_ENABLED
+ if (basedir.begins_with(EditorSettings::get_singleton()->get_project_script_templates_dir())) {
+ return OK;
+ }
+#else
+ if (source.find("_BASE_") != -1) {
return OK;
}
+#endif
{
String source_path = path;
@@ -832,10 +850,10 @@ Error GDScript::reload(bool p_keep_state) {
Error err = parser.parse(source, path, false);
if (err) {
if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
+ GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
}
// TODO: Show all error messages.
- _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), parser.get_errors().front()->get().line, ("Parse Error: " + parser.get_errors().front()->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
ERR_FAIL_V(ERR_PARSE_ERROR);
}
@@ -844,12 +862,12 @@ Error GDScript::reload(bool p_keep_state) {
if (err) {
if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
+ GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), parser.get_errors().front()->get().line, "Parser Error: " + parser.get_errors().front()->get().message);
}
const List<GDScriptParser::ParserError>::Element *e = parser.get_errors().front();
while (e != nullptr) {
- _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), e->get().line, ("Parse Error: " + e->get().message).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
e = e->next();
}
ERR_FAIL_V(ERR_PARSE_ERROR);
@@ -867,9 +885,9 @@ Error GDScript::reload(bool p_keep_state) {
if (err) {
if (can_run) {
if (EngineDebugger::is_active()) {
- GDScriptLanguage::get_singleton()->debug_break_parse(get_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
+ GDScriptLanguage::get_singleton()->debug_break_parse(_get_debug_path(), compiler.get_error_line(), "Parser Error: " + compiler.get_error());
}
- _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error("GDScript::reload", path.is_empty() ? "built-in" : (const char *)path.utf8().get_data(), compiler.get_error_line(), ("Compile Error: " + compiler.get_error()).utf8().get_data(), false, ERR_HANDLER_SCRIPT);
ERR_FAIL_V(ERR_COMPILATION_FAILED);
} else {
return err;
@@ -879,7 +897,7 @@ Error GDScript::reload(bool p_keep_state) {
for (const GDScriptWarning &warning : parser.get_warnings()) {
if (EngineDebugger::is_active()) {
Vector<ScriptLanguage::StackInfo> si;
- EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), ERR_HANDLER_WARNING, si);
+ EngineDebugger::get_script_debugger()->send_error("", get_path(), warning.start_line, warning.get_name(), warning.get_message(), false, ERR_HANDLER_WARNING, si);
}
}
#endif
@@ -979,7 +997,7 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) {
}
void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const {
- p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NOEDITOR | PROPERTY_USAGE_INTERNAL));
+ p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL));
}
void GDScript::_bind_methods() {
@@ -1114,7 +1132,7 @@ String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript)
String class_name;
while (p_gdscript) {
- if (class_name == "") {
+ if (class_name.is_empty()) {
class_name = p_gdscript->get_script_class_name();
} else {
class_name = p_gdscript->get_script_class_name() + "." + class_name;
@@ -1257,6 +1275,8 @@ bool GDScriptInstance::set(const StringName &p_name, const Variant &p_value) {
call(member->setter, &val, 1, err);
if (err.error == Callable::CallError::CALL_OK) {
return true; //function exists, call was successful
+ } else {
+ return false;
}
} else {
if (member->data_type.has_type) {
@@ -1423,7 +1443,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const
pinfo.type = Variant::Type(d["type"].operator int());
ERR_CONTINUE(pinfo.type < 0 || pinfo.type >= Variant::VARIANT_MAX);
pinfo.name = d["name"];
- ERR_CONTINUE(pinfo.name == "");
+ ERR_CONTINUE(pinfo.name.is_empty());
if (d.has("hint")) {
pinfo.hint = PropertyHint(d["hint"].operator int());
}
@@ -2040,15 +2060,15 @@ void GDScriptLanguage::get_reserved_words(List<String> *p_words) const {
bool GDScriptLanguage::is_control_flow_keyword(String p_keyword) const {
return p_keyword == "break" ||
- p_keyword == "continue" ||
- p_keyword == "elif" ||
- p_keyword == "else" ||
- p_keyword == "if" ||
- p_keyword == "for" ||
- p_keyword == "match" ||
- p_keyword == "pass" ||
- p_keyword == "return" ||
- p_keyword == "while";
+ p_keyword == "continue" ||
+ p_keyword == "elif" ||
+ p_keyword == "else" ||
+ p_keyword == "if" ||
+ p_keyword == "for" ||
+ p_keyword == "match" ||
+ p_keyword == "pass" ||
+ p_keyword == "return" ||
+ p_keyword == "while";
}
bool GDScriptLanguage::handles_global_class_type(const String &p_type) const {
@@ -2121,7 +2141,7 @@ String GDScriptLanguage::get_global_class_name(const String &p_path, String *r_b
const GDScriptParser::ClassNode *inner_class = subclass->members[i].m_class;
if (inner_class->identifier->name == extend_classes[0]) {
- extend_classes.remove(0);
+ extend_classes.remove_at(0);
found = true;
subclass = inner_class;
break;
@@ -2186,7 +2206,6 @@ GDScriptLanguage::GDScriptLanguage() {
GLOBAL_DEF("debug/gdscript/warnings/enable", true);
GLOBAL_DEF("debug/gdscript/warnings/treat_warnings_as_errors", false);
GLOBAL_DEF("debug/gdscript/warnings/exclude_addons", true);
- GLOBAL_DEF("debug/gdscript/completion/autocomplete_setters_and_getters", false);
for (int i = 0; i < (int)GDScriptWarning::WARNING_MAX; i++) {
String warning = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)i).to_lower();
bool default_enabled = !warning.begins_with("unsafe_");
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 791f8a1431..2b43e6d21b 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -135,6 +135,7 @@ class GDScript : public Script {
GDScriptInstance *_create_instance(const Variant **p_args, int p_argcount, Object *p_owner, bool p_is_ref_counted, Callable::CallError &r_error);
void _set_subclass_path(Ref<GDScript> &p_sc, const String &p_path);
+ String _get_debug_path() const;
#ifdef TOOLS_ENABLED
Set<PlaceHolderScriptInstance *> placeholders;
@@ -395,7 +396,7 @@ public:
_debug_call_stack_pos--;
}
- virtual Vector<StackInfo> debug_get_current_stack_info() {
+ virtual Vector<StackInfo> debug_get_current_stack_info() override {
if (Thread::get_main_id() != Thread::get_caller_id()) {
return Vector<StackInfo>();
}
@@ -429,77 +430,76 @@ public:
_FORCE_INLINE_ static GDScriptLanguage *get_singleton() { return singleton; }
- virtual String get_name() const;
+ virtual String get_name() const override;
/* LANGUAGE FUNCTIONS */
- virtual void init();
- virtual String get_type() const;
- virtual String get_extension() const;
- virtual Error execute_file(const String &p_path);
- virtual void finish();
+ virtual void init() override;
+ virtual String get_type() const override;
+ virtual String get_extension() const override;
+ virtual Error execute_file(const String &p_path) override;
+ virtual void finish() override;
/* EDITOR FUNCTIONS */
- virtual void get_reserved_words(List<String> *p_words) const;
- virtual bool is_control_flow_keyword(String p_keywords) const;
- virtual void get_comment_delimiters(List<String> *p_delimiters) const;
- virtual void get_string_delimiters(List<String> *p_delimiters) const;
- virtual String _get_processed_template(const String &p_template, const String &p_base_class_name) const;
- virtual Ref<Script> get_template(const String &p_class_name, const String &p_base_class_name) const;
- virtual bool is_using_templates();
- virtual void make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script);
- virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const;
- virtual Script *create_script() const;
- virtual bool has_named_classes() const;
- virtual bool supports_builtin_mode() const;
- virtual bool supports_documentation() const;
- virtual bool can_inherit_from_file() const { return true; }
- virtual int find_function(const String &p_function, const String &p_code) const;
- virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const;
- virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint);
+ virtual void get_reserved_words(List<String> *p_words) const override;
+ virtual bool is_control_flow_keyword(String p_keywords) const override;
+ virtual void get_comment_delimiters(List<String> *p_delimiters) const override;
+ virtual void get_string_delimiters(List<String> *p_delimiters) const override;
+ virtual bool is_using_templates() override;
+ virtual Ref<Script> make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const override;
+ virtual Vector<ScriptTemplate> get_built_in_templates(StringName p_object) override;
+ virtual bool validate(const String &p_script, const String &p_path = "", List<String> *r_functions = nullptr, List<ScriptLanguage::ScriptError> *r_errors = nullptr, List<ScriptLanguage::Warning> *r_warnings = nullptr, Set<int> *r_safe_lines = nullptr) const override;
+ virtual Script *create_script() const override;
+ virtual bool has_named_classes() const override;
+ virtual bool supports_builtin_mode() const override;
+ virtual bool supports_documentation() const override;
+ virtual bool can_inherit_from_file() const override { return true; }
+ virtual int find_function(const String &p_function, const String &p_code) const override;
+ virtual String make_function(const String &p_class, const String &p_name, const PackedStringArray &p_args) const override;
+ virtual Error complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptCodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) override;
#ifdef TOOLS_ENABLED
- virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result);
+ virtual Error lookup_code(const String &p_code, const String &p_symbol, const String &p_path, Object *p_owner, LookupResult &r_result) override;
#endif
virtual String _get_indentation() const;
- virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const;
- virtual void add_global_constant(const StringName &p_variable, const Variant &p_value);
- virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value);
- virtual void remove_named_global_constant(const StringName &p_name);
+ virtual void auto_indent_code(String &p_code, int p_from_line, int p_to_line) const override;
+ virtual void add_global_constant(const StringName &p_variable, const Variant &p_value) override;
+ virtual void add_named_global_constant(const StringName &p_name, const Variant &p_value) override;
+ virtual void remove_named_global_constant(const StringName &p_name) override;
/* DEBUGGER FUNCTIONS */
- virtual String debug_get_error() const;
- virtual int debug_get_stack_level_count() const;
- virtual int debug_get_stack_level_line(int p_level) const;
- virtual String debug_get_stack_level_function(int p_level) const;
- virtual String debug_get_stack_level_source(int p_level) const;
- virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
- virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
- virtual ScriptInstance *debug_get_stack_level_instance(int p_level);
- virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1);
- virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1);
+ virtual String debug_get_error() const override;
+ virtual int debug_get_stack_level_count() const override;
+ virtual int debug_get_stack_level_line(int p_level) const override;
+ virtual String debug_get_stack_level_function(int p_level) const override;
+ virtual String debug_get_stack_level_source(int p_level) const override;
+ virtual void debug_get_stack_level_locals(int p_level, List<String> *p_locals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override;
+ virtual void debug_get_stack_level_members(int p_level, List<String> *p_members, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override;
+ virtual ScriptInstance *debug_get_stack_level_instance(int p_level) override;
+ virtual void debug_get_globals(List<String> *p_globals, List<Variant> *p_values, int p_max_subitems = -1, int p_max_depth = -1) override;
+ virtual String debug_parse_stack_level_expression(int p_level, const String &p_expression, int p_max_subitems = -1, int p_max_depth = -1) override;
- virtual void reload_all_scripts();
- virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload);
+ virtual void reload_all_scripts() override;
+ virtual void reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) override;
- virtual void frame();
+ virtual void frame() override;
- virtual void get_public_functions(List<MethodInfo> *p_functions) const;
- virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const;
+ virtual void get_public_functions(List<MethodInfo> *p_functions) const override;
+ virtual void get_public_constants(List<Pair<String, Variant>> *p_constants) const override;
- virtual void profiling_start();
- virtual void profiling_stop();
+ virtual void profiling_start() override;
+ virtual void profiling_stop() override;
- virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max);
- virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max);
+ virtual int profiling_get_accumulated_data(ProfilingInfo *p_info_arr, int p_info_max) override;
+ virtual int profiling_get_frame_data(ProfilingInfo *p_info_arr, int p_info_max) override;
/* LOADER FUNCTIONS */
- virtual void get_recognized_extensions(List<String> *p_extensions) const;
+ virtual void get_recognized_extensions(List<String> *p_extensions) const override;
/* GLOBAL CLASSES */
- virtual bool handles_global_class_type(const String &p_type) const;
- virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const;
+ virtual bool handles_global_class_type(const String &p_type) const override;
+ virtual String get_global_class_name(const String &p_path, String *r_base_type = nullptr, String *r_icon_path = nullptr) const override;
void add_orphan_subclass(const String &p_qualified_name, const ObjectID &p_subclass);
Ref<GDScript> get_orphan_subclass(const String &p_qualified_name);
diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp
index a5b75cbfe4..0d295c3a51 100644
--- a/modules/gdscript/gdscript_analyzer.cpp
+++ b/modules/gdscript/gdscript_analyzer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -484,7 +484,7 @@ GDScriptParser::DataType GDScriptAnalyzer::resolve_datatype(GDScriptParser::Type
result = parser->head->get_datatype();
} else {
Ref<GDScriptParserRef> ref = get_parser_for(ScriptServer::get_global_class_path(first));
- if (ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
+ if (!ref.is_valid() || ref->raise_status(GDScriptParserRef::INTERFACE_SOLVED) != OK) {
push_error(vformat(R"(Could not parse global class "%s" from "%s".)", first, ScriptServer::get_global_class_path(first)), p_type);
return GDScriptParser::DataType();
}
@@ -881,12 +881,23 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
for (int i = 0; i < p_class->members.size(); i++) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
if (member.type == GDScriptParser::ClassNode::Member::FUNCTION) {
- resolve_function_body(member.function);
-
// Apply annotations.
for (GDScriptParser::AnnotationNode *&E : member.function->annotations) {
E->apply(parser, member.function);
}
+
+#ifdef DEBUG_ENABLED
+ Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ for (uint32_t ignored_warning : member.function->ignored_warnings) {
+ parser->ignored_warning_codes.insert(ignored_warning);
+ }
+#endif // DEBUG_ENABLED
+
+ resolve_function_body(member.function);
+
+#ifdef DEBUG_ENABLED
+ parser->ignored_warning_codes = previously_ignored;
+#endif // DEBUG_ENABLED
} else if (member.type == GDScriptParser::ClassNode::Member::VARIABLE && member.variable->property != GDScriptParser::VariableNode::PROP_NONE) {
if (member.variable->property == GDScriptParser::VariableNode::PROP_INLINE) {
if (member.variable->getter != nullptr) {
@@ -925,6 +936,10 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
GDScriptParser::ClassNode::Member member = p_class->members[i];
if (member.type == GDScriptParser::ClassNode::Member::VARIABLE) {
#ifdef DEBUG_ENABLED
+ Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ for (uint32_t ignored_warning : member.function->ignored_warnings) {
+ parser->ignored_warning_codes.insert(ignored_warning);
+ }
if (member.variable->usages == 0 && String(member.variable->identifier->name).begins_with("_")) {
parser->push_warning(member.variable->identifier, GDScriptWarning::UNUSED_PRIVATE_CLASS_VARIABLE, member.variable->identifier->name);
}
@@ -980,7 +995,7 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
has_valid_setter = true;
#ifdef DEBUG_ENABLED
- if (member.variable->datatype.builtin_type == Variant::INT && setter_function->return_type->datatype.builtin_type == Variant::FLOAT) {
+ if (member.variable->datatype.builtin_type == Variant::FLOAT && setter_function->parameters[0]->datatype.builtin_type == Variant::INT) {
parser->push_warning(member.variable, GDScriptWarning::NARROWING_CONVERSION);
}
#endif
@@ -992,6 +1007,9 @@ void GDScriptAnalyzer::resolve_class_body(GDScriptParser::ClassNode *p_class) {
push_error(vformat(R"(Getter with type "%s" cannot be used along with setter of type "%s".)", getter_function->datatype.to_string(), setter_function->parameters[0]->datatype.to_string()), member.variable);
}
}
+#ifdef DEBUG_ENABLED
+ parser->ignored_warning_codes = previously_ignored;
+#endif // DEBUG_ENABLED
}
}
}
@@ -1186,7 +1204,23 @@ void GDScriptAnalyzer::decide_suite_type(GDScriptParser::Node *p_suite, GDScript
void GDScriptAnalyzer::resolve_suite(GDScriptParser::SuiteNode *p_suite) {
for (int i = 0; i < p_suite->statements.size(); i++) {
GDScriptParser::Node *stmt = p_suite->statements[i];
+ for (GDScriptParser::AnnotationNode *&annotation : stmt->annotations) {
+ annotation->apply(parser, stmt);
+ }
+
+#ifdef DEBUG_ENABLED
+ Set<uint32_t> previously_ignored = parser->ignored_warning_codes;
+ for (uint32_t ignored_warning : stmt->ignored_warnings) {
+ parser->ignored_warning_codes.insert(ignored_warning);
+ }
+#endif // DEBUG_ENABLED
+
resolve_node(stmt);
+
+#ifdef DEBUG_ENABLED
+ parser->ignored_warning_codes = previously_ignored;
+#endif // DEBUG_ENABLED
+
decide_suite_type(p_suite, stmt);
}
}
@@ -1834,13 +1868,14 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
push_error("Cannot assign a new value to a constant.", p_assignment->assignee);
}
- if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) {
- bool compatible = true;
- GDScriptParser::DataType op_type = assigned_value_type;
- if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
- op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value);
- }
+ bool compatible = true;
+ GDScriptParser::DataType op_type = assigned_value_type;
+ if (p_assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ op_type = get_operation_type(p_assignment->variant_op, assignee_type, assigned_value_type, compatible, p_assignment->assigned_value);
+ }
+ p_assignment->set_datatype(op_type);
+ if (!assignee_type.is_variant() && assigned_value_type.is_hard_type()) {
if (compatible) {
compatible = is_type_compatible(assignee_type, op_type, true);
if (!compatible) {
@@ -1865,7 +1900,7 @@ void GDScriptAnalyzer::reduce_assignment(GDScriptParser::AssignmentNode *p_assig
if (assignee_type.has_no_type() || assigned_value_type.is_variant()) {
mark_node_unsafe(p_assignment);
- if (assignee_type.is_hard_type()) {
+ if (assignee_type.is_hard_type() && !assignee_type.is_variant()) {
p_assignment->use_conversion_assign = true;
}
}
@@ -2606,7 +2641,8 @@ void GDScriptAnalyzer::reduce_identifier_from_base(GDScriptParser::IdentifierNod
GDScriptParser::DataType result;
result.type_source = GDScriptParser::DataType::ANNOTATED_EXPLICIT;
result.kind = GDScriptParser::DataType::ENUM_VALUE;
- result.builtin_type = base.builtin_type;
+ result.is_constant = true;
+ result.builtin_type = Variant::INT;
result.native_type = base.native_type;
result.enum_type = name;
p_identifier->set_datatype(result);
@@ -3001,7 +3037,7 @@ void GDScriptAnalyzer::reduce_preload(GDScriptParser::PreloadNode *p_preload) {
// TODO: Don't load if validating: use completion cache.
p_preload->resource = ResourceLoader::load(p_preload->resolved_path);
if (p_preload->resource.is_null()) {
- push_error(vformat(R"(Could not p_preload resource file "%s".)", p_preload->resolved_path), p_preload->path);
+ push_error(vformat(R"(Could not preload resource file "%s".)", p_preload->resolved_path), p_preload->path);
}
}
}
@@ -3691,9 +3727,27 @@ bool GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p
bool GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_local, const String &p_context) {
const StringName &name = p_local->name;
GDScriptParser::DataType base = parser->current_class->get_datatype();
-
GDScriptParser::ClassNode *base_class = base.class_type;
+ {
+ List<MethodInfo> gdscript_funcs;
+ GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
+
+ for (MethodInfo &info : gdscript_funcs) {
+ if (info.name == name) {
+ parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
+ return true;
+ }
+ }
+ if (Variant::has_utility_function(name)) {
+ parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "built-in function");
+ return true;
+ } else if (ClassDB::class_exists(name)) {
+ parser->push_warning(p_local, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_context, name, "global class");
+ return true;
+ }
+ }
+
while (base_class != nullptr) {
if (base_class->has_member(name)) {
parser->push_warning(p_local, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_local->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()));
@@ -3735,6 +3789,7 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
// Unary version.
GDScriptParser::DataType nil_type;
nil_type.builtin_type = Variant::NIL;
+ nil_type.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
return get_operation_type(p_operation, p_a, nil_type, r_valid, p_source);
}
@@ -3744,20 +3799,31 @@ GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator
Variant::Type a_type = p_a.builtin_type;
Variant::Type b_type = p_b.builtin_type;
-
Variant::ValidatedOperatorEvaluator op_eval = Variant::get_validated_operator_evaluator(p_operation, a_type, b_type);
- if (op_eval == nullptr) {
+ bool hard_operation = p_a.is_hard_type() && p_b.is_hard_type();
+ bool validated = op_eval != nullptr;
+
+ if (hard_operation && !validated) {
r_valid = false;
return result;
+ } else if (hard_operation && validated) {
+ r_valid = true;
+ result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
+ result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type);
+ } else if (!hard_operation && !validated) {
+ r_valid = true;
+ result.type_source = GDScriptParser::DataType::UNDETECTED;
+ result.kind = GDScriptParser::DataType::VARIANT;
+ result.builtin_type = Variant::NIL;
+ } else if (!hard_operation && validated) {
+ r_valid = true;
+ result.type_source = GDScriptParser::DataType::INFERRED;
+ result.kind = GDScriptParser::DataType::BUILTIN;
+ result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type);
}
- r_valid = true;
- result.type_source = GDScriptParser::DataType::ANNOTATED_INFERRED;
-
- result.kind = GDScriptParser::DataType::BUILTIN;
- result.builtin_type = Variant::get_operator_return_type(p_operation, a_type, b_type);
-
return result;
}
@@ -3938,7 +4004,9 @@ Ref<GDScriptParserRef> GDScriptAnalyzer::get_parser_for(const String &p_path) {
} else {
Error err = OK;
ref = GDScriptCache::get_parser(p_path, GDScriptParserRef::EMPTY, err, parser->script_path);
- depended_parsers[p_path] = ref;
+ if (ref.is_valid()) {
+ depended_parsers[p_path] = ref;
+ }
}
return ref;
diff --git a/modules/gdscript/gdscript_analyzer.h b/modules/gdscript/gdscript_analyzer.h
index ce4525190b..4cee5cb44a 100644
--- a/modules/gdscript/gdscript_analyzer.h
+++ b/modules/gdscript/gdscript_analyzer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp
index 6a7e4278d2..82aa14795e 100644
--- a/modules/gdscript/gdscript_byte_codegen.cpp
+++ b/modules/gdscript/gdscript_byte_codegen.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -688,6 +688,7 @@ void GDScriptByteCodeGenerator::write_ternary_false_expr(const Address &p_expr)
void GDScriptByteCodeGenerator::write_end_ternary() {
patch_jump(ternary_jump_skip_pos.back()->get());
ternary_jump_skip_pos.pop_back();
+ ternary_result.pop_back();
}
void GDScriptByteCodeGenerator::write_set(const Address &p_target, const Address &p_index, const Address &p_source) {
diff --git a/modules/gdscript/gdscript_byte_codegen.h b/modules/gdscript/gdscript_byte_codegen.h
index fbbf5802fd..db15dc55ef 100644
--- a/modules/gdscript/gdscript_byte_codegen.h
+++ b/modules/gdscript/gdscript_byte_codegen.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp
index bb0d9e9e9b..4ac5a4a60e 100644
--- a/modules/gdscript/gdscript_cache.cpp
+++ b/modules/gdscript/gdscript_cache.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -117,7 +117,7 @@ void GDScriptCache::remove_script(const String &p_path) {
Ref<GDScriptParserRef> GDScriptCache::get_parser(const String &p_path, GDScriptParserRef::Status p_status, Error &r_error, const String &p_owner) {
MutexLock lock(singleton->lock);
Ref<GDScriptParserRef> ref;
- if (p_owner != String()) {
+ if (!p_owner.is_empty()) {
singleton->dependencies[p_owner].insert(p_path);
}
if (singleton->parser_map.has(p_path)) {
@@ -163,7 +163,7 @@ String GDScriptCache::get_source_code(const String &p_path) {
Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const String &p_owner) {
MutexLock lock(singleton->lock);
- if (p_owner != String()) {
+ if (!p_owner.is_empty()) {
singleton->dependencies[p_owner].insert(p_path);
}
if (singleton->full_gdscript_cache.has(p_path)) {
@@ -186,7 +186,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, const Stri
Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_error, const String &p_owner) {
MutexLock lock(singleton->lock);
- if (p_owner != String()) {
+ if (!p_owner.is_empty()) {
singleton->dependencies[p_owner].insert(p_path);
}
diff --git a/modules/gdscript/gdscript_cache.h b/modules/gdscript/gdscript_cache.h
index 9fb661d031..3ce976ee14 100644
--- a/modules/gdscript/gdscript_cache.h
+++ b/modules/gdscript/gdscript_cache.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_codegen.h b/modules/gdscript/gdscript_codegen.h
index e6ecc92d55..4542dd94ae 100644
--- a/modules/gdscript/gdscript_codegen.h
+++ b/modules/gdscript/gdscript_codegen.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp
index ab0fe5c37d..ca125d3a07 100644
--- a/modules/gdscript/gdscript_compiler.cpp
+++ b/modules/gdscript/gdscript_compiler.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -65,7 +65,7 @@ bool GDScriptCompiler::_is_class_member_property(GDScript *owner, const StringNa
}
void GDScriptCompiler::_set_error(const String &p_error, const GDScriptParser::Node *p_node) {
- if (error != "") {
+ if (!error.is_empty()) {
return;
}
@@ -882,7 +882,13 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
#endif
/* Find chain of sets */
- StringName assign_property;
+ StringName assign_class_member_property;
+
+ GDScriptCodeGenerator::Address target_member_property;
+ bool is_member_property = false;
+ bool member_property_has_setter = false;
+ bool member_property_is_in_setter = false;
+ StringName member_property_setter_function;
List<const GDScriptParser::SubscriptNode *> chain;
@@ -892,11 +898,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
while (true) {
chain.push_back(n);
if (n->base->type != GDScriptParser::Node::SUBSCRIPT) {
- // Check for a built-in property.
+ // Check for a property.
if (n->base->type == GDScriptParser::Node::IDENTIFIER) {
GDScriptParser::IdentifierNode *identifier = static_cast<GDScriptParser::IdentifierNode *>(n->base);
- if (_is_class_member_property(codegen, identifier->name)) {
- assign_property = identifier->name;
+ StringName var_name = identifier->name;
+ if (_is_class_member_property(codegen, var_name)) {
+ assign_class_member_property = var_name;
+ } else if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) {
+ is_member_property = true;
+ member_property_setter_function = codegen.script->member_indices[var_name].setter;
+ member_property_has_setter = member_property_setter_function != StringName();
+ member_property_is_in_setter = member_property_has_setter && member_property_setter_function == codegen.function_name;
+ target_member_property.mode = GDScriptCodeGenerator::Address::MEMBER;
+ target_member_property.address = codegen.script->member_indices[var_name].index;
+ target_member_property.type = codegen.script->member_indices[var_name].data_type;
}
}
break;
@@ -969,17 +984,19 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
// Perform operator if any.
if (assignment->operation != GDScriptParser::AssignmentNode::OP_NONE) {
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype()));
GDScriptCodeGenerator::Address value = codegen.add_temporary(_gdtype_from_datatype(subscript->get_datatype()));
if (subscript->is_attribute) {
gen->write_get_named(value, name, prev_base);
} else {
gen->write_get(value, key, prev_base);
}
- gen->write_binary_operator(value, assignment->variant_op, value, assigned);
+ gen->write_binary_operator(op_result, assignment->variant_op, value, assigned);
+ gen->pop_temporary();
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
gen->pop_temporary();
}
- assigned = value;
+ assigned = op_result;
}
// Perform assignment.
@@ -1013,10 +1030,20 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
assigned = info.base;
}
- // If this is a local member, also assign to it.
+ // If this is a class member property, also assign to it.
// This allow things like: position.x += 2.0
- if (assign_property != StringName()) {
- gen->write_set_member(assigned, assign_property);
+ if (assign_class_member_property != StringName()) {
+ gen->write_set_member(assigned, assign_class_member_property);
+ }
+ // Same as above but for members
+ if (is_member_property) {
+ if (member_property_has_setter && !member_property_is_in_setter) {
+ Vector<GDScriptCodeGenerator::Address> args;
+ args.push_back(assigned);
+ gen->write_call(GDScriptCodeGenerator::Address(), GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::SELF), member_property_setter_function, args);
+ } else {
+ gen->write_assign(target_member_property, assigned);
+ }
}
if (assigned.mode == GDScriptCodeGenerator::Address::TEMPORARY) {
@@ -1035,8 +1062,8 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
StringName name = static_cast<GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
if (has_operation) {
- GDScriptCodeGenerator::Address op_result = codegen.add_temporary();
- GDScriptCodeGenerator::Address member = codegen.add_temporary();
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype()));
+ GDScriptCodeGenerator::Address member = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype()));
gen->write_get_member(member, name);
gen->write_binary_operator(op_result, assignment->variant_op, member, assigned_value);
gen->pop_temporary(); // Pop member temp.
@@ -1053,29 +1080,26 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
}
} else {
// Regular assignment.
- GDScriptCodeGenerator::Address target;
-
+ ERR_FAIL_COND_V_MSG(assignment->assignee->type != GDScriptParser::Node::IDENTIFIER, GDScriptCodeGenerator::Address(), "Expected the assignee to be an identifier here.");
+ GDScriptCodeGenerator::Address member;
+ bool is_member = false;
bool has_setter = false;
bool is_in_setter = false;
StringName setter_function;
- if (assignment->assignee->type == GDScriptParser::Node::IDENTIFIER) {
- StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
- if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) {
- setter_function = codegen.script->member_indices[var_name].setter;
- if (setter_function != StringName()) {
- has_setter = true;
- is_in_setter = setter_function == codegen.function_name;
- target.mode = GDScriptCodeGenerator::Address::MEMBER;
- target.address = codegen.script->member_indices[var_name].index;
- }
- }
+ StringName var_name = static_cast<const GDScriptParser::IdentifierNode *>(assignment->assignee)->name;
+ if (!codegen.locals.has(var_name) && codegen.script->member_indices.has(var_name)) {
+ is_member = true;
+ setter_function = codegen.script->member_indices[var_name].setter;
+ has_setter = setter_function != StringName();
+ is_in_setter = has_setter && setter_function == codegen.function_name;
+ member.mode = GDScriptCodeGenerator::Address::MEMBER;
+ member.address = codegen.script->member_indices[var_name].index;
+ member.type = codegen.script->member_indices[var_name].data_type;
}
- if (has_setter) {
- if (!is_in_setter) {
- // Store stack slot for the temp value.
- target = codegen.add_temporary(_gdtype_from_datatype(assignment->assignee->get_datatype()));
- }
+ GDScriptCodeGenerator::Address target;
+ if (is_member) {
+ target = member; // _parse_expression could call its getter, but we want to know the actual address
} else {
target = _parse_expression(codegen, r_error, assignment->assignee);
if (r_error) {
@@ -1092,7 +1116,7 @@ GDScriptCodeGenerator::Address GDScriptCompiler::_parse_expression(CodeGen &code
bool has_operation = assignment->operation != GDScriptParser::AssignmentNode::OP_NONE;
if (has_operation) {
// Perform operation.
- GDScriptCodeGenerator::Address op_result = codegen.add_temporary();
+ GDScriptCodeGenerator::Address op_result = codegen.add_temporary(_gdtype_from_datatype(assignment->get_datatype()));
GDScriptCodeGenerator::Address og_value = _parse_expression(codegen, r_error, assignment->assignee);
gen->write_binary_operator(op_result, assignment->variant_op, og_value, assigned_value);
to_assign = op_result;
@@ -1995,7 +2019,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
codegen.generator->start_parameters();
for (int i = p_func->parameters.size() - optional_parameters; i < p_func->parameters.size(); i++) {
const GDScriptParser::ParameterNode *parameter = p_func->parameters[i];
- GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value, true);
+ GDScriptCodeGenerator::Address src_addr = _parse_expression(codegen, r_error, parameter->default_value);
if (r_error) {
memdelete(codegen.generator);
return nullptr;
@@ -2020,7 +2044,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
if (EngineDebugger::is_active()) {
String signature;
// Path.
- if (p_script->get_path() != String()) {
+ if (!p_script->get_path().is_empty()) {
signature += p_script->get_path();
}
// Location.
@@ -2069,7 +2093,7 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_
if (p_func) {
// if no return statement -> return type is void not unresolved Variant
if (p_func->body->has_return) {
- gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype());
+ gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script);
} else {
gd_function->return_type = GDScriptDataType();
gd_function->return_type.has_type = true;
@@ -2158,7 +2182,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->tool = parser->is_tool();
p_script->name = p_class->identifier ? p_class->identifier->name : "";
- if (p_script->name != "") {
+ if (!p_script->name.is_empty()) {
if (ClassDB::class_exists(p_script->name) && ClassDB::is_class_exposed(p_script->name)) {
_set_error("The class '" + p_script->name + "' shadows a native class", p_class);
return ERR_ALREADY_EXISTS;
@@ -2287,7 +2311,7 @@ Error GDScriptCompiler::_parse_class_level(GDScript *p_script, const GDScriptPar
p_script->constants.insert(name, constant->initializer->reduced_value);
#ifdef TOOLS_ENABLED
p_script->member_lines[name] = constant->start_line;
- if (constant->doc_description != String()) {
+ if (!constant->doc_description.is_empty()) {
p_script->doc_constants[name] = constant->doc_description;
}
#endif
diff --git a/modules/gdscript/gdscript_compiler.h b/modules/gdscript/gdscript_compiler.h
index 7d5bee93ac..8d71437344 100644
--- a/modules/gdscript/gdscript_compiler.h
+++ b/modules/gdscript/gdscript_compiler.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp
index 9287df2ea0..cc0be94a9e 100644
--- a/modules/gdscript/gdscript_disassembler.cpp
+++ b/modules/gdscript/gdscript_disassembler.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp
index 71d2699c2e..d10e120410 100644
--- a/modules/gdscript/gdscript_editor.cpp
+++ b/modules/gdscript/gdscript_editor.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -33,6 +33,7 @@
#include "core/config/engine.h"
#include "core/core_constants.h"
#include "core/io/file_access.h"
+#include "editor_templates/templates.gen.h"
#include "gdscript_analyzer.h"
#include "gdscript_compiler.h"
#include "gdscript_parser.h"
@@ -55,68 +56,44 @@ void GDScriptLanguage::get_string_delimiters(List<String> *p_delimiters) const {
p_delimiters->push_back("\"\"\" \"\"\"");
}
-String GDScriptLanguage::_get_processed_template(const String &p_template, const String &p_base_class_name) const {
- String processed_template = p_template;
+bool GDScriptLanguage::is_using_templates() {
+ return true;
+}
+Ref<Script> GDScriptLanguage::make_template(const String &p_template, const String &p_class_name, const String &p_base_class_name) const {
+ Ref<GDScript> script;
+ script.instantiate();
+ String processed_template = p_template;
#ifdef TOOLS_ENABLED
- if (EDITOR_DEF("text_editor/completion/add_type_hints", false)) {
- processed_template = processed_template.replace("%INT_TYPE%", ": int");
- processed_template = processed_template.replace("%STRING_TYPE%", ": String");
- processed_template = processed_template.replace("%FLOAT_TYPE%", ": float");
- processed_template = processed_template.replace("%VOID_RETURN%", " -> void");
- } else {
- processed_template = processed_template.replace("%INT_TYPE%", "");
- processed_template = processed_template.replace("%STRING_TYPE%", "");
- processed_template = processed_template.replace("%FLOAT_TYPE%", "");
- processed_template = processed_template.replace("%VOID_RETURN%", "");
+ if (!EDITOR_DEF("text_editor/completion/add_type_hints", false)) {
+ processed_template = processed_template.replace(": int", "")
+ .replace(": String", "")
+ .replace(": float", "")
+ .replace(":=", "=")
+ .replace(" -> void", "");
}
#else
- processed_template = processed_template.replace("%INT_TYPE%", "");
- processed_template = processed_template.replace("%STRING_TYPE%", "");
- processed_template = processed_template.replace("%FLOAT_TYPE%", "");
- processed_template = processed_template.replace("%VOID_RETURN%", "");
+ processed_template = processed_template.replace(": int", "")
+ .replace(": String", "")
+ .replace(": float", "")
+ .replace(" -> void", "");
#endif
- processed_template = processed_template.replace("%BASE%", p_base_class_name);
- processed_template = processed_template.replace("%TS%", _get_indentation());
-
- return processed_template;
-}
-
-Ref<Script> GDScriptLanguage::get_template(const String &p_class_name, const String &p_base_class_name) const {
- String _template = "extends %BASE%\n"
- "\n"
- "\n"
- "# Declare member variables here. Examples:\n"
- "# var a%INT_TYPE% = 2\n"
- "# var b%STRING_TYPE% = \"text\"\n"
- "\n"
- "\n"
- "# Called when the node enters the scene tree for the first time.\n"
- "func _ready()%VOID_RETURN%:\n"
- "%TS%pass # Replace with function body.\n"
- "\n"
- "\n"
- "# Called every frame. 'delta' is the elapsed time since the previous frame.\n"
- "#func _process(delta%FLOAT_TYPE%)%VOID_RETURN%:\n"
- "#%TS%pass\n";
-
- _template = _get_processed_template(_template, p_base_class_name);
-
- Ref<GDScript> script;
- script.instantiate();
- script->set_source_code(_template);
-
+ processed_template = processed_template.replace("_BASE_", p_base_class_name)
+ .replace("_CLASS_", p_class_name)
+ .replace("_TS_", _get_indentation());
+ script->set_source_code(processed_template);
return script;
}
-bool GDScriptLanguage::is_using_templates() {
- return true;
-}
-
-void GDScriptLanguage::make_template(const String &p_class_name, const String &p_base_class_name, Ref<Script> &p_script) {
- String _template = _get_processed_template(p_script->get_source_code(), p_base_class_name);
- p_script->set_source_code(_template);
+Vector<ScriptLanguage::ScriptTemplate> GDScriptLanguage::get_built_in_templates(StringName p_object) {
+ Vector<ScriptLanguage::ScriptTemplate> templates;
+ for (int i = 0; i < TEMPLATES_ARRAY_SIZE; i++) {
+ if (TEMPLATES[i].inherit == p_object) {
+ templates.append(TEMPLATES[i]);
+ }
+ }
+ return templates;
}
static void get_function_names_recursively(const GDScriptParser::ClassNode *p_class, const String &p_prefix, Map<int, String> &r_funcs) {
@@ -236,7 +213,7 @@ Script *GDScriptLanguage::create_script() const {
/* DEBUGGER FUNCTIONS */
bool GDScriptLanguage::debug_break_parse(const String &p_file, int p_line, const String &p_error) {
- //break because of parse error
+ // break because of parse error
if (EngineDebugger::is_active() && Thread::get_caller_id() == Thread::get_main_id()) {
_debug_parse_err_line = p_line;
@@ -603,12 +580,50 @@ static String _make_arguments_hint(const GDScriptParser::FunctionNode *p_functio
if (par->default_value) {
String def_val = "<unknown>";
- if (par->default_value->type == GDScriptParser::Node::LITERAL) {
- const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value);
- def_val = literal->value.get_construct_string();
- } else if (par->default_value->type == GDScriptParser::Node::IDENTIFIER) {
- const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value);
- def_val = id->name.operator String();
+ switch (par->default_value->type) {
+ case GDScriptParser::Node::LITERAL: {
+ const GDScriptParser::LiteralNode *literal = static_cast<const GDScriptParser::LiteralNode *>(par->default_value);
+ def_val = literal->value.get_construct_string();
+ } break;
+ case GDScriptParser::Node::IDENTIFIER: {
+ const GDScriptParser::IdentifierNode *id = static_cast<const GDScriptParser::IdentifierNode *>(par->default_value);
+ def_val = id->name.operator String();
+ } break;
+ case GDScriptParser::Node::CALL: {
+ const GDScriptParser::CallNode *call = static_cast<const GDScriptParser::CallNode *>(par->default_value);
+ if (call->is_constant && call->reduced) {
+ def_val = call->function_name.operator String() + call->reduced_value.operator String();
+ }
+ } break;
+ case GDScriptParser::Node::ARRAY: {
+ const GDScriptParser::ArrayNode *arr = static_cast<const GDScriptParser::ArrayNode *>(par->default_value);
+ if (arr->is_constant && arr->reduced) {
+ def_val = arr->reduced_value.operator String();
+ }
+ } break;
+ case GDScriptParser::Node::DICTIONARY: {
+ const GDScriptParser::DictionaryNode *dict = static_cast<const GDScriptParser::DictionaryNode *>(par->default_value);
+ if (dict->is_constant && dict->reduced) {
+ def_val = dict->reduced_value.operator String();
+ }
+ } break;
+ case GDScriptParser::Node::SUBSCRIPT: {
+ const GDScriptParser::SubscriptNode *sub = static_cast<const GDScriptParser::SubscriptNode *>(par->default_value);
+ if (sub->is_constant) {
+ if (sub->datatype.kind == GDScriptParser::DataType::ENUM_VALUE) {
+ def_val = sub->get_datatype().to_string();
+ } else if (sub->reduced) {
+ const Variant::Type vt = sub->reduced_value.get_type();
+ if (vt == Variant::Type::NIL || vt == Variant::Type::FLOAT || vt == Variant::Type::INT || vt == Variant::Type::STRING || vt == Variant::Type::STRING_NAME || vt == Variant::Type::BOOL || vt == Variant::Type::NODE_PATH) {
+ def_val = sub->reduced_value.operator String();
+ } else {
+ def_val = sub->get_datatype().to_string() + sub->reduced_value.operator String();
+ }
+ }
+ }
+ } break;
+ default:
+ break;
}
arghint += " = " + def_val;
}
@@ -669,6 +684,11 @@ static void _find_annotation_arguments(const GDScriptParser::AnnotationNode *p_a
ScriptCodeCompletionOption option(E, ScriptCodeCompletionOption::KIND_CLASS);
r_result.insert(option.display, option);
}
+ } else if (p_annotation->name == "@warning_ignore") {
+ for (int warning_code = 0; warning_code < GDScriptWarning::WARNING_MAX; warning_code++) {
+ ScriptCodeCompletionOption warning(GDScriptWarning::get_name_from_code((GDScriptWarning::Code)warning_code).to_lower(), ScriptCodeCompletionOption::KIND_PLAIN_TEXT);
+ r_result.insert(warning.display, warning);
+ }
}
}
@@ -946,8 +966,7 @@ static void _find_identifiers_in_base(const GDScriptCompletionIdentifier &p_base
if (!_static || Engine::get_singleton()->has_singleton(type)) {
List<MethodInfo> methods;
- bool is_autocompleting_getters = GLOBAL_GET("debug/gdscript/completion/autocomplete_setters_and_getters").booleanize();
- ClassDB::get_method_list(type, &methods, false, !is_autocompleting_getters);
+ ClassDB::get_method_list(type, &methods, false, true);
for (const MethodInfo &E : methods) {
if (E.name.begins_with("_")) {
continue;
@@ -1182,6 +1201,10 @@ static bool _guess_method_return_type_from_base(GDScriptParser::CompletionContex
static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context, const GDScriptParser::ExpressionNode *p_expression, GDScriptCompletionIdentifier &r_type) {
bool found = false;
+ if (p_expression == nullptr) {
+ return false;
+ }
+
if (p_expression->is_constant) {
// Already has a value, so just use that.
r_type = _type_from_variant(p_expression->reduced_value);
@@ -1365,7 +1388,7 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
String arg1 = args[0];
if (arg1.begins_with("/root/")) {
String which = arg1.get_slice("/", 2);
- if (which != "") {
+ if (!which.is_empty()) {
// Try singletons first
if (GDScriptLanguage::get_singleton()->get_named_globals_map().has(which)) {
r_type = _type_from_variant(GDScriptLanguage::get_singleton()->get_named_globals_map()[which]);
@@ -1383,8 +1406,8 @@ static bool _guess_expression_type(GDScriptParser::CompletionContext &p_context,
}
if (!script.ends_with(".gd")) {
- //not a script, try find the script anyway,
- //may have some success
+ // not a script, try find the script anyway,
+ // may have some success
script = script.get_basename() + ".gd";
}
@@ -2753,7 +2776,7 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t
}
String st = l.substr(tc, l.length()).strip_edges();
- if (st == "" || st.begins_with("#")) {
+ if (st.is_empty() || st.begins_with("#")) {
continue; //ignore!
}
@@ -2770,7 +2793,7 @@ void GDScriptLanguage::auto_indent_code(String &p_code, int p_from_line, int p_t
}
if (indent_stack.size() && indent_stack.back()->get() != tc) {
- indent_stack.push_back(tc); //this is not right but gets the job done
+ indent_stack.push_back(tc); // this is not right but gets the job done
}
}
@@ -2810,6 +2833,7 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co
r_result.type = ScriptLanguage::LookupResult::RESULT_SCRIPT_LOCATION;
r_result.location = base_type.class_type->get_member(p_symbol).get_line();
r_result.class_path = base_type.script_path;
+ r_result.script = GDScriptCache::get_shallow_script(r_result.class_path);
return OK;
}
base_type = base_type.class_type->base_type;
diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp
index a3f0c7dfef..f1877df326 100644
--- a/modules/gdscript/gdscript_function.cpp
+++ b/modules/gdscript/gdscript_function.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h
index 9d076a8e4c..db663ca48f 100644
--- a/modules/gdscript/gdscript_function.h
+++ b/modules/gdscript/gdscript_function.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -192,7 +192,7 @@ public:
GDScriptDataType() = default;
- GDScriptDataType &operator=(const GDScriptDataType &p_other) {
+ void operator=(const GDScriptDataType &p_other) {
kind = p_other.kind;
has_type = p_other.has_type;
builtin_type = p_other.builtin_type;
@@ -203,7 +203,6 @@ public:
if (p_other.has_container_element_type()) {
set_container_element_type(p_other.get_container_element_type());
}
- return *this;
}
GDScriptDataType(const GDScriptDataType &p_other) {
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index 0bc109b6e1..baf93e1098 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_lambda_callable.h b/modules/gdscript/gdscript_lambda_callable.h
index 336778d549..f6a54a1a2f 100644
--- a/modules/gdscript/gdscript_lambda_callable.h
+++ b/modules/gdscript/gdscript_lambda_callable.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp
index 7ddb9b93b4..5e210074ed 100644
--- a/modules/gdscript/gdscript_parser.cpp
+++ b/modules/gdscript/gdscript_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -39,6 +39,7 @@
#ifdef DEBUG_ENABLED
#include "core/os/os.h"
#include "core/string/string_builder.h"
+#include "gdscript_warning.h"
#endif // DEBUG_ENABLED
#ifdef TOOLS_ENABLED
@@ -132,9 +133,9 @@ GDScriptParser::GDScriptParser() {
register_annotation(MethodInfo("@export_flags_3d_render"), AnnotationInfo::VARIABLE, &GDScriptParser::export_annotations<PROPERTY_HINT_LAYERS_3D_RENDER, Variant::INT>);
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("@warning_ignore", { Variant::STRING, "warning" }), AnnotationInfo::CLASS | AnnotationInfo::VARIABLE | AnnotationInfo::SIGNAL | AnnotationInfo::CONSTANT | AnnotationInfo::FUNCTION | AnnotationInfo::STATEMENT, &GDScriptParser::warning_annotations, 0, true);
// Networking.
register_annotation(MethodInfo("@rpc", { Variant::STRING, "mode" }, { Variant::STRING, "sync" }, { Variant::STRING, "transfer_mode" }, { Variant::INT, "transfer_channel" }), AnnotationInfo::FUNCTION, &GDScriptParser::network_annotations<Multiplayer::RPC_MODE_AUTHORITY>, 4, true);
- // TODO: Warning annotations.
}
GDScriptParser::~GDScriptParser() {
@@ -196,6 +197,10 @@ void GDScriptParser::push_warning(const Node *p_source, GDScriptWarning::Code p_
return;
}
+ if (ignored_warning_codes.has(p_code)) {
+ return;
+ }
+
String warn_name = GDScriptWarning::get_name_from_code((GDScriptWarning::Code)p_code).to_lower();
if (ignored_warnings.has(warn_name)) {
return;
@@ -701,24 +706,21 @@ void GDScriptParser::parse_extends() {
template <class T>
void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)(), AnnotationInfo::TargetKind p_target, const String &p_member_kind) {
advance();
- T *member = (this->*p_parse_function)();
- if (member == nullptr) {
- return;
- }
+
#ifdef TOOLS_ENABLED
- int doc_comment_line = member->start_line - 1;
+ int doc_comment_line = previous.start_line - 1;
#endif // TOOLS_ENABLED
// Consume annotations.
+ List<AnnotationNode *> annotations;
while (!annotation_stack.is_empty()) {
AnnotationNode *last_annotation = annotation_stack.back()->get();
if (last_annotation->applies_to(p_target)) {
- member->annotations.push_front(last_annotation);
+ annotations.push_front(last_annotation);
annotation_stack.pop_back();
} else {
push_error(vformat(R"(Annotation "%s" cannot be applied to a %s.)", last_annotation->name, p_member_kind));
clear_unused_annotations();
- return;
}
#ifdef TOOLS_ENABLED
if (last_annotation->start_line == doc_comment_line) {
@@ -727,6 +729,16 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
#endif // TOOLS_ENABLED
}
+ T *member = (this->*p_parse_function)();
+ if (member == nullptr) {
+ return;
+ }
+
+ // Apply annotations.
+ for (AnnotationNode *&annotation : annotations) {
+ member->annotations.push_back(annotation);
+ }
+
#ifdef TOOLS_ENABLED
// Consume doc comments.
class_doc_line = MIN(class_doc_line, doc_comment_line - 1);
@@ -740,10 +752,26 @@ void GDScriptParser::parse_class_member(T *(GDScriptParser::*p_parse_function)()
#endif // TOOLS_ENABLED
if (member->identifier != nullptr) {
- // Enums may be unnamed.
- // TODO: Consider names in outer scope too, for constants and classes (and static functions?)
- if (current_class->members_indices.has(member->identifier->name)) {
- push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier);
+ if (!((String)member->identifier->name).is_empty()) { // Enums may be unnamed.
+
+#ifdef DEBUG_ENABLED
+ List<MethodInfo> gdscript_funcs;
+ GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
+ for (MethodInfo &info : gdscript_funcs) {
+ if (info.name == member->identifier->name) {
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
+ }
+ }
+ if (Variant::has_utility_function(member->identifier->name)) {
+ push_warning(member->identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, p_member_kind, member->identifier->name, "built-in function");
+ }
+#endif
+
+ if (current_class->members_indices.has(member->identifier->name)) {
+ push_error(vformat(R"(%s "%s" has the same name as a previously declared %s.)", p_member_kind.capitalize(), member->identifier->name, current_class->get_member(member->identifier->name).get_type_name()), member->identifier);
+ } else {
+ current_class->add_member(member);
+ }
} else {
current_class->add_member(member);
}
@@ -789,6 +817,8 @@ void GDScriptParser::parse_class_body(bool p_is_multiline) {
class_end = true;
break;
default:
+ // Display a completion with identifiers.
+ make_completion_context(COMPLETION_IDENTIFIER, nullptr);
push_error(vformat(R"(Unexpected "%s" in class body.)", current.get_name()));
advance();
break;
@@ -1145,13 +1175,31 @@ GDScriptParser::EnumNode *GDScriptParser::parse_enum() {
HashMap<StringName, int> elements;
+#ifdef DEBUG_ENABLED
+ List<MethodInfo> gdscript_funcs;
+ GDScriptLanguage::get_singleton()->get_public_functions(&gdscript_funcs);
+#endif
+
do {
if (check(GDScriptTokenizer::Token::BRACE_CLOSE)) {
break; // Allow trailing comma.
}
if (consume(GDScriptTokenizer::Token::IDENTIFIER, R"(Expected identifier for enum key.)")) {
EnumNode::Value item;
- item.identifier = parse_identifier();
+ GDScriptParser::IdentifierNode *identifier = parse_identifier();
+#ifdef DEBUG_ENABLED
+ for (MethodInfo &info : gdscript_funcs) {
+ if (info.name == identifier->name) {
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
+ }
+ }
+ if (Variant::has_utility_function(identifier->name)) {
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "built-in function");
+ } else if (ClassDB::class_exists(identifier->name)) {
+ push_warning(identifier, GDScriptWarning::SHADOWED_GLOBAL_IDENTIFIER, "enum member", identifier->name, "global class");
+ }
+#endif
+ item.identifier = identifier;
item.parent_enum = enum_node;
item.line = previous.start_line;
item.leftmost_column = previous.leftmost_column;
@@ -1473,6 +1521,8 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
bool unreachable = current_suite->has_return && !current_suite->has_unreachable_code;
#endif
+ bool is_annotation = false;
+
switch (current.type) {
case GDScriptTokenizer::Token::PASS:
advance();
@@ -1542,6 +1592,7 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
break;
case GDScriptTokenizer::Token::ANNOTATION: {
advance();
+ is_annotation = true;
AnnotationNode *annotation = parse_annotation(AnnotationInfo::STATEMENT);
if (annotation != nullptr) {
annotation_stack.push_back(annotation);
@@ -1582,6 +1633,18 @@ GDScriptParser::Node *GDScriptParser::parse_statement() {
}
}
+ // Apply annotations to statement.
+ while (!is_annotation && result != nullptr && !annotation_stack.is_empty()) {
+ AnnotationNode *last_annotation = annotation_stack.back()->get();
+ if (last_annotation->applies_to(AnnotationInfo::STATEMENT)) {
+ result->annotations.push_front(last_annotation);
+ annotation_stack.pop_back();
+ } else {
+ push_error(vformat(R"(Annotation "%s" cannot be applied to a statement.)", last_annotation->name));
+ clear_unused_annotations();
+ }
+ }
+
#ifdef DEBUG_ENABLED
if (unreachable && result != nullptr) {
current_suite->has_unreachable_code = true;
@@ -2774,6 +2837,23 @@ GDScriptParser::ExpressionNode *GDScriptParser::parse_get_node(ExpressionNode *p
get_node->chain.push_back(identifier);
} while (match(GDScriptTokenizer::Token::SLASH));
return get_node;
+ } else if (match(GDScriptTokenizer::Token::SLASH)) {
+ GetNodeNode *get_node = alloc_node<GetNodeNode>();
+ IdentifierNode *identifier_root = alloc_node<IdentifierNode>();
+ get_node->chain.push_back(identifier_root);
+ int chain_position = 0;
+ do {
+ make_completion_context(COMPLETION_GET_NODE, get_node, chain_position++);
+ if (!current.is_node_name()) {
+ push_error(R"(Expect node path after "/".)");
+ return nullptr;
+ }
+ advance();
+ IdentifierNode *identifier = alloc_node<IdentifierNode>();
+ identifier->name = previous.get_identifier();
+ get_node->chain.push_back(identifier);
+ } while (match(GDScriptTokenizer::Token::SLASH));
+ return get_node;
} else {
push_error(R"(Expect node path as string or identifier after "$".)");
return nullptr;
@@ -3018,7 +3098,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
if (!comments.has(p_line)) {
return;
}
- ERR_FAIL_COND(p_brief != "" || p_desc != "" || p_tutorials.size() != 0);
+ ERR_FAIL_COND(!p_brief.is_empty() || !p_desc.is_empty() || p_tutorials.size() != 0);
int line = p_line;
bool in_codeblock = false;
@@ -3050,7 +3130,7 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
String striped_line = doc_line.strip_edges();
// Set the read mode.
- if (striped_line.begins_with("@desc:") && p_desc == "") {
+ if (striped_line.begins_with("@desc:") && p_desc.is_empty()) {
mode = DESC;
striped_line = striped_line.trim_prefix("@desc:");
in_codeblock = _in_codeblock(doc_line, in_codeblock);
@@ -3068,9 +3148,9 @@ void GDScriptParser::get_class_doc_comment(int p_line, String &p_brief, String &
} else {
/* Syntax:
- @tutorial ( The Title Here ) : https://the.url/
- ^ open ^ close ^ colon ^ url
- */
+ * @tutorial ( The Title Here ) : https://the.url/
+ * ^ open ^ close ^ colon ^ url
+ */
int open_bracket_pos = begin_scan, close_bracket_pos = 0;
while (open_bracket_pos < striped_line.length() && (striped_line[open_bracket_pos] == ' ' || striped_line[open_bracket_pos] == '\t')) {
open_bracket_pos++;
@@ -3331,8 +3411,8 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
Variant::construct(parameter.type, r, &(name), 1, error);
p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
- p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);
return false;
}
break;
@@ -3340,13 +3420,13 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
[[fallthrough]];
default: {
if (argument->type != Node::LITERAL) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
return false;
}
Variant value = static_cast<LiteralNode *>(argument)->value;
if (!Variant::can_convert_strict(value.get_type(), parameter.type)) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
return false;
}
Callable::CallError error;
@@ -3355,8 +3435,8 @@ bool GDScriptParser::validate_annotation_arguments(AnnotationNode *p_annotation)
Variant::construct(parameter.type, r, &(args), 1, error);
p_annotation->resolved_arguments.push_back(r);
if (error.error != Callable::CallError::CALL_OK) {
- push_error(vformat(R"(Expected %s as argument %d of annotation "%s").)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
- p_annotation->resolved_arguments.remove(p_annotation->resolved_arguments.size() - 1);
+ push_error(vformat(R"(Expected %s as argument %d of annotation "%s".)", Variant::get_type_name(parameter.type), i + 1, p_annotation->name));
+ p_annotation->resolved_arguments.remove_at(p_annotation->resolved_arguments.size() - 1);
return false;
}
break;
@@ -3417,7 +3497,7 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint_string = hint_string;
- // This is called after tne analyzer is done finding the type, so this should be set here.
+ // This is called after the analyzer is done finding the type, so this should be set here.
DataType export_type = variable->get_datatype();
if (p_annotation->name == "@export") {
@@ -3459,12 +3539,12 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
variable->export_info.hint = PROPERTY_HINT_ENUM;
String enum_hint_string;
- for (const Map<StringName, int>::Element *E = export_type.enum_values.front(); E; E = E->next()) {
- enum_hint_string += E->key().operator String().capitalize().xml_escape();
+ for (OrderedHashMap<StringName, int>::Element E = export_type.enum_values.front(); E; E = E.next()) {
+ enum_hint_string += E.key().operator String().capitalize().xml_escape();
enum_hint_string += ":";
- enum_hint_string += String::num_int64(E->get()).xml_escape();
+ enum_hint_string += String::num_int64(E.value()).xml_escape();
- if (E->next()) {
+ if (E.next()) {
enum_hint_string += ",";
}
}
@@ -3501,7 +3581,24 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node
}
bool GDScriptParser::warning_annotations(const AnnotationNode *p_annotation, Node *p_node) {
- ERR_FAIL_V_MSG(false, "Not implemented.");
+#ifdef DEBUG_ENABLED
+ bool has_error = false;
+ for (const Variant &warning_name : p_annotation->resolved_arguments) {
+ GDScriptWarning::Code warning = GDScriptWarning::get_code_from_name(String(warning_name).to_upper());
+ if (warning == GDScriptWarning::WARNING_MAX) {
+ push_error(vformat(R"(Invalid warning name: "%s".)", warning_name), p_annotation);
+ has_error = true;
+ } else {
+ p_node->ignored_warnings.push_back(warning);
+ }
+ }
+
+ return !has_error;
+
+#else // ! DEBUG_ENABLED
+ // Only available in debug builds.
+ return true;
+#endif // DEBUG_ENABLED
}
template <Multiplayer::RPCMode t_mode>
@@ -4139,7 +4236,11 @@ void GDScriptParser::TreePrinter::print_get_node(GetNodeNode *p_get_node) {
}
void GDScriptParser::TreePrinter::print_identifier(IdentifierNode *p_identifier) {
- push_text(p_identifier->name);
+ if (p_identifier != nullptr) {
+ push_text(p_identifier->name);
+ } else {
+ push_text("<invalid identifier>");
+ }
}
void GDScriptParser::TreePrinter::print_if(IfNode *p_if, bool p_is_elif) {
@@ -4533,7 +4634,7 @@ void GDScriptParser::TreePrinter::print_tree(const GDScriptParser &p_parser) {
}
print_class(p_parser.get_tree());
- print_line(printed);
+ print_line(String(printed));
}
#endif // DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h
index af9b973ada..e4311d2d5e 100644
--- a/modules/gdscript/gdscript_parser.h
+++ b/modules/gdscript/gdscript_parser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -133,7 +133,7 @@ public:
ClassNode *class_type = nullptr;
MethodInfo method_info; // For callable/signals.
- Map<StringName, int> enum_values; // For enums.
+ OrderedHashMap<StringName, int> enum_values; // For enums.
_FORCE_INLINE_ bool is_set() const { return kind != UNRESOLVED; }
_FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; }
@@ -203,7 +203,7 @@ public:
return !(this->operator==(p_other));
}
- DataType &operator=(const DataType &p_other) {
+ void operator=(const DataType &p_other) {
kind = p_other.kind;
type_source = p_other.type_source;
is_constant = p_other.is_constant;
@@ -221,7 +221,6 @@ public:
if (p_other.has_container_element_type()) {
set_container_element_type(p_other.get_container_element_type());
}
- return *this;
}
DataType() = default;
@@ -298,6 +297,7 @@ public:
int leftmost_column = 0, rightmost_column = 0;
Node *next = nullptr;
List<AnnotationNode *> annotations;
+ Vector<uint32_t> ignored_warnings;
DataType datatype;
@@ -1205,6 +1205,7 @@ private:
#ifdef DEBUG_ENABLED
List<GDScriptWarning> warnings;
Set<String> ignored_warnings;
+ Set<uint32_t> ignored_warning_codes;
Set<int> unsafe_lines;
#endif
diff --git a/modules/gdscript/gdscript_tokenizer.cpp b/modules/gdscript/gdscript_tokenizer.cpp
index d4a098811a..05ea061798 100644
--- a/modules/gdscript/gdscript_tokenizer.cpp
+++ b/modules/gdscript/gdscript_tokenizer.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -795,6 +795,15 @@ GDScriptTokenizer::Token GDScriptTokenizer::string() {
char32_t ch = _peek();
+ if (ch == 0x200E || ch == 0x200F || (ch >= 0x202A && ch <= 0x202E) || (ch >= 0x2066 && ch <= 0x2069)) {
+ Token error = make_error("Invisible text direction control character present in the string, escape it (\"\\u" + String::num_int64(ch, 16) + "\") to avoid confusion.");
+ error.start_column = column;
+ error.leftmost_column = error.start_column;
+ error.end_column = column + 1;
+ error.rightmost_column = error.end_column;
+ push_error(error);
+ }
+
if (ch == '\\') {
// Escape pattern.
_advance();
@@ -1064,7 +1073,8 @@ void GDScriptTokenizer::check_indent() {
// First time indenting, choose character now.
indent_char = current_indent_char;
} else if (current_indent_char != indent_char) {
- Token error = make_error(vformat("Used \"%s\" for indentation instead \"%s\" as used before in the file.", String(&current_indent_char, 1).c_escape(), String(&indent_char, 1).c_escape()));
+ Token error = make_error(vformat("Used %s character for indentation instead of %s as used before in the file.",
+ _get_indent_char_name(current_indent_char), _get_indent_char_name(indent_char)));
error.start_line = line;
error.start_column = 1;
error.leftmost_column = 1;
@@ -1114,6 +1124,12 @@ void GDScriptTokenizer::check_indent() {
}
}
+String GDScriptTokenizer::_get_indent_char_name(char32_t ch) {
+ ERR_FAIL_COND_V(ch != ' ' && ch != '\t', String(&ch, 1).c_escape());
+
+ return ch == ' ' ? "space" : "tab";
+}
+
void GDScriptTokenizer::_skip_whitespace() {
if (pending_indents != 0) {
// Still have some indent/dedent tokens to give.
diff --git a/modules/gdscript/gdscript_tokenizer.h b/modules/gdscript/gdscript_tokenizer.h
index 84b82c07f0..abd090e381 100644
--- a/modules/gdscript/gdscript_tokenizer.h
+++ b/modules/gdscript/gdscript_tokenizer.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -233,6 +233,7 @@ private:
bool has_error() const { return !error_stack.is_empty(); }
Token pop_error();
char32_t _advance();
+ String _get_indent_char_name(char32_t ch);
void _skip_whitespace();
void check_indent();
diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp
index f1b0079536..16b2dac343 100644
--- a/modules/gdscript/gdscript_utility_functions.cpp
+++ b/modules/gdscript/gdscript_utility_functions.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -437,9 +437,13 @@ struct GDScriptUtilityFunctionsDefinitions {
str += p_args[i]->operator String();
}
- ScriptLanguage *script = GDScriptLanguage::get_singleton();
- if (script->debug_get_stack_level_count() > 0) {
- str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
+ if (Thread::get_caller_id() == Thread::get_main_id()) {
+ ScriptLanguage *script = GDScriptLanguage::get_singleton();
+ if (script->debug_get_stack_level_count() > 0) {
+ str += "\n At: " + script->debug_get_stack_level_source(0) + ":" + itos(script->debug_get_stack_level_line(0)) + ":" + script->debug_get_stack_level_function(0) + "()";
+ }
+ } else {
+ str += "\n At: Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id());
}
print_line(str);
@@ -448,15 +452,24 @@ struct GDScriptUtilityFunctionsDefinitions {
static inline void print_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
VALIDATE_ARG_COUNT(0);
+ if (Thread::get_caller_id() != Thread::get_main_id()) {
+ print_line("Cannot retrieve debug info outside the main thread. Thread ID: " + itos(Thread::get_caller_id()));
+ return;
+ }
ScriptLanguage *script = GDScriptLanguage::get_singleton();
for (int i = 0; i < script->debug_get_stack_level_count(); i++) {
print_line("Frame " + itos(i) + " - " + script->debug_get_stack_level_source(i) + ":" + itos(script->debug_get_stack_level_line(i)) + " in function '" + script->debug_get_stack_level_function(i) + "'");
};
+ *r_ret = Variant();
}
static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) {
VALIDATE_ARG_COUNT(0);
+ if (Thread::get_caller_id() != Thread::get_main_id()) {
+ *r_ret = Array();
+ return;
+ }
ScriptLanguage *script = GDScriptLanguage::get_singleton();
Array ret;
diff --git a/modules/gdscript/gdscript_utility_functions.h b/modules/gdscript/gdscript_utility_functions.h
index c6d3718844..9ca7cf33d8 100644
--- a/modules/gdscript/gdscript_utility_functions.h
+++ b/modules/gdscript/gdscript_utility_functions.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp
index 7018c339d7..e0facaf61d 100644
--- a/modules/gdscript/gdscript_vm.cpp
+++ b/modules/gdscript/gdscript_vm.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -488,7 +488,12 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
memnew_placement(&stack[i + 3], Variant(*p_args[i]));
continue;
}
-
+ // If types already match, don't call Variant::construct(). Constructors of some types
+ // (e.g. packed arrays) do copies, whereas they pass by reference when inside a Variant.
+ if (argument_types[i].is_type(*p_args[i], false)) {
+ memnew_placement(&stack[i + 3], Variant(*p_args[i]));
+ continue;
+ }
if (!argument_types[i].is_type(*p_args[i], true)) {
r_err.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT;
r_err.argument = i;
@@ -755,7 +760,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (!valid) {
String v = index->operator String();
- if (v != "") {
+ if (!v.is_empty()) {
v = "'" + v + "'";
} else {
v = "of type '" + _get_var_type(index) + "'";
@@ -785,7 +790,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (!valid) {
String v = index->operator String();
- if (v != "") {
+ if (!v.is_empty()) {
v = "'" + v + "'";
} else {
v = "of type '" + _get_var_type(index) + "'";
@@ -817,7 +822,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (oob) {
String v = index->operator String();
- if (v != "") {
+ if (!v.is_empty()) {
v = "'" + v + "'";
} else {
v = "of type '" + _get_var_type(index) + "'";
@@ -848,7 +853,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (!valid) {
String v = index->operator String();
- if (v != "") {
+ if (!v.is_empty()) {
v = "'" + v + "'";
} else {
v = "of type '" + _get_var_type(index) + "'";
@@ -884,7 +889,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (!valid) {
String v = key->operator String();
- if (v != "") {
+ if (!v.is_empty()) {
v = "'" + v + "'";
} else {
v = "of type '" + _get_var_type(key) + "'";
@@ -917,7 +922,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
#ifdef DEBUG_ENABLED
if (oob) {
String v = index->operator String();
- if (v != "") {
+ if (!v.is_empty()) {
v = "'" + v + "'";
} else {
v = "of type '" + _get_var_type(index) + "'";
@@ -1110,7 +1115,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
} else {
#ifdef DEBUG_ENABLED
err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
- "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
+ "' to a variable of type '" + Variant::get_type_name(var_type) + "'.";
OPCODE_BREAK;
}
} else {
@@ -1132,7 +1137,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (src->get_type() != Variant::ARRAY) {
#ifdef DEBUG_ENABLED
err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
- "' to a variable of type '" + +"'.";
+ "' to a variable of type '" + +"'.";
#endif
OPCODE_BREAK;
}
@@ -1158,14 +1163,14 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
GD_ERR_BREAK(!nc);
if (src->get_type() != Variant::OBJECT && src->get_type() != Variant::NIL) {
err_text = "Trying to assign value of type '" + Variant::get_type_name(src->get_type()) +
- "' to a variable of type '" + nc->get_name() + "'.";
+ "' to a variable of type '" + nc->get_name() + "'.";
OPCODE_BREAK;
}
Object *src_obj = src->operator Object *();
if (src_obj && !ClassDB::is_parent_class(src_obj->get_class_name(), nc->get_name())) {
err_text = "Trying to assign value of type '" + src_obj->get_class_name() +
- "' to a variable of type '" + nc->get_name() + "'.";
+ "' to a variable of type '" + nc->get_name() + "'.";
OPCODE_BREAK;
}
#endif // DEBUG_ENABLED
@@ -1195,7 +1200,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
ScriptInstance *scr_inst = src->operator Object *()->get_script_instance();
if (!scr_inst) {
err_text = "Trying to assign value of type '" + src->operator Object *()->get_class_name() +
- "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+ "' to a variable of type '" + base_type->get_path().get_file() + "'.";
OPCODE_BREAK;
}
@@ -1212,7 +1217,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
if (!valid) {
err_text = "Trying to assign value of type '" + src->operator Object *()->get_script_instance()->get_script()->get_path().get_file() +
- "' to a variable of type '" + base_type->get_path().get_file() + "'.";
+ "' to a variable of type '" + base_type->get_path().get_file() + "'.";
OPCODE_BREAK;
}
}
@@ -3295,27 +3300,27 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a
//error
// function, file, line, error, explanation
String err_file;
- if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->path != "") {
+ if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->path.is_empty()) {
err_file = p_instance->script->path;
} else if (script) {
err_file = script->path;
}
- if (err_file == "") {
+ if (err_file.is_empty()) {
err_file = "<built-in>";
}
String err_func = name;
- if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->name != "") {
+ if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->name.is_empty()) {
err_func = p_instance->script->name + "." + err_func;
}
int err_line = line;
- if (err_text == "") {
- err_text = "Internal Script Error! - opcode #" + itos(last_opcode) + " (report please).";
+ if (err_text.is_empty()) {
+ err_text = "Internal script error! Opcode: " + itos(last_opcode) + " (please report).";
}
if (!GDScriptLanguage::get_singleton()->debug_break(err_text, false)) {
// debugger break did not happen
- _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), ERR_HANDLER_SCRIPT);
+ _err_print_error(err_func.utf8().get_data(), err_file.utf8().get_data(), err_line, err_text.utf8().get_data(), false, ERR_HANDLER_SCRIPT);
}
#endif
diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp
index 7a483a16ba..73536f5f8e 100644
--- a/modules/gdscript/gdscript_warning.cpp
+++ b/modules/gdscript/gdscript_warning.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -148,6 +148,10 @@ String GDScriptWarning::get_message() const {
case EMPTY_FILE: {
return "Empty script file.";
}
+ case SHADOWED_GLOBAL_IDENTIFIER: {
+ CHECK_SYMBOLS(3);
+ return vformat(R"(The %s '%s' has the same name as a %s.)", symbols[0], symbols[1], symbols[2]);
+ }
case WARNING_MAX:
break; // Can't happen, but silences warning
}
@@ -194,6 +198,7 @@ String GDScriptWarning::get_name_from_code(Code p_code) {
"ASSERT_ALWAYS_FALSE",
"REDUNDANT_AWAIT",
"EMPTY_FILE",
+ "SHADOWED_GLOBAL_IDENTIFIER",
};
static_assert((sizeof(names) / sizeof(*names)) == WARNING_MAX, "Amount of warning types don't match the amount of warning names.");
@@ -208,7 +213,7 @@ GDScriptWarning::Code GDScriptWarning::get_code_from_name(const String &p_name)
}
}
- ERR_FAIL_V_MSG(WARNING_MAX, "Invalid GDScript warning name: " + p_name);
+ return WARNING_MAX;
}
#endif // DEBUG_ENABLED
diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h
index 8de46b08c1..112b40781a 100644
--- a/modules/gdscript/gdscript_warning.h
+++ b/modules/gdscript/gdscript_warning.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -69,6 +69,7 @@ public:
ASSERT_ALWAYS_FALSE, // Expression for assert argument is always false.
REDUNDANT_AWAIT, // await is used but expression is synchronous (not a signal nor a coroutine).
EMPTY_FILE, // A script file is empty.
+ SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable.
WARNING_MAX,
};
diff --git a/modules/gdscript/icons/GDScriptInternal.svg b/modules/gdscript/icons/GDScriptInternal.svg
new file mode 100644
index 0000000000..fcabaafbd0
--- /dev/null
+++ b/modules/gdscript/icons/GDScriptInternal.svg
@@ -0,0 +1 @@
+<svg height="16" viewBox="0 0 16 16" width="16" xmlns="http://www.w3.org/2000/svg"><path d="m7 1-.56445 2.2578c-.2364329.0758517-.4668872.16921-.68945.2793l-1.9883-1.1934-1.4141 1.4141 1.1953 1.9941c-.1119126.2211335-.2072287.4502818-.28516.68555l-2.2539.5625v2l2.2578.56445c.075942.2357685.1692993.465568.2793.6875l-1.1934 1.9902 1.4141 1.4141 1.9941-1.1953c.2211335.111913.4502818.207229.68555.28516l.5625 2.2539h2l.56445-2.2578c.2357685-.07594.465568-.169299.6875-.2793l1.9902 1.1934 1.4141-1.4141-1.1953-1.9941c.111913-.221133.207229-.4502818.28516-.68555l2.2539-.5625v-2l-2.2578-.56445c-.075942-.2357685-.169299-.4655679-.2793-.6875l1.1934-1.9902-1.4141-1.4141-1.9941 1.1953c-.221133-.1119126-.4502818-.2072287-.68555-.28516l-.5625-2.2539zm1 5c1.1045695 0 2 .8954305 2 2s-.8954305 2-2 2-2-.8954305-2-2 .8954305-2 2-2z" fill="none" stroke="#e0e0e0"/></svg>
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.cpp b/modules/gdscript/language_server/gdscript_extend_parser.cpp
index f4c0c4d9bb..49f5303ae6 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.cpp
+++ b/modules/gdscript/language_server/gdscript_extend_parser.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -269,7 +269,7 @@ void ExtendGDScriptParser::parse_class_symbol(const GDScriptParser::ClassNode *p
if (j > 0) {
symbol.detail += ", ";
}
- symbol.detail += m.signal->parameters[i]->identifier->name;
+ symbol.detail += m.signal->parameters[j]->identifier->name;
}
symbol.detail += ")";
diff --git a/modules/gdscript/language_server/gdscript_extend_parser.h b/modules/gdscript/language_server/gdscript_extend_parser.h
index 5d7b16765b..99b0bf45d0 100644
--- a/modules/gdscript/language_server/gdscript_extend_parser.h
+++ b/modules/gdscript/language_server/gdscript_extend_parser.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.cpp b/modules/gdscript/language_server/gdscript_language_protocol.cpp
index 5cf1e0fc5f..cdddab319d 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.cpp
+++ b/modules/gdscript/language_server/gdscript_language_protocol.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -115,7 +115,7 @@ Error GDScriptLanguageProtocol::LSPeer::send_data() {
// Response sent
if (res_sent >= c_res.size() - 1) {
res_sent = 0;
- res_queue.remove(0);
+ res_queue.remove_at(0);
}
}
return OK;
diff --git a/modules/gdscript/language_server/gdscript_language_protocol.h b/modules/gdscript/language_server/gdscript_language_protocol.h
index 899446fb42..0fed8597f9 100644
--- a/modules/gdscript/language_server/gdscript_language_protocol.h
+++ b/modules/gdscript/language_server/gdscript_language_protocol.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -38,7 +38,7 @@
#include "gdscript_workspace.h"
#include "lsp.hpp"
-#include "modules/modules_enabled.gen.h"
+#include "modules/modules_enabled.gen.h" // For jsonrpc.
#ifdef MODULE_JSONRPC_ENABLED
#include "modules/jsonrpc/jsonrpc.h"
#else
diff --git a/modules/gdscript/language_server/gdscript_language_server.cpp b/modules/gdscript/language_server/gdscript_language_server.cpp
index 41a2f9e4ad..33c1c834f1 100644
--- a/modules/gdscript/language_server/gdscript_language_server.cpp
+++ b/modules/gdscript/language_server/gdscript_language_server.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/language_server/gdscript_language_server.h b/modules/gdscript/language_server/gdscript_language_server.h
index 85a44a8cc1..8de72fc9c9 100644
--- a/modules/gdscript/language_server/gdscript_language_server.h
+++ b/modules/gdscript/language_server/gdscript_language_server.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -45,15 +45,13 @@ class GDScriptLanguageServer : public EditorPlugin {
bool started = false;
bool use_thread = false;
String host = "127.0.0.1";
- int port = 6008;
+ int port = 6005;
static void thread_main(void *p_userdata);
private:
void _notification(int p_what);
- void _iteration();
public:
- Error parse_script_file(const String &p_path);
GDScriptLanguageServer();
void start();
void stop();
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index 92ce71f395..961295b076 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -428,9 +428,6 @@ GDScriptTextDocument::~GDScriptTextDocument() {
void GDScriptTextDocument::sync_script_content(const String &p_path, const String &p_content) {
String path = GDScriptLanguageProtocol::get_singleton()->get_workspace()->get_file_path(p_path);
- if (!path.begins_with("res://")) {
- return;
- }
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
EditorFileSystem::get_singleton()->update_file(path);
diff --git a/modules/gdscript/language_server/gdscript_text_document.h b/modules/gdscript/language_server/gdscript_text_document.h
index 9021c84a3f..eb7b2c0240 100644
--- a/modules/gdscript/language_server/gdscript_text_document.h
+++ b/modules/gdscript/language_server/gdscript_text_document.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/language_server/gdscript_workspace.cpp b/modules/gdscript/language_server/gdscript_workspace.cpp
index 371e3de419..a944844226 100644
--- a/modules/gdscript/language_server/gdscript_workspace.cpp
+++ b/modules/gdscript/language_server/gdscript_workspace.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -54,9 +54,13 @@ void GDScriptWorkspace::_bind_methods() {
}
void GDScriptWorkspace::apply_new_signal(Object *obj, String function, PackedStringArray args) {
- String function_signature = "func " + function;
Ref<Script> script = obj->get_script();
+ if (script->get_language()->get_name() != "GDScript") {
+ return;
+ }
+
+ String function_signature = "func " + function;
String source = script->get_source_code();
if (source.find(function_signature) != -1) {
@@ -338,7 +342,9 @@ Error GDScriptWorkspace::initialize() {
}
Vector<DocData::MethodDoc> methods_signals;
+ methods_signals.append_array(class_data.constructors);
methods_signals.append_array(class_data.methods);
+ methods_signals.append_array(class_data.operators);
const int signal_start_idx = methods_signals.size();
methods_signals.append_array(class_data.signals);
diff --git a/modules/gdscript/language_server/gdscript_workspace.h b/modules/gdscript/language_server/gdscript_workspace.h
index 6f5600b5cf..ce5bba5f00 100644
--- a/modules/gdscript/language_server/gdscript_workspace.h
+++ b/modules/gdscript/language_server/gdscript_workspace.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/language_server/lsp.hpp b/modules/gdscript/language_server/lsp.hpp
index 3710a84a28..8e503a9df9 100644
--- a/modules/gdscript/language_server/lsp.hpp
+++ b/modules/gdscript/language_server/lsp.hpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -358,21 +358,21 @@ struct Command {
namespace TextDocumentSyncKind {
/**
- * Documents should not be synced at all.
- */
+ * Documents should not be synced at all.
+ */
static const int None = 0;
/**
- * Documents are synced by always sending the full content
- * of the document.
- */
+ * Documents are synced by always sending the full content
+ * of the document.
+ */
static const int Full = 1;
/**
- * Documents are synced by sending the full content on open.
- * After that only incremental updates to the document are
- * send.
- */
+ * Documents are synced by sending the full content on open.
+ * After that only incremental updates to the document are
+ * send.
+ */
static const int Incremental = 2;
}; // namespace TextDocumentSyncKind
@@ -667,20 +667,20 @@ struct TextDocumentContentChangeEvent {
// Use namespace instead of enumeration to follow the LSP specifications
namespace DiagnosticSeverity {
/**
- * Reports an error.
- */
+ * Reports an error.
+ */
static const int Error = 1;
/**
- * Reports a warning.
- */
+ * Reports a warning.
+ */
static const int Warning = 2;
/**
- * Reports an information.
- */
+ * Reports an information.
+ */
static const int Information = 3;
/**
- * Reports a hint.
- */
+ * Reports a hint.
+ */
static const int Hint = 4;
}; // namespace DiagnosticSeverity
@@ -871,18 +871,18 @@ static const int TypeParameter = 25;
*/
namespace InsertTextFormat {
/**
- * The primary text to be inserted is treated as a plain string.
- */
+ * The primary text to be inserted is treated as a plain string.
+ */
static const int PlainText = 1;
/**
- * The primary text to be inserted is treated as a snippet.
- *
- * A snippet can define tab stops and placeholders with `$1`, `$2`
- * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
- * the end of the snippet. Placeholders with equal identifiers are linked,
- * that is typing in one will update others too.
- */
+ * The primary text to be inserted is treated as a snippet.
+ *
+ * A snippet can define tab stops and placeholders with `$1`, `$2`
+ * and `${3:foo}`. `$0` defines the final tab stop, it defaults to
+ * the end of the snippet. Placeholders with equal identifiers are linked,
+ * that is typing in one will update others too.
+ */
static const int Snippet = 2;
}; // namespace InsertTextFormat
@@ -1359,16 +1359,16 @@ struct NativeSymbolInspectParams {
*/
namespace FoldingRangeKind {
/**
- * Folding range for a comment
- */
+ * Folding range for a comment
+ */
static const String Comment = "comment";
/**
- * Folding range for a imports or includes
- */
+ * Folding range for a imports or includes
+ */
static const String Imports = "imports";
/**
- * Folding range for a region (e.g. `#region`)
- */
+ * Folding range for a region (e.g. `#region`)
+ */
static const String Region = "region";
} // namespace FoldingRangeKind
@@ -1419,20 +1419,20 @@ struct FoldingRange {
*/
namespace CompletionTriggerKind {
/**
- * Completion was triggered by typing an identifier (24x7 code
- * complete), manual invocation (e.g Ctrl+Space) or via API.
- */
+ * Completion was triggered by typing an identifier (24x7 code
+ * complete), manual invocation (e.g Ctrl+Space) or via API.
+ */
static const int Invoked = 1;
/**
- * Completion was triggered by a trigger character specified by
- * the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
- */
+ * Completion was triggered by a trigger character specified by
+ * the `triggerCharacters` properties of the `CompletionRegistrationOptions`.
+ */
static const int TriggerCharacter = 2;
/**
- * Completion was re-triggered as the current completion list is incomplete.
- */
+ * Completion was re-triggered as the current completion list is incomplete.
+ */
static const int TriggerForIncompleteCompletions = 3;
} // namespace CompletionTriggerKind
@@ -1441,8 +1441,8 @@ static const int TriggerForIncompleteCompletions = 3;
*/
struct CompletionContext {
/**
- * How the completion was triggered.
- */
+ * How the completion was triggered.
+ */
int triggerKind = CompletionTriggerKind::TriggerCharacter;
/**
@@ -1906,7 +1906,7 @@ struct GodotNativeClassInfo {
struct GodotCapabilities {
/**
* Native class list
- */
+ */
List<GodotNativeClassInfo> native_classes;
Dictionary to_json() {
diff --git a/modules/gdscript/register_types.cpp b/modules/gdscript/register_types.cpp
index c2b1981f31..fcf122f567 100644
--- a/modules/gdscript/register_types.cpp
+++ b/modules/gdscript/register_types.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/register_types.h b/modules/gdscript/register_types.h
index ce1c03d1d0..baa7dcbbd1 100644
--- a/modules/gdscript/register_types.h
+++ b/modules/gdscript/register_types.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/tests/gdscript_test_runner.cpp b/modules/gdscript/tests/gdscript_test_runner.cpp
index 50c1f68440..47772b8039 100644
--- a/modules/gdscript/tests/gdscript_test_runner.cpp
+++ b/modules/gdscript/tests/gdscript_test_runner.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -267,7 +267,7 @@ bool GDScriptTestRunner::generate_class_index() {
String base_type;
String class_name = GDScriptLanguage::get_singleton()->get_global_class_name(test.get_source_file(), &base_type);
- if (class_name == String()) {
+ if (class_name.is_empty()) {
continue;
}
ERR_FAIL_COND_V_MSG(ScriptServer::is_global_class(class_name), false,
@@ -334,7 +334,7 @@ void GDScriptTest::print_handler(void *p_this, const String &p_message, bool p_e
result->output += p_message + "\n";
}
-void GDScriptTest::error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type) {
+void GDScriptTest::error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, bool p_editor_notify, ErrorHandlerType p_type) {
ErrorHandlerData *data = (ErrorHandlerData *)p_this;
GDScriptTest *self = data->self;
TestResult *result = data->result;
@@ -362,16 +362,16 @@ void GDScriptTest::error_handler(void *p_this, const char *p_function, const cha
}
builder.append("\n>> on function: ");
- builder.append(p_function);
+ builder.append(String::utf8(p_function));
builder.append("()\n>> ");
- builder.append(String(p_file).trim_prefix(self->base_dir));
+ builder.append(String::utf8(p_file).trim_prefix(self->base_dir));
builder.append("\n>> ");
builder.append(itos(p_line));
builder.append("\n>> ");
- builder.append(p_error);
+ builder.append(String::utf8(p_error));
if (strlen(p_explanation) > 0) {
builder.append("\n>> ");
- builder.append(p_explanation);
+ builder.append(String::utf8(p_explanation));
}
builder.append("\n");
diff --git a/modules/gdscript/tests/gdscript_test_runner.h b/modules/gdscript/tests/gdscript_test_runner.h
index 9b2d14a371..1a950c6898 100644
--- a/modules/gdscript/tests/gdscript_test_runner.h
+++ b/modules/gdscript/tests/gdscript_test_runner.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
@@ -87,7 +87,7 @@ private:
public:
static void print_handler(void *p_this, const String &p_message, bool p_error);
- static void error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, ErrorHandlerType p_type);
+ static void error_handler(void *p_this, const char *p_function, const char *p_file, int p_line, const char *p_error, const char *p_explanation, bool p_editor_notify, ErrorHandlerType p_type);
TestResult run_test();
bool generate_output();
diff --git a/modules/gdscript/tests/gdscript_test_runner_suite.h b/modules/gdscript/tests/gdscript_test_runner_suite.h
index cf4e61f07d..0722fb800e 100644
--- a/modules/gdscript/tests/gdscript_test_runner_suite.h
+++ b/modules/gdscript/tests/gdscript_test_runner_suite.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd
new file mode 100644
index 0000000000..05d9bd6a3d
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.gd
@@ -0,0 +1,9 @@
+# https://github.com/godotengine/godot/issues/56702
+
+func test():
+ # somewhat obscure feature: referencing parameters in defaults, but only earlier ones!
+ ref_default("non-optional")
+
+
+func ref_default(nondefault1, defa=nondefault1, defb=defc, defc=1):
+ prints(nondefault1, nondefault2, defa, defb, defc)
diff --git a/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out
new file mode 100644
index 0000000000..1d5b5bf393
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/errors/params_default_forward_reference.out
@@ -0,0 +1,2 @@
+GDTEST_ANALYZER_ERROR
+Identifier "defc" not declared in the current scope.
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
new file mode 100644
index 0000000000..877a4ea221
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.gd
@@ -0,0 +1,15 @@
+@warning_ignore(unused_private_class_variable)
+var _unused = 2
+
+@warning_ignore(unused_variable)
+func test():
+ print("test")
+ var unused = 3
+
+ @warning_ignore(redundant_await)
+ print(await regular_func())
+
+ print("done")
+
+func regular_func():
+ return 0
diff --git a/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out
new file mode 100644
index 0000000000..42292774a0
--- /dev/null
+++ b/modules/gdscript/tests/scripts/analyzer/features/warning_ignore_annotation.out
@@ -0,0 +1,4 @@
+GDTEST_OK
+test
+0
+done
diff --git a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
index 6390de9788..31bed2dbc7 100644
--- a/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
+++ b/modules/gdscript/tests/scripts/parser/errors/mixing_tabs_spaces.out
@@ -1,2 +1,2 @@
GDTEST_PARSER_ERROR
-Used "\t" for indentation instead " " as used before in the file.
+Used tab character for indentation instead of space as used before in the file.
diff --git a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
index 9ad98b78a8..e4d6a72f90 100644
--- a/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
+++ b/modules/gdscript/tests/scripts/parser/features/signal_declaration.gd
@@ -6,7 +6,7 @@ signal a
# No parameters.
signal b()
-# With paramters.
+# With parameters.
signal c(a, b, c)
# With parameters multiline.
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd
new file mode 100644
index 0000000000..3c64be571b
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.gd
@@ -0,0 +1,2 @@
+func test():
+ var abs = "This variable has the same name as the built-in function."
diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out
new file mode 100644
index 0000000000..c613140eb8
--- /dev/null
+++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_global_identifier.out
@@ -0,0 +1,9 @@
+GDTEST_OK
+>> WARNING
+>> Line: 2
+>> UNUSED_VARIABLE
+>> The local variable 'abs' is declared but never used in the block. If this is intended, prefix it with an underscore: '_abs'
+>> WARNING
+>> Line: 2
+>> SHADOWED_GLOBAL_IDENTIFIER
+>> The variable 'abs' has the same name as a built-in function.
diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd
new file mode 100644
index 0000000000..8156b4ec68
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.gd
@@ -0,0 +1,35 @@
+# https://github.com/godotengine/godot/issues/56702
+
+func test():
+ const_default()
+ func_result_default()
+ # calling again will run the initializer again,
+ # as the default is not evaluated at time of defining the function (as in python)
+ # but every time the function is called (as in C++)
+ func_result_default()
+ lots_of_defaults("non-optional")
+ # somewhat obscure feature: referencing earlier parameters
+ ref_default("non-optional", 42)
+
+
+func const_default(param=42):
+ print(param)
+
+
+var default_val := 0
+
+func get_default():
+ default_val += 1
+ return default_val
+
+
+func func_result_default(param=get_default()):
+ print(param)
+
+
+func lots_of_defaults(nondefault, one=1, two=2, three=get_default()):
+ prints(nondefault, one, two, three)
+
+
+func ref_default(nondefault1, nondefault2, defa=nondefault1, defb=nondefault2 - 1):
+ prints(nondefault1, nondefault2, defa, defb)
diff --git a/modules/gdscript/tests/scripts/runtime/features/params_default_values.out b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out
new file mode 100644
index 0000000000..50e0885ae5
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/params_default_values.out
@@ -0,0 +1,6 @@
+GDTEST_OK
+42
+1
+2
+non-optional 1 2 3
+non-optional 42 non-optional 41
diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.gd b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
index de269b92b3..fead2df854 100644
--- a/modules/gdscript/tests/scripts/runtime/features/stringify.gd
+++ b/modules/gdscript/tests/scripts/runtime/features/stringify.gd
@@ -17,7 +17,7 @@ func test():
print(Plane(1, 2, 3, 4))
print(Quaternion(1, 2, 3, 4))
print(AABB(Vector3.ZERO, Vector3.ONE))
- print(Basis(Vector3(0, 0, 0)))
+ print(Basis.from_euler(Vector3(0, 0, 0)))
print(Transform3D.IDENTITY)
print(Color(1, 2, 3, 4))
diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp
index 80eabc1596..4255030b4e 100644
--- a/modules/gdscript/tests/test_gdscript.cpp
+++ b/modules/gdscript/tests/test_gdscript.cpp
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */
diff --git a/modules/gdscript/tests/test_gdscript.h b/modules/gdscript/tests/test_gdscript.h
index c7ee5a2208..b6b1f26203 100644
--- a/modules/gdscript/tests/test_gdscript.h
+++ b/modules/gdscript/tests/test_gdscript.h
@@ -5,8 +5,8 @@
/* GODOT ENGINE */
/* https://godotengine.org */
/*************************************************************************/
-/* Copyright (c) 2007-2021 Juan Linietsky, Ariel Manzur. */
-/* Copyright (c) 2014-2021 Godot Engine contributors (cf. AUTHORS.md). */
+/* Copyright (c) 2007-2022 Juan Linietsky, Ariel Manzur. */
+/* Copyright (c) 2014-2022 Godot Engine contributors (cf. AUTHORS.md). */
/* */
/* Permission is hereby granted, free of charge, to any person obtaining */
/* a copy of this software and associated documentation files (the */