You've already forked godot
mirror of
https://github.com/godotengine/godot.git
synced 2025-11-10 13:00:37 +00:00
Merge pull request #79280 from raulsntos/dotnet/better-push-error
C#: Improve `GD.PushError` and `GD.PushWarning`
This commit is contained in:
@@ -569,8 +569,11 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
|
|||||||
error->set_custom_color(1, color);
|
error->set_custom_color(1, color);
|
||||||
|
|
||||||
String error_title;
|
String error_title;
|
||||||
if (oe.callstack.size() > 0) {
|
if (!oe.source_func.is_empty() && source_is_project_file) {
|
||||||
// If available, use the script's stack in the error title.
|
// If source function is inside the project file.
|
||||||
|
error_title += oe.source_func + ": ";
|
||||||
|
} else if (oe.callstack.size() > 0) {
|
||||||
|
// Otherwise, if available, use the script's stack in the error title.
|
||||||
error_title = _format_frame_text(&oe.callstack[0]) + ": ";
|
error_title = _format_frame_text(&oe.callstack[0]) + ": ";
|
||||||
} else if (!oe.source_func.is_empty()) {
|
} else if (!oe.source_func.is_empty()) {
|
||||||
// Otherwise try to use the C++ source function.
|
// Otherwise try to use the C++ source function.
|
||||||
@@ -645,7 +648,10 @@ void ScriptEditorDebugger::_parse_message(const String &p_msg, uint64_t p_thread
|
|||||||
if (i == 0) {
|
if (i == 0) {
|
||||||
stack_trace->set_text(0, "<" + TTR("Stack Trace") + ">");
|
stack_trace->set_text(0, "<" + TTR("Stack Trace") + ">");
|
||||||
stack_trace->set_text_alignment(0, HORIZONTAL_ALIGNMENT_LEFT);
|
stack_trace->set_text_alignment(0, HORIZONTAL_ALIGNMENT_LEFT);
|
||||||
error->set_metadata(0, meta);
|
if (!source_is_project_file) {
|
||||||
|
// Only override metadata if the source is not inside the project.
|
||||||
|
error->set_metadata(0, meta);
|
||||||
|
}
|
||||||
tooltip += TTR("Stack Trace:") + "\n";
|
tooltip += TTR("Stack Trace:") + "\n";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -14,14 +14,46 @@ namespace Godot
|
|||||||
{
|
{
|
||||||
private static void AppendTypeName(this StringBuilder sb, Type type)
|
private static void AppendTypeName(this StringBuilder sb, Type type)
|
||||||
{
|
{
|
||||||
if (type.IsPrimitive)
|
// Use the C# type keyword for built-in types.
|
||||||
sb.Append(type.Name);
|
// https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/builtin-types/built-in-types
|
||||||
else if (type == typeof(void))
|
if (type == typeof(void))
|
||||||
sb.Append("void");
|
sb.Append("void");
|
||||||
|
else if (type == typeof(bool))
|
||||||
|
sb.Append("bool");
|
||||||
|
else if (type == typeof(byte))
|
||||||
|
sb.Append("byte");
|
||||||
|
else if (type == typeof(sbyte))
|
||||||
|
sb.Append("sbyte");
|
||||||
|
else if (type == typeof(char))
|
||||||
|
sb.Append("char");
|
||||||
|
else if (type == typeof(decimal))
|
||||||
|
sb.Append("decimal");
|
||||||
|
else if (type == typeof(double))
|
||||||
|
sb.Append("double");
|
||||||
|
else if (type == typeof(float))
|
||||||
|
sb.Append("float");
|
||||||
|
else if (type == typeof(int))
|
||||||
|
sb.Append("int");
|
||||||
|
else if (type == typeof(uint))
|
||||||
|
sb.Append("uint");
|
||||||
|
else if (type == typeof(nint))
|
||||||
|
sb.Append("nint");
|
||||||
|
else if (type == typeof(nuint))
|
||||||
|
sb.Append("nuint");
|
||||||
|
else if (type == typeof(long))
|
||||||
|
sb.Append("long");
|
||||||
|
else if (type == typeof(ulong))
|
||||||
|
sb.Append("ulong");
|
||||||
|
else if (type == typeof(short))
|
||||||
|
sb.Append("short");
|
||||||
|
else if (type == typeof(ushort))
|
||||||
|
sb.Append("ushort");
|
||||||
|
else if (type == typeof(object))
|
||||||
|
sb.Append("object");
|
||||||
|
else if (type == typeof(string))
|
||||||
|
sb.Append("string");
|
||||||
else
|
else
|
||||||
sb.Append(type);
|
sb.Append(type);
|
||||||
|
|
||||||
sb.Append(' ');
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal static void InstallTraceListener()
|
internal static void InstallTraceListener()
|
||||||
@@ -70,13 +102,26 @@ namespace Godot
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal static unsafe StackFrame? GetCurrentStackFrame(int skipFrames = 0)
|
||||||
|
{
|
||||||
|
// We skip 2 frames:
|
||||||
|
// The first skipped frame is the current method.
|
||||||
|
// The second skipped frame is a method in NativeInterop.NativeFuncs.
|
||||||
|
var stackTrace = new StackTrace(skipFrames: 2 + skipFrames, fNeedFileInfo: true);
|
||||||
|
return stackTrace.GetFrame(0);
|
||||||
|
}
|
||||||
|
|
||||||
[UnmanagedCallersOnly]
|
[UnmanagedCallersOnly]
|
||||||
internal static unsafe void GetCurrentStackInfo(void* destVector)
|
internal static unsafe void GetCurrentStackInfo(void* destVector)
|
||||||
{
|
{
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
var vector = (godot_stack_info_vector*)destVector;
|
var vector = (godot_stack_info_vector*)destVector;
|
||||||
var stackTrace = new StackTrace(skipFrames: 1, fNeedFileInfo: true);
|
|
||||||
|
// We skip 2 frames:
|
||||||
|
// The first skipped frame is the current method.
|
||||||
|
// The second skipped frame is a method in NativeInterop.NativeFuncs.
|
||||||
|
var stackTrace = new StackTrace(skipFrames: 2, fNeedFileInfo: true);
|
||||||
int frameCount = stackTrace.FrameCount;
|
int frameCount = stackTrace.FrameCount;
|
||||||
|
|
||||||
if (frameCount == 0)
|
if (frameCount == 0)
|
||||||
@@ -87,6 +132,14 @@ namespace Godot
|
|||||||
int i = 0;
|
int i = 0;
|
||||||
foreach (StackFrame frame in stackTrace.GetFrames())
|
foreach (StackFrame frame in stackTrace.GetFrames())
|
||||||
{
|
{
|
||||||
|
var method = frame.GetMethod();
|
||||||
|
|
||||||
|
if (method is MethodInfo methodInfo && methodInfo.IsDefined(typeof(StackTraceHiddenAttribute)))
|
||||||
|
{
|
||||||
|
// Skip methods marked hidden from the stack trace.
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
string? fileName = frame.GetFileName();
|
string? fileName = frame.GetFileName();
|
||||||
int fileLineNumber = frame.GetFileLineNumber();
|
int fileLineNumber = frame.GetFileLineNumber();
|
||||||
|
|
||||||
@@ -102,6 +155,9 @@ namespace Godot
|
|||||||
|
|
||||||
i++;
|
i++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Resize the vector again in case we skipped some frames.
|
||||||
|
vector->Resize(i);
|
||||||
}
|
}
|
||||||
catch (Exception e)
|
catch (Exception e)
|
||||||
{
|
{
|
||||||
@@ -122,7 +178,10 @@ namespace Godot
|
|||||||
var sb = new StringBuilder();
|
var sb = new StringBuilder();
|
||||||
|
|
||||||
if (methodBase is MethodInfo methodInfo)
|
if (methodBase is MethodInfo methodInfo)
|
||||||
|
{
|
||||||
sb.AppendTypeName(methodInfo.ReturnType);
|
sb.AppendTypeName(methodInfo.ReturnType);
|
||||||
|
sb.Append(' ');
|
||||||
|
}
|
||||||
|
|
||||||
sb.Append(methodBase.DeclaringType?.FullName ?? "<unknown>");
|
sb.Append(methodBase.DeclaringType?.FullName ?? "<unknown>");
|
||||||
sb.Append('.');
|
sb.Append('.');
|
||||||
|
|||||||
@@ -1,5 +1,6 @@
|
|||||||
using System;
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
|
using System.Diagnostics;
|
||||||
using System.Text;
|
using System.Text;
|
||||||
using Godot.NativeInterop;
|
using Godot.NativeInterop;
|
||||||
|
|
||||||
@@ -334,6 +335,21 @@ namespace Godot
|
|||||||
NativeFuncs.godotsharp_printt(godotStr);
|
NativeFuncs.godotsharp_printt(godotStr);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[StackTraceHidden]
|
||||||
|
private static void ErrPrintError(string message, godot_error_handler_type type = godot_error_handler_type.ERR_HANDLER_ERROR)
|
||||||
|
{
|
||||||
|
// Skip 1 frame to avoid current method.
|
||||||
|
var stackFrame = DebuggingUtils.GetCurrentStackFrame(skipFrames: 1);
|
||||||
|
string callerFilePath = ProjectSettings.LocalizePath(stackFrame.GetFileName());
|
||||||
|
DebuggingUtils.GetStackFrameMethodDecl(stackFrame, out string callerName);
|
||||||
|
int callerLineNumber = stackFrame.GetFileLineNumber();
|
||||||
|
|
||||||
|
using godot_string messageStr = Marshaling.ConvertStringToNative(message);
|
||||||
|
using godot_string callerNameStr = Marshaling.ConvertStringToNative(callerName);
|
||||||
|
using godot_string callerFilePathStr = Marshaling.ConvertStringToNative(callerFilePath);
|
||||||
|
NativeFuncs.godotsharp_err_print_error(callerNameStr, callerFilePathStr, callerLineNumber, messageStr, p_type: type);
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Pushes an error message to Godot's built-in debugger and to the OS terminal.
|
/// Pushes an error message to Godot's built-in debugger and to the OS terminal.
|
||||||
///
|
///
|
||||||
@@ -347,8 +363,7 @@ namespace Godot
|
|||||||
/// <param name="message">Error message.</param>
|
/// <param name="message">Error message.</param>
|
||||||
public static void PushError(string message)
|
public static void PushError(string message)
|
||||||
{
|
{
|
||||||
using var godotStr = Marshaling.ConvertStringToNative(message);
|
ErrPrintError(message);
|
||||||
NativeFuncs.godotsharp_pusherror(godotStr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -364,7 +379,7 @@ namespace Godot
|
|||||||
/// <param name="what">Arguments that form the error message.</param>
|
/// <param name="what">Arguments that form the error message.</param>
|
||||||
public static void PushError(params object[] what)
|
public static void PushError(params object[] what)
|
||||||
{
|
{
|
||||||
PushError(AppendPrintParams(what));
|
ErrPrintError(AppendPrintParams(what));
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -378,8 +393,7 @@ namespace Godot
|
|||||||
/// <param name="message">Warning message.</param>
|
/// <param name="message">Warning message.</param>
|
||||||
public static void PushWarning(string message)
|
public static void PushWarning(string message)
|
||||||
{
|
{
|
||||||
using var godotStr = Marshaling.ConvertStringToNative(message);
|
ErrPrintError(message, type: godot_error_handler_type.ERR_HANDLER_WARNING);
|
||||||
NativeFuncs.godotsharp_pushwarning(godotStr);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
@@ -393,7 +407,7 @@ namespace Godot
|
|||||||
/// <param name="what">Arguments that form the warning message.</param>
|
/// <param name="what">Arguments that form the warning message.</param>
|
||||||
public static void PushWarning(params object[] what)
|
public static void PushWarning(params object[] what)
|
||||||
{
|
{
|
||||||
PushWarning(AppendPrintParams(what));
|
ErrPrintError(AppendPrintParams(what), type: godot_error_handler_type.ERR_HANDLER_WARNING);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
|
|||||||
@@ -95,7 +95,7 @@ namespace Godot.NativeInterop
|
|||||||
}
|
}
|
||||||
|
|
||||||
NativeFuncs.godotsharp_internal_script_debugger_send_error(nFunc, nFile, line,
|
NativeFuncs.godotsharp_internal_script_debugger_send_error(nFunc, nFile, line,
|
||||||
nErrorMsg, nExcMsg, p_warning: godot_bool.False, stackInfoVector);
|
nErrorMsg, nExcMsg, godot_error_handler_type.ERR_HANDLER_ERROR, stackInfoVector);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -1134,4 +1134,13 @@ namespace Godot.NativeInterop
|
|||||||
get => _ptr != null ? *((int*)_ptr - 1) : 0;
|
get => _ptr != null ? *((int*)_ptr - 1) : 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
[SuppressMessage("ReSharper", "InconsistentNaming")]
|
||||||
|
public enum godot_error_handler_type
|
||||||
|
{
|
||||||
|
ERR_HANDLER_ERROR = 0,
|
||||||
|
ERR_HANDLER_WARNING,
|
||||||
|
ERR_HANDLER_SCRIPT,
|
||||||
|
ERR_HANDLER_SHADER,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -58,7 +58,7 @@ namespace Godot.NativeInterop
|
|||||||
|
|
||||||
internal static partial void godotsharp_internal_script_debugger_send_error(in godot_string p_func,
|
internal static partial void godotsharp_internal_script_debugger_send_error(in godot_string p_func,
|
||||||
in godot_string p_file, int p_line, in godot_string p_err, in godot_string p_descr,
|
in godot_string p_file, int p_line, in godot_string p_err, in godot_string p_descr,
|
||||||
godot_bool p_warning, in DebuggingUtils.godot_stack_info_vector p_stack_info_vector);
|
godot_error_handler_type p_type, in DebuggingUtils.godot_stack_info_vector p_stack_info_vector);
|
||||||
|
|
||||||
internal static partial godot_bool godotsharp_internal_script_debugger_is_active();
|
internal static partial godot_bool godotsharp_internal_script_debugger_is_active();
|
||||||
|
|
||||||
@@ -540,9 +540,7 @@ namespace Godot.NativeInterop
|
|||||||
|
|
||||||
internal static partial void godotsharp_var_to_str(in godot_variant p_var, out godot_string r_ret);
|
internal static partial void godotsharp_var_to_str(in godot_variant p_var, out godot_string r_ret);
|
||||||
|
|
||||||
internal static partial void godotsharp_pusherror(in godot_string p_str);
|
internal static partial void godotsharp_err_print_error(in godot_string p_function, in godot_string p_file, int p_line, in godot_string p_error, in godot_string p_message = default, godot_bool p_editor_notify = godot_bool.False, godot_error_handler_type p_type = godot_error_handler_type.ERR_HANDLER_ERROR);
|
||||||
|
|
||||||
internal static partial void godotsharp_pushwarning(in godot_string p_str);
|
|
||||||
|
|
||||||
// Object
|
// Object
|
||||||
|
|
||||||
|
|||||||
@@ -92,10 +92,10 @@ void godotsharp_stack_info_vector_destroy(
|
|||||||
|
|
||||||
void godotsharp_internal_script_debugger_send_error(const String *p_func,
|
void godotsharp_internal_script_debugger_send_error(const String *p_func,
|
||||||
const String *p_file, int32_t p_line, const String *p_err, const String *p_descr,
|
const String *p_file, int32_t p_line, const String *p_err, const String *p_descr,
|
||||||
bool p_warning, const Vector<ScriptLanguage::StackInfo> *p_stack_info_vector) {
|
ErrorHandlerType p_type, const Vector<ScriptLanguage::StackInfo> *p_stack_info_vector) {
|
||||||
const String file = ProjectSettings::get_singleton()->localize_path(p_file->simplify_path());
|
const String file = ProjectSettings::get_singleton()->localize_path(p_file->simplify_path());
|
||||||
EngineDebugger::get_script_debugger()->send_error(*p_func, file, p_line, *p_err, *p_descr,
|
EngineDebugger::get_script_debugger()->send_error(*p_func, file, p_line, *p_err, *p_descr,
|
||||||
true, p_warning ? ERR_HANDLER_WARNING : ERR_HANDLER_ERROR, *p_stack_info_vector);
|
true, p_type, *p_stack_info_vector);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool godotsharp_internal_script_debugger_is_active() {
|
bool godotsharp_internal_script_debugger_is_active() {
|
||||||
@@ -1320,12 +1320,14 @@ void godotsharp_printraw(const godot_string *p_what) {
|
|||||||
OS::get_singleton()->print("%s", reinterpret_cast<const String *>(p_what)->utf8().get_data());
|
OS::get_singleton()->print("%s", reinterpret_cast<const String *>(p_what)->utf8().get_data());
|
||||||
}
|
}
|
||||||
|
|
||||||
void godotsharp_pusherror(const godot_string *p_str) {
|
void godotsharp_err_print_error(const godot_string *p_function, const godot_string *p_file, int32_t p_line, const godot_string *p_error, const godot_string *p_message, bool p_editor_notify, ErrorHandlerType p_type) {
|
||||||
ERR_PRINT(*reinterpret_cast<const String *>(p_str));
|
_err_print_error(
|
||||||
}
|
reinterpret_cast<const String *>(p_function)->utf8().get_data(),
|
||||||
|
reinterpret_cast<const String *>(p_file)->utf8().get_data(),
|
||||||
void godotsharp_pushwarning(const godot_string *p_str) {
|
p_line,
|
||||||
WARN_PRINT(*reinterpret_cast<const String *>(p_str));
|
reinterpret_cast<const String *>(p_error)->utf8().get_data(),
|
||||||
|
reinterpret_cast<const String *>(p_message)->utf8().get_data(),
|
||||||
|
p_editor_notify, p_type);
|
||||||
}
|
}
|
||||||
|
|
||||||
void godotsharp_var_to_str(const godot_variant *p_var, godot_string *r_ret) {
|
void godotsharp_var_to_str(const godot_variant *p_var, godot_string *r_ret) {
|
||||||
@@ -1611,8 +1613,7 @@ static const void *unmanaged_callbacks[]{
|
|||||||
(void *)godotsharp_str_to_var,
|
(void *)godotsharp_str_to_var,
|
||||||
(void *)godotsharp_var_to_bytes,
|
(void *)godotsharp_var_to_bytes,
|
||||||
(void *)godotsharp_var_to_str,
|
(void *)godotsharp_var_to_str,
|
||||||
(void *)godotsharp_pusherror,
|
(void *)godotsharp_err_print_error,
|
||||||
(void *)godotsharp_pushwarning,
|
|
||||||
(void *)godotsharp_object_to_string,
|
(void *)godotsharp_object_to_string,
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user