diff options
Diffstat (limited to 'modules/gdscript')
47 files changed, 478 insertions, 492 deletions
diff --git a/modules/gdscript/doc_classes/@GDScript.xml b/modules/gdscript/doc_classes/@GDScript.xml index 5fe47d69df..0355119442 100644 --- a/modules/gdscript/doc_classes/@GDScript.xml +++ b/modules/gdscript/doc_classes/@GDScript.xml @@ -4,8 +4,8 @@ Built-in GDScript constants, functions, and annotations. </brief_description> <description> - A list of GDScript-specific utility functions and annotations accessible from any script. - For the list of the global functions and constants see [@GlobalScope]. + A list of utility functions and annotations accessible from any script written in GDScript. + For the list of global functions and constants that can be accessed in any scripting language, see [@GlobalScope]. </description> <tutorials> <link title="GDScript exports">$DOCS_URL/tutorials/scripting/gdscript/gdscript_exports.html</link> @@ -61,7 +61,7 @@ <method name="convert" deprecated="Use [method @GlobalScope.type_convert] instead."> <return type="Variant" /> <param index="0" name="what" type="Variant" /> - <param index="1" name="type" type="int" /> + <param index="1" name="type" type="int" enum="Variant.Type" /> <description> Converts [param what] to [param type] in the best way possible. The [param type] uses the [enum Variant.Type] values. [codeblock] @@ -666,7 +666,19 @@ @export var car_label = "Speedy" @export var car_number = 3 [/codeblock] - [b]Note:[/b] Subgroups cannot be nested, they only provide one extra level of depth. Just like the next group ends the previous group, so do the subsequent subgroups. + [b]Note:[/b] Subgroups cannot be nested, but you can use the slash separator ([code]/[/code]) to achieve the desired effect: + [codeblock] + @export_group("Car Properties") + @export_subgroup("Wheels", "wheel_") + @export_subgroup("Wheels/Front", "front_wheel_") + @export var front_wheel_strength = 10 + @export var front_wheel_mobility = 5 + @export_subgroup("Wheels/Rear", "rear_wheel_") + @export var rear_wheel_strength = 8 + @export var rear_wheel_mobility = 3 + @export_subgroup("Wheels", "wheel_") + @export var wheel_material: PhysicsMaterial + [/codeblock] </description> </annotation> <annotation name="@export_tool_button"> diff --git a/modules/gdscript/doc_classes/GDScript.xml b/modules/gdscript/doc_classes/GDScript.xml index 5f7a7e2915..c3fa59dc23 100644 --- a/modules/gdscript/doc_classes/GDScript.xml +++ b/modules/gdscript/doc_classes/GDScript.xml @@ -16,11 +16,10 @@ <return type="Variant" /> <description> Returns a new instance of the script. - For example: [codeblock] var MyClass = load("myclass.gd") var instance = MyClass.new() - assert(instance.get_script() == MyClass) + print(instance.get_script() == MyClass) # Prints true [/codeblock] </description> </method> diff --git a/modules/gdscript/editor/gdscript_highlighter.cpp b/modules/gdscript/editor/gdscript_highlighter.cpp index d765cfa1ea..0b12f2ff76 100644 --- a/modules/gdscript/editor/gdscript_highlighter.cpp +++ b/modules/gdscript/editor/gdscript_highlighter.cpp @@ -701,7 +701,9 @@ void GDScriptSyntaxHighlighter::_update_cache() { List<StringName> types; ClassDB::get_class_list(&types); for (const StringName &E : types) { - class_names[E] = types_color; + if (ClassDB::is_class_exposed(E)) { + class_names[E] = types_color; + } } /* User types. */ diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index 18f2ccc455..8c094c0ab0 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -76,9 +76,16 @@ bool GDScriptNativeClass::_get(const StringName &p_name, Variant &r_ret) const { if (ok) { r_ret = v; return true; - } else { - return false; } + + MethodBind *method = ClassDB::get_method(name, p_name); + if (method && method->is_static()) { + // Native static method. + r_ret = Callable(this, p_name); + return true; + } + + return false; } void GDScriptNativeClass::_bind_methods() { @@ -1068,6 +1075,26 @@ void GDScript::_bind_methods() { ClassDB::bind_vararg_method(METHOD_FLAGS_DEFAULT, "new", &GDScript::_new, MethodInfo("new")); } +void GDScript::set_path_cache(const String &p_path) { + if (ResourceCache::has(p_path)) { + set_path(p_path, true); + return; + } + + if (is_root_script()) { + Script::set_path_cache(p_path); + } + + String old_path = path; + path = p_path; + path_valid = true; + GDScriptCache::move_script(old_path, p_path); + + for (KeyValue<StringName, Ref<GDScript>> &kv : subclasses) { + kv.value->set_path_cache(p_path); + } +} + void GDScript::set_path(const String &p_path, bool p_take_over) { if (is_root_script()) { Script::set_path(p_path, p_take_over); @@ -1835,14 +1862,14 @@ Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool } void GDScriptInstance::validate_property(PropertyInfo &p_property) const { - Variant property = (Dictionary)p_property; - const Variant *args[1] = { &property }; - const GDScript *sptr = script.ptr(); while (sptr) { if (likely(sptr->valid)) { HashMap<StringName, GDScriptFunction *>::ConstIterator E = sptr->member_functions.find(GDScriptLanguage::get_singleton()->strings._validate_property); if (E) { + Variant property = (Dictionary)p_property; + const Variant *args[1] = { &property }; + Callable::CallError err; Variant ret = E->value->call(const_cast<GDScriptInstance *>(this), args, 1, err); if (err.error == Callable::CallError::CALL_OK) { @@ -2546,11 +2573,11 @@ void GDScriptLanguage::reload_all_scripts() { } } } -#endif +#endif // TOOLS_ENABLED } reload_scripts(scripts, true); -#endif +#endif // DEBUG_ENABLED } void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload) { @@ -2620,7 +2647,7 @@ void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload } } -#endif +#endif // TOOLS_ENABLED for (const KeyValue<ObjectID, List<Pair<StringName, Variant>>> &F : scr->pending_reload_state) { map[F.key] = F.value; //pending to reload, use this one instead @@ -2688,7 +2715,7 @@ void GDScriptLanguage::reload_scripts(const Array &p_scripts, bool p_soft_reload //if instance states were saved, set them! } -#endif +#endif // DEBUG_ENABLED } void GDScriptLanguage::reload_tool_script(const Ref<Script> &p_script, bool p_soft_reload) { diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 9bb39aac0f..006a09debb 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -300,6 +300,7 @@ public: virtual Error reload(bool p_keep_state = false) override; + virtual void set_path_cache(const String &p_path) override; virtual void set_path(const String &p_path, bool p_take_over = false) override; String get_script_path() const; Error load_source_code(const String &p_path); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 4a3a3a4b61..6241ada06a 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -940,8 +940,8 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, Finally finally([&]() { ensure_cached_external_parser_for_class(member.get_datatype().class_type, p_class, "Trying to resolve datatype of class member", p_source); GDScriptParser::DataType member_type = member.get_datatype(); - if (member_type.has_container_element_type(0)) { - ensure_cached_external_parser_for_class(member_type.get_container_element_type(0).class_type, p_class, "Trying to resolve datatype of class member", p_source); + for (int i = 0; i < member_type.get_container_element_type_count(); ++i) { + ensure_cached_external_parser_for_class(member_type.get_container_element_type(i).class_type, p_class, "Trying to resolve datatype of class member", p_source); } }); @@ -3816,6 +3816,12 @@ GDScriptParser::DataType GDScriptAnalyzer::make_global_class_meta_type(const Str } Ref<GDScriptParserRef> GDScriptAnalyzer::ensure_cached_external_parser_for_class(const GDScriptParser::ClassNode *p_class, const GDScriptParser::ClassNode *p_from_class, const char *p_context, const GDScriptParser::Node *p_source) { + // Delicate piece of code that intentionally doesn't use the GDScript cache or `get_depended_parser_for`. + // Search dependencies for the parser that owns `p_class` and make a cache entry for it. + // Required for how we store pointers to classes owned by other parser trees and need to call `resolve_class_member` and such on the same parser tree. + // Since https://github.com/godotengine/godot/pull/94871 there can technically be multiple parsers for the same script in the same parser tree. + // Even if unlikely, getting the wrong parser could lead to strange undefined behavior without errors. + if (p_class == nullptr) { return nullptr; } @@ -3832,8 +3838,6 @@ Ref<GDScriptParserRef> GDScriptAnalyzer::ensure_cached_external_parser_for_class p_from_class = parser->head; } - String script_path = p_class->get_datatype().script_path; - Ref<GDScriptParserRef> parser_ref; for (const GDScriptParser::ClassNode *look_class = p_from_class; look_class != nullptr; look_class = look_class->base_type.class_type) { if (parser->has_class(look_class)) { @@ -5805,8 +5809,6 @@ void GDScriptAnalyzer::validate_call_arg(const List<GDScriptParser::DataType> &p #ifdef DEBUG_ENABLED void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier, const String &p_context, const bool p_in_local_scope) { const StringName &name = p_identifier->name; - GDScriptParser::DataType base = parser->current_class->get_datatype(); - GDScriptParser::ClassNode *base_class = base.class_type; { List<MethodInfo> gdscript_funcs; @@ -5834,40 +5836,56 @@ void GDScriptAnalyzer::is_shadowing(GDScriptParser::IdentifierNode *p_identifier } } + const GDScriptParser::DataType current_class_type = parser->current_class->get_datatype(); if (p_in_local_scope) { - while (base_class != nullptr) { + GDScriptParser::ClassNode *base_class = current_class_type.class_type; + + if (base_class != nullptr) { if (base_class->has_member(name)) { parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line())); return; } base_class = base_class->base_type.class_type; } + + while (base_class != nullptr) { + if (base_class->has_member(name)) { + String base_class_name = base_class->get_global_name(); + if (base_class_name.is_empty()) { + base_class_name = base_class->fqcn; + } + + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, base_class->get_member(name).get_type_name(), itos(base_class->get_member(name).get_line()), base_class_name); + return; + } + base_class = base_class->base_type.class_type; + } } - StringName parent = base.native_type; - while (parent != StringName()) { - ERR_FAIL_COND_MSG(!class_exists(parent), "Non-existent native base class."); + StringName native_base_class = current_class_type.native_type; + while (native_base_class != StringName()) { + ERR_FAIL_COND_MSG(!class_exists(native_base_class), "Non-existent native base class."); - if (ClassDB::has_method(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", parent); + if (ClassDB::has_method(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "method", native_base_class); return; - } else if (ClassDB::has_signal(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", parent); + } else if (ClassDB::has_signal(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "signal", native_base_class); return; - } else if (ClassDB::has_property(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", parent); + } else if (ClassDB::has_property(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "property", native_base_class); return; - } else if (ClassDB::has_integer_constant(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", parent); + } else if (ClassDB::has_integer_constant(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "constant", native_base_class); return; - } else if (ClassDB::has_enum(parent, name, true)) { - parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", parent); + } else if (ClassDB::has_enum(native_base_class, name, true)) { + parser->push_warning(p_identifier, GDScriptWarning::SHADOWED_VARIABLE_BASE_CLASS, p_context, p_identifier->name, "enum", native_base_class); return; } - parent = ClassDB::get_parent_class(parent); + native_base_class = ClassDB::get_parent_class(native_base_class); } } -#endif +#endif // DEBUG_ENABLED GDScriptParser::DataType GDScriptAnalyzer::get_operation_type(Variant::Operator p_operation, const GDScriptParser::DataType &p_a, bool &r_valid, const GDScriptParser::Node *p_source) { // Unary version. diff --git a/modules/gdscript/gdscript_cache.cpp b/modules/gdscript/gdscript_cache.cpp index 3c022412bd..fa22798edf 100644 --- a/modules/gdscript/gdscript_cache.cpp +++ b/modules/gdscript/gdscript_cache.cpp @@ -312,7 +312,7 @@ Ref<GDScript> GDScriptCache::get_shallow_script(const String &p_path, Error &r_e Ref<GDScript> script; script.instantiate(); - script->set_path(p_path, true); + script->set_path_cache(p_path); if (remapped_path.get_extension().to_lower() == "gdc") { Vector<uint8_t> buffer = get_binary_tokens(remapped_path); if (buffer.is_empty()) { @@ -360,6 +360,7 @@ Ref<GDScript> GDScriptCache::get_full_script(const String &p_path, Error &r_erro return script; } } + script->set_path(p_path, true); const String remapped_path = ResourceLoader::path_remap(p_path); diff --git a/modules/gdscript/gdscript_disassembler.cpp b/modules/gdscript/gdscript_disassembler.cpp index bc063693a3..d94a6dfda2 100644 --- a/modules/gdscript/gdscript_disassembler.cpp +++ b/modules/gdscript/gdscript_disassembler.cpp @@ -790,8 +790,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += method->get_name(); text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; @@ -833,8 +834,9 @@ void GDScriptFunction::disassemble(const Vector<String> &p_code_lines) const { text += method->get_name(); text += "("; for (int i = 0; i < argc; i++) { - if (i > 0) + if (i > 0) { text += ", "; + } text += DADDR(1 + i); } text += ")"; diff --git a/modules/gdscript/gdscript_editor.cpp b/modules/gdscript/gdscript_editor.cpp index 3de1decc18..951ae6ce99 100644 --- a/modules/gdscript/gdscript_editor.cpp +++ b/modules/gdscript/gdscript_editor.cpp @@ -3164,7 +3164,9 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c HashMap<String, ScriptLanguage::CodeCompletionOption> options; GDScriptParser::CompletionContext completion_context = parser.get_completion_context(); - completion_context.base = p_owner; + if (completion_context.current_class != nullptr && completion_context.current_class->outer == nullptr) { + completion_context.base = p_owner; + } bool is_function = false; switch (completion_context.type) { @@ -3534,13 +3536,13 @@ static void _find_call_arguments(GDScriptParser::CompletionContext &p_context, c return OK; } -#else +#else // !TOOLS_ENABLED Error GDScriptLanguage::complete_code(const String &p_code, const String &p_path, Object *p_owner, List<ScriptLanguage::CodeCompletionOption> *r_options, bool &r_forced, String &r_call_hint) { return OK; } -#endif +#endif // TOOLS_ENABLED //////// END COMPLETION ////////// @@ -4125,4 +4127,4 @@ static Error _lookup_symbol_from_base(const GDScriptParser::DataType &p_base, co return ERR_CANT_RESOLVE; } -#endif +#endif // TOOLS_ENABLED diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index e30f03afad..ee8d53639c 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -244,7 +244,7 @@ void GDScriptParser::apply_pending_warnings() { pending_warnings.clear(); } -#endif +#endif // DEBUG_ENABLED void GDScriptParser::override_completion_context(const Node *p_for_node, CompletionType p_type, Node *p_node, int p_argument) { if (!for_completion) { diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 7f64ae902b..2ec33831a2 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -165,6 +165,10 @@ public: container_element_types.write[p_index] = DataType(p_type); } + _FORCE_INLINE_ int get_container_element_type_count() const { + return container_element_types.size(); + } + _FORCE_INLINE_ DataType get_container_element_type(int p_index) const { ERR_FAIL_INDEX_V(p_index, container_element_types.size(), get_variant_type()); return container_element_types[p_index]; diff --git a/modules/gdscript/gdscript_tokenizer_buffer.h b/modules/gdscript/gdscript_tokenizer_buffer.h index 55df66e50f..d5d2a4d096 100644 --- a/modules/gdscript/gdscript_tokenizer_buffer.h +++ b/modules/gdscript/gdscript_tokenizer_buffer.h @@ -79,7 +79,7 @@ public: virtual bool is_past_cursor() const override; virtual void push_expression_indented_block() override; // For lambdas, or blocks inside expressions. virtual void pop_expression_indented_block() override; // For lambdas, or blocks inside expressions. - virtual bool is_text() override { return false; }; + virtual bool is_text() override { return false; } #ifdef TOOLS_ENABLED virtual const HashMap<int, CommentData> &get_comments() const override { diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 59dd983ed2..8246069696 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -34,7 +34,6 @@ #include "core/io/resource_loader.h" #include "core/object/class_db.h" -#include "core/object/method_bind.h" #include "core/object/object.h" #include "core/templates/oa_hash_map.h" #include "core/templates/vector.h" @@ -42,101 +41,105 @@ #ifdef DEBUG_ENABLED -#define VALIDATE_ARG_COUNT(m_count) \ - if (p_arg_count < m_count) { \ - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \ - r_error.expected = m_count; \ +#define DEBUG_VALIDATE_ARG_COUNT(m_min_count, m_max_count) \ + if (unlikely(p_arg_count < m_min_count)) { \ *r_ret = Variant(); \ + r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; \ + r_error.expected = m_min_count; \ return; \ } \ - if (p_arg_count > m_count) { \ - r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \ - r_error.expected = m_count; \ + if (unlikely(p_arg_count > m_max_count)) { \ *r_ret = Variant(); \ + r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; \ + r_error.expected = m_max_count; \ return; \ } -#define VALIDATE_ARG_INT(m_arg) \ - if (p_args[m_arg]->get_type() != Variant::INT) { \ +#define DEBUG_VALIDATE_ARG_TYPE(m_arg, m_type) \ + if (unlikely(!Variant::can_convert_strict(p_args[m_arg]->get_type(), m_type))) { \ + *r_ret = Variant(); \ + r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \ + r_error.argument = m_arg; \ + r_error.expected = m_type; \ + return; \ + } + +#define DEBUG_VALIDATE_ARG_CUSTOM(m_arg, m_type, m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + *r_ret = m_msg; \ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \ r_error.argument = m_arg; \ - r_error.expected = Variant::INT; \ - *r_ret = Variant(); \ + r_error.expected = m_type; \ return; \ } -#define VALIDATE_ARG_NUM(m_arg) \ - if (!p_args[m_arg]->is_num()) { \ +#else // !DEBUG_ENABLED + +#define DEBUG_VALIDATE_ARG_COUNT(m_min_count, m_max_count) +#define DEBUG_VALIDATE_ARG_TYPE(m_arg, m_type) +#define DEBUG_VALIDATE_ARG_CUSTOM(m_arg, m_type, m_cond, m_msg) + +#endif // DEBUG_ENABLED + +#define VALIDATE_ARG_CUSTOM(m_arg, m_type, m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + *r_ret = m_msg; \ r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; \ r_error.argument = m_arg; \ - r_error.expected = Variant::FLOAT; \ - *r_ret = Variant(); \ + r_error.expected = m_type; \ return; \ } -#else - -#define VALIDATE_ARG_COUNT(m_count) -#define VALIDATE_ARG_INT(m_arg) -#define VALIDATE_ARG_NUM(m_arg) - -#endif +#define GDFUNC_FAIL_COND_MSG(m_cond, m_msg) \ + if (unlikely(m_cond)) { \ + *r_ret = m_msg; \ + r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; \ + return; \ + } struct GDScriptUtilityFunctionsDefinitions { #ifndef DISABLE_DEPRECATED static inline void convert(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(2); - VALIDATE_ARG_INT(1); + DEBUG_VALIDATE_ARG_COUNT(2, 2); + DEBUG_VALIDATE_ARG_TYPE(1, Variant::INT); + int type = *p_args[1]; - if (type < 0 || type >= Variant::VARIANT_MAX) { - *r_ret = RTR("Invalid type argument to convert(), use TYPE_* constants."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::INT; - return; + DEBUG_VALIDATE_ARG_CUSTOM(1, Variant::INT, type < 0 || type >= Variant::VARIANT_MAX, + RTR("Invalid type argument to convert(), use TYPE_* constants.")); - } else { - Variant::construct(Variant::Type(type), *r_ret, p_args, 1, r_error); - if (r_error.error != Callable::CallError::CALL_OK) { - *r_ret = vformat(RTR(R"(Cannot convert "%s" to "%s".)"), Variant::get_type_name(p_args[0]->get_type()), Variant::get_type_name(Variant::Type(type))); - } - } + Variant::construct(Variant::Type(type), *r_ret, p_args, 1, r_error); } #endif // DISABLE_DEPRECATED static inline void type_exists(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(1); + DEBUG_VALIDATE_ARG_COUNT(1, 1); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::STRING_NAME); *r_ret = ClassDB::class_exists(*p_args[0]); } static inline void _char(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(1); - VALIDATE_ARG_INT(0); + DEBUG_VALIDATE_ARG_COUNT(1, 1); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::INT); char32_t result[2] = { *p_args[0], 0 }; *r_ret = String(result); } static inline void range(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { + DEBUG_VALIDATE_ARG_COUNT(1, 3); switch (p_arg_count) { - case 0: { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.expected = 1; - *r_ret = Variant(); - } break; case 1: { - VALIDATE_ARG_NUM(0); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::INT); + int count = *p_args[0]; + Array arr; if (count <= 0) { *r_ret = arr; return; } + Error err = arr.resize(count); - if (err != OK) { - *r_ret = RTR("Cannot resize array."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return; - } + GDFUNC_FAIL_COND_MSG(err != OK, RTR("Cannot resize array.")); for (int i = 0; i < count; i++) { arr[i] = i; @@ -145,8 +148,8 @@ struct GDScriptUtilityFunctionsDefinitions { *r_ret = arr; } break; case 2: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::INT); + DEBUG_VALIDATE_ARG_TYPE(1, Variant::INT); int from = *p_args[0]; int to = *p_args[1]; @@ -156,30 +159,26 @@ struct GDScriptUtilityFunctionsDefinitions { *r_ret = arr; return; } + Error err = arr.resize(to - from); - if (err != OK) { - *r_ret = RTR("Cannot resize array."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return; - } + GDFUNC_FAIL_COND_MSG(err != OK, RTR("Cannot resize array.")); + for (int i = from; i < to; i++) { arr[i - from] = i; } + *r_ret = arr; } break; case 3: { - VALIDATE_ARG_NUM(0); - VALIDATE_ARG_NUM(1); - VALIDATE_ARG_NUM(2); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::INT); + DEBUG_VALIDATE_ARG_TYPE(1, Variant::INT); + DEBUG_VALIDATE_ARG_TYPE(2, Variant::INT); int from = *p_args[0]; int to = *p_args[1]; int incr = *p_args[2]; - if (incr == 0) { - *r_ret = RTR("Step argument is zero!"); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return; - } + + VALIDATE_ARG_CUSTOM(2, Variant::INT, incr == 0, RTR("Step argument is zero!")); Array arr; if (from >= to && incr > 0) { @@ -200,12 +199,7 @@ struct GDScriptUtilityFunctionsDefinitions { } Error err = arr.resize(count); - - if (err != OK) { - *r_ret = RTR("Cannot resize array."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_METHOD; - return; - } + GDFUNC_FAIL_COND_MSG(err != OK, RTR("Cannot resize array.")); if (incr > 0) { int idx = 0; @@ -221,138 +215,79 @@ struct GDScriptUtilityFunctionsDefinitions { *r_ret = arr; } break; - default: { - r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.expected = 3; - *r_ret = Variant(); - - } break; } } static inline void load(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(1); - if (!p_args[0]->is_string()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::STRING; - *r_ret = Variant(); - } else { - *r_ret = ResourceLoader::load(*p_args[0]); - } + DEBUG_VALIDATE_ARG_COUNT(1, 1); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::STRING); + *r_ret = ResourceLoader::load(*p_args[0]); } static inline void inst_to_dict(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(1); + DEBUG_VALIDATE_ARG_COUNT(1, 1); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::OBJECT); if (p_args[0]->get_type() == Variant::NIL) { *r_ret = Variant(); - } else if (p_args[0]->get_type() != Variant::OBJECT) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; + return; + } + + Object *obj = *p_args[0]; + if (!obj) { *r_ret = Variant(); - } else { - Object *obj = *p_args[0]; - if (!obj) { - *r_ret = Variant(); + return; + } - } else if (!obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::DICTIONARY; - *r_ret = RTR("Not a script with an instance"); - return; - } else { - GDScriptInstance *ins = static_cast<GDScriptInstance *>(obj->get_script_instance()); - Ref<GDScript> base = ins->get_script(); - if (base.is_null()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::DICTIONARY; - *r_ret = RTR("Not based on a script"); - return; - } + VALIDATE_ARG_CUSTOM(0, Variant::OBJECT, + !obj->get_script_instance() || obj->get_script_instance()->get_language() != GDScriptLanguage::get_singleton(), + RTR("Not a script with an instance.")); - GDScript *p = base.ptr(); - String path = p->get_script_path(); - Vector<StringName> sname; + GDScriptInstance *inst = static_cast<GDScriptInstance *>(obj->get_script_instance()); - while (p->_owner) { - sname.push_back(p->local_name); - p = p->_owner; - } - sname.reverse(); + Ref<GDScript> base = inst->get_script(); + VALIDATE_ARG_CUSTOM(0, Variant::OBJECT, base.is_null(), RTR("Not based on a script.")); - if (!path.is_resource_file()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::DICTIONARY; - *r_ret = Variant(); + GDScript *p = base.ptr(); + String path = p->get_script_path(); + Vector<StringName> sname; - *r_ret = RTR("Not based on a resource file"); + while (p->_owner) { + sname.push_back(p->local_name); + p = p->_owner; + } + sname.reverse(); - return; - } + VALIDATE_ARG_CUSTOM(0, Variant::OBJECT, !path.is_resource_file(), RTR("Not based on a resource file.")); - NodePath cp(sname, Vector<StringName>(), false); + NodePath cp(sname, Vector<StringName>(), false); - Dictionary d; - d["@subpath"] = cp; - d["@path"] = path; + Dictionary d; + d["@subpath"] = cp; + d["@path"] = path; - for (const KeyValue<StringName, GDScript::MemberInfo> &E : base->member_indices) { - if (!d.has(E.key)) { - d[E.key] = ins->members[E.value.index]; - } - } - *r_ret = d; + for (const KeyValue<StringName, GDScript::MemberInfo> &E : base->member_indices) { + if (!d.has(E.key)) { + d[E.key] = inst->members[E.value.index]; } } + + *r_ret = d; } static inline void dict_to_inst(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(1); - - if (p_args[0]->get_type() != Variant::DICTIONARY) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::DICTIONARY; - *r_ret = Variant(); - - return; - } + DEBUG_VALIDATE_ARG_COUNT(1, 1); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::DICTIONARY); Dictionary d = *p_args[0]; - if (!d.has("@path")) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - *r_ret = RTR("Invalid instance dictionary format (missing @path)"); - - return; - } + VALIDATE_ARG_CUSTOM(0, Variant::DICTIONARY, !d.has("@path"), RTR("Invalid instance dictionary format (missing @path).")); Ref<Script> scr = ResourceLoader::load(d["@path"]); - if (!scr.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - *r_ret = RTR("Invalid instance dictionary format (can't load script at @path)"); - return; - } + VALIDATE_ARG_CUSTOM(0, Variant::DICTIONARY, !scr.is_valid(), RTR("Invalid instance dictionary format (can't load script at @path).")); Ref<GDScript> gdscr = scr; - - if (!gdscr.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - *r_ret = Variant(); - *r_ret = RTR("Invalid instance dictionary format (invalid script at @path)"); - return; - } + VALIDATE_ARG_CUSTOM(0, Variant::DICTIONARY, !gdscr.is_valid(), RTR("Invalid instance dictionary format (invalid script at @path).")); NodePath sub; if (d.has("@subpath")) { @@ -361,54 +296,35 @@ struct GDScriptUtilityFunctionsDefinitions { for (int i = 0; i < sub.get_name_count(); i++) { gdscr = gdscr->subclasses[sub.get_name(i)]; - if (!gdscr.is_valid()) { - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::OBJECT; - *r_ret = Variant(); - *r_ret = RTR("Invalid instance dictionary (invalid subclasses)"); - return; - } + VALIDATE_ARG_CUSTOM(0, Variant::DICTIONARY, !gdscr.is_valid(), RTR("Invalid instance dictionary (invalid subclasses).")); } - *r_ret = gdscr->_new(nullptr, -1 /*skip initializer*/, r_error); + *r_ret = gdscr->_new(nullptr, -1 /* skip initializer */, r_error); if (r_error.error != Callable::CallError::CALL_OK) { *r_ret = RTR("Cannot instantiate GDScript class."); return; } - GDScriptInstance *ins = static_cast<GDScriptInstance *>(static_cast<Object *>(*r_ret)->get_script_instance()); - Ref<GDScript> gd_ref = ins->get_script(); + GDScriptInstance *inst = static_cast<GDScriptInstance *>(static_cast<Object *>(*r_ret)->get_script_instance()); + Ref<GDScript> gd_ref = inst->get_script(); for (KeyValue<StringName, GDScript::MemberInfo> &E : gd_ref->member_indices) { if (d.has(E.key)) { - ins->members.write[E.value.index] = d[E.key]; + inst->members.write[E.value.index] = d[E.key]; } } } static inline void Color8(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - if (p_arg_count < 3) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS; - r_error.expected = 3; - *r_ret = Variant(); - return; - } - if (p_arg_count > 4) { - r_error.error = Callable::CallError::CALL_ERROR_TOO_MANY_ARGUMENTS; - r_error.expected = 4; - *r_ret = Variant(); - return; - } - - VALIDATE_ARG_INT(0); - VALIDATE_ARG_INT(1); - VALIDATE_ARG_INT(2); + DEBUG_VALIDATE_ARG_COUNT(3, 4); + DEBUG_VALIDATE_ARG_TYPE(0, Variant::INT); + DEBUG_VALIDATE_ARG_TYPE(1, Variant::INT); + DEBUG_VALIDATE_ARG_TYPE(2, Variant::INT); Color color((int64_t)*p_args[0] / 255.0f, (int64_t)*p_args[1] / 255.0f, (int64_t)*p_args[2] / 255.0f); if (p_arg_count == 4) { - VALIDATE_ARG_INT(3); + DEBUG_VALIDATE_ARG_TYPE(3, Variant::INT); color.a = (int64_t)*p_args[3] / 255.0f; } @@ -435,7 +351,8 @@ 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); + DEBUG_VALIDATE_ARG_COUNT(0, 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; @@ -449,7 +366,8 @@ struct GDScriptUtilityFunctionsDefinitions { } static inline void get_stack(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(0); + DEBUG_VALIDATE_ARG_COUNT(0, 0); + if (Thread::get_caller_id() != Thread::get_main_id()) { *r_ret = TypedArray<Dictionary>(); return; @@ -468,7 +386,7 @@ struct GDScriptUtilityFunctionsDefinitions { } static inline void len(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(1); + DEBUG_VALIDATE_ARG_COUNT(1, 1); switch (p_args[0]->get_type()) { case Variant::STRING: case Variant::STRING_NAME: { @@ -524,56 +442,34 @@ struct GDScriptUtilityFunctionsDefinitions { *r_ret = d.size(); } break; default: { + *r_ret = vformat(RTR("Value of type '%s' can't provide a length."), Variant::get_type_name(p_args[0]->get_type())); r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; r_error.argument = 0; r_error.expected = Variant::NIL; - *r_ret = vformat(RTR("Value of type '%s' can't provide a length."), Variant::get_type_name(p_args[0]->get_type())); - } + } break; } } static inline void is_instance_of(Variant *r_ret, const Variant **p_args, int p_arg_count, Callable::CallError &r_error) { - VALIDATE_ARG_COUNT(2); + DEBUG_VALIDATE_ARG_COUNT(2, 2); if (p_args[1]->get_type() == Variant::INT) { int builtin_type = *p_args[1]; - if (builtin_type < 0 || builtin_type >= Variant::VARIANT_MAX) { - *r_ret = RTR("Invalid type argument for is_instance_of(), use TYPE_* constants for built-in types."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::NIL; - return; - } + DEBUG_VALIDATE_ARG_CUSTOM(1, Variant::NIL, builtin_type < 0 || builtin_type >= Variant::VARIANT_MAX, + RTR("Invalid type argument for is_instance_of(), use TYPE_* constants for built-in types.")); *r_ret = p_args[0]->get_type() == builtin_type; return; } bool was_type_freed = false; Object *type_object = p_args[1]->get_validated_object_with_check(was_type_freed); - if (was_type_freed) { - *r_ret = RTR("Type argument is a previously freed instance."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::NIL; - return; - } - if (!type_object) { - *r_ret = RTR("Invalid type argument for is_instance_of(), should be a TYPE_* constant, a class or a script."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 1; - r_error.expected = Variant::NIL; - return; - } + VALIDATE_ARG_CUSTOM(1, Variant::NIL, was_type_freed, RTR("Type argument is a previously freed instance.")); + VALIDATE_ARG_CUSTOM(1, Variant::NIL, !type_object, + RTR("Invalid type argument for is_instance_of(), should be a TYPE_* constant, a class or a script.")); bool was_value_freed = false; Object *value_object = p_args[0]->get_validated_object_with_check(was_value_freed); - if (was_value_freed) { - *r_ret = RTR("Value argument is a previously freed instance."); - r_error.error = Callable::CallError::CALL_ERROR_INVALID_ARGUMENT; - r_error.argument = 0; - r_error.expected = Variant::NIL; - return; - } + VALIDATE_ARG_CUSTOM(0, Variant::NIL, was_value_freed, RTR("Value argument is a previously freed instance.")); if (!value_object) { *r_ret = false; return; @@ -618,113 +514,77 @@ struct GDScriptUtilityFunctionInfo { static OAHashMap<StringName, GDScriptUtilityFunctionInfo> utility_function_table; static List<StringName> utility_function_name_table; -static void _register_function(const String &p_name, const MethodInfo &p_method_info, GDScriptUtilityFunctions::FunctionPtr p_function, bool p_is_const) { - StringName sname(p_name); - - ERR_FAIL_COND(utility_function_table.has(sname)); +static void _register_function(const StringName &p_name, const MethodInfo &p_method_info, GDScriptUtilityFunctions::FunctionPtr p_function, bool p_is_const) { + ERR_FAIL_COND(utility_function_table.has(p_name)); GDScriptUtilityFunctionInfo function; function.function = p_function; function.info = p_method_info; function.is_constant = p_is_const; - utility_function_table.insert(sname, function); - utility_function_name_table.push_back(sname); + utility_function_table.insert(p_name, function); + utility_function_name_table.push_back(p_name); } -#define REGISTER_FUNC(m_func, m_is_const, m_return_type, ...) \ +#define REGISTER_FUNC(m_func, m_is_const, m_return, m_args, m_is_vararg, m_default_args) \ { \ String name(#m_func); \ if (name.begins_with("_")) { \ - name = name.substr(1, name.length() - 1); \ + name = name.substr(1); \ } \ - MethodInfo info = MethodInfo(name, __VA_ARGS__); \ - info.return_val.type = m_return_type; \ - _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \ - } - -#define REGISTER_FUNC_NO_ARGS(m_func, m_is_const, m_return_type) \ - { \ - String name(#m_func); \ - if (name.begins_with("_")) { \ - name = name.substr(1, name.length() - 1); \ + MethodInfo info = m_args; \ + info.name = name; \ + info.return_val = m_return; \ + info.default_arguments = m_default_args; \ + if (m_is_vararg) { \ + info.flags |= METHOD_FLAG_VARARG; \ } \ - MethodInfo info = MethodInfo(name); \ - info.return_val.type = m_return_type; \ _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \ } -#define REGISTER_VARARG_FUNC(m_func, m_is_const, m_return_type) \ - { \ - String name(#m_func); \ - if (name.begins_with("_")) { \ - name = name.substr(1, name.length() - 1); \ - } \ - MethodInfo info = MethodInfo(name); \ - info.return_val.type = m_return_type; \ - info.flags |= METHOD_FLAG_VARARG; \ - _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \ - } +#define RET(m_type) \ + PropertyInfo(Variant::m_type, "") -#define REGISTER_VARIANT_FUNC(m_func, m_is_const, ...) \ - { \ - String name(#m_func); \ - if (name.begins_with("_")) { \ - name = name.substr(1, name.length() - 1); \ - } \ - MethodInfo info = MethodInfo(name, __VA_ARGS__); \ - info.return_val.type = Variant::NIL; \ - info.return_val.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; \ - _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \ - } +#define RETVAR \ + PropertyInfo(Variant::NIL, "", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT) -#define REGISTER_CLASS_FUNC(m_func, m_is_const, m_return_type, ...) \ - { \ - String name(#m_func); \ - if (name.begins_with("_")) { \ - name = name.substr(1, name.length() - 1); \ - } \ - MethodInfo info = MethodInfo(name, __VA_ARGS__); \ - info.return_val.type = Variant::OBJECT; \ - info.return_val.hint = PROPERTY_HINT_RESOURCE_TYPE; \ - info.return_val.class_name = m_return_type; \ - _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \ - } +#define RETCLS(m_class) \ + PropertyInfo(Variant::OBJECT, "", PROPERTY_HINT_RESOURCE_TYPE, m_class) -#define REGISTER_FUNC_DEF(m_func, m_is_const, m_default, m_return_type, ...) \ - { \ - String name(#m_func); \ - if (name.begins_with("_")) { \ - name = name.substr(1, name.length() - 1); \ - } \ - MethodInfo info = MethodInfo(name, __VA_ARGS__); \ - info.return_val.type = m_return_type; \ - info.default_arguments.push_back(m_default); \ - _register_function(name, info, GDScriptUtilityFunctionsDefinitions::m_func, m_is_const); \ - } +#define NOARGS \ + MethodInfo() + +#define ARGS(...) \ + MethodInfo("", __VA_ARGS__) #define ARG(m_name, m_type) \ - PropertyInfo(m_type, m_name) + PropertyInfo(Variant::m_type, m_name) + +#define ARGVAR(m_name) \ + PropertyInfo(Variant::NIL, m_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NIL_IS_VARIANT) -#define VARARG(m_name) \ - PropertyInfo(Variant::NIL, m_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_DEFAULT | PROPERTY_USAGE_NIL_IS_VARIANT) +#define ARGTYPE(m_name) \ + PropertyInfo(Variant::INT, m_name, PROPERTY_HINT_NONE, "", PROPERTY_USAGE_CLASS_IS_ENUM, "Variant.Type") void GDScriptUtilityFunctions::register_functions() { + /* clang-format off */ #ifndef DISABLE_DEPRECATED - REGISTER_VARIANT_FUNC(convert, true, VARARG("what"), ARG("type", Variant::INT)); + REGISTER_FUNC( convert, true, RETVAR, ARGS( ARGVAR("what"), ARGTYPE("type") ), false, varray( )); #endif // DISABLE_DEPRECATED - REGISTER_FUNC(type_exists, true, Variant::BOOL, ARG("type", Variant::STRING_NAME)); - REGISTER_FUNC(_char, true, Variant::STRING, ARG("char", Variant::INT)); - REGISTER_VARARG_FUNC(range, false, Variant::ARRAY); - REGISTER_CLASS_FUNC(load, false, "Resource", ARG("path", Variant::STRING)); - REGISTER_FUNC(inst_to_dict, false, Variant::DICTIONARY, ARG("instance", Variant::OBJECT)); - REGISTER_FUNC(dict_to_inst, false, Variant::OBJECT, ARG("dictionary", Variant::DICTIONARY)); - REGISTER_FUNC_DEF(Color8, true, 255, Variant::COLOR, ARG("r8", Variant::INT), ARG("g8", Variant::INT), ARG("b8", Variant::INT), ARG("a8", Variant::INT)); - REGISTER_VARARG_FUNC(print_debug, false, Variant::NIL); - REGISTER_FUNC_NO_ARGS(print_stack, false, Variant::NIL); - REGISTER_FUNC_NO_ARGS(get_stack, false, Variant::ARRAY); - REGISTER_FUNC(len, true, Variant::INT, VARARG("var")); - REGISTER_FUNC(is_instance_of, true, Variant::BOOL, VARARG("value"), VARARG("type")); + REGISTER_FUNC( type_exists, true, RET(BOOL), ARGS( ARG("type", STRING_NAME) ), false, varray( )); + REGISTER_FUNC( _char, true, RET(STRING), ARGS( ARG("char", INT) ), false, varray( )); + REGISTER_FUNC( range, false, RET(ARRAY), NOARGS, true, varray( )); + REGISTER_FUNC( load, false, RETCLS("Resource"), ARGS( ARG("path", STRING) ), false, varray( )); + REGISTER_FUNC( inst_to_dict, false, RET(DICTIONARY), ARGS( ARG("instance", OBJECT) ), false, varray( )); + REGISTER_FUNC( dict_to_inst, false, RET(OBJECT), ARGS( ARG("dictionary", DICTIONARY) ), false, varray( )); + REGISTER_FUNC( Color8, true, RET(COLOR), ARGS( ARG("r8", INT), ARG("g8", INT), + ARG("b8", INT), ARG("a8", INT) ), false, varray( 255 )); + REGISTER_FUNC( print_debug, false, RET(NIL), NOARGS, true, varray( )); + REGISTER_FUNC( print_stack, false, RET(NIL), NOARGS, false, varray( )); + REGISTER_FUNC( get_stack, false, RET(ARRAY), NOARGS, false, varray( )); + REGISTER_FUNC( len, true, RET(INT), ARGS( ARGVAR("var") ), false, varray( )); + REGISTER_FUNC( is_instance_of, true, RET(BOOL), ARGS( ARGVAR("value"), ARGVAR("type") ), false, varray( )); + /* clang-format on */ } void GDScriptUtilityFunctions::unregister_functions() { diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index d8139d913a..26c5cfe23c 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -397,32 +397,36 @@ void (*type_init_function_table[])(Variant *) = { #define OPCODES_OUT \ OPSOUT: #define OPCODE_SWITCH(m_test) goto *switch_table_ops[m_test]; + #ifdef DEBUG_ENABLED #define DISPATCH_OPCODE \ last_opcode = _code_ptr[ip]; \ goto *switch_table_ops[last_opcode] -#else +#else // !DEBUG_ENABLED #define DISPATCH_OPCODE goto *switch_table_ops[_code_ptr[ip]] -#endif +#endif // DEBUG_ENABLED + #define OPCODE_BREAK goto OPSEXIT #define OPCODE_OUT goto OPSOUT -#else +#else // !(defined(__GNUC__) || defined(__clang__)) #define OPCODES_TABLE #define OPCODE(m_op) case m_op: #define OPCODE_WHILE(m_test) while (m_test) #define OPCODES_END #define OPCODES_OUT #define DISPATCH_OPCODE continue + #ifdef _MSC_VER #define OPCODE_SWITCH(m_test) \ __assume(m_test <= OPCODE_END); \ switch (m_test) -#else +#else // !_MSC_VER #define OPCODE_SWITCH(m_test) switch (m_test) -#endif +#endif // _MSC_VER + #define OPCODE_BREAK break #define OPCODE_OUT break -#endif +#endif // defined(__GNUC__) || defined(__clang__) // Helpers for VariantInternal methods in macros. #define OP_GET_BOOL get_bool @@ -663,7 +667,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; \ } -#else +#else // !DEBUG_ENABLED #define GD_ERR_BREAK(m_cond) #define CHECK_SPACE(m_space) @@ -676,7 +680,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a OPCODE_BREAK; \ } -#endif +#endif // DEBUG_ENABLED #define LOAD_INSTRUCTION_ARGS \ int instr_arg_count = _code_ptr[ip + 1]; \ @@ -1965,7 +1969,7 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a err_text = _get_call_error("function '" + methodstr + (is_callable ? "" : "' in base '" + basestr) + "'", (const Variant **)argptrs, temp_ret, err); OPCODE_BREAK; } -#endif +#endif // DEBUG_ENABLED ip += 3; } diff --git a/modules/gdscript/gdscript_warning.cpp b/modules/gdscript/gdscript_warning.cpp index 4ffb4bd9d1..a601cc4993 100644 --- a/modules/gdscript/gdscript_warning.cpp +++ b/modules/gdscript/gdscript_warning.cpp @@ -61,10 +61,13 @@ String GDScriptWarning::get_message() const { return vformat(R"(The signal "%s" is declared but never explicitly used in the class.)", symbols[0]); case SHADOWED_VARIABLE: CHECK_SYMBOLS(4); - return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s.)", symbols[0], symbols[1], symbols[2], symbols[3]); + return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s in the current class.)", symbols[0], symbols[1], symbols[2], symbols[3]); case SHADOWED_VARIABLE_BASE_CLASS: CHECK_SYMBOLS(4); - return vformat(R"(The local %s "%s" is shadowing an already-declared %s at the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3]); + if (symbols.size() > 4) { + return vformat(R"(The local %s "%s" is shadowing an already-declared %s at line %s in the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3], symbols[4]); + } + return vformat(R"(The local %s "%s" is shadowing an already-declared %s in the base class "%s".)", symbols[0], symbols[1], symbols[2], symbols[3]); 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]); diff --git a/modules/gdscript/gdscript_warning.h b/modules/gdscript/gdscript_warning.h index ffcf00a830..99e9b30af5 100644 --- a/modules/gdscript/gdscript_warning.h +++ b/modules/gdscript/gdscript_warning.h @@ -53,8 +53,8 @@ public: UNUSED_PRIVATE_CLASS_VARIABLE, // Class variable is declared private ("_" prefix) but never used in the class. UNUSED_PARAMETER, // Function parameter is never used. UNUSED_SIGNAL, // Signal is defined but never explicitly used in the class. - SHADOWED_VARIABLE, // Variable name shadowed by other variable in same class. - SHADOWED_VARIABLE_BASE_CLASS, // Variable name shadowed by other variable in some base class. + SHADOWED_VARIABLE, // A local variable/constant shadows a current class member. + SHADOWED_VARIABLE_BASE_CLASS, // A local variable/constant shadows a base class member. SHADOWED_GLOBAL_IDENTIFIER, // A global class or function has the same name as variable. UNREACHABLE_CODE, // Code after a return statement. UNREACHABLE_PATTERN, // Pattern in a match statement after a catch all pattern (wildcard or bind). diff --git a/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out index 94e2ec2af8..fb616f1e94 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out +++ b/modules/gdscript/tests/scripts/analyzer/features/class_inference_is_weak.out @@ -1,2 +1,2 @@ GDTEST_OK -0 +0.0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/const_conversions.gd b/modules/gdscript/tests/scripts/analyzer/features/const_conversions.gd index 5318d11f33..e91c7386fe 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/const_conversions.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/const_conversions.gd @@ -7,17 +7,17 @@ const const_packed_ints: PackedFloat64Array = [52] func test(): Utils.check(typeof(const_float_int) == TYPE_FLOAT) - Utils.check(str(const_float_int) == '19') + Utils.check(str(const_float_int) == '19.0') Utils.check(typeof(const_float_plus) == TYPE_FLOAT) - Utils.check(str(const_float_plus) == '34') + Utils.check(str(const_float_plus) == '34.0') Utils.check(typeof(const_float_cast) == TYPE_FLOAT) - Utils.check(str(const_float_cast) == '76') + Utils.check(str(const_float_cast) == '76.0') Utils.check(typeof(const_packed_empty) == TYPE_PACKED_FLOAT64_ARRAY) Utils.check(str(const_packed_empty) == '[]') Utils.check(typeof(const_packed_ints) == TYPE_PACKED_FLOAT64_ARRAY) - Utils.check(str(const_packed_ints) == '[52]') + Utils.check(str(const_packed_ints) == '[52.0]') Utils.check(typeof(const_packed_ints[0]) == TYPE_FLOAT) - Utils.check(str(const_packed_ints[0]) == '52') + Utils.check(str(const_packed_ints[0]) == '52.0') print('ok') diff --git a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out index 15666c46ad..abf11548cb 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out +++ b/modules/gdscript/tests/scripts/analyzer/features/external_inner_class_as_constant.out @@ -1,2 +1,2 @@ GDTEST_OK -4 +4.0 diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd index fe0274c27b..eb53d0a700 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_array_usage.gd @@ -54,39 +54,39 @@ func test(): untyped_basic.push_back(430.0) inferred_basic.push_back(263.0) typed_basic.push_back(518.0) - Utils.check(str(empty_floats) == '[705, 430, 263, 518]') - Utils.check(str(untyped_basic) == '[705, 430, 263, 518]') - Utils.check(str(inferred_basic) == '[705, 430, 263, 518]') - Utils.check(str(typed_basic) == '[705, 430, 263, 518]') + Utils.check(str(empty_floats) == '[705.0, 430.0, 263.0, 518.0]') + Utils.check(str(untyped_basic) == '[705.0, 430.0, 263.0, 518.0]') + Utils.check(str(inferred_basic) == '[705.0, 430.0, 263.0, 518.0]') + Utils.check(str(typed_basic) == '[705.0, 430.0, 263.0, 518.0]') const constant_float := 950.0 const constant_int := 170 var typed_float := 954.0 var filled_floats: Array[float] = [constant_float, constant_int, typed_float, empty_floats[1] + empty_floats[2]] - Utils.check(str(filled_floats) == '[950, 170, 954, 693]') + Utils.check(str(filled_floats) == '[950.0, 170.0, 954.0, 693.0]') Utils.check(filled_floats.get_typed_builtin() == TYPE_FLOAT) var casted_floats := [empty_floats[2] * 2] as Array[float] - Utils.check(str(casted_floats) == '[526]') + Utils.check(str(casted_floats) == '[526.0]') Utils.check(casted_floats.get_typed_builtin() == TYPE_FLOAT) var returned_floats = (func () -> Array[float]: return [554]).call() - Utils.check(str(returned_floats) == '[554]') + Utils.check(str(returned_floats) == '[554.0]') Utils.check(returned_floats.get_typed_builtin() == TYPE_FLOAT) var passed_floats = floats_identity([663.0 if randf() > 0.5 else 663.0]) - Utils.check(str(passed_floats) == '[663]') + Utils.check(str(passed_floats) == '[663.0]') Utils.check(passed_floats.get_typed_builtin() == TYPE_FLOAT) var default_floats = (func (floats: Array[float] = [364.0]): return floats).call() - Utils.check(str(default_floats) == '[364]') + Utils.check(str(default_floats) == '[364.0]') Utils.check(default_floats.get_typed_builtin() == TYPE_FLOAT) var typed_int := 556 var converted_floats: Array[float] = [typed_int] converted_floats.push_back(498) - Utils.check(str(converted_floats) == '[556, 498]') + Utils.check(str(converted_floats) == '[556.0, 498.0]') Utils.check(converted_floats.get_typed_builtin() == TYPE_FLOAT) @@ -95,7 +95,7 @@ func test(): Utils.check(constant_basic.get_typed_builtin() == TYPE_NIL) const constant_floats: Array[float] = [constant_float - constant_basic[0] - constant_int] - Utils.check(str(constant_floats) == '[552]') + Utils.check(str(constant_floats) == '[552.0]') Utils.check(constant_floats.get_typed_builtin() == TYPE_FLOAT) @@ -103,15 +103,15 @@ func test(): untyped_basic = source_floats var destination_floats: Array[float] = untyped_basic destination_floats[0] -= 0.74 - Utils.check(str(source_floats) == '[999]') - Utils.check(str(untyped_basic) == '[999]') - Utils.check(str(destination_floats) == '[999]') + Utils.check(str(source_floats) == '[999.0]') + Utils.check(str(untyped_basic) == '[999.0]') + Utils.check(str(destination_floats) == '[999.0]') Utils.check(destination_floats.get_typed_builtin() == TYPE_FLOAT) var duplicated_floats := empty_floats.duplicate().slice(2, 3) duplicated_floats[0] *= 3 - Utils.check(str(duplicated_floats) == '[789]') + Utils.check(str(duplicated_floats) == '[789.0]') Utils.check(duplicated_floats.get_typed_builtin() == TYPE_FLOAT) diff --git a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.gd b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.gd index 9d3fffd1de..c9ab368f45 100644 --- a/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.gd +++ b/modules/gdscript/tests/scripts/analyzer/features/typed_dictionary_usage.gd @@ -62,44 +62,44 @@ func test(): untyped_basic[430.0] = 34.0 inferred_basic[263.0] = 362.0 typed_basic[518.0] = 815.0 - Utils.check(str(empty_floats) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') - Utils.check(str(untyped_basic) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') - Utils.check(str(inferred_basic) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') - Utils.check(str(typed_basic) == '{ 705: 507, 430: 34, 263: 362, 518: 815 }') + Utils.check(str(empty_floats) == '{ 705.0: 507.0, 430.0: 34.0, 263.0: 362.0, 518.0: 815.0 }') + Utils.check(str(untyped_basic) == '{ 705.0: 507.0, 430.0: 34.0, 263.0: 362.0, 518.0: 815.0 }') + Utils.check(str(inferred_basic) == '{ 705.0: 507.0, 430.0: 34.0, 263.0: 362.0, 518.0: 815.0 }') + Utils.check(str(typed_basic) == '{ 705.0: 507.0, 430.0: 34.0, 263.0: 362.0, 518.0: 815.0 }') const constant_float := 950.0 const constant_int := 170 var typed_float := 954.0 var filled_floats: Dictionary[float, float] = { constant_float: constant_int, typed_float: empty_floats[430.0] + empty_floats[263.0] } - Utils.check(str(filled_floats) == '{ 950: 170, 954: 396 }') + Utils.check(str(filled_floats) == '{ 950.0: 170.0, 954.0: 396.0 }') Utils.check(filled_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(filled_floats.get_typed_value_builtin() == TYPE_FLOAT) var casted_floats := { empty_floats[263.0] * 2: empty_floats[263.0] / 2 } as Dictionary[float, float] - Utils.check(str(casted_floats) == '{ 724: 181 }') + Utils.check(str(casted_floats) == '{ 724.0: 181.0 }') Utils.check(casted_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(casted_floats.get_typed_value_builtin() == TYPE_FLOAT) var returned_floats = (func () -> Dictionary[float, float]: return { 554: 455 }).call() - Utils.check(str(returned_floats) == '{ 554: 455 }') + Utils.check(str(returned_floats) == '{ 554.0: 455.0 }') Utils.check(returned_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(returned_floats.get_typed_value_builtin() == TYPE_FLOAT) var passed_floats = floats_identity({ 663.0 if randf() > 0.5 else 663.0: 366.0 if randf() <= 0.5 else 366.0 }) - Utils.check(str(passed_floats) == '{ 663: 366 }') + Utils.check(str(passed_floats) == '{ 663.0: 366.0 }') Utils.check(passed_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(passed_floats.get_typed_value_builtin() == TYPE_FLOAT) var default_floats = (func (floats: Dictionary[float, float] = { 364.0: 463.0 }): return floats).call() - Utils.check(str(default_floats) == '{ 364: 463 }') + Utils.check(str(default_floats) == '{ 364.0: 463.0 }') Utils.check(default_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(default_floats.get_typed_value_builtin() == TYPE_FLOAT) var typed_int := 556 var converted_floats: Dictionary[float, float] = { typed_int: typed_int } converted_floats[498.0] = 894 - Utils.check(str(converted_floats) == '{ 556: 556, 498: 894 }') + Utils.check(str(converted_floats) == '{ 556.0: 556.0, 498.0: 894.0 }') Utils.check(converted_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(converted_floats.get_typed_value_builtin() == TYPE_FLOAT) @@ -110,7 +110,7 @@ func test(): Utils.check(constant_basic.get_typed_value_builtin() == TYPE_NIL) const constant_floats: Dictionary[float, float] = { constant_float - constant_basic[228] - constant_int: constant_float + constant_basic[228] + constant_int } - Utils.check(str(constant_floats) == '{ -42: 1942 }') + Utils.check(str(constant_floats) == '{ -42.0: 1942.0 }') Utils.check(constant_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(constant_floats.get_typed_value_builtin() == TYPE_FLOAT) @@ -119,9 +119,9 @@ func test(): untyped_basic = source_floats var destination_floats: Dictionary[float, float] = untyped_basic destination_floats[999.74] -= 0.999 - Utils.check(str(source_floats) == '{ 999.74: 47 }') - Utils.check(str(untyped_basic) == '{ 999.74: 47 }') - Utils.check(str(destination_floats) == '{ 999.74: 47 }') + Utils.check(str(source_floats) == '{ 999.74: 47.0 }') + Utils.check(str(untyped_basic) == '{ 999.74: 47.0 }') + Utils.check(str(destination_floats) == '{ 999.74: 47.0 }') Utils.check(destination_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(destination_floats.get_typed_value_builtin() == TYPE_FLOAT) @@ -131,7 +131,7 @@ func test(): duplicated_floats.erase(430.0) duplicated_floats.erase(518.0) duplicated_floats[263.0] *= 3 - Utils.check(str(duplicated_floats) == '{ 263: 1086 }') + Utils.check(str(duplicated_floats) == '{ 263.0: 1086.0 }') Utils.check(duplicated_floats.get_typed_key_builtin() == TYPE_FLOAT) Utils.check(duplicated_floats.get_typed_value_builtin() == TYPE_FLOAT) diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out index 0e0d607831..cfe91e00bd 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage.out @@ -6,6 +6,6 @@ GDTEST_OK >> WARNING >> Line: 5 >> SHADOWED_VARIABLE ->> The local variable "a" is shadowing an already-declared variable at line 1. +>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class. 1 2 diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out index 228a510490..ae0f2d8b8b 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_initializer.out @@ -10,6 +10,6 @@ GDTEST_OK >> WARNING >> Line: 5 >> SHADOWED_VARIABLE ->> The local variable "a" is shadowing an already-declared variable at line 1. +>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class. 1 2 diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out index 0d20e9f7a0..101d27df9d 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/confusable_local_usage_loop.out @@ -6,7 +6,7 @@ GDTEST_OK >> WARNING >> Line: 6 >> SHADOWED_VARIABLE ->> The local variable "a" is shadowing an already-declared variable at line 1. +>> The local variable "a" is shadowing an already-declared variable at line 1 in the current class. 1 2 1 diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out index a98d80514c..5d059b9193 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/lambda_shadowing_arg.out @@ -2,5 +2,5 @@ GDTEST_OK >> WARNING >> Line: 4 >> SHADOWED_VARIABLE ->> The local function parameter "shadow" is shadowing an already-declared variable at line 1. +>> The local function parameter "shadow" is shadowing an already-declared variable at line 1 in the current class. shadow diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowing_base.notest.gd b/modules/gdscript/tests/scripts/analyzer/warnings/shadowing_base.notest.gd new file mode 100644 index 0000000000..5819246ded --- /dev/null +++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowing_base.notest.gd @@ -0,0 +1,7 @@ +class_name ShadowingBase + +const base_const_member = 1 +var base_variable_member + +func base_function_member(): + pass diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd index 939e787ea5..6a16ae6bcc 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd +++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.gd @@ -1,4 +1,5 @@ class_name ShadowedClass +extends ShadowingBase var member: int = 0 @@ -7,6 +8,7 @@ var print_debug := 'print_debug' var print := 'print' @warning_ignore("unused_variable") +@warning_ignore("unused_local_constant") func test(): var Array := 'Array' var Node := 'Node' @@ -15,5 +17,8 @@ func test(): var member := 'member' var reference := 'reference' var ShadowedClass := 'ShadowedClass' + var base_variable_member + const base_function_member = 1 + var base_const_member print('warn') diff --git a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out index 8297eed4b8..075f5d3225 100644 --- a/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out +++ b/modules/gdscript/tests/scripts/analyzer/warnings/shadowning.out @@ -1,34 +1,46 @@ GDTEST_OK >> WARNING ->> Line: 5 +>> Line: 6 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "print_debug" has the same name as a built-in function. >> WARNING ->> Line: 11 +>> Line: 13 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "Array" has the same name as a built-in type. >> WARNING ->> Line: 12 +>> Line: 14 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "Node" has the same name as a native class. >> WARNING ->> Line: 13 +>> Line: 15 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "is_same" has the same name as a built-in function. >> WARNING ->> Line: 14 +>> Line: 16 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "sqrt" has the same name as a built-in function. >> WARNING ->> Line: 15 +>> Line: 17 >> SHADOWED_VARIABLE ->> The local variable "member" is shadowing an already-declared variable at line 3. +>> The local variable "member" is shadowing an already-declared variable at line 4 in the current class. >> WARNING ->> Line: 16 +>> Line: 18 >> SHADOWED_VARIABLE_BASE_CLASS ->> The local variable "reference" is shadowing an already-declared method at the base class "RefCounted". +>> The local variable "reference" is shadowing an already-declared method in the base class "RefCounted". >> WARNING ->> Line: 17 +>> Line: 19 >> SHADOWED_GLOBAL_IDENTIFIER >> The variable "ShadowedClass" has the same name as a global class defined in "shadowning.gd". +>> WARNING +>> Line: 20 +>> SHADOWED_VARIABLE_BASE_CLASS +>> The local variable "base_variable_member" is shadowing an already-declared variable at line 4 in the base class "ShadowingBase". +>> WARNING +>> Line: 21 +>> SHADOWED_VARIABLE_BASE_CLASS +>> The local constant "base_function_member" is shadowing an already-declared function at line 6 in the base class "ShadowingBase". +>> WARNING +>> Line: 22 +>> SHADOWED_VARIABLE_BASE_CLASS +>> The local variable "base_const_member" is shadowing an already-declared constant at line 3 in the base class "ShadowingBase". warn diff --git a/modules/gdscript/tests/scripts/parser/features/export_arrays.out b/modules/gdscript/tests/scripts/parser/features/export_arrays.out index f1522d096f..7201d8082d 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_arrays.out +++ b/modules/gdscript/tests/scripts/parser/features/export_arrays.out @@ -80,21 +80,21 @@ var test_placeholder: Array var test_placeholder_packed: PackedStringArray hint=TYPE_STRING hint_string="<String>/<PLACEHOLDER_TEXT>:Placeholder" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int: Array - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed_byte: PackedByteArray - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed32: PackedInt32Array - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_packed64: PackedInt64Array - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_int_float_step: Array - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10,0.01" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0,0.01" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float: Array - hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<float>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float_packed32: PackedFloat32Array - hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<float>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_float_packed64: PackedFloat64Array - hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<float>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing: Array hint=TYPE_STRING hint_string="<float>/<EXP_EASING>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_exp_easing_packed32: PackedFloat32Array @@ -126,14 +126,14 @@ var test_weak_packed_vector3_array: PackedVector3Array var test_weak_packed_vector4_array: PackedVector4Array hint=TYPE_STRING hint_string="<Vector4>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_byte_array: PackedByteArray - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_int32_array: PackedInt32Array - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_int64_array: PackedInt64Array - hint=TYPE_STRING hint_string="<int>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<int>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_float32_array: PackedFloat32Array - hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<float>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_weak_packed_float64_array: PackedFloat64Array - hint=TYPE_STRING hint_string="<float>/<RANGE>:1,10" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=TYPE_STRING hint_string="<float>/<RANGE>:1.0,10.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_noalpha_weak_packed_color_array: PackedColorArray hint=TYPE_STRING hint_string="<Color>/<COLOR_NO_ALPHA>:" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" diff --git a/modules/gdscript/tests/scripts/parser/features/export_variable.out b/modules/gdscript/tests/scripts/parser/features/export_variable.out index 0d915e00e6..c0bf4d6e06 100644 --- a/modules/gdscript/tests/scripts/parser/features/export_variable.out +++ b/modules/gdscript/tests/scripts/parser/features/export_variable.out @@ -4,11 +4,11 @@ var test_weak_int: int = 1 var test_hard_int: int = 2 hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range: int = 100 - hint=RANGE hint_string="0,100" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=RANGE hint_string="0.0,100.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_step: int = 101 - hint=RANGE hint_string="0,100,1" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=RANGE hint_string="0.0,100.0,1.0" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_range_step_or_greater: int = 102 - hint=RANGE hint_string="0,100,1,or_greater" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" + hint=RANGE hint_string="0.0,100.0,1.0,or_greater" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color: Color = Color(0, 0, 0, 1) hint=NONE hint_string="" usage=DEFAULT|SCRIPT_VARIABLE class_name=&"" var test_color_no_alpha: Color = Color(0, 0, 0, 1) diff --git a/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out index c5958365ec..d94cbe5556 100644 --- a/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out +++ b/modules/gdscript/tests/scripts/parser/features/number_literals_with_sign.out @@ -13,4 +13,4 @@ true 0 -255 256 -2 +2.0 diff --git a/modules/gdscript/tests/scripts/parser/features/number_separators.out b/modules/gdscript/tests/scripts/parser/features/number_separators.out index b0d2fd94fe..9407af9cd8 100644 --- a/modules/gdscript/tests/scripts/parser/features/number_separators.out +++ b/modules/gdscript/tests/scripts/parser/features/number_separators.out @@ -13,12 +13,12 @@ GDTEST_OK --- -1234.4567 -1234.4567 --1234 --1234 +-1234.0 +-1234.0 0.4567 0.4567 --- --1234500 --1234500 --1234500 --1234500 +-1234500.0 +-1234500.0 +-1234500.0 +-1234500.0 diff --git a/modules/gdscript/tests/scripts/parser/features/operator_assign.out b/modules/gdscript/tests/scripts/parser/features/operator_assign.out index b0cb63ef59..29910adf38 100644 --- a/modules/gdscript/tests/scripts/parser/features/operator_assign.out +++ b/modules/gdscript/tests/scripts/parser/features/operator_assign.out @@ -1,2 +1,2 @@ GDTEST_OK -8 +8.0 diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out index 75fa01f928..04df229f66 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_constant.out @@ -6,4 +6,4 @@ GDTEST_OK >> WARNING >> Line: 8 >> SHADOWED_VARIABLE ->> The local constant "TEST" is shadowing an already-declared constant at line 2. +>> The local constant "TEST" is shadowing an already-declared constant at line 2 in the current class. diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out index aab27e78e2..4a6964f503 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_class.out @@ -6,4 +6,4 @@ GDTEST_OK >> WARNING >> Line: 8 >> SHADOWED_VARIABLE ->> The local variable "foo" is shadowing an already-declared variable at line 1. +>> The local variable "foo" is shadowing an already-declared variable at line 1 in the current class. diff --git a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out index e3cd358126..45fb771829 100644 --- a/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out +++ b/modules/gdscript/tests/scripts/parser/warnings/shadowed_variable_function.out @@ -6,4 +6,4 @@ GDTEST_OK >> WARNING >> Line: 2 >> SHADOWED_VARIABLE ->> The local variable "test" is shadowing an already-declared function at line 1. +>> The local variable "test" is shadowing an already-declared function at line 1 in the current class. diff --git a/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out b/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out index 22929bf636..04b0773991 100644 --- a/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out +++ b/modules/gdscript/tests/scripts/runtime/features/chain_assignment_works.out @@ -1,7 +1,7 @@ GDTEST_OK -{ 1: (2, 0) } -{ 3: (4, 0) } -[[(5, 0)]] -[[(6, 0)]] -[[(7, 0)]] -[X: (8, 9, 7), Y: (0, 1, 0), Z: (0, 0, 1), O: (0, 0, 0)] +{ 1: (2.0, 0.0) } +{ 3: (4.0, 0.0) } +[[(5.0, 0.0)]] +[[(6.0, 0.0)]] +[[(7.0, 0.0)]] +[X: (8.0, 9.0, 7.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0), O: (0.0, 0.0, 0.0)] diff --git a/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out index a9ef4919cf..78ea2a2d80 100644 --- a/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out +++ b/modules/gdscript/tests/scripts/runtime/features/conversion_for_default_parameter.out @@ -1,8 +1,8 @@ GDTEST_OK -x is 1 +x is 1.0 typeof x is 3 -x is 2 +x is 2.0 typeof x is 3 -x is 3 +x is 3.0 typeof x is 3 ok diff --git a/modules/gdscript/tests/scripts/runtime/features/gdscript_utility_implicit_conversion.gd b/modules/gdscript/tests/scripts/runtime/features/gdscript_utility_implicit_conversion.gd new file mode 100644 index 0000000000..59bdb6eceb --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/gdscript_utility_implicit_conversion.gd @@ -0,0 +1,12 @@ +func test(): + const COLOR = Color8(255, 0.0, false) + var false_value := false + @warning_ignore("narrowing_conversion") + var color = Color8(255, 0.0, false_value) + print(var_to_str(COLOR)) + print(var_to_str(color)) + + var string := "Node" + var string_name := &"Node" + print(type_exists(string)) + print(type_exists(string_name)) diff --git a/modules/gdscript/tests/scripts/runtime/features/gdscript_utility_implicit_conversion.out b/modules/gdscript/tests/scripts/runtime/features/gdscript_utility_implicit_conversion.out new file mode 100644 index 0000000000..00913faa49 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/gdscript_utility_implicit_conversion.out @@ -0,0 +1,5 @@ +GDTEST_OK +Color(1, 0, 0, 1) +Color(1, 0, 0, 1) +true +true diff --git a/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd new file mode 100644 index 0000000000..63d5935d1e --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.gd @@ -0,0 +1,8 @@ +func get_parse_string(t: Variant): + return t.parse_string + +func test(): + var a: Callable = JSON.parse_string + var b: Callable = get_parse_string(JSON) + prints(a.call("{\"test\": \"a\"}"), a.is_valid()) + prints(b.call("{\"test\": \"b\"}"), b.is_valid()) diff --git a/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out new file mode 100644 index 0000000000..a2cb4b9a07 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/native_static_method_as_callable.out @@ -0,0 +1,3 @@ +GDTEST_OK +{ "test": "a" } false +{ "test": "b" } false diff --git a/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out b/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out index 5b981bc8bb..1650acadb5 100644 --- a/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out +++ b/modules/gdscript/tests/scripts/runtime/features/parameter_shadowing.out @@ -2,16 +2,16 @@ GDTEST_OK >> WARNING >> Line: 5 >> SHADOWED_VARIABLE ->> The local function parameter "a" is shadowing an already-declared variable at line 3. +>> The local function parameter "a" is shadowing an already-declared variable at line 3 in the current class. >> WARNING >> Line: 15 >> SHADOWED_VARIABLE ->> The local function parameter "v" is shadowing an already-declared variable at line 13. +>> The local function parameter "v" is shadowing an already-declared variable at line 13 in the current class. a 1 b 1 -(1, 1) -(0, 0) -(6, 1) -(0, 0) +(1.0, 1.0) +(0.0, 0.0) +(6.0, 1.0) +(0.0, 0.0) diff --git a/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.out b/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.out index c51759f481..e82e31bbed 100644 --- a/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.out +++ b/modules/gdscript/tests/scripts/runtime/features/setter_chain_shared_types.out @@ -1,26 +1,26 @@ GDTEST_OK === -prop1 setter (0, 0) -prop1 setter (1, 0) +prop1 setter (0.0, 0.0) +prop1 setter (1.0, 0.0) --- prop1 setter <Inner> subprop getter -subprop setter (1, 0) +subprop setter (1.0, 0.0) === prop2 setter <Inner> subprop getter -subprop setter (1, 0) +subprop setter (1.0, 0.0) === -prop3 setter (0, 0) +prop3 setter (0.0, 0.0) prop3 getter -prop3 setter (1, 0) +prop3 setter (1.0, 0.0) --- prop3 setter <Inner> prop3 getter subprop getter -subprop setter (1, 0) +subprop setter (1.0, 0.0) === prop4 setter <Inner> prop4 getter subprop getter -subprop setter (1, 0) +subprop setter (1.0, 0.0) diff --git a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out index 31b3b3a3a8..8617a65c33 100644 --- a/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out +++ b/modules/gdscript/tests/scripts/runtime/features/simple_setter_chain_call_setter.out @@ -1,4 +1,4 @@ GDTEST_OK -setting vec from (0, 0) to (2, 0) -setting vec from (0, 0) to (0, 2) -vec is (0, 0) +setting vec from (0.0, 0.0) to (2.0, 0.0) +setting vec from (0.0, 0.0) to (0.0, 2.0) +vec is (0.0, 0.0) diff --git a/modules/gdscript/tests/scripts/runtime/features/stringify.out b/modules/gdscript/tests/scripts/runtime/features/stringify.out index 7833b6e213..2463d70ef4 100644 --- a/modules/gdscript/tests/scripts/runtime/features/stringify.out +++ b/modules/gdscript/tests/scripts/runtime/features/stringify.out @@ -9,13 +9,13 @@ hello world [P: (0, 0), S: (0, 0)] (0.25, 0.25, 0.25) (0, 0, 0) -[X: (1, 0), Y: (0, 1), O: (0, 0)] -[N: (1, 2, 3), D: 4] -(1, 2, 3, 4) -[P: (0, 0, 0), S: (1, 1, 1)] -[X: (1, 0, 0), Y: (0, 1, 0), Z: (0, 0, 1)] -[X: (1, 0, 0), Y: (0, 1, 0), Z: (0, 0, 1), O: (0, 0, 0)] +[X: (1.0, 0.0), Y: (0.0, 1.0), O: (0.0, 0.0)] +[N: (1.0, 2.0, 3.0), D: 4] (1, 2, 3, 4) +[P: (0.0, 0.0, 0.0), S: (1.0, 1.0, 1.0)] +[X: (1.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0)] +[X: (1.0, 0.0, 0.0), Y: (0.0, 1.0, 0.0), Z: (0.0, 0.0, 1.0), O: (0.0, 0.0, 0.0)] +(1.0, 2.0, 3.0, 4.0) hello hello/world RID(0) @@ -26,10 +26,10 @@ Node::[signal]property_list_changed [255, 0, 1] [-1, 0, 1] [-1, 0, 1] -[-1, 0, 1] -[-1, 0, 1] +[-1.0, 0.0, 1.0] +[-1.0, 0.0, 1.0] ["hello", "world"] -[(1, 1), (0, 0)] -[(1, 1, 1), (0, 0, 0)] -[(1, 0, 0, 1), (0, 0, 1, 1), (0, 1, 0, 1)] +[(1.0, 1.0), (0.0, 0.0)] +[(1.0, 1.0, 1.0), (0.0, 0.0, 0.0)] +[(1.0, 0.0, 0.0, 1.0), (0.0, 0.0, 1.0, 1.0), (0.0, 1.0, 0.0, 1.0)] [(1, 1, 1, 1), (0, 0, 0, 0)] diff --git a/modules/gdscript/tests/scripts/utils.notest.gd b/modules/gdscript/tests/scripts/utils.notest.gd index fa289e442f..225bcb3008 100644 --- a/modules/gdscript/tests/scripts/utils.notest.gd +++ b/modules/gdscript/tests/scripts/utils.notest.gd @@ -1,6 +1,5 @@ class_name Utils - # `assert()` is not evaluated in non-debug builds. Do not use `assert()` # for anything other than testing the `assert()` itself. static func check(condition: Variant) -> void: |