Fix Callable call error reporting.
* Fix potential crash when using bind in `Variant::get_callable_error_text()` * Properly compute bound arguments so they can be properly shown. * Add a function to obtain the actual bound arguments.
This commit is contained in:
parent
91713ced81
commit
33d3b7eea7
8 changed files with 108 additions and 2 deletions
|
@ -1055,7 +1055,7 @@ Error Object::emit_signalp(const StringName &p_name, const Variant **p_args, int
|
|||
if (ce.error == Callable::CallError::CALL_ERROR_INVALID_METHOD && !ClassDB::class_exists(target->get_class_name())) {
|
||||
//most likely object is not initialized yet, do not throw error.
|
||||
} else {
|
||||
ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc + c.callable.get_bound_arguments_count(), ce) + ".");
|
||||
ERR_PRINT("Error calling from signal '" + String(p_name) + "' to callable: " + Variant::get_callable_error_text(c.callable, args, argc, ce) + ".");
|
||||
err = ERR_METHOD_NOT_FOUND;
|
||||
}
|
||||
}
|
||||
|
|
|
@ -117,6 +117,7 @@ Callable Callable::bindv(const Array &p_arguments) {
|
|||
}
|
||||
|
||||
Callable Callable::unbind(int p_argcount) const {
|
||||
ERR_FAIL_COND_V_MSG(p_argcount <= 0, Callable(*this), "Amount of unbind() arguments must be 1 or greater.");
|
||||
return Callable(memnew(CallableCustomUnbind(*this, p_argcount)));
|
||||
}
|
||||
|
||||
|
@ -159,6 +160,27 @@ int Callable::get_bound_arguments_count() const {
|
|||
}
|
||||
}
|
||||
|
||||
void Callable::get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const {
|
||||
if (!is_null() && is_custom()) {
|
||||
custom->get_bound_arguments(r_arguments, r_argcount);
|
||||
} else {
|
||||
r_arguments.clear();
|
||||
r_argcount = 0;
|
||||
}
|
||||
}
|
||||
|
||||
Array Callable::get_bound_arguments() const {
|
||||
Vector<Variant> arr;
|
||||
int ac;
|
||||
get_bound_arguments_ref(arr, ac);
|
||||
Array ret;
|
||||
ret.resize(arr.size());
|
||||
for (int i = 0; i < arr.size(); i++) {
|
||||
ret[i] = arr[i];
|
||||
}
|
||||
return ret;
|
||||
}
|
||||
|
||||
CallableCustom *Callable::get_custom() const {
|
||||
ERR_FAIL_COND_V_MSG(!is_custom(), nullptr,
|
||||
vformat("Can't get custom on non-CallableCustom \"%s\".", operator String()));
|
||||
|
@ -370,6 +392,11 @@ int CallableCustom::get_bound_arguments_count() const {
|
|||
return 0;
|
||||
}
|
||||
|
||||
void CallableCustom::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
|
||||
r_arguments = Vector<Variant>();
|
||||
r_argcount = 0;
|
||||
}
|
||||
|
||||
CallableCustom::CallableCustom() {
|
||||
ref_count.init();
|
||||
}
|
||||
|
|
|
@ -108,6 +108,8 @@ public:
|
|||
StringName get_method() const;
|
||||
CallableCustom *get_custom() const;
|
||||
int get_bound_arguments_count() const;
|
||||
void get_bound_arguments_ref(Vector<Variant> &r_arguments, int &r_argcount) const; // Internal engine use, the exposed one is below.
|
||||
Array get_bound_arguments() const;
|
||||
|
||||
uint32_t hash() const;
|
||||
|
||||
|
@ -149,6 +151,7 @@ public:
|
|||
virtual Error rpc(int p_peer_id, const Variant **p_arguments, int p_argcount, Callable::CallError &r_call_error) const;
|
||||
virtual const Callable *get_base_comparator() const;
|
||||
virtual int get_bound_arguments_count() const;
|
||||
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const;
|
||||
|
||||
CallableCustom();
|
||||
virtual ~CallableCustom() {}
|
||||
|
|
|
@ -91,6 +91,43 @@ int CallableCustomBind::get_bound_arguments_count() const {
|
|||
return callable.get_bound_arguments_count() + binds.size();
|
||||
}
|
||||
|
||||
void CallableCustomBind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
|
||||
Vector<Variant> sub_args;
|
||||
int sub_count;
|
||||
callable.get_bound_arguments_ref(sub_args, sub_count);
|
||||
|
||||
if (sub_count == 0) {
|
||||
r_arguments = binds;
|
||||
r_argcount = binds.size();
|
||||
return;
|
||||
}
|
||||
|
||||
int new_count = sub_count + binds.size();
|
||||
r_argcount = new_count;
|
||||
|
||||
if (new_count <= 0) {
|
||||
// Removed more arguments than it adds.
|
||||
r_arguments = Vector<Variant>();
|
||||
return;
|
||||
}
|
||||
|
||||
r_arguments.resize(new_count);
|
||||
|
||||
if (sub_count > 0) {
|
||||
for (int i = 0; i < sub_count; i++) {
|
||||
r_arguments.write[i] = sub_args[i];
|
||||
}
|
||||
for (int i = 0; i < binds.size(); i++) {
|
||||
r_arguments.write[i + sub_count] = binds[i];
|
||||
}
|
||||
r_argcount = new_count;
|
||||
} else {
|
||||
for (int i = 0; i < binds.size() + sub_count; i++) {
|
||||
r_arguments.write[i] = binds[i - sub_count];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CallableCustomBind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
|
||||
const Variant **args = (const Variant **)alloca(sizeof(const Variant **) * (binds.size() + p_argcount));
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
|
@ -172,6 +209,21 @@ int CallableCustomUnbind::get_bound_arguments_count() const {
|
|||
return callable.get_bound_arguments_count() - argcount;
|
||||
}
|
||||
|
||||
void CallableCustomUnbind::get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const {
|
||||
Vector<Variant> sub_args;
|
||||
int sub_count;
|
||||
callable.get_bound_arguments_ref(sub_args, sub_count);
|
||||
|
||||
r_argcount = sub_args.size() - argcount;
|
||||
|
||||
if (argcount >= sub_args.size()) {
|
||||
r_arguments = Vector<Variant>();
|
||||
} else {
|
||||
sub_args.resize(sub_args.size() - argcount);
|
||||
r_arguments = sub_args;
|
||||
}
|
||||
}
|
||||
|
||||
void CallableCustomUnbind::call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
|
||||
if (argcount > p_argcount) {
|
||||
r_call_error.error = Callable::CallError::CALL_ERROR_TOO_FEW_ARGUMENTS;
|
||||
|
|
|
@ -52,6 +52,7 @@ public:
|
|||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||
virtual const Callable *get_base_comparator() const override;
|
||||
virtual int get_bound_arguments_count() const override;
|
||||
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
|
||||
Callable get_callable() { return callable; }
|
||||
Vector<Variant> get_binds() { return binds; }
|
||||
|
||||
|
@ -77,6 +78,7 @@ public:
|
|||
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override;
|
||||
virtual const Callable *get_base_comparator() const override;
|
||||
virtual int get_bound_arguments_count() const override;
|
||||
virtual void get_bound_arguments(Vector<Variant> &r_arguments, int &r_argcount) const override;
|
||||
|
||||
Callable get_callable() { return callable; }
|
||||
int get_unbinds() { return argcount; }
|
||||
|
|
|
@ -3654,7 +3654,22 @@ String Variant::get_call_error_text(Object *p_base, const StringName &p_method,
|
|||
}
|
||||
|
||||
String Variant::get_callable_error_text(const Callable &p_callable, const Variant **p_argptrs, int p_argcount, const Callable::CallError &ce) {
|
||||
return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, p_argcount, ce);
|
||||
Vector<Variant> binds;
|
||||
int args_bound;
|
||||
p_callable.get_bound_arguments_ref(binds, args_bound);
|
||||
if (args_bound <= 0) {
|
||||
return get_call_error_text(p_callable.get_object(), p_callable.get_method(), p_argptrs, MAX(0, p_argcount + args_bound), ce);
|
||||
} else {
|
||||
Vector<const Variant *> argptrs;
|
||||
argptrs.resize(p_argcount + binds.size());
|
||||
for (int i = 0; i < p_argcount; i++) {
|
||||
argptrs.write[i] = p_argptrs[i];
|
||||
}
|
||||
for (int i = 0; i < binds.size(); i++) {
|
||||
argptrs.write[i + p_argcount] = &binds[i];
|
||||
}
|
||||
return get_call_error_text(p_callable.get_object(), p_callable.get_method(), (const Variant **)argptrs.ptr(), argptrs.size(), ce);
|
||||
}
|
||||
}
|
||||
|
||||
void Variant::register_types() {
|
||||
|
|
|
@ -2017,6 +2017,7 @@ static void _register_variant_builtin_methods() {
|
|||
bind_method(Callable, get_object_id, sarray(), varray());
|
||||
bind_method(Callable, get_method, sarray(), varray());
|
||||
bind_method(Callable, get_bound_arguments_count, sarray(), varray());
|
||||
bind_method(Callable, get_bound_arguments, sarray(), varray());
|
||||
bind_method(Callable, hash, sarray(), varray());
|
||||
bind_method(Callable, bindv, sarray("arguments"), varray());
|
||||
bind_method(Callable, unbind, sarray("argcount"), varray());
|
||||
|
|
|
@ -107,6 +107,12 @@
|
|||
Calls the method represented by this [Callable]. Unlike [method call], this method expects all arguments to be contained inside the [param arguments] [Array].
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_bound_arguments" qualifiers="const">
|
||||
<return type="Array" />
|
||||
<description>
|
||||
Return the bound arguments (as long as [method get_bound_arguments_count] is greater than zero), or empty (if [method get_bound_arguments_count] is less than or equal to zero).
|
||||
</description>
|
||||
</method>
|
||||
<method name="get_bound_arguments_count" qualifiers="const">
|
||||
<return type="int" />
|
||||
<description>
|
||||
|
|
Loading…
Reference in a new issue