diff options
author | Danil Alexeev <danil@alexeev.xyz> | 2023-08-28 19:20:10 +0300 |
---|---|---|
committer | Danil Alexeev <danil@alexeev.xyz> | 2023-09-04 00:21:03 +0300 |
commit | 462d8f47521d3406a7ee8b5b024699112c4337aa (patch) | |
tree | bc3915ef18cbdef583cb53560d8eb55200ce581d | |
parent | fa3428ff25bc577d2a3433090478a6d615567056 (diff) | |
download | redot-engine-462d8f47521d3406a7ee8b5b024699112c4337aa.tar.gz |
GDScript: Fix `get_*_list()` methods return incorrect info
-rw-r--r-- | modules/gdscript/editor/gdscript_docgen.cpp | 9 | ||||
-rw-r--r-- | modules/gdscript/gdscript.cpp | 127 | ||||
-rw-r--r-- | modules/gdscript/gdscript.h | 14 | ||||
-rw-r--r-- | modules/gdscript/gdscript_analyzer.cpp | 10 | ||||
-rw-r--r-- | modules/gdscript/gdscript_byte_codegen.cpp | 3 | ||||
-rw-r--r-- | modules/gdscript/gdscript_compiler.cpp | 49 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.cpp | 36 | ||||
-rw-r--r-- | modules/gdscript/gdscript_function.h | 188 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.cpp | 100 | ||||
-rw-r--r-- | modules/gdscript/gdscript_parser.h | 9 | ||||
-rw-r--r-- | modules/gdscript/gdscript_utility_functions.cpp | 2 | ||||
-rw-r--r-- | modules/gdscript/gdscript_vm.cpp | 8 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/runtime/features/member_info.gd | 125 | ||||
-rw-r--r-- | modules/gdscript/tests/scripts/runtime/features/member_info.out | 45 | ||||
-rw-r--r-- | modules/gdscript/tests/test_gdscript.cpp | 9 |
15 files changed, 429 insertions, 305 deletions
diff --git a/modules/gdscript/editor/gdscript_docgen.cpp b/modules/gdscript/editor/gdscript_docgen.cpp index 1aecfc6de1..0b440274c0 100644 --- a/modules/gdscript/editor/gdscript_docgen.cpp +++ b/modules/gdscript/editor/gdscript_docgen.cpp @@ -87,7 +87,7 @@ static void _doctype_from_gdtype(const GDType &p_gdtype, String &r_type, String case GDType::SCRIPT: if (p_gdtype.script_type.is_valid()) { if (p_gdtype.script_type->get_global_name() != StringName()) { - r_type = _get_script_path(p_gdtype.script_type->get_global_name()); + r_type = p_gdtype.script_type->get_global_name(); return; } if (!p_gdtype.script_type->get_path().is_empty()) { @@ -129,10 +129,10 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c DocData::ClassDoc &doc = p_script->doc; doc.script_path = _get_script_path(p_script->get_script_path()); - if (p_script->name.is_empty()) { + if (p_script->local_name == StringName()) { doc.name = doc.script_path; } else { - doc.name = p_script->name; + doc.name = p_script->local_name; } if (p_script->_owner) { @@ -204,6 +204,9 @@ void GDScriptDocGen::generate_docs(GDScript *p_script, const GDP::ClassNode *p_c if (m_func->return_type) { _doctype_from_gdtype(m_func->return_type->get_datatype(), method_doc.return_type, method_doc.return_enum, true); + } else if (!m_func->body->has_return) { + // If no `return` statement, then return type is `void`, not `Variant`. + method_doc.return_type = "void"; } else { method_doc.return_type = "Variant"; } diff --git a/modules/gdscript/gdscript.cpp b/modules/gdscript/gdscript.cpp index ccbcb3ee96..114c04a38f 100644 --- a/modules/gdscript/gdscript.cpp +++ b/modules/gdscript/gdscript.cpp @@ -254,7 +254,7 @@ Ref<Script> GDScript::get_base_script() const { } StringName GDScript::get_global_name() const { - return name; + return global_name; } StringName GDScript::get_instance_base_type() const { @@ -284,27 +284,9 @@ void GDScript::_get_script_method_list(List<MethodInfo> *r_list, bool p_include_ const GDScript *current = this; while (current) { for (const KeyValue<StringName, GDScriptFunction *> &E : current->member_functions) { - GDScriptFunction *func = E.value; - MethodInfo mi; - mi.name = E.key; - - if (func->is_static()) { - mi.flags |= METHOD_FLAG_STATIC; - } - - for (int i = 0; i < func->get_argument_count(); i++) { - PropertyInfo arginfo = func->get_argument_type(i); -#ifdef TOOLS_ENABLED - arginfo.name = func->get_argument_name(i); -#endif - mi.arguments.push_back(arginfo); - } -#ifdef TOOLS_ENABLED - mi.default_arguments.append_array(func->get_default_arg_values()); -#endif - mi.return_val = func->get_return_type(); - r_list->push_back(mi); + r_list->push_back(E.value->get_method_info()); } + if (!p_include_base) { return; } @@ -323,10 +305,9 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl while (sptr) { Vector<_GDScriptMemberSort> msort; - for (const KeyValue<StringName, PropertyInfo> &E : sptr->member_info) { + for (const KeyValue<StringName, MemberInfo> &E : sptr->member_indices) { _GDScriptMemberSort ms; - ERR_CONTINUE(!sptr->member_indices.has(E.key)); - ms.index = sptr->member_indices[E.key].index; + ms.index = E.value.index; ms.name = E.key; msort.push_back(ms); } @@ -334,7 +315,7 @@ void GDScript::_get_script_property_list(List<PropertyInfo> *r_list, bool p_incl msort.sort(); msort.reverse(); for (int i = 0; i < msort.size(); i++) { - props.push_front(sptr->member_info[msort[i].name]); + props.push_front(sptr->member_indices[msort[i].name].property_info); } #ifdef TOOLS_ENABLED @@ -368,15 +349,7 @@ MethodInfo GDScript::get_method_info(const StringName &p_method) const { return MethodInfo(); } - GDScriptFunction *func = E->value; - MethodInfo mi; - mi.name = E->key; - for (int i = 0; i < func->get_argument_count(); i++) { - mi.arguments.push_back(func->get_argument_type(i)); - } - - mi.return_val = func->get_return_type(); - return mi; + return E->value->get_method_info(); } bool GDScript::get_property_default_value(const StringName &p_property, Variant &r_value) const { @@ -557,13 +530,7 @@ bool GDScript::_update_exports(bool *r_err, bool p_recursive_call, PlaceHolderSc member_default_values_cache[member.variable->identifier->name] = default_value; } break; case GDScriptParser::ClassNode::Member::SIGNAL: { - // TODO: Cache this in parser to avoid loops like this. - Vector<StringName> parameters_names; - parameters_names.resize(member.signal->parameters.size()); - for (int j = 0; j < member.signal->parameters.size(); j++) { - parameters_names.write[j] = member.signal->parameters[j]->identifier->name; - } - _signals[member.signal->identifier->name] = parameters_names; + _signals[member.signal->identifier->name] = member.signal->method_info; } break; case GDScriptParser::ClassNode::Member::GROUP: { members_cache.push_back(member.annotation->export_info); @@ -977,22 +944,26 @@ bool GDScript::_set(const StringName &p_name, const Variant &p_value) { void GDScript::_get_property_list(List<PropertyInfo> *p_properties) const { p_properties->push_back(PropertyInfo(Variant::STRING, "script/source", PROPERTY_HINT_NONE, "", PROPERTY_USAGE_NO_EDITOR | PROPERTY_USAGE_INTERNAL)); - List<PropertyInfo> property_list; - + List<const GDScript *> classes; const GDScript *top = this; while (top) { - for (const KeyValue<StringName, MemberInfo> &E : top->static_variables_indices) { - PropertyInfo pi = PropertyInfo(E.value.data_type); - pi.name = E.key; - pi.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; // For the script (as a class) it is a non-static property. - property_list.push_back(pi); - } - + classes.push_back(top); top = top->_base; } - for (const List<PropertyInfo>::Element *E = property_list.back(); E; E = E->prev()) { - p_properties->push_back(E->get()); + for (const List<const GDScript *>::Element *E = classes.back(); E; E = E->prev()) { + Vector<_GDScriptMemberSort> msort; + for (const KeyValue<StringName, MemberInfo> &F : E->get()->static_variables_indices) { + _GDScriptMemberSort ms; + ms.index = F.value.index; + ms.name = F.key; + msort.push_back(ms); + } + msort.sort(); + + for (int i = 0; i < msort.size(); i++) { + p_properties->push_back(E->get()->static_variables_indices[msort[i].name].property_info); + } } } @@ -1110,7 +1081,7 @@ GDScript *GDScript::find_class(const String &p_qualified_name) { Vector<String> class_names; GDScript *result = nullptr; // Empty initial name means start here. - if (first.is_empty() || first == name) { + if (first.is_empty() || first == global_name) { class_names = p_qualified_name.split("::"); result = this; } else if (p_qualified_name.begins_with(get_root_script()->path)) { @@ -1245,15 +1216,8 @@ bool GDScript::has_script_signal(const StringName &p_signal) const { } void GDScript::_get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const { - for (const KeyValue<StringName, Vector<StringName>> &E : _signals) { - MethodInfo mi; - mi.name = E.key; - for (int i = 0; i < E.value.size(); i++) { - PropertyInfo arg; - arg.name = E.value[i]; - mi.arguments.push_back(arg); - } - r_list->push_back(mi); + for (const KeyValue<StringName, MethodInfo> &E : _signals) { + r_list->push_back(E.value); } if (!p_include_base) { @@ -1274,21 +1238,6 @@ void GDScript::get_script_signal_list(List<MethodInfo> *r_signals) const { _get_script_signal_list(r_signals, true); } -String GDScript::_get_gdscript_reference_class_name(const GDScript *p_gdscript) { - ERR_FAIL_NULL_V(p_gdscript, String()); - - String class_name; - while (p_gdscript) { - if (class_name.is_empty()) { - class_name = p_gdscript->get_script_class_name(); - } else { - class_name = p_gdscript->get_script_class_name() + "." + class_name; - } - p_gdscript = p_gdscript->_owner; - } - return class_name; -} - GDScript *GDScript::_get_gdscript_from_variant(const Variant &p_variant) { Object *obj = p_variant; if (obj == nullptr || obj->get_instance_id().is_null()) { @@ -1420,8 +1369,8 @@ String GDScript::debug_get_script_name(const Ref<Script> &p_script) { if (p_script.is_valid()) { Ref<GDScript> gdscript = p_script; if (gdscript.is_valid()) { - if (!gdscript->get_script_class_name().is_empty()) { - return gdscript->get_script_class_name(); + if (gdscript->get_local_name() != StringName()) { + return gdscript->get_local_name(); } return gdscript->get_fully_qualified_name().get_file(); } @@ -1667,7 +1616,7 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { } { - HashMap<StringName, Vector<StringName>>::ConstIterator E = sptr->_signals.find(p_name); + HashMap<StringName, MethodInfo>::ConstIterator E = sptr->_signals.find(p_name); if (E) { r_ret = Signal(this->owner, E->key); return true; @@ -1717,11 +1666,11 @@ bool GDScriptInstance::get(const StringName &p_name, Variant &r_ret) const { Variant::Type GDScriptInstance::get_property_type(const StringName &p_name, bool *r_is_valid) const { const GDScript *sptr = script.ptr(); while (sptr) { - if (sptr->member_info.has(p_name)) { + if (sptr->member_indices.has(p_name)) { if (r_is_valid) { *r_is_valid = true; } - return sptr->member_info[p_name].type; + return sptr->member_indices[p_name].property_info.type; } sptr = sptr->_base; } @@ -1798,10 +1747,9 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const //instance a fake script for editing the values Vector<_GDScriptMemberSort> msort; - for (const KeyValue<StringName, PropertyInfo> &F : sptr->member_info) { + for (const KeyValue<StringName, GDScript::MemberInfo> &F : sptr->member_indices) { _GDScriptMemberSort ms; - ERR_CONTINUE(!sptr->member_indices.has(F.key)); - ms.index = sptr->member_indices[F.key].index; + ms.index = F.value.index; ms.name = F.key; msort.push_back(ms); } @@ -1809,7 +1757,7 @@ void GDScriptInstance::get_property_list(List<PropertyInfo> *p_properties) const msort.sort(); msort.reverse(); for (int i = 0; i < msort.size(); i++) { - props.push_front(sptr->member_info[msort[i].name]); + props.push_front(sptr->member_indices[msort[i].name].property_info); } #ifdef TOOLS_ENABLED @@ -1872,12 +1820,7 @@ void GDScriptInstance::get_method_list(List<MethodInfo> *p_list) const { const GDScript *sptr = script.ptr(); while (sptr) { for (const KeyValue<StringName, GDScriptFunction *> &E : sptr->member_functions) { - MethodInfo mi; - mi.name = E.key; - for (int i = 0; i < E.value->get_argument_count(); i++) { - mi.arguments.push_back(PropertyInfo(Variant::NIL, "arg" + itos(i))); - } - p_list->push_back(mi); + p_list->push_back(E.value->get_method_info()); } sptr = sptr->_base; } diff --git a/modules/gdscript/gdscript.h b/modules/gdscript/gdscript.h index 0ba007683c..0eaaac8811 100644 --- a/modules/gdscript/gdscript.h +++ b/modules/gdscript/gdscript.h @@ -69,6 +69,7 @@ class GDScript : public Script { StringName setter; StringName getter; GDScriptDataType data_type; + PropertyInfo property_info; }; struct ClearData { @@ -100,7 +101,7 @@ class GDScript : public Script { HashMap<StringName, GDScriptFunction *> member_functions; HashMap<StringName, MemberInfo> member_indices; //members are just indices to the instantiated script. HashMap<StringName, Ref<GDScript>> subclasses; - HashMap<StringName, Vector<StringName>> _signals; + HashMap<StringName, MethodInfo> _signals; Dictionary rpc_config; #ifdef TOOLS_ENABLED @@ -126,8 +127,6 @@ class GDScript : public Script { void _add_doc(const DocData::ClassDoc &p_inner_class); #endif - HashMap<StringName, PropertyInfo> member_info; - GDScriptFunction *implicit_initializer = nullptr; GDScriptFunction *initializer = nullptr; //direct pointer to new , faster to locate GDScriptFunction *implicit_ready = nullptr; @@ -142,7 +141,8 @@ class GDScript : public Script { //exported members String source; String path; - String name; + StringName local_name; // Inner class identifier or `class_name`. + StringName global_name; // `class_name`. String fully_qualified_name; String simplified_icon_path; SelfList<GDScript> script_list; @@ -174,9 +174,6 @@ class GDScript : public Script { void _get_script_method_list(List<MethodInfo> *r_list, bool p_include_base) const; void _get_script_signal_list(List<MethodInfo> *r_list, bool p_include_base) const; - // This method will map the class name from "RefCounted" to "MyClass.InnerClass". - static String _get_gdscript_reference_class_name(const GDScript *p_gdscript); - GDScript *_get_gdscript_from_variant(const Variant &p_variant); void _get_dependencies(RBSet<GDScript *> &p_dependencies, const GDScript *p_except); @@ -194,6 +191,8 @@ public: static String debug_get_script_name(const Ref<Script> &p_script); #endif + _FORCE_INLINE_ StringName get_local_name() const { return local_name; } + void clear(GDScript::ClearData *p_clear_data = nullptr); virtual bool is_valid() const override { return valid; } @@ -214,7 +213,6 @@ public: } const HashMap<StringName, GDScriptFunction *> &get_member_functions() const { return member_functions; } const Ref<GDScriptNativeClass> &get_native() const { return native; } - const String &get_script_class_name() const { return name; } RBSet<GDScript *> get_dependencies(); RBSet<GDScript *> get_inverted_dependencies(); diff --git a/modules/gdscript/gdscript_analyzer.cpp b/modules/gdscript/gdscript_analyzer.cpp index 18c69467dc..0eda7b2664 100644 --- a/modules/gdscript/gdscript_analyzer.cpp +++ b/modules/gdscript/gdscript_analyzer.cpp @@ -1000,10 +1000,11 @@ void GDScriptAnalyzer::resolve_class_member(GDScriptParser::ClassNode *p_class, GDScriptParser::ParameterNode *param = member.signal->parameters[j]; GDScriptParser::DataType param_type = type_from_metatype(resolve_datatype(param->datatype_specifier)); param->set_datatype(param_type); - mi.arguments.push_back(PropertyInfo(param_type.builtin_type, param->identifier->name)); - // TODO: add signal parameter default values + mi.arguments.push_back(param_type.to_property_info(param->identifier->name)); + // Signals do not support parameter default values. } member.signal->set_datatype(make_signal_type(mi)); + member.signal->method_info = mi; // Apply annotations. for (GDScriptParser::AnnotationNode *&E : member.signal->annotations) { @@ -1604,9 +1605,11 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * } is_shadowing(p_function->parameters[i]->identifier, "function parameter", true); #endif // DEBUG_ENABLED -#ifdef TOOLS_ENABLED + if (p_function->parameters[i]->initializer) { +#ifdef TOOLS_ENABLED default_value_count++; +#endif // TOOLS_ENABLED if (p_function->parameters[i]->initializer->is_constant) { p_function->default_arg_values.push_back(p_function->parameters[i]->initializer->reduced_value); @@ -1614,7 +1617,6 @@ void GDScriptAnalyzer::resolve_function_signature(GDScriptParser::FunctionNode * p_function->default_arg_values.push_back(Variant()); // Prevent shift. } } -#endif // TOOLS_ENABLED } if (!p_is_lambda && function_name == GDScriptLanguage::get_singleton()->strings._init) { diff --git a/modules/gdscript/gdscript_byte_codegen.cpp b/modules/gdscript/gdscript_byte_codegen.cpp index af7862efc5..8394fce9b3 100644 --- a/modules/gdscript/gdscript_byte_codegen.cpp +++ b/modules/gdscript/gdscript_byte_codegen.cpp @@ -35,9 +35,6 @@ #include "core/debugger/engine_debugger.h" uint32_t GDScriptByteCodeGenerator::add_parameter(const StringName &p_name, bool p_is_optional, const GDScriptDataType &p_type) { -#ifdef TOOLS_ENABLED - function->arg_names.push_back(p_name); -#endif function->_argument_count++; function->argument_types.push_back(p_type); if (p_is_optional) { diff --git a/modules/gdscript/gdscript_compiler.cpp b/modules/gdscript/gdscript_compiler.cpp index 985eb97b29..70f95321be 100644 --- a/modules/gdscript/gdscript_compiler.cpp +++ b/modules/gdscript/gdscript_compiler.cpp @@ -2165,8 +2165,14 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ } } + MethodInfo method_info; + codegen.function_name = func_name; + method_info.name = func_name; codegen.is_static = is_static; + if (is_static) { + method_info.flags |= METHOD_FLAG_STATIC; + } codegen.generator->write_start(p_script, func_name, is_static, rpc_config, return_type); int optional_parameters = 0; @@ -2178,10 +2184,14 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ uint32_t par_addr = codegen.generator->add_parameter(parameter->identifier->name, parameter->initializer != nullptr, par_type); codegen.parameters[parameter->identifier->name] = GDScriptCodeGenerator::Address(GDScriptCodeGenerator::Address::FUNCTION_PARAMETER, par_addr, par_type); + method_info.arguments.push_back(parameter->get_datatype().to_property_info(parameter->identifier->name)); + if (parameter->initializer != nullptr) { optional_parameters++; } } + + method_info.default_arguments.append_array(p_func->default_arg_values); } // Parse initializer if applies. @@ -2335,20 +2345,20 @@ GDScriptFunction *GDScriptCompiler::_parse_function(Error &r_error, GDScript *p_ } if (p_func) { - // if no return statement -> return type is void not unresolved Variant + // If no `return` statement, then return type is `void`, not `Variant`. if (p_func->body->has_return) { gd_function->return_type = _gdtype_from_datatype(p_func->get_datatype(), p_script); + method_info.return_val = p_func->get_datatype().to_property_info(String()); } else { gd_function->return_type = GDScriptDataType(); gd_function->return_type.has_type = true; gd_function->return_type.kind = GDScriptDataType::BUILTIN; gd_function->return_type.builtin_type = Variant::NIL; } -#ifdef TOOLS_ENABLED - gd_function->default_arg_values = p_func->default_arg_values; -#endif } + gd_function->method_info = method_info; + if (!is_implicit_initializer && !is_implicit_ready && !p_for_lambda) { p_script->member_functions[func_name] = gd_function; } @@ -2554,7 +2564,6 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri p_script->member_functions.clear(); p_script->member_indices.clear(); - p_script->member_info.clear(); p_script->static_variables_indices.clear(); p_script->static_variables.clear(); p_script->_signals.clear(); @@ -2567,9 +2576,9 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri p_script->tool = parser->is_tool(); - if (!p_script->name.is_empty()) { - if (ClassDB::class_exists(p_script->name) && ClassDB::is_class_exposed(p_script->name)) { - _set_error("The class '" + p_script->name + "' shadows a native class", p_class); + if (p_script->local_name != StringName()) { + if (ClassDB::class_exists(p_script->local_name) && ClassDB::is_class_exposed(p_script->local_name)) { + _set_error(vformat(R"(The class "%s" shadows a native class)", p_script->local_name), p_class); return ERR_ALREADY_EXISTS; } } @@ -2636,7 +2645,6 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri StringName name = variable->identifier->name; GDScript::MemberInfo minfo; - minfo.index = p_script->member_indices.size(); switch (variable->property) { case GDScriptParser::VariableNode::PROP_NONE: break; // Nothing to do. @@ -2659,8 +2667,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri } minfo.data_type = _gdtype_from_datatype(variable->get_datatype(), p_script); - PropertyInfo prop_info = minfo.data_type; - prop_info.name = name; + PropertyInfo prop_info = variable->get_datatype().to_property_info(name); PropertyInfo export_info = variable->export_info; if (variable->exported) { @@ -2670,16 +2677,16 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri } prop_info.hint = export_info.hint; prop_info.hint_string = export_info.hint_string; - prop_info.usage = export_info.usage | PROPERTY_USAGE_SCRIPT_VARIABLE; - } else { - prop_info.usage = PROPERTY_USAGE_SCRIPT_VARIABLE; + prop_info.usage = export_info.usage; } + prop_info.usage |= PROPERTY_USAGE_SCRIPT_VARIABLE; + minfo.property_info = prop_info; if (variable->is_static) { minfo.index = p_script->static_variables_indices.size(); p_script->static_variables_indices[name] = minfo; } else { - p_script->member_info[name] = prop_info; + minfo.index = p_script->member_indices.size(); p_script->member_indices[name] = minfo; p_script->members.insert(name); } @@ -2712,12 +2719,7 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri const GDScriptParser::SignalNode *signal = member.signal; StringName name = signal->identifier->name; - Vector<StringName> parameters_names; - parameters_names.resize(signal->parameters.size()); - for (int j = 0; j < signal->parameters.size(); j++) { - parameters_names.write[j] = signal->parameters[j]->identifier->name; - } - p_script->_signals[name] = parameters_names; + p_script->_signals[name] = signal->method_info; } break; case GDScriptParser::ClassNode::Member::ENUM: { @@ -2740,8 +2742,8 @@ Error GDScriptCompiler::_populate_class_members(GDScript *p_script, const GDScri prop_info.name = annotation->export_info.name; prop_info.usage = annotation->export_info.usage; prop_info.hint_string = annotation->export_info.hint_string; + minfo.property_info = prop_info; - p_script->member_info[name] = prop_info; p_script->member_indices[name] = minfo; p_script->members.insert(Variant()); } break; @@ -2927,7 +2929,8 @@ void GDScriptCompiler::convert_to_initializer_type(Variant &p_variant, const GDS void GDScriptCompiler::make_scripts(GDScript *p_script, const GDScriptParser::ClassNode *p_class, bool p_keep_state) { p_script->fully_qualified_name = p_class->fqcn; - p_script->name = p_class->identifier ? p_class->identifier->name : ""; + p_script->local_name = p_class->identifier ? p_class->identifier->name : StringName(); + p_script->global_name = p_class->get_global_name(); p_script->simplified_icon_path = p_class->simplified_icon_path; HashMap<StringName, Ref<GDScript>> old_subclasses; diff --git a/modules/gdscript/gdscript_function.cpp b/modules/gdscript/gdscript_function.cpp index a6b4dc7981..4f5a65a709 100644 --- a/modules/gdscript/gdscript_function.cpp +++ b/modules/gdscript/gdscript_function.cpp @@ -32,14 +32,6 @@ #include "gdscript.h" -const int *GDScriptFunction::get_code() const { - return _code_ptr; -} - -int GDScriptFunction::get_code_size() const { - return _code_size; -} - Variant GDScriptFunction::get_constant(int p_idx) const { ERR_FAIL_INDEX_V(p_idx, constants.size(), "<errconst>"); return constants[p_idx]; @@ -50,32 +42,6 @@ StringName GDScriptFunction::get_global_name(int p_idx) const { return global_names[p_idx]; } -int GDScriptFunction::get_default_argument_count() const { - return _default_arg_count; -} - -int GDScriptFunction::get_default_argument_addr(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), -1); - return default_arguments[p_idx]; -} - -GDScriptDataType GDScriptFunction::get_return_type() const { - return return_type; -} - -GDScriptDataType GDScriptFunction::get_argument_type(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, argument_types.size(), GDScriptDataType()); - return argument_types[p_idx]; -} - -StringName GDScriptFunction::get_name() const { - return name; -} - -int GDScriptFunction::get_max_stack_size() const { - return _stack_size; -} - struct _GDFKC { int order = 0; List<int> pos; @@ -161,9 +127,7 @@ GDScriptFunction::~GDScriptFunction() { return_type.script_type_ref = Ref<Script>(); #ifdef DEBUG_ENABLED - MutexLock lock(GDScriptLanguage::get_singleton()->mutex); - GDScriptLanguage::get_singleton()->function_list.remove(&function_list); #endif } diff --git a/modules/gdscript/gdscript_function.h b/modules/gdscript/gdscript_function.h index 5230773c13..31da70f9ae 100644 --- a/modules/gdscript/gdscript_function.h +++ b/modules/gdscript/gdscript_function.h @@ -147,33 +147,6 @@ public: return false; } - operator PropertyInfo() const { - PropertyInfo info; - info.usage = PROPERTY_USAGE_NONE; - if (has_type) { - switch (kind) { - case UNINITIALIZED: - break; - case BUILTIN: { - info.type = builtin_type; - } break; - case NATIVE: { - info.type = Variant::OBJECT; - info.class_name = native_type; - } break; - case SCRIPT: - case GDSCRIPT: { - info.type = Variant::OBJECT; - info.class_name = script_type->get_instance_base_type(); - } break; - } - } else { - info.type = Variant::NIL; - info.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; - } - return info; - } - void set_container_element_type(const GDScriptDataType &p_element_type) { container_element_type = memnew(GDScriptDataType(p_element_type)); } @@ -437,59 +410,32 @@ private: friend class GDScript; friend class GDScriptCompiler; friend class GDScriptByteCodeGenerator; + friend class GDScriptLanguage; + StringName name; StringName source; + bool _static = false; + Vector<GDScriptDataType> argument_types; + GDScriptDataType return_type; + MethodInfo method_info; + Variant rpc_config; - mutable Variant nil; - mutable Variant *_constants_ptr = nullptr; - int _constant_count = 0; - const StringName *_global_names_ptr = nullptr; - int _global_names_count = 0; - const int *_default_arg_ptr = nullptr; - int _default_arg_count = 0; - int _operator_funcs_count = 0; - const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr; - int _setters_count = 0; - const Variant::ValidatedSetter *_setters_ptr = nullptr; - int _getters_count = 0; - const Variant::ValidatedGetter *_getters_ptr = nullptr; - int _keyed_setters_count = 0; - const Variant::ValidatedKeyedSetter *_keyed_setters_ptr = nullptr; - int _keyed_getters_count = 0; - const Variant::ValidatedKeyedGetter *_keyed_getters_ptr = nullptr; - int _indexed_setters_count = 0; - const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr; - int _indexed_getters_count = 0; - const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr; - int _builtin_methods_count = 0; - const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr; - int _constructors_count = 0; - const Variant::ValidatedConstructor *_constructors_ptr = nullptr; - int _utilities_count = 0; - const Variant::ValidatedUtilityFunction *_utilities_ptr = nullptr; - int _gds_utilities_count = 0; - const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr; - int _methods_count = 0; - MethodBind **_methods_ptr = nullptr; - int _lambdas_count = 0; - GDScriptFunction **_lambdas_ptr = nullptr; - int *_code_ptr = nullptr; - int _code_size = 0; + GDScript *_script = nullptr; + int _initial_line = 0; int _argument_count = 0; int _stack_size = 0; int _instruction_args_size = 0; int _ptrcall_args_size = 0; - int _initial_line = 0; - bool _static = false; - Variant rpc_config; - - GDScript *_script = nullptr; + SelfList<GDScriptFunction> function_list{ this }; + mutable Variant nil; + HashMap<int, Variant::Type> temporary_slots; + List<StackDebug> stack_debug; - StringName name; + Vector<int> code; + Vector<int> default_arguments; Vector<Variant> constants; Vector<StringName> global_names; - Vector<int> default_arguments; Vector<Variant::ValidatedOperatorEvaluator> operator_funcs; Vector<Variant::ValidatedSetter> setters; Vector<Variant::ValidatedGetter> getters; @@ -503,18 +449,47 @@ private: Vector<GDScriptUtilityFunctions::FunctionPtr> gds_utilities; Vector<MethodBind *> methods; Vector<GDScriptFunction *> lambdas; - Vector<int> code; - Vector<GDScriptDataType> argument_types; - GDScriptDataType return_type; - HashMap<int, Variant::Type> temporary_slots; + int _code_size = 0; + int _default_arg_count = 0; + int _constant_count = 0; + int _global_names_count = 0; + int _operator_funcs_count = 0; + int _setters_count = 0; + int _getters_count = 0; + int _keyed_setters_count = 0; + int _keyed_getters_count = 0; + int _indexed_setters_count = 0; + int _indexed_getters_count = 0; + int _builtin_methods_count = 0; + int _constructors_count = 0; + int _utilities_count = 0; + int _gds_utilities_count = 0; + int _methods_count = 0; + int _lambdas_count = 0; -#ifdef TOOLS_ENABLED - Vector<StringName> arg_names; - Vector<Variant> default_arg_values; -#endif + int *_code_ptr = nullptr; + const int *_default_arg_ptr = nullptr; + mutable Variant *_constants_ptr = nullptr; + const StringName *_global_names_ptr = nullptr; + const Variant::ValidatedOperatorEvaluator *_operator_funcs_ptr = nullptr; + const Variant::ValidatedSetter *_setters_ptr = nullptr; + const Variant::ValidatedGetter *_getters_ptr = nullptr; + const Variant::ValidatedKeyedSetter *_keyed_setters_ptr = nullptr; + const Variant::ValidatedKeyedGetter *_keyed_getters_ptr = nullptr; + const Variant::ValidatedIndexedSetter *_indexed_setters_ptr = nullptr; + const Variant::ValidatedIndexedGetter *_indexed_getters_ptr = nullptr; + const Variant::ValidatedBuiltInMethod *_builtin_methods_ptr = nullptr; + const Variant::ValidatedConstructor *_constructors_ptr = nullptr; + const Variant::ValidatedUtilityFunction *_utilities_ptr = nullptr; + const GDScriptUtilityFunctions::FunctionPtr *_gds_utilities_ptr = nullptr; + MethodBind **_methods_ptr = nullptr; + GDScriptFunction **_lambdas_ptr = nullptr; #ifdef DEBUG_ENABLED + CharString func_cname; + const char *_func_cname = nullptr; + Vector<String> operator_names; Vector<String> setter_names; Vector<String> getter_names; @@ -522,20 +497,6 @@ private: Vector<String> constructors_names; Vector<String> utilities_names; Vector<String> gds_utilities_names; -#endif - - List<StackDebug> stack_debug; - - Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type); - - _FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const; - - friend class GDScriptLanguage; - - SelfList<GDScriptFunction> function_list{ this }; -#ifdef DEBUG_ENABLED - CharString func_cname; - const char *_func_cname = nullptr; struct Profile { StringName signature; @@ -549,9 +510,11 @@ private: uint64_t last_frame_self_time = 0; uint64_t last_frame_total_time = 0; } profile; - #endif + _FORCE_INLINE_ String _get_call_error(const Callable::CallError &p_err, const String &p_where, const Variant **argptrs) const; + Variant _get_default_variant_for_data_type(const GDScriptDataType &p_data_type); + public: static constexpr int MAX_CALL_DEPTH = 2048; // Limit to try to avoid crash because of a stack overflow. @@ -571,51 +534,24 @@ public: Variant result; }; + _FORCE_INLINE_ StringName get_name() const { return name; } + _FORCE_INLINE_ StringName get_source() const { return source; } + _FORCE_INLINE_ GDScript *get_script() const { return _script; } _FORCE_INLINE_ bool is_static() const { return _static; } + _FORCE_INLINE_ MethodInfo get_method_info() const { return method_info; } + _FORCE_INLINE_ Variant get_rpc_config() const { return rpc_config; } + _FORCE_INLINE_ int get_max_stack_size() const { return _stack_size; } - const int *get_code() const; //used for debug - int get_code_size() const; Variant get_constant(int p_idx) const; StringName get_global_name(int p_idx) const; - StringName get_name() const; - int get_max_stack_size() const; - int get_default_argument_count() const; - int get_default_argument_addr(int p_idx) const; - GDScriptDataType get_return_type() const; - GDScriptDataType get_argument_type(int p_idx) const; - GDScript *get_script() const { return _script; } - StringName get_source() const { return source; } - - void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const; - - _FORCE_INLINE_ bool is_empty() const { return _code_size == 0; } - - int get_argument_count() const { return _argument_count; } - StringName get_argument_name(int p_idx) const { -#ifdef TOOLS_ENABLED - ERR_FAIL_INDEX_V(p_idx, arg_names.size(), StringName()); - return arg_names[p_idx]; -#else - return StringName(); -#endif - } - Variant get_default_argument(int p_idx) const { - ERR_FAIL_INDEX_V(p_idx, default_arguments.size(), Variant()); - return default_arguments[p_idx]; - } -#ifdef TOOLS_ENABLED - const Vector<Variant> &get_default_arg_values() const { - return default_arg_values; - } -#endif // TOOLS_ENABLED Variant call(GDScriptInstance *p_instance, const Variant **p_args, int p_argcount, Callable::CallError &r_err, CallState *p_state = nullptr); + void debug_get_stack_member_state(int p_line, List<Pair<StringName, int>> *r_stackvars) const; #ifdef DEBUG_ENABLED void disassemble(const Vector<String> &p_code_lines) const; #endif - _FORCE_INLINE_ const Variant get_rpc_config() const { return rpc_config; } GDScriptFunction(); ~GDScriptFunction(); }; diff --git a/modules/gdscript/gdscript_parser.cpp b/modules/gdscript/gdscript_parser.cpp index 039d46f678..9f8e3ce9ee 100644 --- a/modules/gdscript/gdscript_parser.cpp +++ b/modules/gdscript/gdscript_parser.cpp @@ -4099,6 +4099,8 @@ bool GDScriptParser::export_annotations(const AnnotationNode *p_annotation, Node } variable->export_info.hint_string = enum_hint_string; + variable->export_info.usage |= PROPERTY_USAGE_CLASS_IS_ENUM; + variable->export_info.class_name = String(export_type.native_type).replace("::", "."); } break; default: push_error(R"(Export type can only be built-in, a resource, a node, or an enum.)", variable); @@ -4357,6 +4359,104 @@ String GDScriptParser::DataType::to_string() const { ERR_FAIL_V_MSG("<unresolved type>", "Kind set outside the enum range."); } +PropertyInfo GDScriptParser::DataType::to_property_info(const String &p_name) const { + PropertyInfo result; + result.name = p_name; + result.usage = PROPERTY_USAGE_NONE; + + if (!is_hard_type()) { + result.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + return result; + } + + switch (kind) { + case BUILTIN: + result.type = builtin_type; + if (builtin_type == Variant::ARRAY && has_container_element_type()) { + const DataType *elem_type = container_element_type; + switch (elem_type->kind) { + case BUILTIN: + result.hint = PROPERTY_HINT_ARRAY_TYPE; + result.hint_string = Variant::get_type_name(elem_type->builtin_type); + break; + case NATIVE: + result.hint = PROPERTY_HINT_ARRAY_TYPE; + result.hint_string = elem_type->native_type; + break; + case SCRIPT: + result.hint = PROPERTY_HINT_ARRAY_TYPE; + if (elem_type->script_type.is_valid() && elem_type->script_type->get_global_name() != StringName()) { + result.hint_string = elem_type->script_type->get_global_name(); + } else { + result.hint_string = elem_type->native_type; + } + break; + case CLASS: + result.hint = PROPERTY_HINT_ARRAY_TYPE; + if (elem_type->class_type != nullptr && elem_type->class_type->get_global_name() != StringName()) { + result.hint_string = elem_type->class_type->get_global_name(); + } else { + result.hint_string = elem_type->native_type; + } + break; + case ENUM: + result.hint = PROPERTY_HINT_ARRAY_TYPE; + result.hint_string = String(elem_type->native_type).replace("::", "."); + break; + case VARIANT: + case RESOLVING: + case UNRESOLVED: + break; + } + } + break; + case NATIVE: + result.type = Variant::OBJECT; + if (is_meta_type) { + result.class_name = GDScriptNativeClass::get_class_static(); + } else { + result.class_name = native_type; + } + break; + case SCRIPT: + result.type = Variant::OBJECT; + if (is_meta_type) { + result.class_name = script_type.is_valid() ? script_type->get_class() : Script::get_class_static(); + } else if (script_type.is_valid() && script_type->get_global_name() != StringName()) { + result.class_name = script_type->get_global_name(); + } else { + result.class_name = native_type; + } + break; + case CLASS: + result.type = Variant::OBJECT; + if (is_meta_type) { + result.class_name = GDScript::get_class_static(); + } else if (class_type != nullptr && class_type->get_global_name() != StringName()) { + result.class_name = class_type->get_global_name(); + } else { + result.class_name = native_type; + } + break; + case ENUM: + if (is_meta_type) { + result.type = Variant::DICTIONARY; + } else { + result.type = Variant::INT; + result.usage |= PROPERTY_USAGE_CLASS_IS_ENUM; + result.class_name = String(native_type).replace("::", "."); + } + break; + case VARIANT: + case RESOLVING: + case UNRESOLVED: + result.usage |= PROPERTY_USAGE_NIL_IS_VARIANT; + break; + } + + return result; +} + static Variant::Type _variant_type_to_typed_array_element_type(Variant::Type p_type) { switch (p_type) { case Variant::PACKED_BYTE_ARRAY: diff --git a/modules/gdscript/gdscript_parser.h b/modules/gdscript/gdscript_parser.h index 05c5bc2f11..5a1fd40ba2 100644 --- a/modules/gdscript/gdscript_parser.h +++ b/modules/gdscript/gdscript_parser.h @@ -147,7 +147,9 @@ public: _FORCE_INLINE_ bool has_no_type() const { return type_source == UNDETECTED; } _FORCE_INLINE_ bool is_variant() const { return kind == VARIANT || kind == RESOLVING || kind == UNRESOLVED; } _FORCE_INLINE_ bool is_hard_type() const { return type_source > INFERRED; } + String to_string() const; + PropertyInfo to_property_info(const String &p_name) const; _FORCE_INLINE_ void set_container_element_type(const DataType &p_type) { container_element_type = memnew(DataType(p_type)); @@ -749,6 +751,10 @@ public: bool resolved_interface = false; bool resolved_body = false; + StringName get_global_name() const { + return (outer == nullptr && identifier != nullptr) ? identifier->name : StringName(); + } + Member get_member(const StringName &p_name) const { return members[members_indices[p_name]]; } @@ -836,8 +842,8 @@ public: Variant rpc_config; MethodInfo info; LambdaNode *source_lambda = nullptr; -#ifdef TOOLS_ENABLED Vector<Variant> default_arg_values; +#ifdef TOOLS_ENABLED MemberDocData doc_data; #endif // TOOLS_ENABLED @@ -1026,6 +1032,7 @@ public: IdentifierNode *identifier = nullptr; Vector<ParameterNode *> parameters; HashMap<StringName, int> parameters_indices; + MethodInfo method_info; #ifdef TOOLS_ENABLED MemberDocData doc_data; #endif // TOOLS_ENABLED diff --git a/modules/gdscript/gdscript_utility_functions.cpp b/modules/gdscript/gdscript_utility_functions.cpp index 030950267d..52966799f3 100644 --- a/modules/gdscript/gdscript_utility_functions.cpp +++ b/modules/gdscript/gdscript_utility_functions.cpp @@ -277,7 +277,7 @@ struct GDScriptUtilityFunctionsDefinitions { Vector<StringName> sname; while (p->_owner) { - sname.push_back(p->name); + sname.push_back(p->local_name); p = p->_owner; } sname.reverse(); diff --git a/modules/gdscript/gdscript_vm.cpp b/modules/gdscript/gdscript_vm.cpp index 1ddd54b323..a7dc0b6d59 100644 --- a/modules/gdscript/gdscript_vm.cpp +++ b/modules/gdscript/gdscript_vm.cpp @@ -466,8 +466,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a err_file = "<built-in>"; } String err_func = name; - if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && !p_instance->script->name.is_empty()) { - err_func = p_instance->script->name + "." + err_func; + if (p_instance && ObjectDB::get_instance(p_instance->owner_id) != nullptr && p_instance->script->is_valid() && p_instance->script->local_name != StringName()) { + err_func = p_instance->script->local_name.operator String() + "." + err_func; } int err_line = _initial_line; const char *err_text = "Stack overflow. Check for infinite recursion in your script."; @@ -3649,8 +3649,8 @@ Variant GDScriptFunction::call(GDScriptInstance *p_instance, const Variant **p_a err_file = "<built-in>"; } String err_func = name; - if (instance_valid_with_script && !p_instance->script->name.is_empty()) { - err_func = p_instance->script->name + "." + err_func; + if (instance_valid_with_script && p_instance->script->local_name != StringName()) { + err_func = p_instance->script->local_name.operator String() + "." + err_func; } int err_line = line; if (err_text.is_empty()) { diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.gd b/modules/gdscript/tests/scripts/runtime/features/member_info.gd new file mode 100644 index 0000000000..50f840cef3 --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.gd @@ -0,0 +1,125 @@ +class_name TestMemberInfo + +class MyClass: + pass + +enum MyEnum {} + +static var test_static_var_untyped +static var test_static_var_weak_null = null +static var test_static_var_weak_int = 1 +static var test_static_var_hard_int: int + +var test_var_untyped +var test_var_weak_null = null +var test_var_weak_int = 1 +@export var test_var_weak_int_exported = 1 +var test_var_weak_variant_type = TYPE_NIL +@export var test_var_weak_variant_type_exported = TYPE_NIL +var test_var_hard_variant: Variant +var test_var_hard_int: int +var test_var_hard_variant_type: Variant.Type +@export var test_var_hard_variant_type_exported: Variant.Type +var test_var_hard_node_process_mode: Node.ProcessMode +var test_var_hard_my_enum: MyEnum +var test_var_hard_array: Array +var test_var_hard_array_int: Array[int] +var test_var_hard_array_variant_type: Array[Variant.Type] +var test_var_hard_array_node_process_mode: Array[Node.ProcessMode] +var test_var_hard_array_my_enum: Array[MyEnum] +var test_var_hard_array_resource: Array[Resource] +var test_var_hard_array_this: Array[TestMemberInfo] +var test_var_hard_array_my_class: Array[MyClass] +var test_var_hard_resource: Resource +var test_var_hard_this: TestMemberInfo +var test_var_hard_my_class: MyClass + +static func test_static_func(): pass + +func test_func_implicit_void(): pass +func test_func_explicit_void() -> void: pass +func test_func_weak_null(): return null +func test_func_weak_int(): return 1 +func test_func_hard_variant() -> Variant: return null +func test_func_hard_int() -> int: return 1 +func test_func_args_1(_a: int, _b: Array[int], _c: int = 1, _d = 2): pass +func test_func_args_2(_a = 1, _b = _a, _c = [2], _d = 3): pass + +signal test_signal_1() +signal test_signal_2(a: Variant, b) +signal test_signal_3(a: int, b: Array[int]) +signal test_signal_4(a: Variant.Type, b: Array[Variant.Type]) +signal test_signal_5(a: MyEnum, b: Array[MyEnum]) +signal test_signal_6(a: Resource, b: Array[Resource]) +signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo]) +signal test_signal_8(a: MyClass, b: Array[MyClass]) + +func test(): + var script: Script = get_script() + for property in script.get_property_list(): + if str(property.name).begins_with("test_"): + if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE): + print("Error: Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.") + print("static var ", property.name, ": ", get_type(property)) + for property in get_property_list(): + if str(property.name).begins_with("test_"): + if not (property.usage & PROPERTY_USAGE_SCRIPT_VARIABLE): + print("Error: Missing `PROPERTY_USAGE_SCRIPT_VARIABLE` flag.") + print("var ", property.name, ": ", get_type(property)) + for method in get_method_list(): + if str(method.name).begins_with("test_"): + print(get_signature(method)) + for method in get_signal_list(): + if str(method.name).begins_with("test_"): + print(get_signature(method, true)) + +func get_type(property: Dictionary, is_return: bool = false) -> String: + match property.type: + TYPE_NIL: + if property.usage & PROPERTY_USAGE_NIL_IS_VARIANT: + return "Variant" + return "void" if is_return else "null" + TYPE_BOOL: + return "bool" + TYPE_INT: + if property.usage & PROPERTY_USAGE_CLASS_IS_ENUM: + return property.class_name + return "int" + TYPE_STRING: + return "String" + TYPE_DICTIONARY: + return "Dictionary" + TYPE_ARRAY: + if property.hint == PROPERTY_HINT_ARRAY_TYPE: + return "Array[%s]" % property.hint_string + return "Array" + TYPE_OBJECT: + if not str(property.class_name).is_empty(): + return property.class_name + return "Object" + return "<error>" + +func get_signature(method: Dictionary, is_signal: bool = false) -> String: + var result: String = "" + if method.flags & METHOD_FLAG_STATIC: + result += "static " + result += ("signal " if is_signal else "func ") + method.name + "(" + + var args: Array[Dictionary] = method.args + var default_args: Array = method.default_args + var mandatory_argc: int = args.size() - default_args.size() + for i in args.size(): + if i > 0: + result += ", " + var arg: Dictionary = args[i] + result += arg.name + ": " + get_type(arg) + if i >= mandatory_argc: + result += " = " + var_to_str(default_args[i - mandatory_argc]) + + result += ")" + if is_signal: + if get_type(method.return, true) != "void": + print("Error: Signal return type must be `void`.") + else: + result += " -> " + get_type(method.return, true) + return result diff --git a/modules/gdscript/tests/scripts/runtime/features/member_info.out b/modules/gdscript/tests/scripts/runtime/features/member_info.out new file mode 100644 index 0000000000..7c826ac05a --- /dev/null +++ b/modules/gdscript/tests/scripts/runtime/features/member_info.out @@ -0,0 +1,45 @@ +GDTEST_OK +static var test_static_var_untyped: Variant +static var test_static_var_weak_null: Variant +static var test_static_var_weak_int: Variant +static var test_static_var_hard_int: int +var test_var_untyped: Variant +var test_var_weak_null: Variant +var test_var_weak_int: Variant +var test_var_weak_int_exported: int +var test_var_weak_variant_type: Variant +var test_var_weak_variant_type_exported: Variant.Type +var test_var_hard_variant: Variant +var test_var_hard_int: int +var test_var_hard_variant_type: Variant.Type +var test_var_hard_variant_type_exported: Variant.Type +var test_var_hard_node_process_mode: Node.ProcessMode +var test_var_hard_my_enum: TestMemberInfo.MyEnum +var test_var_hard_array: Array +var test_var_hard_array_int: Array[int] +var test_var_hard_array_variant_type: Array[Variant.Type] +var test_var_hard_array_node_process_mode: Array[Node.ProcessMode] +var test_var_hard_array_my_enum: Array[TestMemberInfo.MyEnum] +var test_var_hard_array_resource: Array[Resource] +var test_var_hard_array_this: Array[TestMemberInfo] +var test_var_hard_array_my_class: Array[RefCounted] +var test_var_hard_resource: Resource +var test_var_hard_this: TestMemberInfo +var test_var_hard_my_class: RefCounted +static func test_static_func() -> void +func test_func_implicit_void() -> void +func test_func_explicit_void() -> void +func test_func_weak_null() -> Variant +func test_func_weak_int() -> Variant +func test_func_hard_variant() -> Variant +func test_func_hard_int() -> int +func test_func_args_1(_a: int, _b: Array[int], _c: int = 1, _d: Variant = 2) -> void +func test_func_args_2(_a: Variant = 1, _b: Variant = null, _c: Variant = null, _d: Variant = 3) -> void +signal test_signal_1() +signal test_signal_2(a: Variant, b: Variant) +signal test_signal_3(a: int, b: Array[int]) +signal test_signal_4(a: Variant.Type, b: Array[Variant.Type]) +signal test_signal_5(a: TestMemberInfo.MyEnum, b: Array[TestMemberInfo.MyEnum]) +signal test_signal_6(a: Resource, b: Array[Resource]) +signal test_signal_7(a: TestMemberInfo, b: Array[TestMemberInfo]) +signal test_signal_8(a: RefCounted, b: Array[RefCounted]) diff --git a/modules/gdscript/tests/test_gdscript.cpp b/modules/gdscript/tests/test_gdscript.cpp index 0446a7aad6..b86a8b3cb1 100644 --- a/modules/gdscript/tests/test_gdscript.cpp +++ b/modules/gdscript/tests/test_gdscript.cpp @@ -138,12 +138,13 @@ static void recursively_disassemble_functions(const Ref<GDScript> script, const for (const KeyValue<StringName, GDScriptFunction *> &E : script->get_member_functions()) { const GDScriptFunction *func = E.value; - String signature = "Disassembling " + func->get_name().operator String() + "("; - for (int i = 0; i < func->get_argument_count(); i++) { + const MethodInfo &mi = func->get_method_info(); + String signature = "Disassembling " + mi.name + "("; + for (int i = 0; i < mi.arguments.size(); i++) { if (i > 0) { signature += ", "; } - signature += func->get_argument_name(i); + signature += mi.arguments[i].name; } print_line(signature + ")"); #ifdef TOOLS_ENABLED @@ -156,7 +157,7 @@ static void recursively_disassemble_functions(const Ref<GDScript> script, const for (const KeyValue<StringName, Ref<GDScript>> &F : script->get_subclasses()) { const Ref<GDScript> inner_script = F.value; print_line(""); - print_line(vformat("Inner Class: %s", inner_script->get_script_class_name())); + print_line(vformat("Inner Class: %s", inner_script->get_local_name())); print_line(""); recursively_disassemble_functions(inner_script, p_lines); } |