Implement error return documetation

Adds ability to add error return documetation to the binder and class reference.
Usage example:

```C++
void MyClass::_bind_method() {
	[..]
	BIND_METHOD_ERR_RETURN_DOC("load", ERR_FILE_CANT_OPEN, ERR_FILE_UNRECOGNIZED);
}
```

One function of ConfigFile was changed as example.
This commit is contained in:
reduz 2021-08-24 15:16:25 -03:00
parent ca7f53dd25
commit 96f8254b24
7 changed files with 106 additions and 1 deletions

View File

@ -67,6 +67,7 @@ public:
String qualifiers; String qualifiers;
String description; String description;
Vector<ArgumentDoc> arguments; Vector<ArgumentDoc> arguments;
Vector<int> errors_returned;
bool operator<(const MethodDoc &p_method) const { bool operator<(const MethodDoc &p_method) const {
if (name == p_method.name) { if (name == p_method.name) {
// Must be a constructor since there is no overloading. // Must be a constructor since there is no overloading.

View File

@ -315,6 +315,8 @@ void ConfigFile::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse); ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save); ClassDB::bind_method(D_METHOD("save", "path"), &ConfigFile::save);
BIND_METHOD_ERR_RETURN_DOC("load", ERR_FILE_CANT_OPEN);
ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted); ClassDB::bind_method(D_METHOD("load_encrypted", "path", "key"), &ConfigFile::load_encrypted);
ClassDB::bind_method(D_METHOD("load_encrypted_pass", "path", "password"), &ConfigFile::load_encrypted_pass); ClassDB::bind_method(D_METHOD("load_encrypted_pass", "path", "password"), &ConfigFile::load_encrypted_pass);

View File

@ -892,6 +892,32 @@ void ClassDB::get_enum_constants(const StringName &p_class, const StringName &p_
} }
} }
void ClassDB::set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values) {
OBJTYPE_RLOCK;
#ifdef DEBUG_METHODS_ENABLED
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_COND(!type);
type->method_error_values[p_method] = p_values;
#endif
}
Vector<Error> ClassDB::get_method_error_return_values(const StringName &p_class, const StringName &p_method) {
#ifdef DEBUG_METHODS_ENABLED
ClassInfo *type = classes.getptr(p_class);
ERR_FAIL_COND_V(!type, Vector<Error>());
if (!type->method_error_values.has(p_method)) {
return Vector<Error>();
}
return type->method_error_values[p_method];
#else
return Vector<Error>();
#endif
}
bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) { bool ClassDB::has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance) {
OBJTYPE_RLOCK; OBJTYPE_RLOCK;

View File

@ -132,6 +132,7 @@ public:
List<MethodInfo> virtual_methods; List<MethodInfo> virtual_methods;
Map<StringName, MethodInfo> virtual_methods_map; Map<StringName, MethodInfo> virtual_methods_map;
StringName category; StringName category;
Map<StringName, Vector<Error>> method_error_values;
#endif #endif
HashMap<StringName, PropertySetGet> property_setget; HashMap<StringName, PropertySetGet> property_setget;
@ -385,6 +386,8 @@ public:
static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false); static void get_enum_constants(const StringName &p_class, const StringName &p_enum, List<StringName> *p_constants, bool p_no_inheritance = false);
static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false); static bool has_enum(const StringName &p_class, const StringName &p_name, bool p_no_inheritance = false);
static void set_method_error_return_values(const StringName &p_class, const StringName &p_method, const Vector<Error> &p_values);
static Vector<Error> get_method_error_return_values(const StringName &p_class, const StringName &p_method);
static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr); static Variant class_get_default_property_value(const StringName &p_class, const StringName &p_property, bool *r_valid = nullptr);
static StringName get_category(const StringName &p_node); static StringName get_category(const StringName &p_node);
@ -415,6 +418,29 @@ public:
#define BIND_ENUM_CONSTANT(m_constant) \ #define BIND_ENUM_CONSTANT(m_constant) \
::ClassDB::bind_integer_constant(get_class_static(), __constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant); ::ClassDB::bind_integer_constant(get_class_static(), __constant_get_enum_name(m_constant, #m_constant), #m_constant, m_constant);
_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr) {
}
_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr, const Error &p_err) {
arr.push_back(p_err);
}
template <class... P>
_FORCE_INLINE_ void errarray_add_str(Vector<Error> &arr, const Error &p_err, P... p_args) {
arr.push_back(p_err);
errarray_add_str(arr, p_args...);
}
template <class... P>
_FORCE_INLINE_ Vector<Error> errarray(P... p_args) {
Vector<Error> arr;
errarray_add_str(arr, p_args...);
return arr;
}
#define BIND_METHOD_ERR_RETURN_DOC(m_method, ...) \
::ClassDB::set_method_error_return_values(get_class_static(), m_method, errarray(__VA_ARGS__));
#else #else
#define BIND_CONSTANT(m_constant) \ #define BIND_CONSTANT(m_constant) \
@ -423,6 +449,8 @@ public:
#define BIND_ENUM_CONSTANT(m_constant) \ #define BIND_ENUM_CONSTANT(m_constant) \
::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant); ::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
#define BIND_METHOD_ERR_RETURN_DOC(m_method, ...)
#endif #endif
#define GDREGISTER_CLASS(m_class) \ #define GDREGISTER_CLASS(m_class) \

View File

@ -149,6 +149,8 @@
</method> </method>
<method name="load"> <method name="load">
<return type="int" enum="Error" /> <return type="int" enum="Error" />
<returns_error number="0"/>
<returns_error number="12"/>
<argument index="0" name="path" type="String" /> <argument index="0" name="path" type="String" />
<description> <description>
Loads the config file specified as a parameter. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on. Loads the config file specified as a parameter. The file's contents are parsed and loaded in the [ConfigFile] object which the method was called on.

View File

@ -434,6 +434,18 @@ void DocTools::generate(bool p_basic_types) {
} }
} }
Vector<Error> errs = ClassDB::get_method_error_return_values(name, E.name);
if (errs.size()) {
if (errs.find(OK) == -1) {
errs.insert(0, OK);
}
for (int i = 0; i < errs.size(); i++) {
if (method.errors_returned.find(errs[i]) == -1) {
method.errors_returned.push_back(errs[i]);
}
}
}
c.methods.push_back(method); c.methods.push_back(method);
} }
@ -874,6 +886,9 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
if (parser->has_attribute("enum")) { if (parser->has_attribute("enum")) {
method.return_enum = parser->get_attribute_value("enum"); method.return_enum = parser->get_attribute_value("enum");
} }
} else if (name == "returns_error") {
ERR_FAIL_COND_V(!parser->has_attribute("number"), ERR_FILE_CORRUPT);
method.errors_returned.push_back(parser->get_attribute_value("number").to_int());
} else if (name == "argument") { } else if (name == "argument") {
DocData::ArgumentDoc argument; DocData::ArgumentDoc argument;
ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT); ERR_FAIL_COND_V(!parser->has_attribute("name"), ERR_FILE_CORRUPT);
@ -1222,6 +1237,11 @@ Error DocTools::save_classes(const String &p_default_path, const Map<String, Str
} }
_write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + " />"); _write_string(f, 3, "<return type=\"" + m.return_type + "\"" + enum_text + " />");
} }
if (m.errors_returned.size() > 0) {
for (int j = 0; j < m.errors_returned.size(); j++) {
_write_string(f, 3, "<returns_error number=\"" + itos(m.errors_returned[j]) + "\"/>");
}
}
for (int j = 0; j < m.arguments.size(); j++) { for (int j = 0; j < m.arguments.size(); j++) {
const DocData::ArgumentDoc &a = m.arguments[j]; const DocData::ArgumentDoc &a = m.arguments[j];

View File

@ -30,6 +30,7 @@
#include "editor_help.h" #include "editor_help.h"
#include "core/core_constants.h"
#include "core/input/input.h" #include "core/input/input.h"
#include "core/os/keyboard.h" #include "core/os/keyboard.h"
#include "doc_data_compressed.gen.h" #include "doc_data_compressed.gen.h"
@ -695,7 +696,7 @@ void EditorHelp::_update_doc() {
class_desc->pop(); //cell class_desc->pop(); //cell
} }
if (m[i].description != "") { if (m[i].description != "" || m[i].errors_returned.size() > 0) {
method_descr = true; method_descr = true;
} }
@ -1227,6 +1228,31 @@ void EditorHelp::_update_doc() {
class_desc->push_color(text_color); class_desc->push_color(text_color);
class_desc->push_font(doc_font); class_desc->push_font(doc_font);
class_desc->push_indent(1); class_desc->push_indent(1);
if (methods_filtered[i].errors_returned.size()) {
class_desc->append_bbcode(TTR("Error codes returned:"));
class_desc->add_newline();
class_desc->push_list(0, RichTextLabel::LIST_DOTS, false);
for (int j = 0; j < methods_filtered[i].errors_returned.size(); j++) {
if (j > 0) {
class_desc->add_newline();
}
int val = methods_filtered[i].errors_returned[j];
String text = itos(val);
for (int k = 0; k < CoreConstants::get_global_constant_count(); k++) {
if (CoreConstants::get_global_constant_value(k) == val && CoreConstants::get_global_constant_enum(k) == SNAME("Error")) {
text = CoreConstants::get_global_constant_name(k);
break;
}
}
class_desc->push_bold();
class_desc->append_bbcode(text);
class_desc->pop();
}
class_desc->pop();
class_desc->add_newline();
class_desc->add_newline();
}
if (!methods_filtered[i].description.strip_edges().is_empty()) { if (!methods_filtered[i].description.strip_edges().is_empty()) {
_add_text(DTR(methods_filtered[i].description)); _add_text(DTR(methods_filtered[i].description));
} else { } else {