Browse Source

Merge pull request #52077 from reduz/error-ret-doc

Implement error return documentation
Juan Linietsky 4 years ago
parent
commit
34e286d6a3

+ 1 - 0
core/doc_data.h

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

+ 2 - 0
core/io/config_file.cpp

@@ -315,6 +315,8 @@ void ConfigFile::_bind_methods() {
 	ClassDB::bind_method(D_METHOD("parse", "data"), &ConfigFile::parse);
 	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_pass", "path", "password"), &ConfigFile::load_encrypted_pass);
 

+ 26 - 0
core/object/class_db.cpp

@@ -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) {
 	OBJTYPE_RLOCK;
 

+ 28 - 0
core/object/class_db.h

@@ -132,6 +132,7 @@ public:
 		List<MethodInfo> virtual_methods;
 		Map<StringName, MethodInfo> virtual_methods_map;
 		StringName category;
+		Map<StringName, Vector<Error>> method_error_values;
 #endif
 		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 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 StringName get_category(const StringName &p_node);
@@ -415,6 +418,29 @@ public:
 #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);
 
+_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
 
 #define BIND_CONSTANT(m_constant) \
@@ -423,6 +449,8 @@ public:
 #define BIND_ENUM_CONSTANT(m_constant) \
 	::ClassDB::bind_integer_constant(get_class_static(), StringName(), #m_constant, m_constant);
 
+#define BIND_METHOD_ERR_RETURN_DOC(m_method, ...)
+
 #endif
 
 #define GDREGISTER_CLASS(m_class)                    \

+ 2 - 0
doc/classes/ConfigFile.xml

@@ -149,6 +149,8 @@
 		</method>
 		<method name="load">
 			<return type="int" enum="Error" />
+			<returns_error number="0"/>
+			<returns_error number="12"/>
 			<argument index="0" name="path" type="String" />
 			<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.

+ 20 - 0
editor/doc_tools.cpp

@@ -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);
 		}
 
@@ -874,6 +886,9 @@ static Error _parse_methods(Ref<XMLParser> &parser, Vector<DocData::MethodDoc> &
 							if (parser->has_attribute("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") {
 							DocData::ArgumentDoc argument;
 							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 + " />");
 			}
+			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++) {
 				const DocData::ArgumentDoc &a = m.arguments[j];

+ 27 - 1
editor/editor_help.cpp

@@ -30,6 +30,7 @@
 
 #include "editor_help.h"
 
+#include "core/core_constants.h"
 #include "core/input/input.h"
 #include "core/os/keyboard.h"
 #include "doc_data_compressed.gen.h"
@@ -695,7 +696,7 @@ void EditorHelp::_update_doc() {
 					class_desc->pop(); //cell
 				}
 
-				if (m[i].description != "") {
+				if (m[i].description != "" || m[i].errors_returned.size() > 0) {
 					method_descr = true;
 				}
 
@@ -1227,6 +1228,31 @@ void EditorHelp::_update_doc() {
 				class_desc->push_color(text_color);
 				class_desc->push_font(doc_font);
 				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()) {
 					_add_text(DTR(methods_filtered[i].description));
 				} else {