mirror of
https://github.com/godotengine/godot.git
synced 2024-11-27 09:16:35 +08:00
Merge pull request #81079 from dalexeev/gds-fix-get-method-list
GDScript: Fix `get_*_list()` methods return incorrect info
This commit is contained in:
commit
13f0ab88f2
@ -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";
|
||||
}
|
||||
|
@ -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;
|
||||
}
|
||||
|
@ -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();
|
||||
|
@ -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) {
|
||||
|
@ -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) {
|
||||
|
@ -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;
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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;
|
||||
SelfList<GDScriptFunction> function_list{ this };
|
||||
mutable Variant nil;
|
||||
HashMap<int, Variant::Type> temporary_slots;
|
||||
List<StackDebug> stack_debug;
|
||||
|
||||
GDScript *_script = nullptr;
|
||||
|
||||
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();
|
||||
};
|
||||
|
@ -4112,6 +4112,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);
|
||||
@ -4370,6 +4372,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:
|
||||
|
@ -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
|
||||
|
@ -279,7 +279,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();
|
||||
|
@ -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()) {
|
||||
|
125
modules/gdscript/tests/scripts/runtime/features/member_info.gd
Normal file
125
modules/gdscript/tests/scripts/runtime/features/member_info.gd
Normal file
@ -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
|
@ -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])
|
@ -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);
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user