summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorDanil Alexeev <danil@alexeev.xyz>2023-08-28 19:20:10 +0300
committerDanil Alexeev <danil@alexeev.xyz>2023-09-04 00:21:03 +0300
commit462d8f47521d3406a7ee8b5b024699112c4337aa (patch)
treebc3915ef18cbdef583cb53560d8eb55200ce581d
parentfa3428ff25bc577d2a3433090478a6d615567056 (diff)
downloadredot-engine-462d8f47521d3406a7ee8b5b024699112c4337aa.tar.gz
GDScript: Fix `get_*_list()` methods return incorrect info
-rw-r--r--modules/gdscript/editor/gdscript_docgen.cpp9
-rw-r--r--modules/gdscript/gdscript.cpp127
-rw-r--r--modules/gdscript/gdscript.h14
-rw-r--r--modules/gdscript/gdscript_analyzer.cpp10
-rw-r--r--modules/gdscript/gdscript_byte_codegen.cpp3
-rw-r--r--modules/gdscript/gdscript_compiler.cpp49
-rw-r--r--modules/gdscript/gdscript_function.cpp36
-rw-r--r--modules/gdscript/gdscript_function.h188
-rw-r--r--modules/gdscript/gdscript_parser.cpp100
-rw-r--r--modules/gdscript/gdscript_parser.h9
-rw-r--r--modules/gdscript/gdscript_utility_functions.cpp2
-rw-r--r--modules/gdscript/gdscript_vm.cpp8
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info.gd125
-rw-r--r--modules/gdscript/tests/scripts/runtime/features/member_info.out45
-rw-r--r--modules/gdscript/tests/test_gdscript.cpp9
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);
}