diff options
Diffstat (limited to 'modules/gdscript')
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> |