From 47a7d85cc42a871106d57f45af744ea85d19be47 Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Wed, 9 Feb 2022 18:59:22 +0100 Subject: Fix references to global constants in C# documentation generator Tries to find the referenced constants in the GlobalScope if not found in the target class or if no class is specified. --- modules/mono/editor/bindings_generator.cpp | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 07128770b7..c4f6165ccd 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -415,6 +415,11 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf } } else if (link_tag == "constant") { if (!target_itype || !target_itype->is_object_type) { + // Search in @GlobalScope as a last resort if no class was specified + if (link_target_parts.size() == 1) { + goto find_constant_in_global_scope; + } + if (OS::get_singleton()->is_stdout_verbose()) { if (target_itype) { OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); @@ -428,6 +433,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(link_target); xml_output.append(""); } else if (!target_itype && target_cname == name_cache.type_at_GlobalScope) { + find_constant_in_global_scope: const String target_name = (String)target_cname; // Try to find as a global constant @@ -498,6 +504,11 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(target_iconst->proxy_name); xml_output.append("\"/>"); } else { + // Also search in @GlobalScope as a last resort if no class was specified + if (link_target_parts.size() == 1) { + goto find_constant_in_global_scope; + } + ERR_PRINT("Cannot resolve constant reference in documentation: '" + link_target + "'."); xml_output.append(""); -- cgit v1.2.3 From 424817039aca0c70f94727ad7069bec1023fb78e Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Thu, 10 Feb 2022 16:01:22 +0100 Subject: Check for missing methods/members in C# documentation generator - Outputs errors for missing members or methods when generating the C# documentation. - Hardcodes a special case for the `_init` method, in C# we'll reference the constructor. - Ignores properties with slashes (since they are not declared in C# and can't be referenced in the documentation). --- modules/mono/editor/bindings_generator.cpp | 38 +++++++++++++++++++++++++----- 1 file changed, 32 insertions(+), 6 deletions(-) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index c4f6165ccd..4a2f2be3ba 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -325,18 +325,38 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(link_target); xml_output.append(""); } else { - const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname); - - if (target_imethod) { + if (target_cname == "_init") { + // The _init method is not declared in C#, reference the constructor instead xml_output.append("proxy_name); xml_output.append("."); - xml_output.append(target_imethod->proxy_name); - xml_output.append("\"/>"); + xml_output.append(target_itype->proxy_name); + xml_output.append("()\"/>"); + } else { + const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname); + + if (target_imethod) { + xml_output.append("proxy_name); + xml_output.append("."); + xml_output.append(target_imethod->proxy_name); + xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve method reference in documentation: '" + link_target + "'."); + + xml_output.append(""); + xml_output.append(link_target); + xml_output.append(""); + } } } } else if (link_tag == "member") { - if (!target_itype || !target_itype->is_object_type) { + if (link_target.find("/") >= 0) { + // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference. + xml_output.append(""); + xml_output.append(link_target); + xml_output.append(""); + } else if (!target_itype || !target_itype->is_object_type) { if (OS::get_singleton()->is_stdout_verbose()) { if (target_itype) { OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); @@ -358,6 +378,12 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append("."); xml_output.append(target_iprop->proxy_name); xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve member reference in documentation: '" + link_target + "'."); + + xml_output.append(""); + xml_output.append(link_target); + xml_output.append(""); } } } else if (link_tag == "signal") { -- cgit v1.2.3 From e601c9eb8fd7d42b167d640accb38cfb28c65dcd Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Fri, 11 Feb 2022 17:21:47 +0100 Subject: Fix checking for `@GlobalScope` in C# documentation generator --- modules/mono/editor/bindings_generator.cpp | 49 ++++++++++++++++++------------ 1 file changed, 29 insertions(+), 20 deletions(-) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 4a2f2be3ba..85e2a70c0d 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -311,7 +311,16 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf } if (link_tag == "method") { - if (!target_itype || !target_itype->is_object_type) { + if (link_target_parts[0] == name_cache.type_at_GlobalScope) { + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Cannot resolve @GlobalScope method reference in documentation: %s\n", link_target.utf8().get_data()); + } + + // TODO Map what we can + xml_output.append(""); + xml_output.append(link_target); + xml_output.append(""); + } else if (!target_itype || !target_itype->is_object_type) { if (OS::get_singleton()->is_stdout_verbose()) { if (target_itype) { OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); @@ -440,25 +449,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(""); } } else if (link_tag == "constant") { - if (!target_itype || !target_itype->is_object_type) { - // Search in @GlobalScope as a last resort if no class was specified - if (link_target_parts.size() == 1) { - goto find_constant_in_global_scope; - } - - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } else if (!target_itype && target_cname == name_cache.type_at_GlobalScope) { + if (link_target_parts[0] == name_cache.type_at_GlobalScope) { find_constant_in_global_scope: const String target_name = (String)target_cname; @@ -496,6 +487,24 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(""); } } + } else if (!target_itype || !target_itype->is_object_type) { + // Search in @GlobalScope as a last resort if no class was specified + if (link_target_parts.size() == 1) { + goto find_constant_in_global_scope; + } + + if (OS::get_singleton()->is_stdout_verbose()) { + if (target_itype) { + OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data()); + } + } + + // TODO Map what we can + xml_output.append(""); + xml_output.append(link_target); + xml_output.append(""); } else { const String target_name = (String)target_cname; -- cgit v1.2.3 From 42989befd6364a8df3cff7ef546fe9728124e7a6 Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Mon, 14 Feb 2022 16:24:35 +0100 Subject: Add theme_item support to C# documentation generator --- modules/mono/editor/bindings_generator.cpp | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 85e2a70c0d..1c64d2180b 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -278,7 +278,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf } else if (code_tag) { xml_output.append("["); pos = brk_pos + 1; - } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ")) { + } else if (tag.begins_with("method ") || tag.begins_with("member ") || tag.begins_with("signal ") || tag.begins_with("enum ") || tag.begins_with("constant ") || tag.begins_with("theme_item ")) { const int tag_end = tag.find(" "); const String link_tag = tag.substr(0, tag_end); const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" "); @@ -552,6 +552,11 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf } } } + } else if (link_tag == "theme_item") { + // We do not declare theme_items in any way in C#, so there is nothing to reference + xml_output.append(""); + xml_output.append(link_target); + xml_output.append(""); } pos = brk_end + 1; -- cgit v1.2.3 From 84615b4b537100269c9a7ba270ee2a2911fef05e Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Thu, 3 Mar 2022 19:53:06 +0100 Subject: Find inherited members in C# documentation generator --- modules/mono/editor/bindings_generator.cpp | 12 ++++++++++-- 1 file changed, 10 insertions(+), 2 deletions(-) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index 1c64d2180b..a08f6448db 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -379,11 +379,19 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf xml_output.append(link_target); xml_output.append(""); } else { - const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname); + const TypeInterface *current_itype = target_itype; + const PropertyInterface *target_iprop = nullptr; + + while (target_iprop == nullptr && current_itype != nullptr) { + target_iprop = current_itype->find_property_by_name(target_cname); + if (target_iprop == nullptr) { + current_itype = _get_type_or_null(TypeReference(current_itype->base_name)); + } + } if (target_iprop) { xml_output.append("proxy_name); + xml_output.append(current_itype->proxy_name); xml_output.append("."); xml_output.append(target_iprop->proxy_name); xml_output.append("\"/>"); -- cgit v1.2.3 From eaddb79ec64d6f04ecd540312d5b046e344894a5 Mon Sep 17 00:00:00 2001 From: Raul Santos Date: Thu, 3 Mar 2022 23:35:10 +0100 Subject: Refactor `bbcode_to_xml` into multiple specific methods The specific `_append_xml_*` methods implement the logic that generates the proper XML documentation for the given BBCode tag and target and appends it to the output. --- modules/mono/editor/bindings_generator.cpp | 490 ++++++++++++++--------------- modules/mono/editor/bindings_generator.h | 8 + 2 files changed, 249 insertions(+), 249 deletions(-) diff --git a/modules/mono/editor/bindings_generator.cpp b/modules/mono/editor/bindings_generator.cpp index a08f6448db..272283432d 100644 --- a/modules/mono/editor/bindings_generator.cpp +++ b/modules/mono/editor/bindings_generator.cpp @@ -283,7 +283,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf const String link_tag = tag.substr(0, tag_end); const String link_target = tag.substr(tag_end + 1, tag.length()).lstrip(" "); - Vector link_target_parts = link_target.split("."); + const Vector link_target_parts = link_target.split("."); if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) { ERR_PRINT("Invalid reference format: '" + tag + "'."); @@ -311,260 +311,18 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf } if (link_tag == "method") { - if (link_target_parts[0] == name_cache.type_at_GlobalScope) { - if (OS::get_singleton()->is_stdout_verbose()) { - OS::get_singleton()->print("Cannot resolve @GlobalScope method reference in documentation: %s\n", link_target.utf8().get_data()); - } - - // TODO Map what we can - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } else if (!target_itype || !target_itype->is_object_type) { - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } else { - if (target_cname == "_init") { - // The _init method is not declared in C#, reference the constructor instead - xml_output.append("proxy_name); - xml_output.append("."); - xml_output.append(target_itype->proxy_name); - xml_output.append("()\"/>"); - } else { - const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname); - - if (target_imethod) { - xml_output.append("proxy_name); - xml_output.append("."); - xml_output.append(target_imethod->proxy_name); - xml_output.append("\"/>"); - } else { - ERR_PRINT("Cannot resolve method reference in documentation: '" + link_target + "'."); - - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } - } - } + _append_xml_method(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "member") { - if (link_target.find("/") >= 0) { - // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference. - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } else if (!target_itype || !target_itype->is_object_type) { - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } else { - const TypeInterface *current_itype = target_itype; - const PropertyInterface *target_iprop = nullptr; - - while (target_iprop == nullptr && current_itype != nullptr) { - target_iprop = current_itype->find_property_by_name(target_cname); - if (target_iprop == nullptr) { - current_itype = _get_type_or_null(TypeReference(current_itype->base_name)); - } - } - - if (target_iprop) { - xml_output.append("proxy_name); - xml_output.append("."); - xml_output.append(target_iprop->proxy_name); - xml_output.append("\"/>"); - } else { - ERR_PRINT("Cannot resolve member reference in documentation: '" + link_target + "'."); - - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } - } + _append_xml_member(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "signal") { - if (!target_itype || !target_itype->is_object_type) { - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve signal reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from signal reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } else { - const SignalInterface *target_isignal = target_itype->find_signal_by_name(target_cname); - - if (target_isignal) { - xml_output.append("proxy_name); - xml_output.append("."); - xml_output.append(target_isignal->proxy_name); - xml_output.append("\"/>"); - } else { - ERR_PRINT("Cannot resolve signal reference in documentation: '" + link_target + "'."); - - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } - } + _append_xml_signal(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "enum") { - const StringName search_cname = !target_itype ? target_cname : StringName(target_itype->name + "." + (String)target_cname); - - const Map::Element *enum_match = enum_types.find(search_cname); - - if (!enum_match && search_cname != target_cname) { - enum_match = enum_types.find(target_cname); - } - - if (enum_match) { - const TypeInterface &target_enum_itype = enum_match->value(); - - xml_output.append(""); - } else { - ERR_PRINT("Cannot resolve enum reference in documentation: '" + link_target + "'."); - - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } + _append_xml_enum(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "constant") { - if (link_target_parts[0] == name_cache.type_at_GlobalScope) { - find_constant_in_global_scope: - const String target_name = (String)target_cname; - - // Try to find as a global constant - const ConstantInterface *target_iconst = find_constant_by_name(target_name, global_constants); - - if (target_iconst) { - // Found global constant - xml_output.append("proxy_name); - xml_output.append("\"/>"); - } else { - // Try to find as global enum constant - const EnumInterface *target_ienum = nullptr; - - for (const EnumInterface &ienum : global_enums) { - target_ienum = &ienum; - target_iconst = find_constant_by_name(target_name, target_ienum->constants); - if (target_iconst) { - break; - } - } - - if (target_iconst) { - xml_output.append("cname); - xml_output.append("."); - xml_output.append(target_iconst->proxy_name); - xml_output.append("\"/>"); - } else { - ERR_PRINT("Cannot resolve global constant reference in documentation: '" + link_target + "'."); - - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } - } - } else if (!target_itype || !target_itype->is_object_type) { - // Search in @GlobalScope as a last resort if no class was specified - if (link_target_parts.size() == 1) { - goto find_constant_in_global_scope; - } - - if (OS::get_singleton()->is_stdout_verbose()) { - if (target_itype) { - OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", link_target.utf8().get_data()); - } else { - OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", link_target.utf8().get_data()); - } - } - - // TODO Map what we can - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } else { - const String target_name = (String)target_cname; - - // Try to find the constant in the current class - const ConstantInterface *target_iconst = find_constant_by_name(target_name, target_itype->constants); - - if (target_iconst) { - // Found constant in current class - xml_output.append("proxy_name); - xml_output.append("."); - xml_output.append(target_iconst->proxy_name); - xml_output.append("\"/>"); - } else { - // Try to find as enum constant in the current class - const EnumInterface *target_ienum = nullptr; - - for (const EnumInterface &ienum : target_itype->enums) { - target_ienum = &ienum; - target_iconst = find_constant_by_name(target_name, target_ienum->constants); - if (target_iconst) { - break; - } - } - - if (target_iconst) { - xml_output.append("proxy_name); - xml_output.append("."); - xml_output.append(target_ienum->cname); - xml_output.append("."); - xml_output.append(target_iconst->proxy_name); - xml_output.append("\"/>"); - } else { - // Also search in @GlobalScope as a last resort if no class was specified - if (link_target_parts.size() == 1) { - goto find_constant_in_global_scope; - } - - ERR_PRINT("Cannot resolve constant reference in documentation: '" + link_target + "'."); - - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); - } - } - } + _append_xml_constant(xml_output, target_itype, target_cname, link_target, link_target_parts); } else if (link_tag == "theme_item") { // We do not declare theme_items in any way in C#, so there is nothing to reference - xml_output.append(""); - xml_output.append(link_target); - xml_output.append(""); + _append_xml_undeclared(xml_output, link_target); } pos = brk_end + 1; @@ -729,6 +487,240 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf return xml_output.as_string(); } +void BindingsGenerator::_append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts) { + if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) { + if (OS::get_singleton()->is_stdout_verbose()) { + OS::get_singleton()->print("Cannot resolve @GlobalScope method reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else if (!p_target_itype || !p_target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve method reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from method reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + if (p_target_cname == "_init") { + // The _init method is not declared in C#, reference the constructor instead + p_xml_output.append("proxy_name); + p_xml_output.append("."); + p_xml_output.append(p_target_itype->proxy_name); + p_xml_output.append("()\"/>"); + } else { + const MethodInterface *target_imethod = p_target_itype->find_method_by_name(p_target_cname); + + if (target_imethod) { + p_xml_output.append("proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_imethod->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve method reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } + } +} + +void BindingsGenerator::_append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts) { + if (p_link_target.find("/") >= 0) { + // Properties with '/' (slash) in the name are not declared in C#, so there is nothing to reference. + _append_xml_undeclared(p_xml_output, p_link_target); + } else if (!p_target_itype || !p_target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve member reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from member reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + const TypeInterface *current_itype = p_target_itype; + const PropertyInterface *target_iprop = nullptr; + + while (target_iprop == nullptr && current_itype != nullptr) { + target_iprop = current_itype->find_property_by_name(p_target_cname); + if (target_iprop == nullptr) { + current_itype = _get_type_or_null(TypeReference(current_itype->base_name)); + } + } + + if (target_iprop) { + p_xml_output.append("proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_iprop->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve member reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } +} + +void BindingsGenerator::_append_xml_signal(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts) { + if (!p_target_itype || !p_target_itype->is_object_type) { + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve signal reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from signal reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + const SignalInterface *target_isignal = p_target_itype->find_signal_by_name(p_target_cname); + + if (target_isignal) { + p_xml_output.append("proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_isignal->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve signal reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } +} + +void BindingsGenerator::_append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts) { + const StringName search_cname = !p_target_itype ? p_target_cname : StringName(p_target_itype->name + "." + (String)p_target_cname); + + const Map::Element *enum_match = enum_types.find(search_cname); + + if (!enum_match && search_cname != p_target_cname) { + enum_match = enum_types.find(p_target_cname); + } + + if (enum_match) { + const TypeInterface &target_enum_itype = enum_match->value(); + + p_xml_output.append(""); + } else { + ERR_PRINT("Cannot resolve enum reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } +} + +void BindingsGenerator::_append_xml_constant(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts) { + if (p_link_target_parts[0] == name_cache.type_at_GlobalScope) { + _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target); + } else if (!p_target_itype || !p_target_itype->is_object_type) { + // Search in @GlobalScope as a last resort if no class was specified + if (p_link_target_parts.size() == 1) { + _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target); + return; + } + + if (OS::get_singleton()->is_stdout_verbose()) { + if (p_target_itype) { + OS::get_singleton()->print("Cannot resolve constant reference for non-Godot.Object type in documentation: %s\n", p_link_target.utf8().get_data()); + } else { + OS::get_singleton()->print("Cannot resolve type from constant reference in documentation: %s\n", p_link_target.utf8().get_data()); + } + } + + // TODO Map what we can + _append_xml_undeclared(p_xml_output, p_link_target); + } else { + // Try to find the constant in the current class + const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, p_target_itype->constants); + + if (target_iconst) { + // Found constant in current class + p_xml_output.append("proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_iconst->proxy_name); + p_xml_output.append("\"/>"); + } else { + // Try to find as enum constant in the current class + const EnumInterface *target_ienum = nullptr; + + for (const EnumInterface &ienum : p_target_itype->enums) { + target_ienum = &ienum; + target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants); + if (target_iconst) { + break; + } + } + + if (target_iconst) { + p_xml_output.append("proxy_name); + p_xml_output.append("."); + p_xml_output.append(target_ienum->cname); + p_xml_output.append("."); + p_xml_output.append(target_iconst->proxy_name); + p_xml_output.append("\"/>"); + } else if (p_link_target_parts.size() == 1) { + // Also search in @GlobalScope as a last resort if no class was specified + _append_xml_constant_in_global_scope(p_xml_output, p_target_cname, p_link_target); + } else { + ERR_PRINT("Cannot resolve constant reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } + } +} + +void BindingsGenerator::_append_xml_constant_in_global_scope(StringBuilder &p_xml_output, const String &p_target_cname, const String &p_link_target) { + // Try to find as a global constant + const ConstantInterface *target_iconst = find_constant_by_name(p_target_cname, global_constants); + + if (target_iconst) { + // Found global constant + p_xml_output.append("proxy_name); + p_xml_output.append("\"/>"); + } else { + // Try to find as global enum constant + const EnumInterface *target_ienum = nullptr; + + for (const EnumInterface &ienum : global_enums) { + target_ienum = &ienum; + target_iconst = find_constant_by_name(p_target_cname, target_ienum->constants); + if (target_iconst) { + break; + } + } + + if (target_iconst) { + p_xml_output.append("cname); + p_xml_output.append("."); + p_xml_output.append(target_iconst->proxy_name); + p_xml_output.append("\"/>"); + } else { + ERR_PRINT("Cannot resolve global constant reference in documentation: '" + p_link_target + "'."); + _append_xml_undeclared(p_xml_output, p_link_target); + } + } +} + +void BindingsGenerator::_append_xml_undeclared(StringBuilder &p_xml_output, const String &p_link_target) { + p_xml_output.append(""); + p_xml_output.append(p_link_target); + p_xml_output.append(""); +} + int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) { CRASH_COND(p_ienum.constants.is_empty()); diff --git a/modules/mono/editor/bindings_generator.h b/modules/mono/editor/bindings_generator.h index 5460f018f0..f601ffde2b 100644 --- a/modules/mono/editor/bindings_generator.h +++ b/modules/mono/editor/bindings_generator.h @@ -658,6 +658,14 @@ class BindingsGenerator { String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype); + void _append_xml_method(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts); + void _append_xml_member(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts); + void _append_xml_signal(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts); + void _append_xml_enum(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts); + void _append_xml_constant(StringBuilder &p_xml_output, const TypeInterface *p_target_itype, const StringName &p_target_cname, const String &p_link_target, const Vector &p_link_target_parts); + void _append_xml_constant_in_global_scope(StringBuilder &p_xml_output, const String &p_target_cname, const String &p_link_target); + void _append_xml_undeclared(StringBuilder &p_xml_output, const String &p_link_target); + int _determine_enum_prefix(const EnumInterface &p_ienum); void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length); -- cgit v1.2.3