Merge pull request #27359 from neikeq/who-reads-docs-anyway
C#: Bindings generator now translates BBCode docs to XML comments
This commit is contained in:
commit
e453934824
2 changed files with 472 additions and 79 deletions
|
@ -38,6 +38,7 @@
|
|||
#include "core/os/dir_access.h"
|
||||
#include "core/os/file_access.h"
|
||||
#include "core/os/os.h"
|
||||
#include "core/string_builder.h"
|
||||
#include "core/ucaps.h"
|
||||
|
||||
#include "../glue/cs_compressed.gen.h"
|
||||
|
@ -105,6 +106,16 @@ bool BindingsGenerator::verbose_output = false;
|
|||
|
||||
BindingsGenerator *BindingsGenerator::singleton = NULL;
|
||||
|
||||
static String fix_doc_description(const String &p_bbcode) {
|
||||
|
||||
// This seems to be the correct way to do this. It's the same EditorHelp does.
|
||||
|
||||
return p_bbcode.dedent()
|
||||
.replace("\t", "")
|
||||
.replace("\r", "")
|
||||
.strip_edges();
|
||||
}
|
||||
|
||||
static String snake_to_pascal_case(const String &p_identifier, bool p_input_is_upper = false) {
|
||||
|
||||
String ret;
|
||||
|
@ -173,6 +184,366 @@ static String snake_to_camel_case(const String &p_identifier, bool p_input_is_up
|
|||
return ret;
|
||||
}
|
||||
|
||||
String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype) {
|
||||
|
||||
// Based on the version in EditorHelp
|
||||
|
||||
if (p_bbcode.empty())
|
||||
return String();
|
||||
|
||||
DocData *doc = EditorHelp::get_doc_data();
|
||||
|
||||
String bbcode = p_bbcode;
|
||||
|
||||
StringBuilder xml_output;
|
||||
|
||||
xml_output.append("<para>");
|
||||
|
||||
List<String> tag_stack;
|
||||
bool code_tag = false;
|
||||
|
||||
int pos = 0;
|
||||
while (pos < bbcode.length()) {
|
||||
int brk_pos = bbcode.find("[", pos);
|
||||
|
||||
if (brk_pos < 0)
|
||||
brk_pos = bbcode.length();
|
||||
|
||||
if (brk_pos > pos) {
|
||||
String text = bbcode.substr(pos, brk_pos - pos);
|
||||
if (code_tag || tag_stack.size() > 0) {
|
||||
xml_output.append(text.xml_escape());
|
||||
} else {
|
||||
Vector<String> lines = text.split("\n");
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (i != 0)
|
||||
xml_output.append("<para>");
|
||||
|
||||
xml_output.append(lines[i].xml_escape());
|
||||
|
||||
if (i != lines.size() - 1)
|
||||
xml_output.append("</para>\n");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (brk_pos == bbcode.length())
|
||||
break; // nothing else to add
|
||||
|
||||
int brk_end = bbcode.find("]", brk_pos + 1);
|
||||
|
||||
if (brk_end == -1) {
|
||||
String text = bbcode.substr(brk_pos, bbcode.length() - brk_pos);
|
||||
if (code_tag || tag_stack.size() > 0) {
|
||||
xml_output.append(text.xml_escape());
|
||||
} else {
|
||||
Vector<String> lines = text.split("\n");
|
||||
for (int i = 0; i < lines.size(); i++) {
|
||||
if (i != 0)
|
||||
xml_output.append("<para>");
|
||||
|
||||
xml_output.append(lines[i].xml_escape());
|
||||
|
||||
if (i != lines.size() - 1)
|
||||
xml_output.append("</para>\n");
|
||||
}
|
||||
}
|
||||
|
||||
break;
|
||||
}
|
||||
|
||||
String tag = bbcode.substr(brk_pos + 1, brk_end - brk_pos - 1);
|
||||
|
||||
if (tag.begins_with("/")) {
|
||||
bool tag_ok = tag_stack.size() && tag_stack.front()->get() == tag.substr(1, tag.length());
|
||||
|
||||
if (!tag_ok) {
|
||||
xml_output.append("[");
|
||||
pos = brk_pos + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
tag_stack.pop_front();
|
||||
pos = brk_end + 1;
|
||||
code_tag = false;
|
||||
|
||||
if (tag == "/url") {
|
||||
xml_output.append("</a>");
|
||||
} else if (tag == "/code") {
|
||||
xml_output.append("</c>");
|
||||
} else if (tag == "/codeblock") {
|
||||
xml_output.append("</code>");
|
||||
}
|
||||
} 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 ")) {
|
||||
String link_target = tag.substr(tag.find(" ") + 1, tag.length());
|
||||
String link_tag = tag.substr(0, tag.find(" "));
|
||||
|
||||
Vector<String> link_target_parts = link_target.split(".");
|
||||
|
||||
if (link_target_parts.size() <= 0 || link_target_parts.size() > 2) {
|
||||
ERR_PRINTS("Invalid reference format: " + tag);
|
||||
|
||||
xml_output.append("<c>");
|
||||
xml_output.append(tag);
|
||||
xml_output.append("</c>");
|
||||
|
||||
pos = brk_end + 1;
|
||||
continue;
|
||||
}
|
||||
|
||||
const TypeInterface *target_itype;
|
||||
StringName target_cname;
|
||||
|
||||
if (link_target_parts.size() == 2) {
|
||||
target_itype = _get_type_or_null(TypeReference(link_target_parts[0]));
|
||||
if (!target_itype) {
|
||||
target_itype = _get_type_or_null(TypeReference("_" + link_target_parts[0]));
|
||||
}
|
||||
target_cname = link_target_parts[1];
|
||||
} else {
|
||||
target_itype = p_itype;
|
||||
target_cname = link_target_parts[0];
|
||||
}
|
||||
|
||||
if (link_tag == "method") {
|
||||
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("<c>");
|
||||
xml_output.append(link_target);
|
||||
xml_output.append("</c>");
|
||||
} else {
|
||||
const MethodInterface *target_imethod = target_itype->find_method_by_name(target_cname);
|
||||
|
||||
if (target_imethod) {
|
||||
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||
xml_output.append(target_itype->proxy_name);
|
||||
xml_output.append(".");
|
||||
xml_output.append(target_imethod->proxy_name);
|
||||
xml_output.append("\"/>");
|
||||
}
|
||||
}
|
||||
} else if (link_tag == "member") {
|
||||
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("<c>");
|
||||
xml_output.append(link_target);
|
||||
xml_output.append("</c>");
|
||||
} else {
|
||||
const PropertyInterface *target_iprop = target_itype->find_property_by_name(target_cname);
|
||||
|
||||
if (target_iprop) {
|
||||
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||
xml_output.append(target_itype->proxy_name);
|
||||
xml_output.append(".");
|
||||
xml_output.append(target_iprop->proxy_name);
|
||||
xml_output.append("\"/>");
|
||||
}
|
||||
}
|
||||
} else if (link_tag == "signal") {
|
||||
// We do not declare signals in any way in C#, so there is nothing to reference
|
||||
xml_output.append("<c>");
|
||||
xml_output.append(link_target);
|
||||
xml_output.append("</c>");
|
||||
} else if (link_tag == "enum") {
|
||||
StringName search_cname = !target_itype ? target_cname :
|
||||
StringName(target_itype->name + "." + (String)target_cname);
|
||||
|
||||
const Map<StringName, TypeInterface>::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("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||
xml_output.append(target_enum_itype.proxy_name); // Includes nesting class if any
|
||||
xml_output.append("\"/>");
|
||||
} else {
|
||||
ERR_PRINTS("Cannot resolve enum reference in documentation: " + link_target);
|
||||
|
||||
xml_output.append("<c>");
|
||||
xml_output.append(link_target);
|
||||
xml_output.append("</c>");
|
||||
}
|
||||
}
|
||||
|
||||
pos = brk_end + 1;
|
||||
} else if (doc->class_list.has(tag)) {
|
||||
if (tag == "Array" || tag == "Dictionary") {
|
||||
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE_COLLECTIONS ".");
|
||||
xml_output.append(tag);
|
||||
xml_output.append("\"/>");
|
||||
} else if (tag == "bool" || tag == "int") {
|
||||
xml_output.append("<see cref=\"");
|
||||
xml_output.append(tag);
|
||||
xml_output.append("\"/>");
|
||||
} else if (tag == "float") {
|
||||
xml_output.append("<see cref=\""
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
"double"
|
||||
#else
|
||||
"float"
|
||||
#endif
|
||||
"\"/>");
|
||||
} else if (tag == "Variant") {
|
||||
// We use System.Object for Variant, so there is no Variant type in C#
|
||||
xml_output.append("<c>Variant</c>");
|
||||
} else if (tag == "String") {
|
||||
xml_output.append("<see cref=\"string\"/>");
|
||||
} else if (tag == "Nil") {
|
||||
xml_output.append("<see langword=\"null\"/>");
|
||||
} else if (tag.begins_with("@")) {
|
||||
// @Global Scope, @GDScript, etc
|
||||
xml_output.append("<c>");
|
||||
xml_output.append(tag);
|
||||
xml_output.append("</c>");
|
||||
} else if (tag == "PoolByteArray") {
|
||||
xml_output.append("<see cref=\"byte\"/>");
|
||||
} else if (tag == "PoolIntArray") {
|
||||
xml_output.append("<see cref=\"int\"/>");
|
||||
} else if (tag == "PoolRealArray") {
|
||||
#ifdef REAL_T_IS_DOUBLE
|
||||
xml_output.append("<see cref=\"double\"/>");
|
||||
#else
|
||||
xml_output.append("<see cref=\"float\"/>");
|
||||
#endif
|
||||
} else if (tag == "PoolStringArray") {
|
||||
xml_output.append("<see cref=\"string\"/>");
|
||||
} else if (tag == "PoolVector2Array") {
|
||||
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector2\"/>");
|
||||
} else if (tag == "PoolVector3Array") {
|
||||
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Vector3\"/>");
|
||||
} else if (tag == "PoolColorArray") {
|
||||
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".Color\"/>");
|
||||
} else {
|
||||
const TypeInterface *target_itype = _get_type_or_null(TypeReference(tag));
|
||||
|
||||
if (!target_itype) {
|
||||
target_itype = _get_type_or_null(TypeReference("_" + tag));
|
||||
}
|
||||
|
||||
if (target_itype) {
|
||||
xml_output.append("<see cref=\"" BINDINGS_NAMESPACE ".");
|
||||
xml_output.append(target_itype->proxy_name);
|
||||
xml_output.append("\"/>");
|
||||
} else {
|
||||
ERR_PRINTS("Cannot resolve type reference in documentation: " + tag);
|
||||
|
||||
xml_output.append("<c>");
|
||||
xml_output.append(tag);
|
||||
xml_output.append("</c>");
|
||||
}
|
||||
}
|
||||
|
||||
pos = brk_end + 1;
|
||||
} else if (tag == "b") {
|
||||
// bold is not supported in xml comments
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag == "i") {
|
||||
// italics is not supported in xml comments
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag == "code") {
|
||||
xml_output.append("<c>");
|
||||
|
||||
code_tag = true;
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag == "codeblock") {
|
||||
xml_output.append("<code>");
|
||||
|
||||
code_tag = true;
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag == "center") {
|
||||
// center is alignment not supported in xml comments
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag == "br") {
|
||||
xml_output.append("\n"); // FIXME: Should use <para> instead. Luckily this tag isn't used for now.
|
||||
pos = brk_end + 1;
|
||||
} else if (tag == "u") {
|
||||
// underline is not supported in xml comments
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag == "s") {
|
||||
// strikethrough is not supported in xml comments
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag == "url") {
|
||||
int end = bbcode.find("[", brk_end);
|
||||
if (end == -1)
|
||||
end = bbcode.length();
|
||||
String url = bbcode.substr(brk_end + 1, end - brk_end - 1);
|
||||
xml_output.append("<a href=\"");
|
||||
xml_output.append(url);
|
||||
xml_output.append("\">");
|
||||
xml_output.append(url);
|
||||
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag.begins_with("url=")) {
|
||||
String url = tag.substr(4, tag.length());
|
||||
xml_output.append("<a href=\"");
|
||||
xml_output.append(url);
|
||||
xml_output.append("\">");
|
||||
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front("url");
|
||||
} else if (tag == "img") {
|
||||
int end = bbcode.find("[", brk_end);
|
||||
if (end == -1)
|
||||
end = bbcode.length();
|
||||
String image = bbcode.substr(brk_end + 1, end - brk_end - 1);
|
||||
|
||||
// Not supported. Just append the bbcode.
|
||||
xml_output.append("[img]");
|
||||
xml_output.append(image);
|
||||
xml_output.append("[/img]");
|
||||
|
||||
pos = end;
|
||||
tag_stack.push_front(tag);
|
||||
} else if (tag.begins_with("color=")) {
|
||||
// Not supported.
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front("color");
|
||||
} else if (tag.begins_with("font=")) {
|
||||
// Not supported.
|
||||
pos = brk_end + 1;
|
||||
tag_stack.push_front("font");
|
||||
} else {
|
||||
xml_output.append("["); // ignore
|
||||
pos = brk_pos + 1;
|
||||
}
|
||||
}
|
||||
|
||||
xml_output.append("</para>");
|
||||
|
||||
return xml_output.as_string();
|
||||
}
|
||||
|
||||
int BindingsGenerator::_determine_enum_prefix(const EnumInterface &p_ienum) {
|
||||
|
||||
CRASH_COND(p_ienum.constants.empty());
|
||||
|
@ -299,6 +670,9 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
|||
|
||||
// Constants (in partial GD class)
|
||||
|
||||
p_output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
|
||||
"'Missing XML comment for publicly visible type or member'\n");
|
||||
|
||||
p_output.push_back("namespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
|
||||
p_output.push_back(INDENT1 "public static partial class " BINDINGS_GLOBAL_SCOPE_CLASS "\n" INDENT1 "{");
|
||||
|
||||
|
@ -306,20 +680,20 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
|||
const ConstantInterface &iconstant = E->get();
|
||||
|
||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
|
||||
Vector<String> summary_lines = xml_summary.split("\n");
|
||||
|
||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
||||
if (summary_lines.size()) {
|
||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
|
||||
for (int i = 0; i < description_lines.size(); i++) {
|
||||
String description_line = description_lines[i].strip_edges();
|
||||
if (description_line.size()) {
|
||||
for (int i = 0; i < summary_lines.size(); i++) {
|
||||
p_output.push_back(INDENT2 "/// ");
|
||||
p_output.push_back(description_line.xml_escape());
|
||||
p_output.push_back(summary_lines[i]);
|
||||
p_output.push_back("\n");
|
||||
}
|
||||
}
|
||||
|
||||
p_output.push_back(INDENT2 "/// </summary>");
|
||||
p_output.push_back(INDENT2 "/// </summary>");
|
||||
}
|
||||
}
|
||||
|
||||
p_output.push_back(MEMBER_BEGIN "public const int ");
|
||||
|
@ -369,20 +743,20 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
|||
const ConstantInterface &iconstant = F->get();
|
||||
|
||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||
p_output.push_back(INDENT2 "/// <summary>\n");
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), NULL);
|
||||
Vector<String> summary_lines = xml_summary.split("\n");
|
||||
|
||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
||||
if (summary_lines.size()) {
|
||||
p_output.push_back(INDENT2 "/// <summary>\n");
|
||||
|
||||
for (int i = 0; i < description_lines.size(); i++) {
|
||||
String description_line = description_lines[i].strip_edges();
|
||||
if (description_line.size()) {
|
||||
for (int i = 0; i < summary_lines.size(); i++) {
|
||||
p_output.push_back(INDENT2 "/// ");
|
||||
p_output.push_back(description_line.xml_escape());
|
||||
p_output.push_back(summary_lines[i]);
|
||||
p_output.push_back("\n");
|
||||
}
|
||||
}
|
||||
|
||||
p_output.push_back(INDENT2 "/// </summary>\n");
|
||||
p_output.push_back(INDENT2 "/// </summary>\n");
|
||||
}
|
||||
}
|
||||
|
||||
p_output.push_back(INDENT2);
|
||||
|
@ -399,6 +773,8 @@ void BindingsGenerator::_generate_global_constants(List<String> &p_output) {
|
|||
}
|
||||
|
||||
p_output.push_back(CLOSE_BLOCK); // end of namespace
|
||||
|
||||
p_output.push_back("\n#pragma warning restore CS1591\n");
|
||||
}
|
||||
|
||||
Error BindingsGenerator::generate_cs_core_project(const String &p_solution_dir, DotNetSolution &r_solution, bool p_verbose_output) {
|
||||
|
@ -712,28 +1088,31 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
output.push_back("using System;\n"); // IntPtr
|
||||
output.push_back("using System.Diagnostics;\n"); // DebuggerBrowsable
|
||||
|
||||
output.push_back("\n#pragma warning disable CS1591 // Disable warning: "
|
||||
"'Missing XML comment for publicly visible type or member'\n");
|
||||
output.push_back("\n"
|
||||
"#pragma warning disable CS1591 // Disable warning: "
|
||||
"'Missing XML comment for publicly visible type or member'\n"
|
||||
"#pragma warning disable CS1573 // Disable warning: "
|
||||
"'Parameter has no matching param tag in the XML comment'\n");
|
||||
|
||||
output.push_back("\nnamespace " BINDINGS_NAMESPACE "\n" OPEN_BLOCK);
|
||||
|
||||
const DocData::ClassDoc *class_doc = itype.class_doc;
|
||||
|
||||
if (class_doc && class_doc->description.size()) {
|
||||
output.push_back(INDENT1 "/// <summary>\n");
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(class_doc->description), &itype);
|
||||
Vector<String> summary_lines = xml_summary.split("\n");
|
||||
|
||||
Vector<String> description_lines = class_doc->description.split("\n");
|
||||
if (summary_lines.size()) {
|
||||
output.push_back(INDENT1 "/// <summary>\n");
|
||||
|
||||
for (int i = 0; i < description_lines.size(); i++) {
|
||||
String description_line = description_lines[i].strip_edges();
|
||||
if (description_line.size()) {
|
||||
for (int i = 0; i < summary_lines.size(); i++) {
|
||||
output.push_back(INDENT1 "/// ");
|
||||
output.push_back(description_line.xml_escape());
|
||||
output.push_back(summary_lines[i]);
|
||||
output.push_back("\n");
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(INDENT1 "/// </summary>\n");
|
||||
output.push_back(INDENT1 "/// </summary>\n");
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(INDENT1 "public ");
|
||||
|
@ -767,20 +1146,20 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
const ConstantInterface &iconstant = E->get();
|
||||
|
||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||
output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype);
|
||||
Vector<String> summary_lines = xml_summary.split("\n");
|
||||
|
||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
||||
if (summary_lines.size()) {
|
||||
output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
|
||||
for (int i = 0; i < description_lines.size(); i++) {
|
||||
String description_line = description_lines[i].strip_edges();
|
||||
if (description_line.size()) {
|
||||
for (int i = 0; i < summary_lines.size(); i++) {
|
||||
output.push_back(INDENT2 "/// ");
|
||||
output.push_back(description_line.xml_escape());
|
||||
output.push_back(summary_lines[i]);
|
||||
output.push_back("\n");
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(INDENT2 "/// </summary>");
|
||||
output.push_back(INDENT2 "/// </summary>");
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(MEMBER_BEGIN "public const int ");
|
||||
|
@ -808,20 +1187,20 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
const ConstantInterface &iconstant = F->get();
|
||||
|
||||
if (iconstant.const_doc && iconstant.const_doc->description.size()) {
|
||||
output.push_back(INDENT3 "/// <summary>\n");
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(iconstant.const_doc->description), &itype);
|
||||
Vector<String> summary_lines = xml_summary.split("\n");
|
||||
|
||||
Vector<String> description_lines = iconstant.const_doc->description.split("\n");
|
||||
if (summary_lines.size()) {
|
||||
output.push_back(INDENT3 "/// <summary>\n");
|
||||
|
||||
for (int i = 0; i < description_lines.size(); i++) {
|
||||
String description_line = description_lines[i].strip_edges();
|
||||
if (description_line.size()) {
|
||||
for (int i = 0; i < summary_lines.size(); i++) {
|
||||
output.push_back(INDENT3 "/// ");
|
||||
output.push_back(description_line.xml_escape());
|
||||
output.push_back(summary_lines[i]);
|
||||
output.push_back("\n");
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(INDENT3 "/// </summary>\n");
|
||||
output.push_back(INDENT3 "/// </summary>\n");
|
||||
}
|
||||
}
|
||||
|
||||
output.push_back(INDENT3);
|
||||
|
@ -928,7 +1307,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
|
|||
output.push_back(INDENT1 CLOSE_BLOCK /* class */
|
||||
CLOSE_BLOCK /* namespace */);
|
||||
|
||||
output.push_back("\n#pragma warning restore CS1591\n");
|
||||
output.push_back("\n"
|
||||
"#pragma warning restore CS1591\n"
|
||||
"#pragma warning restore CS1573\n");
|
||||
|
||||
return _save_file(p_output_file, output);
|
||||
}
|
||||
|
@ -978,33 +1359,21 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
|
|||
const TypeInterface *prop_itype = _get_type_or_null(proptype_name);
|
||||
ERR_FAIL_NULL_V(prop_itype, ERR_BUG); // Property type not found
|
||||
|
||||
String prop_proxy_name = escape_csharp_keyword(snake_to_pascal_case(p_iprop.cname));
|
||||
|
||||
// Prevent property and enclosing type from sharing the same name
|
||||
if (prop_proxy_name == p_itype.proxy_name) {
|
||||
if (verbose_output) {
|
||||
WARN_PRINTS("Name of property `" + prop_proxy_name + "` is ambiguous with the name of its class `" +
|
||||
p_itype.proxy_name + "`. Renaming property to `" + prop_proxy_name + "_`");
|
||||
}
|
||||
|
||||
prop_proxy_name += "_";
|
||||
}
|
||||
|
||||
if (p_iprop.prop_doc && p_iprop.prop_doc->description.size()) {
|
||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(p_iprop.prop_doc->description), &p_itype);
|
||||
Vector<String> summary_lines = xml_summary.split("\n");
|
||||
|
||||
Vector<String> description_lines = p_iprop.prop_doc->description.split("\n");
|
||||
if (summary_lines.size()) {
|
||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
|
||||
for (int i = 0; i < description_lines.size(); i++) {
|
||||
String description_line = description_lines[i].strip_edges();
|
||||
if (description_line.size()) {
|
||||
for (int i = 0; i < summary_lines.size(); i++) {
|
||||
p_output.push_back(INDENT2 "/// ");
|
||||
p_output.push_back(description_line.xml_escape());
|
||||
p_output.push_back(summary_lines[i]);
|
||||
p_output.push_back("\n");
|
||||
}
|
||||
}
|
||||
|
||||
p_output.push_back(INDENT2 "/// </summary>");
|
||||
p_output.push_back(INDENT2 "/// </summary>");
|
||||
}
|
||||
}
|
||||
|
||||
p_output.push_back(MEMBER_BEGIN "public ");
|
||||
|
@ -1014,7 +1383,7 @@ Error BindingsGenerator::_generate_cs_property(const BindingsGenerator::TypeInte
|
|||
|
||||
p_output.push_back(prop_itype->cs_type);
|
||||
p_output.push_back(" ");
|
||||
p_output.push_back(prop_proxy_name.replace("/", "__"));
|
||||
p_output.push_back(p_iprop.proxy_name);
|
||||
p_output.push_back("\n" INDENT2 OPEN_BLOCK);
|
||||
|
||||
if (getter) {
|
||||
|
@ -1135,7 +1504,10 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
|||
|
||||
icall_params += arg_type->cs_in.empty() ? arg_in : sformat(arg_type->cs_in, arg_in);
|
||||
|
||||
default_args_doc.push_back(INDENT2 "/// <param name=\"" + iarg.name + "\">If the param is null, then the default value is " + def_arg + "</param>\n");
|
||||
// Apparently the name attribute must not include the @
|
||||
String param_tag_name = iarg.name.begins_with("@") ? iarg.name.substr(1, iarg.name.length()) : iarg.name;
|
||||
|
||||
default_args_doc.push_back(INDENT2 "/// <param name=\"" + param_tag_name + "\">If the parameter is null, then the default value is " + def_arg + "</param>\n");
|
||||
} else {
|
||||
icall_params += arg_type->cs_in.empty() ? iarg.name : sformat(arg_type->cs_in, iarg.name);
|
||||
}
|
||||
|
@ -1151,24 +1523,24 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
|||
}
|
||||
|
||||
if (p_imethod.method_doc && p_imethod.method_doc->description.size()) {
|
||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
String xml_summary = bbcode_to_xml(fix_doc_description(p_imethod.method_doc->description), &p_itype);
|
||||
Vector<String> summary_lines = xml_summary.split("\n");
|
||||
|
||||
Vector<String> description_lines = p_imethod.method_doc->description.split("\n");
|
||||
if (summary_lines.size() || default_args_doc.size()) {
|
||||
p_output.push_back(MEMBER_BEGIN "/// <summary>\n");
|
||||
|
||||
for (int i = 0; i < description_lines.size(); i++) {
|
||||
String description_line = description_lines[i].strip_edges();
|
||||
if (description_line.size()) {
|
||||
for (int i = 0; i < summary_lines.size(); i++) {
|
||||
p_output.push_back(INDENT2 "/// ");
|
||||
p_output.push_back(description_line.xml_escape());
|
||||
p_output.push_back(summary_lines[i]);
|
||||
p_output.push_back("\n");
|
||||
}
|
||||
}
|
||||
|
||||
for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
|
||||
p_output.push_back(E->get().xml_escape());
|
||||
}
|
||||
for (List<String>::Element *E = default_args_doc.front(); E; E = E->next()) {
|
||||
p_output.push_back(E->get());
|
||||
}
|
||||
|
||||
p_output.push_back(INDENT2 "/// </summary>");
|
||||
p_output.push_back(INDENT2 "/// </summary>");
|
||||
}
|
||||
}
|
||||
|
||||
if (!p_imethod.is_internal) {
|
||||
|
@ -1728,7 +2100,6 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||
|
||||
PropertyInterface iprop;
|
||||
iprop.cname = property.name;
|
||||
iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
|
||||
iprop.setter = ClassDB::get_property_setter(type_cname, iprop.cname);
|
||||
iprop.getter = ClassDB::get_property_getter(type_cname, iprop.cname);
|
||||
|
||||
|
@ -1736,6 +2107,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||
iprop.index = ClassDB::get_property_index(type_cname, iprop.cname, &valid);
|
||||
ERR_FAIL_COND(!valid);
|
||||
|
||||
iprop.proxy_name = escape_csharp_keyword(snake_to_pascal_case(iprop.cname));
|
||||
|
||||
// Prevent property and enclosing type from sharing the same name
|
||||
if (iprop.proxy_name == itype.proxy_name) {
|
||||
if (verbose_output) {
|
||||
|
@ -1746,6 +2119,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
|
|||
iprop.proxy_name += "_";
|
||||
}
|
||||
|
||||
iprop.proxy_name = iprop.proxy_name.replace("/", "__"); // Some members have a slash...
|
||||
|
||||
iprop.prop_doc = NULL;
|
||||
|
||||
for (int i = 0; i < itype.class_doc->properties.size(); i++) {
|
||||
|
|
|
@ -87,8 +87,13 @@ class BindingsGenerator {
|
|||
StringName cname;
|
||||
bool is_enum;
|
||||
|
||||
TypeReference() {
|
||||
is_enum = false;
|
||||
TypeReference() :
|
||||
is_enum(false) {
|
||||
}
|
||||
|
||||
TypeReference(const StringName &p_cname) :
|
||||
cname(p_cname),
|
||||
is_enum(false) {
|
||||
}
|
||||
};
|
||||
|
||||
|
@ -321,6 +326,15 @@ class BindingsGenerator {
|
|||
return NULL;
|
||||
}
|
||||
|
||||
const PropertyInterface *find_property_by_name(const StringName &p_cname) const {
|
||||
for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
|
||||
if (E->get().cname == p_cname)
|
||||
return &E->get();
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
const PropertyInterface *find_property_by_proxy_name(const String &p_proxy_name) const {
|
||||
for (const List<PropertyInterface>::Element *E = properties.front(); E; E = E->next()) {
|
||||
if (E->get().proxy_name == p_proxy_name)
|
||||
|
@ -482,6 +496,7 @@ class BindingsGenerator {
|
|||
StringName type_VarArg;
|
||||
StringName type_Object;
|
||||
StringName type_Reference;
|
||||
StringName type_String;
|
||||
StringName enum_Error;
|
||||
|
||||
NameCache() {
|
||||
|
@ -493,6 +508,7 @@ class BindingsGenerator {
|
|||
type_VarArg = StaticCString::create("VarArg");
|
||||
type_Object = StaticCString::create("Object");
|
||||
type_Reference = StaticCString::create("Reference");
|
||||
type_String = StaticCString::create("String");
|
||||
enum_Error = StaticCString::create("Error");
|
||||
}
|
||||
|
||||
|
@ -522,6 +538,8 @@ class BindingsGenerator {
|
|||
return p_type.name;
|
||||
}
|
||||
|
||||
String bbcode_to_xml(const String &p_bbcode, const TypeInterface *p_itype);
|
||||
|
||||
int _determine_enum_prefix(const EnumInterface &p_ienum);
|
||||
void _apply_prefix_to_enum_constants(EnumInterface &p_ienum, int p_prefix_length);
|
||||
|
||||
|
|
Loading…
Reference in a new issue