summaryrefslogtreecommitdiffstats
path: root/modules/gdscript
diff options
context:
space:
mode:
Diffstat (limited to 'modules/gdscript')
-rw-r--r--modules/gdscript/.editorconfig5
-rw-r--r--modules/gdscript/gdscript.cpp7
-rw-r--r--modules/gdscript/gdscript.h2
-rw-r--r--modules/gdscript/gdscript_lambda_callable.cpp24
-rw-r--r--modules/gdscript/language_server/gdscript_text_document.cpp15
-rw-r--r--modules/gdscript/language_server/godot_lsp.h32
-rw-r--r--modules/gdscript/tests/scripts/.editorconfig12
-rw-r--r--modules/gdscript/tests/scripts/parser/.editorconfig2
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.gd7
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.gd7
-rw-r--r--modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.out6
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/self_destruction.gd50
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/self_destruction.out5
14 files changed, 132 insertions, 48 deletions
diff --git a/modules/gdscript/.editorconfig b/modules/gdscript/.editorconfig
index 640c205093..b380846f86 100644
--- a/modules/gdscript/.editorconfig
+++ b/modules/gdscript/.editorconfig
@@ -1,8 +1,3 @@
[*.gd]
-indent_style = tab
indent_size = 4
-insert_final_newline = true
trim_trailing_whitespace = true
-
-[*.out]
-insert_final_newline = true
diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp
index 276a12f5de..7b9aa70686 100644
--- a/modules/gdscript/gdscript.cpp
+++ b/modules/gdscript/gdscript.cpp
@@ -880,6 +880,11 @@ Error GDScript::reload(bool p_keep_state) {
if (can_run && p_keep_state) {
_restore_old_static_data();
}
+
+ if (p_keep_state) {
+ // Update the properties in the inspector.
+ update_exports();
+ }
#endif
reloading = false;
@@ -906,7 +911,7 @@ void GDScript::get_members(HashSet<StringName> *p_members) {
}
}
-const Variant GDScript::get_rpc_config() const {
+Variant GDScript::get_rpc_config() const {
return rpc_config;
}
diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h
index 4d21651365..9bb39aac0f 100644
--- a/modules/gdscript/gdscript.h
+++ b/modules/gdscript/gdscript.h
@@ -334,7 +334,7 @@ public:
virtual void get_constants(HashMap<StringName, Variant> *p_constants) override;
virtual void get_members(HashSet<StringName> *p_members) override;
- virtual const Variant get_rpc_config() const override;
+ virtual Variant get_rpc_config() const override;
void unload_static() const;
diff --git a/modules/gdscript/gdscript_lambda_callable.cpp b/modules/gdscript/gdscript_lambda_callable.cpp
index 2de5811bca..d6fd5d043b 100644
--- a/modules/gdscript/gdscript_lambda_callable.cpp
+++ b/modules/gdscript/gdscript_lambda_callable.cpp
@@ -97,25 +97,25 @@ void GDScriptLambdaCallable::call(const Variant **p_arguments, int p_argcount, V
}
if (captures_amount > 0) {
- Vector<const Variant *> args;
- args.resize(p_argcount + captures_amount);
+ const int total_argcount = p_argcount + captures_amount;
+ const Variant **args = (const Variant **)alloca(sizeof(Variant *) * total_argcount);
for (int i = 0; i < captures_amount; i++) {
- args.write[i] = &captures[i];
+ args[i] = &captures[i];
if (captures[i].get_type() == Variant::OBJECT) {
bool was_freed = false;
captures[i].get_validated_object_with_check(was_freed);
if (was_freed) {
ERR_PRINT(vformat(R"(Lambda capture at index %d was freed. Passed "null" instead.)", i));
static Variant nil;
- args.write[i] = &nil;
+ args[i] = &nil;
}
}
}
for (int i = 0; i < p_argcount; i++) {
- args.write[i + captures_amount] = p_arguments[i];
+ args[i + captures_amount] = p_arguments[i];
}
- r_return_value = function->call(nullptr, args.ptrw(), args.size(), r_call_error);
+ r_return_value = function->call(nullptr, args, total_argcount, r_call_error);
switch (r_call_error.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
r_call_error.argument -= captures_amount;
@@ -229,25 +229,25 @@ void GDScriptLambdaSelfCallable::call(const Variant **p_arguments, int p_argcoun
}
if (captures_amount > 0) {
- Vector<const Variant *> args;
- args.resize(p_argcount + captures_amount);
+ const int total_argcount = p_argcount + captures_amount;
+ const Variant **args = (const Variant **)alloca(sizeof(Variant *) * total_argcount);
for (int i = 0; i < captures_amount; i++) {
- args.write[i] = &captures[i];
+ args[i] = &captures[i];
if (captures[i].get_type() == Variant::OBJECT) {
bool was_freed = false;
captures[i].get_validated_object_with_check(was_freed);
if (was_freed) {
ERR_PRINT(vformat(R"(Lambda capture at index %d was freed. Passed "null" instead.)", i));
static Variant nil;
- args.write[i] = &nil;
+ args[i] = &nil;
}
}
}
for (int i = 0; i < p_argcount; i++) {
- args.write[i + captures_amount] = p_arguments[i];
+ args[i + captures_amount] = p_arguments[i];
}
- r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), args.ptrw(), args.size(), r_call_error);
+ r_return_value = function->call(static_cast<GDScriptInstance *>(object->get_script_instance()), args, total_argcount, r_call_error);
switch (r_call_error.error) {
case Callable::CallError::CALL_ERROR_INVALID_ARGUMENT:
r_call_error.argument -= captures_amount;
diff --git a/modules/gdscript/language_server/gdscript_text_document.cpp b/modules/gdscript/language_server/gdscript_text_document.cpp
index fa5f279db9..06e9775360 100644
--- a/modules/gdscript/language_server/gdscript_text_document.cpp
+++ b/modules/gdscript/language_server/gdscript_text_document.cpp
@@ -229,19 +229,6 @@ Array GDScriptTextDocument::completion(const Dictionary &p_params) {
arr[i] = item.to_json();
i++;
}
- } else if (GDScriptLanguageProtocol::get_singleton()->is_smart_resolve_enabled()) {
- arr = native_member_completions.duplicate();
-
- for (KeyValue<String, ExtendGDScriptParser *> &E : GDScriptLanguageProtocol::get_singleton()->get_workspace()->scripts) {
- ExtendGDScriptParser *scr = E.value;
- const Array &items = scr->get_member_completions();
-
- const int start_size = arr.size();
- arr.resize(start_size + items.size());
- for (int i = start_size; i < arr.size(); i++) {
- arr[i] = items[i - start_size];
- }
- }
}
return arr;
}
@@ -485,8 +472,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);
GDScriptLanguageProtocol::get_singleton()->get_workspace()->parse_script(path, p_content);
-
- EditorFileSystem::get_singleton()->update_file(path);
}
void GDScriptTextDocument::show_native_symbol_in_editor(const String &p_symbol_id) {
diff --git a/modules/gdscript/language_server/godot_lsp.h b/modules/gdscript/language_server/godot_lsp.h
index bdf339f5fe..6e19cd7a23 100644
--- a/modules/gdscript/language_server/godot_lsp.h
+++ b/modules/gdscript/language_server/godot_lsp.h
@@ -958,28 +958,30 @@ struct CompletionItem {
/**
* A string that should be used when comparing this item
- * with other items. When `falsy` the label is used.
+ * with other items. When omitted the label is used
+ * as the filter text for this item.
*/
String sortText;
/**
* A string that should be used when filtering a set of
- * completion items. When `falsy` the label is used.
+ * completion items. When omitted the label is used as the
+ * filter text for this item.
*/
String filterText;
/**
* A string that should be inserted into a document when selecting
- * this completion. When `falsy` the label is used.
+ * this completion. When omitted the label is used as the insert text
+ * for this item.
*
* The `insertText` is subject to interpretation by the client side.
* Some tools might not take the string literally. For example
- * VS Code when code complete is requested in this example `con<cursor position>`
- * and a completion item with an `insertText` of `console` is provided it
- * will only insert `sole`. Therefore it is recommended to use `textEdit` instead
- * since it avoids additional client side interpretation.
- *
- * @deprecated Use textEdit instead.
+ * VS Code when code complete is requested in this example
+ * `con<cursor position>` and a completion item with an `insertText` of
+ * `console` is provided it will only insert `sole`. Therefore it is
+ * recommended to use `textEdit` instead since it avoids additional client
+ * side interpretation.
*/
String insertText;
@@ -1034,14 +1036,20 @@ struct CompletionItem {
dict["label"] = label;
dict["kind"] = kind;
dict["data"] = data;
- dict["insertText"] = insertText;
+ if (!insertText.is_empty()) {
+ dict["insertText"] = insertText;
+ }
if (resolved) {
dict["detail"] = detail;
dict["documentation"] = documentation.to_json();
dict["deprecated"] = deprecated;
dict["preselect"] = preselect;
- dict["sortText"] = sortText;
- dict["filterText"] = filterText;
+ if (!sortText.is_empty()) {
+ dict["sortText"] = sortText;
+ }
+ if (!filterText.is_empty()) {
+ dict["filterText"] = filterText;
+ }
if (commitCharacters.size()) {
dict["commitCharacters"] = commitCharacters;
}
diff --git a/modules/gdscript/tests/scripts/.editorconfig b/modules/gdscript/tests/scripts/.editorconfig
new file mode 100644
index 0000000000..da1efefe3c
--- /dev/null
+++ b/modules/gdscript/tests/scripts/.editorconfig
@@ -0,0 +1,12 @@
+# This file is required to workaround `.editorconfig` autogeneration (see #96845).
+
+# Some tests handle invalid syntax deliberately; exclude relevant attributes.
+
+[parser/features/mixed_indentation_on_blank_lines.gd]
+trim_trailing_whitespace = false
+
+[parser/warnings/empty_file_newline.notest.gd]
+insert_final_newline = false
+
+[parser/warnings/empty_file_newline_comment.notest.gd]
+insert_final_newline = false
diff --git a/modules/gdscript/tests/scripts/parser/.editorconfig b/modules/gdscript/tests/scripts/parser/.editorconfig
deleted file mode 100644
index fa43b3ad78..0000000000
--- a/modules/gdscript/tests/scripts/parser/.editorconfig
+++ /dev/null
@@ -1,2 +0,0 @@
-[*.{gd,out}]
-trim_trailing_whitespace = false
diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.gd b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.gd
new file mode 100644
index 0000000000..2f0b3bd0eb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.gd
@@ -0,0 +1,7 @@
+func get_key() -> Variant:
+ return "key"
+
+func test():
+ var typed: Dictionary[int, int]
+ typed[get_key()] = 0
+ print('not ok')
diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.out b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.out
new file mode 100644
index 0000000000..5f6dd7f641
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_key.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/typed_dictionary_assign_differently_typed_key.gd
+>> 6
+>> Invalid assignment of property or key 'key' with value of type 'int' on a base object of type 'Dictionary[int, int]'.
diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.gd b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.gd
new file mode 100644
index 0000000000..b171159aed
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.gd
@@ -0,0 +1,7 @@
+func get_value() -> Variant:
+ return "value"
+
+func test():
+ var typed: Dictionary[int, int]
+ typed[0] = get_value()
+ print("not ok")
diff --git a/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.out b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.out
new file mode 100644
index 0000000000..f766d14261
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/errors/typed_dictionary_assign_differently_typed_value.out
@@ -0,0 +1,6 @@
+GDTEST_RUNTIME_ERROR
+>> SCRIPT ERROR
+>> on function: test()
+>> runtime/errors/typed_dictionary_assign_differently_typed_value.gd
+>> 6
+>> Invalid assignment of property or key '0' with value of type 'String' on a base object of type 'Dictionary[int, int]'.
diff --git a/modules/gdscript/tests/scripts/runtime/features/self_destruction.gd b/modules/gdscript/tests/scripts/runtime/features/self_destruction.gd
new file mode 100644
index 0000000000..442335faeb
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/self_destruction.gd
@@ -0,0 +1,50 @@
+# https://github.com/godotengine/godot/issues/75658
+
+class MyObj:
+ var callable: Callable
+
+ func run():
+ callable.call()
+
+ var prop:
+ set(value):
+ callable.call()
+ get:
+ callable.call()
+ return 0
+
+ func _on_some_signal():
+ callable.call()
+
+ func _init(p_callable: Callable):
+ self.callable = p_callable
+
+signal some_signal
+
+var obj: MyObj
+
+func test():
+ # Call.
+ obj = MyObj.new(nullify_obj)
+ obj.run()
+ print(obj)
+
+ # Get.
+ obj = MyObj.new(nullify_obj)
+ var _aux = obj.prop
+ print(obj)
+
+ # Set.
+ obj = MyObj.new(nullify_obj)
+ obj.prop = 1
+ print(obj)
+
+ # Signal handling.
+ obj = MyObj.new(nullify_obj)
+ @warning_ignore("return_value_discarded")
+ some_signal.connect(obj._on_some_signal)
+ some_signal.emit()
+ print(obj)
+
+func nullify_obj():
+ obj = null
diff --git a/modules/gdscript/tests/scripts/runtime/features/self_destruction.out b/modules/gdscript/tests/scripts/runtime/features/self_destruction.out
new file mode 100644
index 0000000000..ee4024a524
--- /dev/null
+++ b/modules/gdscript/tests/scripts/runtime/features/self_destruction.out
@@ -0,0 +1,5 @@
+GDTEST_OK
+<null>
+<null>
+<null>
+<null>