Browse Source

Merge pull request #31221 from neikeq/err-explain-to-msg-mono

Replace 'ERR_EXPLAIN' with 'ERR_FAIL_*_MSG' in 'modules/mono'
Rémi Verschelde 6 years ago
parent
commit
3ea33c0e45

+ 42 - 70
modules/mono/csharp_script.cpp

@@ -115,7 +115,7 @@ void CSharpLanguage::init() {
 	gdmono->initialize();
 
 #if defined(TOOLS_ENABLED) && defined(DEBUG_METHODS_ENABLED)
-	// Generate bindings here, before loading assemblies. `initialize_load_assemblies` aborts
+	// Generate bindings here, before loading assemblies. 'initialize_load_assemblies' aborts
 	// the applications if the api assemblies or the main tools assembly is missing, but this
 	// is not a problem for BindingsGenerator as it only needs the tools project editor assembly.
 	List<String> cmdline_args = OS::get_singleton()->get_cmdline_args();
@@ -123,7 +123,7 @@ void CSharpLanguage::init() {
 #endif
 
 #ifndef MONO_GLUE_ENABLED
-	print_line("Run this binary with `--generate-mono-glue path/to/modules/mono/glue`");
+	print_line("Run this binary with '--generate-mono-glue path/to/modules/mono/glue'");
 #endif
 
 	gdmono->initialize_load_assemblies();
@@ -1036,6 +1036,7 @@ void CSharpLanguage::_load_scripts_metadata() {
 		String old_json;
 
 		Error ferr = read_all_file_utf8(scripts_metadata_path, old_json);
+
 		ERR_FAIL_COND(ferr != OK);
 
 		Variant old_dict_var;
@@ -1043,7 +1044,7 @@ void CSharpLanguage::_load_scripts_metadata() {
 		int err_line;
 		Error json_err = JSON::parse(old_json, old_dict_var, err_str, err_line);
 		if (json_err != OK) {
-			ERR_PRINTS("Failed to parse metadata file: '" + err_str + "' (" + String::num_int64(err_line) + ")");
+			ERR_PRINTS("Failed to parse metadata file: '" + err_str + "' (" + String::num_int64(err_line) + ").");
 			return;
 		}
 
@@ -1053,7 +1054,7 @@ void CSharpLanguage::_load_scripts_metadata() {
 		print_verbose("Successfully loaded scripts metadata");
 	} else {
 		if (!Engine::get_singleton()->is_editor_hint()) {
-			ERR_PRINT("Missing scripts metadata file");
+			ERR_PRINT("Missing scripts metadata file.");
 		}
 	}
 }
@@ -1768,12 +1769,8 @@ MonoObject *CSharpInstance::_internal_new_managed() {
 
 	// Search the constructor first, to fail with an error if it's not found before allocating anything else.
 	GDMonoMethod *ctor = script->script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
-	if (ctor == NULL) {
-		ERR_PRINTS("Cannot create script instance because the class does not define a parameterless constructor: " + script->get_path());
-
-		ERR_EXPLAIN("Constructor not found");
-		ERR_FAIL_V(NULL);
-	}
+	ERR_FAIL_NULL_V_MSG(ctor, NULL,
+			"Cannot create script instance because the class does not define a parameterless constructor: '" + script->get_path() + "'.");
 
 	CSharpLanguage::get_singleton()->release_script_gchandle(gchandle);
 
@@ -1792,8 +1789,7 @@ MonoObject *CSharpInstance::_internal_new_managed() {
 
 		owner = NULL;
 
-		ERR_EXPLAIN("Failed to allocate memory for the object");
-		ERR_FAIL_V(NULL);
+		ERR_FAIL_V_MSG(NULL, "Failed to allocate memory for the object.");
 	}
 
 	// Tie managed to unmanaged
@@ -2233,7 +2229,7 @@ bool CSharpScript::_update_exports() {
 		MonoObject *tmp_object = mono_object_new(mono_domain_get(), script_class->get_mono_ptr());
 
 		if (!tmp_object) {
-			ERR_PRINT("Failed to allocate temporary MonoObject");
+			ERR_PRINT("Failed to allocate temporary MonoObject.");
 			return false;
 		}
 
@@ -2241,12 +2237,8 @@ bool CSharpScript::_update_exports() {
 
 		GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), 0);
 
-		if (ctor == NULL) {
-			ERR_PRINTS("Cannot construct temporary MonoObject because the class does not define a parameterless constructor: " + get_path());
-
-			ERR_EXPLAIN("Constructor not found");
-			ERR_FAIL_V(NULL);
-		}
+		ERR_FAIL_NULL_V_MSG(ctor, NULL,
+				"Cannot construct temporary MonoObject because the class does not define a parameterless constructor: '" + get_path() + "'.");
 
 		MonoException *ctor_exc = NULL;
 		ctor->invoke(tmp_object, NULL, &ctor_exc);
@@ -2399,7 +2391,7 @@ bool CSharpScript::_get_signal(GDMonoClass *p_class, GDMonoClass *p_delegate, Ve
 					arg.type = GDMonoMarshal::managed_to_variant_type(types[i]);
 
 					if (arg.type == Variant::NIL) {
-						ERR_PRINTS("Unknown type of signal parameter: " + arg.name + " in " + p_class->get_full_name());
+						ERR_PRINTS("Unknown type of signal parameter: '" + arg.name + "' in '" + p_class->get_full_name() + "'.");
 						return false;
 					}
 
@@ -2427,7 +2419,7 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
 
 	if (p_member->is_static()) {
 		if (p_member->has_attribute(CACHED_CLASS(ExportAttribute)))
-			ERR_PRINTS("Cannot export member because it is static: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
+			ERR_PRINTS("Cannot export member because it is static: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
 		return false;
 	}
 
@@ -2450,12 +2442,12 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
 		GDMonoProperty *property = static_cast<GDMonoProperty *>(p_member);
 		if (!property->has_getter()) {
 			if (exported)
-				ERR_PRINTS("Read-only property cannot be exported: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
+				ERR_PRINTS("Read-only property cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
 			return false;
 		}
 		if (!property->has_setter()) {
 			if (exported)
-				ERR_PRINTS("Write-only property (without getter) cannot be exported: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
+				ERR_PRINTS("Write-only property (without getter) cannot be exported: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
 			return false;
 		}
 	}
@@ -2474,16 +2466,15 @@ bool CSharpScript::_get_member_export(IMonoClassMember *p_member, bool p_inspect
 	String hint_string;
 
 	if (variant_type == Variant::NIL) {
-		ERR_PRINTS("Unknown exported member type: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
+		ERR_PRINTS("Unknown exported member type: '" + MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
 		return false;
 	}
 
 	int hint_res = _try_get_member_export_hint(p_member, type, variant_type, /* allow_generics: */ true, hint, hint_string);
 
-	if (hint_res == -1) {
-		ERR_EXPLAIN("Error while trying to determine information about the exported member: " + MEMBER_FULL_QUALIFIED_NAME(p_member));
-		ERR_FAIL_V(false);
-	}
+	ERR_FAIL_COND_V_MSG(hint_res == -1, false,
+			"Error while trying to determine information about the exported member: '" +
+					MEMBER_FULL_QUALIFIED_NAME(p_member) + "'.");
 
 	if (hint_res == 0) {
 		hint = PropertyHint(CACHED_FIELD(ExportAttribute, hint)->get_int_value(attr));
@@ -2532,17 +2523,11 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
 
 			MonoObject *val_obj = mono_field_get_value_object(mono_domain_get(), field, NULL);
 
-			if (val_obj == NULL) {
-				ERR_EXPLAIN("Failed to get '" + enum_field_name + "' constant enum value");
-				ERR_FAIL_V(-1);
-			}
+			ERR_FAIL_NULL_V_MSG(val_obj, -1, "Failed to get '" + enum_field_name + "' constant enum value.");
 
 			bool r_error;
 			uint64_t val = GDMonoUtils::unbox_enum_value(val_obj, enum_basetype, r_error);
-			if (r_error) {
-				ERR_EXPLAIN("Failed to unbox '" + enum_field_name + "' constant enum value");
-				ERR_FAIL_V(-1);
-			}
+			ERR_FAIL_COND_V_MSG(r_error, -1, "Failed to unbox '" + enum_field_name + "' constant enum value.");
 
 			if (val != (unsigned int)i) {
 				uses_default_values = false;
@@ -2577,17 +2562,11 @@ int CSharpScript::_try_get_member_export_hint(IMonoClassMember *p_member, Manage
 		PropertyHint elem_hint = PROPERTY_HINT_NONE;
 		String elem_hint_string;
 
-		if (elem_variant_type == Variant::NIL) {
-			ERR_EXPLAIN("Unknown array element type");
-			ERR_FAIL_V(-1);
-		}
+		ERR_FAIL_COND_V_MSG(elem_variant_type == Variant::NIL, -1, "Unknown array element type.");
 
 		int hint_res = _try_get_member_export_hint(p_member, elem_type, elem_variant_type, /* allow_generics: */ false, elem_hint, elem_hint_string);
 
-		if (hint_res == -1) {
-			ERR_EXPLAIN("Error while trying to determine information about the array element type");
-			ERR_FAIL_V(-1);
-		}
+		ERR_FAIL_COND_V_MSG(hint_res == -1, -1, "Error while trying to determine information about the array element type.");
 
 		// Format: type/hint:hint_string
 		r_hint_string = itos(elem_variant_type) + "/" + itos(elem_hint) + ":" + elem_hint_string;
@@ -2775,7 +2754,7 @@ bool CSharpScript::can_instance() const {
 						"Compile",
 						ProjectSettings::get_singleton()->globalize_path(get_path()));
 			} else {
-				ERR_PRINTS("Cannot add " + get_path() + " to the C# project because it could not be created.");
+				ERR_PRINTS("C# project could not be created; cannot add file: '" + get_path() + "'.");
 			}
 		}
 	}
@@ -2793,12 +2772,10 @@ bool CSharpScript::can_instance() const {
 	if (extra_cond && !script_class) {
 		if (GDMono::get_singleton()->get_project_assembly() == NULL) {
 			// The project assembly is not loaded
-			ERR_EXPLAIN("Cannot instance script because the project assembly is not loaded. Script: " + get_path());
-			ERR_FAIL_V(NULL);
+			ERR_FAIL_V_MSG(NULL, "Cannot instance script because the project assembly is not loaded. Script: '" + get_path() + "'.");
 		} else {
 			// The project assembly is loaded, but the class could not found
-			ERR_EXPLAIN("Cannot instance script because the class '" + name + "' could not be found. Script: " + get_path());
-			ERR_FAIL_V(NULL);
+			ERR_FAIL_V_MSG(NULL, "Cannot instance script because the class '" + name + "' could not be found. Script: '" + get_path() + "'.");
 		}
 	}
 
@@ -2820,14 +2797,12 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
 	// Search the constructor first, to fail with an error if it's not found before allocating anything else.
 	GDMonoMethod *ctor = script_class->get_method(CACHED_STRING_NAME(dotctor), p_argcount);
 	if (ctor == NULL) {
-		if (p_argcount == 0) {
-			String path = get_path();
-			ERR_PRINTS("Cannot create script instance. The class '" + script_class->get_full_name() +
-					   "' does not define a parameterless constructor." + (path.empty() ? String() : ". Path: " + path));
-		}
+		ERR_FAIL_COND_V_MSG(p_argcount == 0, NULL,
+				"Cannot create script instance. The class '" + script_class->get_full_name() +
+						"' does not define a parameterless constructor." +
+						(get_path().empty() ? String() : " Path: '" + get_path() + "'."));
 
-		ERR_EXPLAIN("Constructor not found");
-		ERR_FAIL_V(NULL);
+		ERR_FAIL_V_MSG(NULL, "Constructor not found.");
 	}
 
 	Ref<Reference> ref;
@@ -2878,8 +2853,7 @@ CSharpInstance *CSharpScript::_create_instance(const Variant **p_args, int p_arg
 
 		p_owner->set_script_instance(NULL);
 		r_error.error = Variant::CallError::CALL_ERROR_INSTANCE_IS_NULL;
-		ERR_EXPLAIN("Failed to allocate memory for the object");
-		ERR_FAIL_V(NULL);
+		ERR_FAIL_V_MSG(NULL, "Failed to allocate memory for the object.");
 	}
 
 	// Tie managed to unmanaged
@@ -2950,8 +2924,8 @@ ScriptInstance *CSharpScript::instance_create(Object *p_this) {
 			if (ScriptDebugger::get_singleton()) {
 				CSharpLanguage::get_singleton()->debug_break_parse(get_path(), 0, "Script inherits from native type '" + native_name + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
 			}
-			ERR_EXPLAIN("Script inherits from native type '" + native_name + "', so it can't be instanced in object of type: '" + p_this->get_class() + "'");
-			ERR_FAIL_V(NULL);
+			ERR_FAIL_V_MSG(NULL, "Script inherits from native type '" + native_name +
+										 "', so it can't be instanced in object of type: '" + p_this->get_class() + "'.");
 		}
 	}
 
@@ -3203,12 +3177,12 @@ int CSharpScript::get_member_line(const StringName &p_member) const {
 Error CSharpScript::load_source_code(const String &p_path) {
 
 	Error ferr = read_all_file_utf8(p_path, source);
-	if (ferr != OK) {
-		if (ferr == ERR_INVALID_DATA) {
-			ERR_EXPLAIN("Script '" + p_path + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
-		}
-		ERR_FAIL_V(ferr);
-	}
+
+	ERR_FAIL_COND_V_MSG(ferr != OK, ferr,
+			ferr == ERR_INVALID_DATA ?
+					"Script '" + p_path + "' contains invalid unicode (UTF-8), so it was not loaded."
+										  " Please ensure that scripts are saved in valid UTF-8 unicode." :
+					"Failed to read file: '" + p_path + "'.");
 
 #ifdef TOOLS_ENABLED
 	source_changed_cache = true;
@@ -3277,8 +3251,7 @@ RES ResourceFormatLoaderCSharpScript::load(const String &p_path, const String &p
 
 #ifdef DEBUG_ENABLED
 	// User is responsible for thread attach/detach
-	ERR_EXPLAIN("Thread is not attached");
-	CRASH_COND(mono_domain_get() == NULL);
+	CRASH_COND_MSG(mono_domain_get() == NULL, "Thread is not attached.");
 #endif
 
 #endif
@@ -3345,8 +3318,7 @@ Error ResourceFormatSaverCSharpScript::save(const String &p_path, const RES &p_r
 					"Compile",
 					ProjectSettings::get_singleton()->globalize_path(p_path));
 		} else {
-			ERR_PRINTS("Failed to create C# project");
-			ERR_PRINTS("Cannot add " + p_path + " to the C# project");
+			ERR_PRINTS("C# project could not be created; cannot add file: '" + p_path + "'.");
 		}
 	}
 #endif

+ 56 - 67
modules/mono/editor/bindings_generator.cpp

@@ -279,7 +279,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
 			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);
+				ERR_PRINTS("Invalid reference format: '" + tag + "'.");
 
 				xml_output.append("<c>");
 				xml_output.append(tag);
@@ -375,7 +375,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
 					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);
+					ERR_PRINTS("Cannot resolve enum reference in documentation: '" + link_target + "'.");
 
 					xml_output.append("<c>");
 					xml_output.append(link_target);
@@ -424,7 +424,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
 							xml_output.append(target_iconst->proxy_name);
 							xml_output.append("\"/>");
 						} else {
-							ERR_PRINTS("Cannot resolve global constant reference in documentation: " + link_target);
+							ERR_PRINTS("Cannot resolve global constant reference in documentation: '" + link_target + "'.");
 
 							xml_output.append("<c>");
 							xml_output.append(link_target);
@@ -464,7 +464,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
 							xml_output.append(target_iconst->proxy_name);
 							xml_output.append("\"/>");
 						} else {
-							ERR_PRINTS("Cannot resolve constant reference in documentation: " + link_target);
+							ERR_PRINTS("Cannot resolve constant reference in documentation: '" + link_target + "'.");
 
 							xml_output.append("<c>");
 							xml_output.append(link_target);
@@ -534,7 +534,7 @@ String BindingsGenerator::bbcode_to_xml(const String &p_bbcode, const TypeInterf
 					xml_output.append(target_itype->proxy_name);
 					xml_output.append("\"/>");
 				} else {
-					ERR_PRINTS("Cannot resolve type reference in documentation: " + tag);
+					ERR_PRINTS("Cannot resolve type reference in documentation: '" + tag + "'.");
 
 					xml_output.append("<c>");
 					xml_output.append(tag);
@@ -812,7 +812,7 @@ void BindingsGenerator::_generate_global_constants(StringBuilder &p_output) {
 
 			CRASH_COND(enum_class_name != "Variant"); // Hard-coded...
 
-			_log("Declaring global enum `%s` inside static class `%s`\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data());
+			_log("Declaring global enum '%s' inside static class '%s'\n", enum_proxy_name.utf8().get_data(), enum_class_name.utf8().get_data());
 
 			p_output.append("\n" INDENT1 "public static partial class ");
 			p_output.append(enum_class_name);
@@ -1083,7 +1083,7 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
 
 	proj_err = generate_cs_core_project(core_proj_dir, core_compile_items);
 	if (proj_err != OK) {
-		ERR_PRINT("Generation of the Core API C# project failed");
+		ERR_PRINT("Generation of the Core API C# project failed.");
 		return proj_err;
 	}
 
@@ -1094,7 +1094,7 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
 
 	proj_err = generate_cs_editor_project(editor_proj_dir, editor_compile_items);
 	if (proj_err != OK) {
-		ERR_PRINT("Generation of the Editor API C# project failed");
+		ERR_PRINT("Generation of the Editor API C# project failed.");
 		return proj_err;
 	}
 
@@ -1112,7 +1112,7 @@ Error BindingsGenerator::generate_cs_api(const String &p_output_dir) {
 
 // FIXME: There are some members that hide other inherited members.
 // - In the case of both members being the same kind, the new one must be declared
-// explicitly as `new` to avoid the warning (and we must print a message about it).
+// explicitly as 'new' to avoid the warning (and we must print a message about it).
 // - In the case of both members being of a different kind, then the new one must
 // be renamed to avoid the name collision (and we must print a warning about it).
 // - Csc warning e.g.:
@@ -1186,7 +1186,7 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
 			output.append(obj_types[itype.base_name].proxy_name);
 			output.append("\n");
 		} else {
-			ERR_PRINTS("Base type '" + itype.base_name.operator String() + "' does not exist, for class " + itype.name);
+			ERR_PRINTS("Base type '" + itype.base_name.operator String() + "' does not exist, for class '" + itype.name + "'.");
 			return ERR_INVALID_DATA;
 		}
 	}
@@ -1273,11 +1273,9 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
 		for (const List<PropertyInterface>::Element *E = itype.properties.front(); E; E = E->next()) {
 			const PropertyInterface &iprop = E->get();
 			Error prop_err = _generate_cs_property(itype, iprop, output);
-			if (prop_err != OK) {
-				ERR_EXPLAIN("Failed to generate property '" + iprop.cname.operator String() +
-							"' for class '" + itype.name + "'");
-				ERR_FAIL_V(prop_err);
-			}
+			ERR_FAIL_COND_V_MSG(prop_err != OK, prop_err,
+					"Failed to generate property '" + iprop.cname.operator String() +
+							"' for class '" + itype.name + "'.");
 		}
 	}
 
@@ -1340,10 +1338,8 @@ Error BindingsGenerator::_generate_cs_type(const TypeInterface &itype, const Str
 	for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
 		const MethodInterface &imethod = E->get();
 		Error method_err = _generate_cs_method(itype, imethod, method_bind_count, output);
-		if (method_err != OK) {
-			ERR_EXPLAIN("Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'");
-			ERR_FAIL_V(method_err);
-		}
+		ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
+				"Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
 	}
 
 	if (itype.is_singleton) {
@@ -1626,7 +1622,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
 
 		if (p_imethod.is_deprecated) {
 			if (p_imethod.deprecation_message.empty())
-				WARN_PRINTS("An empty deprecation message is discouraged. Method: " + p_imethod.proxy_name);
+				WARN_PRINTS("An empty deprecation message is discouraged. Method: '" + p_imethod.proxy_name + "'.");
 
 			p_output.append(MEMBER_BEGIN "[Obsolete(\"");
 			p_output.append(p_imethod.deprecation_message);
@@ -1708,8 +1704,7 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
 Error BindingsGenerator::generate_glue(const String &p_output_dir) {
 
 	bool dir_exists = DirAccess::exists(p_output_dir);
-	ERR_EXPLAIN("The output directory does not exist.");
-	ERR_FAIL_COND_V(!dir_exists, ERR_FILE_BAD_PATH);
+	ERR_FAIL_COND_V_MSG(!dir_exists, ERR_FILE_BAD_PATH, "The output directory does not exist.");
 
 	StringBuilder output;
 
@@ -1742,10 +1737,8 @@ Error BindingsGenerator::generate_glue(const String &p_output_dir) {
 		for (const List<MethodInterface>::Element *E = itype.methods.front(); E; E = E->next()) {
 			const MethodInterface &imethod = E->get();
 			Error method_err = _generate_glue_method(itype, imethod, output);
-			if (method_err != OK) {
-				ERR_EXPLAIN("Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'");
-				ERR_FAIL_V(method_err);
-			}
+			ERR_FAIL_COND_V_MSG(method_err != OK, method_err,
+					"Failed to generate method '" + imethod.name + "' for class '" + itype.name + "'.");
 		}
 
 		if (itype.is_singleton) {
@@ -1879,8 +1872,7 @@ Error BindingsGenerator::_save_file(const String &p_path, const StringBuilder &p
 
 	FileAccessRef file = FileAccess::open(p_path, FileAccess::WRITE);
 
-	ERR_EXPLAIN("Cannot open file: " + p_path);
-	ERR_FAIL_COND_V(!file, ERR_FILE_CANT_WRITE);
+	ERR_FAIL_COND_V_MSG(!file, ERR_FILE_CANT_WRITE, "Cannot open file: '" + p_path + "'.");
 
 	file->store_string(p_content.as_string());
 	file->close();
@@ -2091,7 +2083,7 @@ const BindingsGenerator::TypeInterface *BindingsGenerator::_get_type_or_placehol
 	if (found)
 		return found;
 
-	ERR_PRINTS(String() + "Type not found. Creating placeholder: " + p_typeref.cname.operator String());
+	ERR_PRINTS(String() + "Type not found. Creating placeholder: '" + p_typeref.cname.operator String() + "'.");
 
 	const Map<StringName, TypeInterface>::Element *match = placeholder_types.find(p_typeref.cname);
 
@@ -2175,13 +2167,13 @@ void BindingsGenerator::_populate_object_type_interfaces() {
 		}
 
 		if (!ClassDB::is_class_exposed(type_cname)) {
-			_log("Ignoring type `%s` because it's not exposed\n", String(type_cname).utf8().get_data());
+			_log("Ignoring type '%s' because it's not exposed\n", String(type_cname).utf8().get_data());
 			class_list.pop_front();
 			continue;
 		}
 
 		if (!ClassDB::is_class_enabled(type_cname)) {
-			_log("Ignoring type `%s` because it's not enabled\n", String(type_cname).utf8().get_data());
+			_log("Ignoring type '%s' because it's not enabled\n", String(type_cname).utf8().get_data());
 			class_list.pop_front();
 			continue;
 		}
@@ -2240,7 +2232,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
 
 			// Prevent the property and its enclosing type from sharing the same name
 			if (iprop.proxy_name == itype.proxy_name) {
-				_log("Name of property `%s` is ambiguous with the name of its enclosing class `%s`. Renaming property to `%s_`\n",
+				_log("Name of property '%s' is ambiguous with the name of its enclosing class '%s'. Renaming property to '%s_'\n",
 						iprop.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), iprop.proxy_name.utf8().get_data());
 
 				iprop.proxy_name += "_";
@@ -2298,28 +2290,26 @@ void BindingsGenerator::_populate_object_type_interfaces() {
 			imethod.is_vararg = m && m->is_vararg();
 
 			if (!m && !imethod.is_virtual) {
-				if (virtual_method_list.find(method_info)) {
-					// A virtual method without the virtual flag. This is a special case.
-
-					// There is no method bind, so let's fallback to Godot's object.Call(string, params)
-					imethod.requires_object_call = true;
-
-					// The method Object.free is registered as a virtual method, but without the virtual flag.
-					// This is because this method is not supposed to be overridden, but called.
-					// We assume the return type is void.
-					imethod.return_type.cname = name_cache.type_void;
-
-					// Actually, more methods like this may be added in the future,
-					// which could actually will return something different.
-					// Let's put this to notify us if that ever happens.
-					if (itype.cname != name_cache.type_Object || imethod.name != "free") {
-						ERR_PRINTS("Notification: New unexpected virtual non-overridable method found.\n"
-								   "We only expected Object.free, but found " +
-								   itype.name + "." + imethod.name);
-					}
-				} else {
-					ERR_EXPLAIN("Missing MethodBind for non-virtual method: " + itype.name + "." + imethod.name);
-					ERR_FAIL();
+				ERR_FAIL_COND_MSG(!virtual_method_list.find(method_info),
+						"Missing MethodBind for non-virtual method: '" + itype.name + "." + imethod.name + "'.");
+
+				// A virtual method without the virtual flag. This is a special case.
+
+				// There is no method bind, so let's fallback to Godot's object.Call(string, params)
+				imethod.requires_object_call = true;
+
+				// The method Object.free is registered as a virtual method, but without the virtual flag.
+				// This is because this method is not supposed to be overridden, but called.
+				// We assume the return type is void.
+				imethod.return_type.cname = name_cache.type_void;
+
+				// Actually, more methods like this may be added in the future,
+				// which could actually will return something different.
+				// Let's put this to notify us if that ever happens.
+				if (itype.cname != name_cache.type_Object || imethod.name != "free") {
+					ERR_PRINTS("Notification: New unexpected virtual non-overridable method found."
+							   " We only expected Object.free, but found '" +
+							   itype.name + "." + imethod.name + "'.");
 				}
 			} else if (return_info.type == Variant::INT && return_info.usage & PROPERTY_USAGE_CLASS_IS_ENUM) {
 				imethod.return_type.cname = return_info.class_name;
@@ -2328,8 +2318,8 @@ void BindingsGenerator::_populate_object_type_interfaces() {
 				imethod.return_type.cname = return_info.class_name;
 				if (!imethod.is_virtual && ClassDB::is_parent_class(return_info.class_name, name_cache.type_Reference) && return_info.hint != PROPERTY_HINT_RESOURCE_TYPE) {
 					/* clang-format off */
-					ERR_PRINTS("Return type is reference but hint is not " _STR(PROPERTY_HINT_RESOURCE_TYPE) "."
-							" Are you returning a reference type by pointer? Method: " + itype.name + "." + imethod.name);
+					ERR_PRINTS("Return type is reference but hint is not '" _STR(PROPERTY_HINT_RESOURCE_TYPE) "'."
+							" Are you returning a reference type by pointer? Method: '" + itype.name + "." + imethod.name + "'.");
 					/* clang-format on */
 					ERR_FAIL();
 				}
@@ -2394,7 +2384,7 @@ void BindingsGenerator::_populate_object_type_interfaces() {
 
 			// Prevent the method and its enclosing type from sharing the same name
 			if (imethod.proxy_name == itype.proxy_name) {
-				_log("Name of method `%s` is ambiguous with the name of its enclosing class `%s`. Renaming method to `%s_`\n",
+				_log("Name of method '%s' is ambiguous with the name of its enclosing class '%s'. Renaming method to '%s_'\n",
 						imethod.proxy_name.utf8().get_data(), itype.proxy_name.utf8().get_data(), imethod.proxy_name.utf8().get_data());
 
 				imethod.proxy_name += "_";
@@ -2880,8 +2870,7 @@ void BindingsGenerator::_populate_global_constants() {
 	if (global_constants_count > 0) {
 		Map<String, DocData::ClassDoc>::Element *match = EditorHelp::get_doc_data()->class_list.find("@GlobalScope");
 
-		ERR_EXPLAIN("Could not find `@GlobalScope` in DocData");
-		CRASH_COND(!match);
+		CRASH_COND_MSG(!match, "Could not find '@GlobalScope' in DocData.");
 
 		const DocData::ClassDoc &global_scope_doc = match->value();
 
@@ -2935,7 +2924,7 @@ void BindingsGenerator::_populate_global_constants() {
 			// HARDCODED: The Error enum have the prefix 'ERR_' for everything except 'OK' and 'FAILED'.
 			if (ienum.cname == name_cache.enum_Error) {
 				if (prefix_length > 0) { // Just in case it ever changes
-					ERR_PRINTS("Prefix for enum 'Error' is not empty");
+					ERR_PRINTS("Prefix for enum '" _STR(Error) "' is not empty.");
 				}
 
 				prefix_length = 1; // 'ERR_'
@@ -3024,7 +3013,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
 				glue_dir_path = path_elem->get();
 				elem = elem->next();
 			} else {
-				ERR_PRINTS(generate_all_glue_option + ": No output directory specified (expected path to {GODOT_ROOT}/modules/mono/glue)");
+				ERR_PRINTS(generate_all_glue_option + ": No output directory specified (expected path to '{GODOT_ROOT}/modules/mono/glue').");
 			}
 
 			--options_left;
@@ -3035,7 +3024,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
 				cs_dir_path = path_elem->get();
 				elem = elem->next();
 			} else {
-				ERR_PRINTS(generate_cs_glue_option + ": No output directory specified");
+				ERR_PRINTS(generate_cs_glue_option + ": No output directory specified.");
 			}
 
 			--options_left;
@@ -3046,7 +3035,7 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
 				cpp_dir_path = path_elem->get();
 				elem = elem->next();
 			} else {
-				ERR_PRINTS(generate_cpp_glue_option + ": No output directory specified");
+				ERR_PRINTS(generate_cpp_glue_option + ": No output directory specified.");
 			}
 
 			--options_left;
@@ -3061,20 +3050,20 @@ void BindingsGenerator::handle_cmdline_args(const List<String> &p_cmdline_args)
 
 		if (glue_dir_path.length()) {
 			if (bindings_generator.generate_glue(glue_dir_path) != OK)
-				ERR_PRINTS(generate_all_glue_option + ": Failed to generate the C++ glue");
+				ERR_PRINTS(generate_all_glue_option + ": Failed to generate the C++ glue.");
 
 			if (bindings_generator.generate_cs_api(glue_dir_path.plus_file("Managed/Generated")) != OK)
-				ERR_PRINTS(generate_all_glue_option + ": Failed to generate the C# API");
+				ERR_PRINTS(generate_all_glue_option + ": Failed to generate the C# API.");
 		}
 
 		if (cs_dir_path.length()) {
 			if (bindings_generator.generate_cs_api(cs_dir_path) != OK)
-				ERR_PRINTS(generate_cs_glue_option + ": Failed to generate the C# API");
+				ERR_PRINTS(generate_cs_glue_option + ": Failed to generate the C# API.");
 		}
 
 		if (cpp_dir_path.length()) {
 			if (bindings_generator.generate_glue(cpp_dir_path) != OK)
-				ERR_PRINTS(generate_cpp_glue_option + ": Failed to generate the C++ glue");
+				ERR_PRINTS(generate_cpp_glue_option + ": Failed to generate the C++ glue.");
 		}
 
 		// Exit once done

+ 1 - 1
modules/mono/editor/bindings_generator.h

@@ -147,7 +147,7 @@ class BindingsGenerator {
 		bool requires_object_call;
 
 		/**
-		 * Determines if the method visibility is `internal` (visible only to files in the same assembly).
+		 * Determines if the method visibility is 'internal' (visible only to files in the same assembly).
 		 * Currently, we only use this for methods that are not meant to be exposed,
 		 * but are required by properties as getters or setters.
 		 * Methods that are not meant to be exposed are those that begin with underscore and are not virtual.

+ 4 - 6
modules/mono/editor/csharp_project.cpp

@@ -81,16 +81,14 @@ bool generate_api_solution(const String &p_solution_dir, const String &p_core_pr
 
 		_GDMONO_SCOPE_DOMAIN_(temp_domain);
 
-		GDMonoAssembly *tools_project_editor_assembly = NULL;
+		GDMonoAssembly *tools_project_editor_asm = NULL;
 
-		if (!GDMono::get_singleton()->load_assembly("GodotTools.ProjectEditor", &tools_project_editor_assembly)) {
-			ERR_EXPLAIN("Failed to load assembly: 'GodotTools.ProjectEditor'");
-			ERR_FAIL_V(false);
-		}
+		bool assembly_loaded = GDMono::get_singleton()->load_assembly(TOOLS_PROJECT_EDITOR_ASM_NAME, &tools_project_editor_asm);
+		ERR_FAIL_COND_V_MSG(!assembly_loaded, false, "Failed to load assembly: '" TOOLS_PROJECT_EDITOR_ASM_NAME "'.");
 
 		return generate_api_solution_impl(p_solution_dir, p_core_proj_dir, p_core_compile_items,
 				p_editor_proj_dir, p_editor_compile_items,
-				tools_project_editor_assembly);
+				tools_project_editor_asm);
 	}
 }
 

+ 3 - 10
modules/mono/editor/godotsharp_export.cpp

@@ -85,18 +85,12 @@ Error GodotSharpExport::get_assembly_dependencies(GDMonoAssembly *p_assembly, co
 			}
 		}
 
-		if (!ref_assembly) {
-			ERR_EXPLAIN("Cannot load assembly (refonly): " + ref_name);
-			ERR_FAIL_V(ERR_CANT_RESOLVE);
-		}
+		ERR_FAIL_COND_V_MSG(!ref_assembly, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + ref_name + "'.");
 
 		r_dependencies[ref_name] = ref_assembly->get_path();
 
 		Error err = get_assembly_dependencies(ref_assembly, p_search_dirs, r_dependencies);
-		if (err != OK) {
-			ERR_EXPLAIN("Cannot load one of the dependencies for the assembly: " + ref_name);
-			ERR_FAIL_V(err);
-		}
+		ERR_FAIL_COND_V_MSG(err != OK, err, "Cannot load one of the dependencies for the assembly: '" + ref_name + "'.");
 	}
 
 	return OK;
@@ -113,8 +107,7 @@ Error GodotSharpExport::get_exported_assembly_dependencies(const String &p_proje
 	bool load_success = GDMono::get_singleton()->load_assembly_from(p_project_dll_name,
 			p_project_dll_src_path, &scripts_assembly, /* refonly: */ true);
 
-	ERR_EXPLAIN("Cannot load assembly (refonly): " + p_project_dll_name);
-	ERR_FAIL_COND_V(!load_success, ERR_CANT_RESOLVE);
+	ERR_FAIL_COND_V_MSG(!load_success, ERR_CANT_RESOLVE, "Cannot load assembly (refonly): '" + p_project_dll_name + "'.");
 
 	Vector<String> search_dirs;
 	GDMonoAssembly::fill_search_dirs(search_dirs, p_build_config, p_custom_lib_dir);

+ 9 - 9
modules/mono/editor/script_class_parser.cpp

@@ -162,8 +162,8 @@ ScriptClassParser::Token ScriptClassParser::get_token() {
 						error = true;
 						return TK_ERROR;
 					} else if (code[idx] == begin_str) {
-						if (verbatim && code[idx + 1] == '"') { // `""` is verbatim string's `\"`
-							idx += 2; // skip next `"` as well
+						if (verbatim && code[idx + 1] == '"') { // '""' is verbatim string's '\"'
+							idx += 2; // skip next '"' as well
 							continue;
 						}
 
@@ -590,7 +590,7 @@ Error ScriptClassParser::parse(const String &p_code) {
 					name = String(value);
 				} else if (tk == TK_CURLY_BRACKET_OPEN) {
 					if (name.empty()) {
-						error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword `struct`, found " + get_token_name(TK_CURLY_BRACKET_OPEN);
+						error_str = "Expected " + get_token_name(TK_IDENTIFIER) + " after keyword 'struct', found " + get_token_name(TK_CURLY_BRACKET_OPEN);
 						error = true;
 						return ERR_PARSE_ERROR;
 					}
@@ -657,12 +657,12 @@ Error ScriptClassParser::parse_file(const String &p_filepath) {
 	String source;
 
 	Error ferr = read_all_file_utf8(p_filepath, source);
-	if (ferr != OK) {
-		if (ferr == ERR_INVALID_DATA) {
-			ERR_EXPLAIN("File '" + p_filepath + "' contains invalid unicode (utf-8), so it was not loaded. Please ensure that scripts are saved in valid utf-8 unicode.");
-		}
-		ERR_FAIL_V(ferr);
-	}
+
+	ERR_FAIL_COND_V_MSG(ferr != OK, ferr,
+			ferr == ERR_INVALID_DATA ?
+					"File '" + p_filepath + "' contains invalid unicode (UTF-8), so it was not loaded."
+											" Please ensure that scripts are saved in valid UTF-8 unicode." :
+					"Failed to read file: '" + p_filepath + "'.");
 
 	return parse(source);
 }

+ 2 - 3
modules/mono/glue/gd_glue.cpp

@@ -167,7 +167,7 @@ MonoObject *godot_icall_GD_str2var(MonoString *p_str) {
 	int line;
 	Error err = VariantParser::parse(&ss, ret, errs, line);
 	if (err != OK) {
-		String err_str = "Parse error at line " + itos(line) + ": " + errs;
+		String err_str = "Parse error at line " + itos(line) + ": " + errs + ".";
 		ERR_PRINTS(err_str);
 		ret = err_str;
 	}
@@ -193,8 +193,7 @@ MonoArray *godot_icall_GD_var2bytes(MonoObject *p_var, MonoBoolean p_full_object
 	PoolByteArray barr;
 	int len;
 	Error err = encode_variant(var, NULL, len, p_full_objects);
-	ERR_EXPLAIN("Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
-	ERR_FAIL_COND_V(err != OK, NULL);
+	ERR_FAIL_COND_V_MSG(err != OK, NULL, "Unexpected error encoding variable to bytes, likely unserializable type found (Object or RID).");
 
 	barr.resize(len);
 	{

+ 2 - 2
modules/mono/godotsharp_defs.h

@@ -39,8 +39,8 @@
 #define API_SOLUTION_NAME "GodotSharp"
 #define CORE_API_ASSEMBLY_NAME "GodotSharp"
 #define EDITOR_API_ASSEMBLY_NAME "GodotSharpEditor"
-#define TOOLS_ASSEMBLY_NAME "GodotTools"
-#define TOOLS_PROJECT_EDITOR_ASSEMBLY_NAME "GodotTools.ProjectEditor"
+#define TOOLS_ASM_NAME "GodotTools"
+#define TOOLS_PROJECT_EDITOR_ASM_NAME "GodotTools.ProjectEditor"
 
 #define BINDINGS_CLASS_NATIVECALLS "NativeCalls"
 #define BINDINGS_CLASS_NATIVECALLS_EDITOR "EditorNativeCalls"

+ 46 - 72
modules/mono/mono_gd/gd_mono.cpp

@@ -265,7 +265,7 @@ void GDMono::initialize() {
 
 #ifdef WINDOWS_ENABLED
 	if (assembly_rootdir.empty() || config_dir.empty()) {
-		ERR_PRINT("Cannot find Mono in the registry");
+		ERR_PRINT("Cannot find Mono in the registry.");
 		// Assertion: if they are not set, then they weren't found in the registry
 		CRASH_COND(mono_reg_info.assembly_dir.length() > 0 || mono_reg_info.config_dir.length() > 0);
 	}
@@ -318,9 +318,7 @@ void GDMono::initialize() {
 #endif
 
 	root_domain = mono_jit_init_version("GodotEngine.RootDomain", "v4.0.30319");
-
-	ERR_EXPLAIN("Mono: Failed to initialize runtime");
-	ERR_FAIL_NULL(root_domain);
+	ERR_FAIL_NULL_MSG(root_domain, "Mono: Failed to initialize runtime.");
 
 	GDMonoUtils::set_main_thread(GDMonoUtils::get_current_thread());
 
@@ -331,11 +329,11 @@ void GDMono::initialize() {
 	print_verbose("Mono: Runtime initialized");
 
 	// mscorlib assembly MUST be present at initialization
-	ERR_EXPLAIN("Mono: Failed to load mscorlib assembly");
-	ERR_FAIL_COND(!_load_corlib_assembly());
+	bool corlib_loaded = _load_corlib_assembly();
+	ERR_FAIL_COND_MSG(!corlib_loaded, "Mono: Failed to load mscorlib assembly.");
 
-	ERR_EXPLAIN("Mono: Failed to load scripts domain");
-	ERR_FAIL_COND(_load_scripts_domain() != OK);
+	Error domain_load_err = _load_scripts_domain();
+	ERR_FAIL_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
 
 #ifdef DEBUG_ENABLED
 	bool debugger_attached = _wait_for_debugger_msecs(500);
@@ -351,8 +349,7 @@ void GDMono::initialize() {
 void GDMono::initialize_load_assemblies() {
 
 #ifndef MONO_GLUE_ENABLED
-	ERR_EXPLAIN("Mono: This binary was built with `mono_glue=no`; cannot load assemblies");
-	CRASH_NOW();
+	CRASH_NOW_MSG("Mono: This binary was built with 'mono_glue=no'; cannot load assemblies.");
 #endif
 
 	// Load assemblies. The API and tools assemblies are required,
@@ -361,10 +358,8 @@ void GDMono::initialize_load_assemblies() {
 	_load_api_assemblies();
 
 #if defined(TOOLS_ENABLED)
-	if (!_load_tools_assemblies()) {
-		ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
-		CRASH_NOW();
-	}
+	bool tool_assemblies_loaded = _load_tools_assemblies();
+	CRASH_COND_MSG(!tool_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies.");
 #endif
 
 	// Load the project's main assembly. This doesn't necessarily need to succeed.
@@ -428,12 +423,12 @@ void GDMono::_initialize_and_check_api_hashes() {
 
 #ifdef MONO_GLUE_ENABLED
 	if (get_api_core_hash() != GodotSharpBindings::get_core_api_hash()) {
-		ERR_PRINT("Mono: Core API hash mismatch!");
+		ERR_PRINT("Mono: Core API hash mismatch.");
 	}
 
 #ifdef TOOLS_ENABLED
 	if (get_api_editor_hash() != GodotSharpBindings::get_editor_api_hash()) {
-		ERR_PRINT("Mono: Editor API hash mismatch!");
+		ERR_PRINT("Mono: Editor API hash mismatch.");
 	}
 #endif // TOOLS_ENABLED
 #endif // MONO_GLUE_ENABLED
@@ -579,7 +574,7 @@ bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type) {
 		memdelete(da);
 
 		if (err != OK) {
-			ERR_PRINTS("Failed to create destination directory for the API assemblies. Error: " + itos(err));
+			ERR_PRINTS("Failed to create destination directory for the API assemblies. Error: " + itos(err) + ".");
 			return false;
 		}
 	}
@@ -593,16 +588,16 @@ bool GDMono::copy_prebuilt_api_assembly(APIAssembly::Type p_api_type) {
 
 		String xml_file = assembly_name + ".xml";
 		if (da->copy(src_dir.plus_file(xml_file), dst_dir.plus_file(xml_file)) != OK)
-			WARN_PRINTS("Failed to copy " + xml_file);
+			WARN_PRINTS("Failed to copy '" + xml_file + "'.");
 
 		String pdb_file = assembly_name + ".pdb";
 		if (da->copy(src_dir.plus_file(pdb_file), dst_dir.plus_file(pdb_file)) != OK)
-			WARN_PRINTS("Failed to copy " + pdb_file);
+			WARN_PRINTS("Failed to copy '" + pdb_file + "'.");
 
 		Error err = da->copy(assembly_src, assembly_dst);
 
 		if (err != OK) {
-			ERR_PRINTS("Failed to copy " + assembly_file);
+			ERR_PRINTS("Failed to copy '" + assembly_file + "'.");
 			return false;
 		}
 
@@ -617,11 +612,11 @@ String GDMono::update_api_assemblies_from_prebuilt() {
 #define FAIL_REASON(m_out_of_sync, m_prebuilt_exists)                            \
 	(                                                                            \
 			(m_out_of_sync ?                                                     \
-							String("The assembly is invalidated") :              \
-							String("The assembly was not found")) +              \
+							String("The assembly is invalidated ") :             \
+							String("The assembly was not found ")) +             \
 			(m_prebuilt_exists ?                                                 \
-							String(" and the prebuilt assemblies are missing") : \
-							String(" and we failed to copy the prebuilt assemblies")))
+							String("and the prebuilt assemblies are missing.") : \
+							String("and we failed to copy the prebuilt assemblies.")))
 
 	bool api_assembly_out_of_sync = core_api_assembly_out_of_sync || editor_api_assembly_out_of_sync;
 
@@ -755,29 +750,19 @@ void GDMono::_load_api_assemblies() {
 		// update them from the prebuilt assemblies directory before trying to load them.
 
 		// Shouldn't happen. The project manager loads the prebuilt API assemblies
-		if (Main::is_project_manager()) {
-			ERR_EXPLAIN("Failed to load one of the prebuilt API assemblies");
-			CRASH_NOW();
-		}
+		CRASH_COND_MSG(Main::is_project_manager(), "Failed to load one of the prebuilt API assemblies.");
 
 		// 1. Unload the scripts domain
-		if (_unload_scripts_domain() != OK) {
-			ERR_EXPLAIN("Mono: Failed to unload scripts domain");
-			CRASH_NOW();
-		}
+		Error domain_unload_err = _unload_scripts_domain();
+		CRASH_COND_MSG(domain_unload_err != OK, "Mono: Failed to unload scripts domain.");
 
 		// 2. Update the API assemblies
 		String update_error = update_api_assemblies_from_prebuilt();
-		if (!update_error.empty()) {
-			ERR_EXPLAIN(update_error);
-			CRASH_NOW();
-		}
+		CRASH_COND_MSG(!update_error.empty(), update_error);
 
 		// 3. Load the scripts domain again
-		if (_load_scripts_domain() != OK) {
-			ERR_EXPLAIN("Mono: Failed to load scripts domain");
-			CRASH_NOW();
-		}
+		Error domain_load_err = _load_scripts_domain();
+		CRASH_COND_MSG(domain_load_err != OK, "Mono: Failed to load scripts domain.");
 
 		// 4. Try loading the updated assemblies
 		if (!_try_load_api_assemblies()) {
@@ -785,24 +770,22 @@ void GDMono::_load_api_assemblies() {
 
 			if (_are_api_assemblies_out_of_sync()) {
 				if (core_api_assembly_out_of_sync) {
-					ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync");
+					ERR_PRINT("The assembly '" CORE_API_ASSEMBLY_NAME "' is out of sync.");
 				} else if (!GDMonoUtils::mono_cache.godot_api_cache_updated) {
-					ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed");
+					ERR_PRINT("The loaded assembly '" CORE_API_ASSEMBLY_NAME "' is in sync, but the cache update failed.");
 				}
 
 				if (editor_api_assembly_out_of_sync) {
-					ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync");
+					ERR_PRINT("The assembly '" EDITOR_API_ASSEMBLY_NAME "' is out of sync.");
 				}
 
 				CRASH_NOW();
 			} else {
-				ERR_EXPLAIN("Failed to load one of the API assemblies");
-				CRASH_NOW();
+				CRASH_NOW_MSG("Failed to load one of the API assemblies.");
 			}
 		}
 #else
-		ERR_EXPLAIN("Failed to load one of the API assemblies");
-		CRASH_NOW();
+		CRASH_NOW_MSG("Failed to load one of the API assemblies.");
 #endif
 	}
 }
@@ -813,8 +796,8 @@ bool GDMono::_load_tools_assemblies() {
 	if (tools_assembly && tools_project_editor_assembly)
 		return true;
 
-	bool success = load_assembly(TOOLS_ASSEMBLY_NAME, &tools_assembly) &&
-				   load_assembly(TOOLS_PROJECT_EDITOR_ASSEMBLY_NAME, &tools_project_editor_assembly);
+	bool success = load_assembly(TOOLS_ASM_NAME, &tools_assembly) &&
+				   load_assembly(TOOLS_PROJECT_EDITOR_ASM_NAME, &tools_project_editor_assembly);
 
 	return success;
 }
@@ -851,7 +834,7 @@ void GDMono::_install_trace_listener() {
 			(DebuggingUtils_InstallTraceListener)debug_utils->get_method_thunk("InstallTraceListener");
 	install_func((MonoObject **)&exc);
 	if (exc) {
-		ERR_PRINT("Failed to install System.Diagnostics.Trace listener");
+		ERR_PRINT("Failed to install 'System.Diagnostics.Trace' listener.");
 		GDMonoUtils::debug_print_unhandled_exception(exc);
 	}
 #endif
@@ -865,8 +848,7 @@ Error GDMono::_load_scripts_domain() {
 
 	scripts_domain = GDMonoUtils::create_domain("GodotEngine.ScriptsDomain");
 
-	ERR_EXPLAIN("Mono: Could not create scripts app domain");
-	ERR_FAIL_NULL_V(scripts_domain, ERR_CANT_CREATE);
+	ERR_FAIL_NULL_V_MSG(scripts_domain, ERR_CANT_CREATE, "Mono: Could not create scripts app domain.");
 
 	mono_domain_set(scripts_domain, true);
 
@@ -885,7 +867,7 @@ Error GDMono::_unload_scripts_domain() {
 	finalizing_scripts_domain = true;
 
 	if (!mono_domain_finalize(scripts_domain, 2000)) {
-		ERR_PRINT("Mono: Domain finalization timeout");
+		ERR_PRINT("Mono: Domain finalization timeout.");
 	}
 
 	finalizing_scripts_domain = false;
@@ -911,7 +893,7 @@ Error GDMono::_unload_scripts_domain() {
 	mono_domain_try_unload(domain, (MonoObject **)&exc);
 
 	if (exc) {
-		ERR_PRINT("Exception thrown when unloading scripts domain");
+		ERR_PRINT("Exception thrown when unloading scripts domain.");
 		GDMonoUtils::debug_unhandled_exception(exc);
 		return FAILED;
 	}
@@ -925,20 +907,14 @@ Error GDMono::reload_scripts_domain() {
 	ERR_FAIL_COND_V(!runtime_initialized, ERR_BUG);
 
 	if (scripts_domain) {
-		Error err = _unload_scripts_domain();
-		if (err != OK) {
-			ERR_PRINT("Mono: Failed to unload scripts domain");
-			return err;
-		}
+		Error domain_unload_err = _unload_scripts_domain();
+		ERR_FAIL_COND_V_MSG(domain_unload_err != OK, domain_unload_err, "Mono: Failed to unload scripts domain.");
 	}
 
 	CSharpLanguage::get_singleton()->_on_scripts_domain_unloaded();
 
-	Error err = _load_scripts_domain();
-	if (err != OK) {
-		ERR_PRINT("Mono: Failed to load scripts domain");
-		return err;
-	}
+	Error domain_load_err = _load_scripts_domain();
+	ERR_FAIL_COND_V_MSG(domain_load_err != OK, domain_load_err, "Mono: Failed to load scripts domain.");
 
 	// Load assemblies. The API and tools assemblies are required,
 	// the application is aborted if these assemblies cannot be loaded.
@@ -946,10 +922,8 @@ Error GDMono::reload_scripts_domain() {
 	_load_api_assemblies();
 
 #if defined(TOOLS_ENABLED)
-	if (!_load_tools_assemblies()) {
-		ERR_EXPLAIN("Mono: Failed to load GodotTools assemblies");
-		CRASH_NOW();
-	}
+	bool tools_assemblies_loaded = _load_tools_assemblies();
+	CRASH_COND_MSG(!tools_assemblies_loaded, "Mono: Failed to load '" TOOLS_ASM_NAME "' assemblies.");
 #endif
 
 	// Load the project's main assembly. Here, during hot-reloading, we do
@@ -971,13 +945,13 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
 
 	String domain_name = mono_domain_get_friendly_name(p_domain);
 
-	print_verbose("Mono: Unloading domain `" + domain_name + "`...");
+	print_verbose("Mono: Unloading domain '" + domain_name + "'...");
 
 	if (mono_domain_get() == p_domain)
 		mono_domain_set(root_domain, true);
 
 	if (!mono_domain_finalize(p_domain, 2000)) {
-		ERR_PRINT("Mono: Domain finalization timeout");
+		ERR_PRINT("Mono: Domain finalization timeout.");
 	}
 
 	mono_gc_collect(mono_gc_max_generation());
@@ -988,7 +962,7 @@ Error GDMono::finalize_and_unload_domain(MonoDomain *p_domain) {
 	mono_domain_try_unload(p_domain, (MonoObject **)&exc);
 
 	if (exc) {
-		ERR_PRINTS("Exception thrown when unloading domain `" + domain_name + "`");
+		ERR_PRINTS("Exception thrown when unloading domain '" + domain_name + "'.");
 		GDMonoUtils::debug_print_unhandled_exception(exc);
 		return FAILED;
 	}
@@ -1105,7 +1079,7 @@ GDMono::~GDMono() {
 		if (scripts_domain) {
 			Error err = _unload_scripts_domain();
 			if (err != OK) {
-				ERR_PRINT("Mono: Failed to unload scripts domain");
+				ERR_PRINT("Mono: Failed to unload scripts domain.");
 			}
 		}
 

+ 5 - 5
modules/mono/mono_gd/gd_mono_assembly.cpp

@@ -151,14 +151,14 @@ MonoAssembly *GDMonoAssembly::_preload_hook(MonoAssemblyName *aname, char **, vo
 	}
 
 	{
-		// If we find the assembly here, we load it with `mono_assembly_load_from_full`,
+		// If we find the assembly here, we load it with 'mono_assembly_load_from_full',
 		// which in turn invokes load hooks before returning the MonoAssembly to us.
-		// One of the load hooks is `load_aot_module`. This hook can end up calling preload hooks
-		// again for the same assembly in certain in certain circumstances (the `do_load_image` part).
+		// One of the load hooks is 'load_aot_module'. This hook can end up calling preload hooks
+		// again for the same assembly in certain in certain circumstances (the 'do_load_image' part).
 		// If this is the case and we return NULL due to the no_search condition below,
 		// it will result in an internal crash later on. Therefore we need to return the assembly we didn't
-		// get yet from `mono_assembly_load_from_full`. Luckily we have the image, which already got it.
-		// This must be done here. If done in search hooks, it would cause `mono_assembly_load_from_full`
+		// get yet from 'mono_assembly_load_from_full'. Luckily we have the image, which already got it.
+		// This must be done here. If done in search hooks, it would cause 'mono_assembly_load_from_full'
 		// to think another MonoAssembly for this assembly was already loaded, making it delete its own,
 		// when in fact both pointers were the same... This hooks thing is confusing.
 		if (image_corlib_loading) {

+ 4 - 4
modules/mono/mono_gd/gd_mono_class.cpp

@@ -165,8 +165,8 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
 
 #ifdef DEBUG_ENABLED
 			String fullname = method->get_ret_type_full_name() + " " + name + "(" + method->get_signature_desc(true) + ")";
-			WARN_PRINTS("Method `" + fullname + "` is hidden by Godot API method. Should be `" +
-						method->get_full_name_no_class() + "`. In class `" + namespace_name + "." + class_name + "`.");
+			WARN_PRINTS("Method '" + fullname + "' is hidden by Godot API method. Should be '" +
+						method->get_full_name_no_class() + "'. In class '" + namespace_name + "." + class_name + "'.");
 #endif
 			continue;
 		}
@@ -184,8 +184,8 @@ void GDMonoClass::fetch_methods_with_godot_api_checks(GDMonoClass *p_native_base
 				if (m && m->get_name() != name) {
 					// found
 					String fullname = m->get_ret_type_full_name() + " " + name + "(" + m->get_signature_desc(true) + ")";
-					WARN_PRINTS("Method `" + fullname + "` should be `" + m->get_full_name_no_class() +
-								"`. In class `" + namespace_name + "." + class_name + "`.");
+					WARN_PRINTS("Method '" + fullname + "' should be '" + m->get_full_name_no_class() +
+								"'. In class '" + namespace_name + "." + class_name + "'.");
 					break;
 				}
 

+ 5 - 9
modules/mono/mono_gd/gd_mono_field.cpp

@@ -219,16 +219,14 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 						break;
 					}
 					default: {
-						ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
-						ERR_FAIL();
+						ERR_FAIL_MSG("Attempted to convert Variant to a managed enum value of unmarshallable base type.");
 					}
 				}
 
 				break;
 			}
 
-			ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + tclass->get_name());
-			ERR_FAIL();
+			ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + tclass->get_name() + "'.");
 		} break;
 
 		case MONO_TYPE_ARRAY:
@@ -275,8 +273,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 				break;
 			}
 
-			ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
-			ERR_FAIL();
+			ERR_FAIL_MSG("Attempted to convert Variant to a managed array of unmarshallable element type.");
 		} break;
 
 		case MONO_TYPE_CLASS: {
@@ -351,8 +348,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 				}
 			}
 
-			ERR_EXPLAIN(String() + "Attempted to set the value of a field of unmarshallable type: " + type_class->get_name());
-			ERR_FAIL();
+			ERR_FAIL_MSG("Attempted to set the value of a field of unmarshallable type: '" + type_class->get_name() + "'.");
 		} break;
 
 		case MONO_TYPE_OBJECT: {
@@ -508,7 +504,7 @@ void GDMonoField::set_value_from_variant(MonoObject *p_object, const Variant &p_
 		} break;
 
 		default: {
-			ERR_PRINTS(String() + "Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding));
+			ERR_PRINTS("Attempted to set the value of a field of unexpected type encoding: " + itos(type.type_encoding) + ".");
 		} break;
 	}
 

+ 1 - 1
modules/mono/mono_gd/gd_mono_internals.cpp

@@ -48,7 +48,7 @@ void tie_managed_to_unmanaged(MonoObject *managed, Object *unmanaged) {
 
 	CRASH_COND(!unmanaged);
 
-	// All mono objects created from the managed world (e.g.: `new Player()`)
+	// All mono objects created from the managed world (e.g.: 'new Player()')
 	// need to have a CSharpScript in order for their methods to be callable from the unmanaged side
 
 	Reference *ref = Object::cast_to<Reference>(unmanaged);

+ 4 - 5
modules/mono/mono_gd/gd_mono_log.cpp

@@ -72,7 +72,7 @@ static void mono_log_callback(const char *log_domain, const char *log_level, con
 	}
 
 	if (fatal) {
-		ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: " + GDMonoLog::get_singleton()->get_log_file_path() + "\n");
+		ERR_PRINTS("Mono: FATAL ERROR, ABORTING! Logfile: '" + GDMonoLog::get_singleton()->get_log_file_path() + "'.");
 		// Make sure to flush before aborting
 		f->flush();
 		f->close();
@@ -90,8 +90,7 @@ bool GDMonoLog::_try_create_logs_dir(const String &p_logs_dir) {
 		DirAccessRef diraccess = DirAccess::create(DirAccess::ACCESS_FILESYSTEM);
 		ERR_FAIL_COND_V(!diraccess, false);
 		Error logs_mkdir_err = diraccess->make_dir_recursive(p_logs_dir);
-		ERR_EXPLAIN("Failed to create mono logs directory");
-		ERR_FAIL_COND_V(logs_mkdir_err != OK, false);
+		ERR_FAIL_COND_V_MSG(logs_mkdir_err != OK, false, "Failed to create mono logs directory.");
 	}
 
 	return true;
@@ -131,7 +130,7 @@ void GDMonoLog::initialize() {
 	CharString log_level = OS::get_singleton()->get_environment("GODOT_MONO_LOG_LEVEL").utf8();
 
 	if (log_level.length() != 0 && log_level_get_id(log_level.get_data()) == -1) {
-		ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): " + log_level.get_data());
+		ERR_PRINTS(String() + "Mono: Ignoring invalid log level (GODOT_MONO_LOG_LEVEL): '" + log_level.get_data() + "'.");
 		log_level = CharString();
 	}
 
@@ -160,7 +159,7 @@ void GDMonoLog::initialize() {
 
 		log_file = FileAccess::open(log_file_path, FileAccess::WRITE);
 		if (!log_file) {
-			ERR_PRINT("Mono: Cannot create log file");
+			ERR_PRINT("Mono: Cannot create log file.");
 		}
 	}
 

+ 8 - 13
modules/mono/mono_gd/gd_mono_marshal.cpp

@@ -276,7 +276,7 @@ String mono_to_utf8_string(MonoString *p_mono_string) {
 	char *utf8 = mono_string_to_utf8_checked(p_mono_string, &error);
 
 	if (!mono_error_ok(&error)) {
-		ERR_PRINTS(String("Failed to convert MonoString* to UTF-8: ") + mono_error_get_message(&error));
+		ERR_PRINTS(String() + "Failed to convert MonoString* to UTF-8: '" + mono_error_get_message(&error) + "'.");
 		mono_error_cleanup(&error);
 		return String();
 	}
@@ -474,8 +474,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 						return BOX_ENUM(enum_baseclass, val);
 					}
 					default: {
-						ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
-						ERR_FAIL_V(NULL);
+						ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed enum value of unmarshallable base type.");
 					}
 				}
 			}
@@ -509,8 +508,7 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 			if (array_type->eklass == CACHED_CLASS_RAW(Color))
 				return (MonoObject *)PoolColorArray_to_mono_array(p_var->operator PoolColorArray());
 
-			ERR_EXPLAIN(String() + "Attempted to convert Variant to a managed array of unmarshallable element type.");
-			ERR_FAIL_V(NULL);
+			ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to a managed array of unmarshallable element type.");
 		} break;
 
 		case MONO_TYPE_CLASS: {
@@ -695,9 +693,8 @@ MonoObject *variant_to_mono_object(const Variant *p_var, const ManagedType &p_ty
 		} break;
 	}
 
-	ERR_EXPLAIN(String() + "Attempted to convert Variant to an unmarshallable managed type. Name: \'" +
-				p_type.type_class->get_name() + "\' Encoding: " + itos(p_type.type_encoding));
-	ERR_FAIL_V(NULL);
+	ERR_FAIL_V_MSG(NULL, "Attempted to convert Variant to an unmarshallable managed type. Name: '" +
+								 p_type.type_class->get_name() + "' Encoding: " + itos(p_type.type_encoding) + ".");
 }
 
 Variant mono_object_to_variant(MonoObject *p_obj) {
@@ -809,8 +806,7 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 			if (array_type->eklass == CACHED_CLASS_RAW(Color))
 				return mono_array_to_PoolColorArray((MonoArray *)p_obj);
 
-			ERR_EXPLAIN(String() + "Attempted to convert a managed array of unmarshallable element type to Variant.");
-			ERR_FAIL_V(Variant());
+			ERR_FAIL_V_MSG(Variant(), "Attempted to convert a managed array of unmarshallable element type to Variant.");
 		} break;
 
 		case MONO_TYPE_CLASS: {
@@ -908,9 +904,8 @@ Variant mono_object_to_variant(MonoObject *p_obj) {
 		} break;
 	}
 
-	ERR_EXPLAIN(String() + "Attempted to convert an unmarshallable managed type to Variant. Name: \'" +
-				type.type_class->get_name() + "\' Encoding: " + itos(type.type_encoding));
-	ERR_FAIL_V(Variant());
+	ERR_FAIL_V_MSG(Variant(), "Attempted to convert an unmarshallable managed type to Variant. Name: '" +
+									  type.type_class->get_name() + "' Encoding: " + itos(type.type_encoding) + ".");
 }
 
 MonoArray *Array_to_mono_array(const Array &p_array) {

+ 8 - 12
modules/mono/mono_gd/gd_mono_utils.cpp

@@ -52,14 +52,11 @@ namespace GDMonoUtils {
 
 MonoCache mono_cache;
 
-#define CACHE_AND_CHECK(m_var, m_val)                             \
-	{                                                             \
-		CRASH_COND(m_var != NULL);                                \
-		m_var = m_val;                                            \
-		if (!m_var) {                                             \
-			ERR_EXPLAIN("Mono Cache: Member " #m_var " is null"); \
-			ERR_FAIL();                                           \
-		}                                                         \
+#define CACHE_AND_CHECK(m_var, m_val)                                        \
+	{                                                                        \
+		CRASH_COND(m_var != NULL);                                           \
+		m_var = m_val;                                                       \
+		ERR_FAIL_COND_MSG(!m_var, "Mono Cache: Member " #m_var " is null."); \
 	}
 
 #define CACHE_CLASS_AND_CHECK(m_class, m_val) CACHE_AND_CHECK(GDMonoUtils::mono_cache.class_##m_class, m_val)
@@ -453,10 +450,9 @@ GDMonoClass *get_class_native_base(GDMonoClass *p_class) {
 }
 
 MonoObject *create_managed_for_godot_object(GDMonoClass *p_class, const StringName &p_native, Object *p_object) {
-	if (!ClassDB::is_parent_class(p_object->get_class_name(), p_native)) {
-		ERR_EXPLAIN("Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'");
-		ERR_FAIL_V(NULL);
-	}
+	bool parent_is_object_class = ClassDB::is_parent_class(p_object->get_class_name(), p_native);
+	ERR_FAIL_COND_V_MSG(!parent_is_object_class, NULL,
+			"Type inherits from native type '" + p_native + "', so it can't be instanced in object of type: '" + p_object->get_class() + "'.");
 
 	MonoObject *mono_object = mono_object_new(mono_domain_get(), p_class->get_mono_ptr());
 	ERR_FAIL_NULL_V(mono_object, NULL);

+ 2 - 4
modules/mono/signal_awaiter_utils.cpp

@@ -67,10 +67,8 @@ Error connect_signal_awaiter(Object *p_source, const String &p_signal, Object *p
 Variant SignalAwaiterHandle::_signal_callback(const Variant **p_args, int p_argcount, Variant::CallError &r_error) {
 
 #ifdef DEBUG_ENABLED
-	if (conn_target_id && !ObjectDB::get_instance(conn_target_id)) {
-		ERR_EXPLAIN("Resumed after await, but class instance is gone");
-		ERR_FAIL_V(Variant());
-	}
+	ERR_FAIL_COND_V_MSG(conn_target_id && !ObjectDB::get_instance(conn_target_id), Variant(),
+			"Resumed after await, but class instance is gone.");
 #endif
 
 	if (p_argcount < 1) {

+ 1 - 4
modules/mono/utils/string_utils.cpp

@@ -55,10 +55,7 @@ int sfind(const String &p_text, int p_from) {
 		for (int j = 0; j < src_len; j++) {
 			int read_pos = i + j;
 
-			if (read_pos >= len) {
-				ERR_PRINT("read_pos >= len");
-				return -1;
-			};
+			ERR_FAIL_COND_V(read_pos >= len, -1);
 
 			switch (j) {
 				case 0: