mirror of
https://github.com/godotengine/godot.git
synced 2024-11-25 21:52:51 +00:00
Merge pull request #79249 from raulsntos/dotnet/dont-ignore-call-error
C#: Print error when MethodBind/Callable call fails
This commit is contained in:
commit
ed301a4078
@ -2128,6 +2128,11 @@ Error BindingsGenerator::_generate_cs_method(const BindingsGenerator::TypeInterf
|
||||
cs_in_expr_is_unsafe |= arg_type->cs_in_expr_is_unsafe;
|
||||
}
|
||||
|
||||
// Collect caller name for MethodBind
|
||||
if (p_imethod.is_vararg) {
|
||||
icall_params += ", (godot_string_name)MethodName." + p_imethod.proxy_name + ".NativeValue";
|
||||
}
|
||||
|
||||
// Generate method
|
||||
{
|
||||
if (!p_imethod.is_virtual && !p_imethod.requires_object_call) {
|
||||
@ -2501,6 +2506,11 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
|
||||
i++;
|
||||
}
|
||||
|
||||
// Collect caller name for MethodBind
|
||||
if (p_icall.is_vararg) {
|
||||
c_func_sig << ", godot_string_name caller";
|
||||
}
|
||||
|
||||
String icall_method = p_icall.name;
|
||||
|
||||
// Generate icall function
|
||||
@ -2566,7 +2576,12 @@ Error BindingsGenerator::_generate_cs_native_calls(const InternalCall &p_icall,
|
||||
r_output << C_CLASS_NATIVE_FUNCS ".godotsharp_method_bind_call("
|
||||
<< CS_PARAM_METHODBIND ", " << (p_icall.is_static ? "IntPtr.Zero" : CS_PARAM_INSTANCE)
|
||||
<< ", " << (p_icall.get_arguments_count() ? "(godot_variant**)" C_LOCAL_PTRCALL_ARGS : "null")
|
||||
<< ", total_length, out _);\n";
|
||||
<< ", total_length, out godot_variant_call_error vcall_error);\n";
|
||||
|
||||
r_output << base_indent << "ExceptionUtils.DebugCheckCallError(caller"
|
||||
<< ", " << (p_icall.is_static ? "IntPtr.Zero" : CS_PARAM_INSTANCE)
|
||||
<< ", " << (p_icall.get_arguments_count() ? "(godot_variant**)" C_LOCAL_PTRCALL_ARGS : "null")
|
||||
<< ", total_length, vcall_error);\n";
|
||||
|
||||
if (!ret_void) {
|
||||
if (return_type->cname != name_cache.type_Variant) {
|
||||
|
@ -109,7 +109,8 @@ namespace Godot
|
||||
}
|
||||
|
||||
godot_variant ret = NativeFuncs.godotsharp_callable_call(callable,
|
||||
(godot_variant**)argsPtr, argc, out _);
|
||||
(godot_variant**)argsPtr, argc, out godot_variant_call_error vcall_error);
|
||||
ExceptionUtils.DebugCheckCallError(callable, (godot_variant**)argsPtr, argc, vcall_error);
|
||||
return Variant.CreateTakingOwnershipOfDisposableValue(ret);
|
||||
}
|
||||
}
|
||||
|
@ -135,5 +135,109 @@ namespace Godot.NativeInterop
|
||||
OnExceptionLoggerException(unexpected, e);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public unsafe static void DebugCheckCallError(godot_string_name method, IntPtr instance, godot_variant** args, int argCount, godot_variant_call_error error)
|
||||
{
|
||||
if (error.Error != godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_OK)
|
||||
{
|
||||
using godot_variant instanceVariant = VariantUtils.CreateFromGodotObjectPtr(instance);
|
||||
string where = GetCallErrorWhere(method, &instanceVariant, args, argCount);
|
||||
string errorText = GetCallErrorMessage(error, where, args);
|
||||
GD.PushError(errorText);
|
||||
}
|
||||
}
|
||||
|
||||
[Conditional("DEBUG")]
|
||||
public unsafe static void DebugCheckCallError(in godot_callable callable, godot_variant** args, int argCount, godot_variant_call_error error)
|
||||
{
|
||||
if (error.Error != godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_OK)
|
||||
{
|
||||
using godot_variant callableVariant = VariantUtils.CreateFromCallableTakingOwnershipOfDisposableValue(callable);
|
||||
string where = $"callable '{VariantUtils.ConvertToString(callableVariant)}'";
|
||||
string errorText = GetCallErrorMessage(error, where, args);
|
||||
GD.PushError(errorText);
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe static string GetCallErrorWhere(godot_string_name method, godot_variant* instance, godot_variant** args, int argCount)
|
||||
{
|
||||
string? methodstr = null;
|
||||
string basestr = GetVariantTypeName(instance);
|
||||
|
||||
if (method == GodotObject.MethodName.Call || (basestr == "Godot.TreeItem" && method == TreeItem.MethodName.CallRecursive))
|
||||
{
|
||||
if (argCount >= 1)
|
||||
{
|
||||
methodstr = VariantUtils.ConvertToString(*args[0]);
|
||||
}
|
||||
}
|
||||
|
||||
if (string.IsNullOrEmpty(methodstr))
|
||||
{
|
||||
methodstr = StringName.CreateTakingOwnershipOfDisposableValue(method);
|
||||
}
|
||||
|
||||
return $"function '{methodstr}' in base '{basestr}'";
|
||||
}
|
||||
|
||||
private unsafe static string GetCallErrorMessage(godot_variant_call_error error, string where, godot_variant** args)
|
||||
{
|
||||
switch (error.Error)
|
||||
{
|
||||
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_ARGUMENT:
|
||||
{
|
||||
int errorarg = error.Argument;
|
||||
// Handle the Object to Object case separately as we don't have further class details.
|
||||
#if DEBUG
|
||||
if (error.Expected == Variant.Type.Object && args[errorarg]->Type == error.Expected)
|
||||
{
|
||||
return $"Invalid type in {where}. The Object-derived class of argument {errorarg + 1} (" + GetVariantTypeName(args[errorarg]) + ") is not a subclass of the expected argument class.";
|
||||
}
|
||||
else if (error.Expected == Variant.Type.Array && args[errorarg]->Type == error.Expected)
|
||||
{
|
||||
return $"Invalid type in {where}. The array of argument {errorarg + 1} (" + GetVariantTypeName(args[errorarg]) + ") does not have the same element type as the expected typed array argument.";
|
||||
}
|
||||
else
|
||||
#endif
|
||||
{
|
||||
return $"Invalid type in {where}. Cannot convert argument {errorarg + 1} from {args[errorarg]->Type} to {error.Expected}.";
|
||||
}
|
||||
}
|
||||
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_TOO_MANY_ARGUMENTS:
|
||||
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_TOO_FEW_ARGUMENTS:
|
||||
return $"Invalid call to {where}. Expected {error.Argument} arguments.";
|
||||
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INVALID_METHOD:
|
||||
return $"Invalid call. Nonexistent {where}.";
|
||||
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL:
|
||||
return $"Attempt to call {where} on a null instance.";
|
||||
case godot_variant_call_error_error.GODOT_CALL_ERROR_CALL_ERROR_METHOD_NOT_CONST:
|
||||
return $"Attempt to call {where} on a const instance.";
|
||||
default:
|
||||
return $"Bug, call error: #{error.Error}";
|
||||
}
|
||||
}
|
||||
|
||||
private unsafe static string GetVariantTypeName(godot_variant* variant)
|
||||
{
|
||||
if (variant->Type == Variant.Type.Object)
|
||||
{
|
||||
GodotObject obj = VariantUtils.ConvertToGodotObject(*variant);
|
||||
if (obj == null)
|
||||
{
|
||||
return "null instance";
|
||||
}
|
||||
else if (!GodotObject.IsInstanceValid(obj))
|
||||
{
|
||||
return "previously freed";
|
||||
}
|
||||
else
|
||||
{
|
||||
return obj.GetType().ToString();
|
||||
}
|
||||
}
|
||||
|
||||
return variant->Type.ToString();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -71,6 +71,7 @@ namespace Godot.NativeInterop
|
||||
GODOT_CALL_ERROR_CALL_ERROR_TOO_MANY_ARGUMENTS,
|
||||
GODOT_CALL_ERROR_CALL_ERROR_TOO_FEW_ARGUMENTS,
|
||||
GODOT_CALL_ERROR_CALL_ERROR_INSTANCE_IS_NULL,
|
||||
GODOT_CALL_ERROR_CALL_ERROR_METHOD_NOT_CONST,
|
||||
}
|
||||
|
||||
[StructLayout(LayoutKind.Sequential)]
|
||||
|
Loading…
Reference in New Issue
Block a user