Skip to content

Commit a1c476f

Browse files
committed
Merge pull request #87680 from AThousandShips/the_angry_count
Add methods to get argument count of methods
2 parents 89ba617 + 59bcc28 commit a1c476f

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

50 files changed

+821
-3
lines changed

core/core_bind.cpp

+6
Original file line numberDiff line numberDiff line change
@@ -1434,6 +1434,10 @@ bool ClassDB::class_has_method(const StringName &p_class, const StringName &p_me
14341434
return ::ClassDB::has_method(p_class, p_method, p_no_inheritance);
14351435
}
14361436

1437+
int ClassDB::class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance) const {
1438+
return ::ClassDB::get_method_argument_count(p_class, p_method, nullptr, p_no_inheritance);
1439+
}
1440+
14371441
TypedArray<Dictionary> ClassDB::class_get_method_list(const StringName &p_class, bool p_no_inheritance) const {
14381442
List<MethodInfo> methods;
14391443
::ClassDB::get_method_list(p_class, &methods, p_no_inheritance);
@@ -1562,6 +1566,8 @@ void ClassDB::_bind_methods() {
15621566

15631567
::ClassDB::bind_method(D_METHOD("class_has_method", "class", "method", "no_inheritance"), &ClassDB::class_has_method, DEFVAL(false));
15641568

1569+
::ClassDB::bind_method(D_METHOD("class_get_method_argument_count", "class", "method", "no_inheritance"), &ClassDB::class_get_method_argument_count, DEFVAL(false));
1570+
15651571
::ClassDB::bind_method(D_METHOD("class_get_method_list", "class", "no_inheritance"), &ClassDB::class_get_method_list, DEFVAL(false));
15661572

15671573
::ClassDB::bind_method(D_METHOD("class_get_integer_constant_list", "class", "no_inheritance"), &ClassDB::class_get_integer_constant_list, DEFVAL(false));

core/core_bind.h

+2
Original file line numberDiff line numberDiff line change
@@ -447,6 +447,8 @@ class ClassDB : public Object {
447447

448448
bool class_has_method(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
449449

450+
int class_get_method_argument_count(const StringName &p_class, const StringName &p_method, bool p_no_inheritance = false) const;
451+
450452
TypedArray<Dictionary> class_get_method_list(const StringName &p_class, bool p_no_inheritance = false) const;
451453

452454
PackedStringArray class_get_integer_constant_list(const StringName &p_class, bool p_no_inheritance = false) const;

core/extension/gdextension_interface.cpp

+56
Original file line numberDiff line numberDiff line change
@@ -59,6 +59,8 @@ class CallableCustomExtension : public CallableCustom {
5959

6060
GDExtensionCallableCustomToString to_string_func;
6161

62+
GDExtensionCallableCustomGetArgumentCount get_argument_count_func;
63+
6264
uint32_t _hash;
6365

6466
static bool default_compare_equal(const CallableCustom *p_a, const CallableCustom *p_b) {
@@ -143,6 +145,21 @@ class CallableCustomExtension : public CallableCustom {
143145
return object;
144146
}
145147

148+
int get_argument_count(bool &r_is_valid) const override {
149+
if (get_argument_count_func != nullptr) {
150+
GDExtensionBool is_valid = false;
151+
152+
GDExtensionInt ret = get_argument_count_func(userdata, &is_valid);
153+
154+
if (is_valid) {
155+
r_is_valid = true;
156+
return ret;
157+
}
158+
}
159+
r_is_valid = false;
160+
return 0;
161+
}
162+
146163
void *get_userdata(void *p_token) const {
147164
return (p_token == token) ? userdata : nullptr;
148165
}
@@ -157,6 +174,7 @@ class CallableCustomExtension : public CallableCustom {
157174
r_call_error.expected = error.expected;
158175
}
159176

177+
#ifndef DISABLE_DEPRECATED
160178
CallableCustomExtension(GDExtensionCallableCustomInfo *p_info) {
161179
userdata = p_info->callable_userdata;
162180
token = p_info->token;
@@ -172,6 +190,35 @@ class CallableCustomExtension : public CallableCustom {
172190

173191
to_string_func = p_info->to_string_func;
174192

193+
get_argument_count_func = nullptr;
194+
195+
// Pre-calculate the hash.
196+
if (p_info->hash_func != nullptr) {
197+
_hash = p_info->hash_func(userdata);
198+
} else {
199+
_hash = hash_murmur3_one_64((uint64_t)call_func);
200+
_hash = hash_murmur3_one_64((uint64_t)userdata, _hash);
201+
}
202+
}
203+
#endif
204+
205+
CallableCustomExtension(GDExtensionCallableCustomInfo2 *p_info) {
206+
userdata = p_info->callable_userdata;
207+
token = p_info->token;
208+
209+
object = p_info->object_id;
210+
211+
call_func = p_info->call_func;
212+
is_valid_func = p_info->is_valid_func;
213+
free_func = p_info->free_func;
214+
215+
equal_func = p_info->equal_func;
216+
less_than_func = p_info->less_than_func;
217+
218+
to_string_func = p_info->to_string_func;
219+
220+
get_argument_count_func = p_info->get_argument_count_func;
221+
175222
// Pre-calculate the hash.
176223
if (p_info->hash_func != nullptr) {
177224
_hash = p_info->hash_func(userdata);
@@ -1378,9 +1425,15 @@ static GDExtensionScriptInstancePtr gdextension_object_get_script_instance(GDExt
13781425
return script_instance_extension->instance;
13791426
}
13801427

1428+
#ifndef DISABLE_DEPRECATED
13811429
static void gdextension_callable_custom_create(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_custom_callable_info) {
13821430
memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info))));
13831431
}
1432+
#endif
1433+
1434+
static void gdextension_callable_custom_create2(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo2 *p_custom_callable_info) {
1435+
memnew_placement(r_callable, Callable(memnew(CallableCustomExtension(p_custom_callable_info))));
1436+
}
13841437

13851438
static void *gdextension_callable_custom_get_userdata(GDExtensionTypePtr p_callable, void *p_token) {
13861439
const Callable &callable = *reinterpret_cast<const Callable *>(p_callable);
@@ -1595,7 +1648,10 @@ void gdextension_setup_interface() {
15951648
REGISTER_INTERFACE_FUNC(placeholder_script_instance_create);
15961649
REGISTER_INTERFACE_FUNC(placeholder_script_instance_update);
15971650
REGISTER_INTERFACE_FUNC(object_get_script_instance);
1651+
#ifndef DISABLE_DEPRECATED
15981652
REGISTER_INTERFACE_FUNC(callable_custom_create);
1653+
#endif // DISABLE_DEPRECATED
1654+
REGISTER_INTERFACE_FUNC(callable_custom_create2);
15991655
REGISTER_INTERFACE_FUNC(callable_custom_get_userdata);
16001656
REGISTER_INTERFACE_FUNC(classdb_construct_object);
16011657
REGISTER_INTERFACE_FUNC(classdb_get_method_bind);

core/extension/gdextension_interface.h

+50-1
Original file line numberDiff line numberDiff line change
@@ -442,6 +442,8 @@ typedef GDExtensionBool (*GDExtensionCallableCustomLessThan)(void *callable_user
442442

443443
typedef void (*GDExtensionCallableCustomToString)(void *callable_userdata, GDExtensionBool *r_is_valid, GDExtensionStringPtr r_out);
444444

445+
typedef GDExtensionInt (*GDExtensionCallableCustomGetArgumentCount)(void *callable_userdata, GDExtensionBool *r_is_valid);
446+
445447
typedef struct {
446448
/* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method.
447449
*
@@ -471,7 +473,40 @@ typedef struct {
471473
GDExtensionCallableCustomLessThan less_than_func;
472474

473475
GDExtensionCallableCustomToString to_string_func;
474-
} GDExtensionCallableCustomInfo;
476+
} GDExtensionCallableCustomInfo; // Deprecated. Use GDExtensionCallableCustomInfo2 instead.
477+
478+
typedef struct {
479+
/* Only `call_func` and `token` are strictly required, however, `object_id` should be passed if its not a static method.
480+
*
481+
* `token` should point to an address that uniquely identifies the GDExtension (for example, the
482+
* `GDExtensionClassLibraryPtr` passed to the entry symbol function.
483+
*
484+
* `hash_func`, `equal_func`, and `less_than_func` are optional. If not provided both `call_func` and
485+
* `callable_userdata` together are used as the identity of the callable for hashing and comparison purposes.
486+
*
487+
* The hash returned by `hash_func` is cached, `hash_func` will not be called more than once per callable.
488+
*
489+
* `is_valid_func` is necessary if the validity of the callable can change before destruction.
490+
*
491+
* `free_func` is necessary if `callable_userdata` needs to be cleaned up when the callable is freed.
492+
*/
493+
void *callable_userdata;
494+
void *token;
495+
496+
GDObjectInstanceID object_id;
497+
498+
GDExtensionCallableCustomCall call_func;
499+
GDExtensionCallableCustomIsValid is_valid_func;
500+
GDExtensionCallableCustomFree free_func;
501+
502+
GDExtensionCallableCustomHash hash_func;
503+
GDExtensionCallableCustomEqual equal_func;
504+
GDExtensionCallableCustomLessThan less_than_func;
505+
506+
GDExtensionCallableCustomToString to_string_func;
507+
508+
GDExtensionCallableCustomGetArgumentCount get_argument_count_func;
509+
} GDExtensionCallableCustomInfo2;
475510

476511
/* SCRIPT INSTANCE EXTENSION */
477512

@@ -2510,6 +2545,7 @@ typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptIn
25102545
/**
25112546
* @name callable_custom_create
25122547
* @since 4.2
2548+
* @deprecated in Godot 4.3. Use `callable_custom_create2` instead.
25132549
*
25142550
* Creates a custom Callable object from a function pointer.
25152551
*
@@ -2520,6 +2556,19 @@ typedef GDExtensionScriptInstanceDataPtr (*GDExtensionInterfaceObjectGetScriptIn
25202556
*/
25212557
typedef void (*GDExtensionInterfaceCallableCustomCreate)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo *p_callable_custom_info);
25222558

2559+
/**
2560+
* @name callable_custom_create2
2561+
* @since 4.3
2562+
*
2563+
* Creates a custom Callable object from a function pointer.
2564+
*
2565+
* Provided struct can be safely freed once the function returns.
2566+
*
2567+
* @param r_callable A pointer that will receive the new Callable.
2568+
* @param p_callable_custom_info The info required to construct a Callable.
2569+
*/
2570+
typedef void (*GDExtensionInterfaceCallableCustomCreate2)(GDExtensionUninitializedTypePtr r_callable, GDExtensionCallableCustomInfo2 *p_callable_custom_info);
2571+
25232572
/**
25242573
* @name callable_custom_get_userdata
25252574
* @since 4.2

core/object/callable_method_pointer.h

+25
Original file line numberDiff line numberDiff line change
@@ -93,6 +93,11 @@ class CallableCustomMethodPointer : public CallableCustomMethodPointerBase {
9393
return data.instance->get_instance_id();
9494
}
9595

96+
virtual int get_argument_count(bool &r_is_valid) const {
97+
r_is_valid = true;
98+
return sizeof...(P);
99+
}
100+
96101
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
97102
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
98103
call_with_variant_args(data.instance, data.method, p_arguments, p_argcount, r_call_error);
@@ -140,6 +145,11 @@ class CallableCustomMethodPointerRet : public CallableCustomMethodPointerBase {
140145
return data.instance->get_instance_id();
141146
}
142147

148+
virtual int get_argument_count(bool &r_is_valid) const {
149+
r_is_valid = true;
150+
return sizeof...(P);
151+
}
152+
143153
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const {
144154
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
145155
call_with_variant_args_ret(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
@@ -187,6 +197,11 @@ class CallableCustomMethodPointerRetC : public CallableCustomMethodPointerBase {
187197
return data.instance->get_instance_id();
188198
}
189199

200+
virtual int get_argument_count(bool &r_is_valid) const override {
201+
r_is_valid = true;
202+
return sizeof...(P);
203+
}
204+
190205
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
191206
ERR_FAIL_NULL_MSG(ObjectDB::get_instance(ObjectID(data.object_id)), "Invalid Object id '" + uitos(data.object_id) + "', can't call method.");
192207
call_with_variant_args_retc(data.instance, data.method, p_arguments, p_argcount, r_return_value, r_call_error);
@@ -238,6 +253,11 @@ class CallableCustomStaticMethodPointer : public CallableCustomMethodPointerBase
238253
return ObjectID();
239254
}
240255

256+
virtual int get_argument_count(bool &r_is_valid) const override {
257+
r_is_valid = true;
258+
return sizeof...(P);
259+
}
260+
241261
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
242262
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
243263
r_return_value = Variant();
@@ -280,6 +300,11 @@ class CallableCustomStaticMethodPointerRet : public CallableCustomMethodPointerB
280300
return ObjectID();
281301
}
282302

303+
virtual int get_argument_count(bool &r_is_valid) const override {
304+
r_is_valid = true;
305+
return sizeof...(P);
306+
}
307+
283308
virtual void call(const Variant **p_arguments, int p_argcount, Variant &r_return_value, Callable::CallError &r_call_error) const override {
284309
call_with_variant_args_static_ret(data.method, p_arguments, p_argcount, r_return_value, r_call_error);
285310
}

core/object/class_db.cpp

+25
Original file line numberDiff line numberDiff line change
@@ -1666,6 +1666,31 @@ bool ClassDB::has_method(const StringName &p_class, const StringName &p_method,
16661666
return false;
16671667
}
16681668

1669+
int ClassDB::get_method_argument_count(const StringName &p_class, const StringName &p_method, bool *r_is_valid, bool p_no_inheritance) {
1670+
OBJTYPE_RLOCK;
1671+
1672+
ClassInfo *type = classes.getptr(p_class);
1673+
1674+
while (type) {
1675+
MethodBind **method = type->method_map.getptr(p_method);
1676+
if (method && *method) {
1677+
if (r_is_valid) {
1678+
*r_is_valid = true;
1679+
}
1680+
return (*method)->get_argument_count();
1681+
}
1682+
if (p_no_inheritance) {
1683+
break;
1684+
}
1685+
type = type->inherits_ptr;
1686+
}
1687+
1688+
if (r_is_valid) {
1689+
*r_is_valid = false;
1690+
}
1691+
return 0;
1692+
}
1693+
16691694
void ClassDB::bind_method_custom(const StringName &p_class, MethodBind *p_method) {
16701695
_bind_method_custom(p_class, p_method, false);
16711696
}

core/object/class_db.h

+1
Original file line numberDiff line numberDiff line change
@@ -430,6 +430,7 @@ class ClassDB {
430430
static void get_method_list(const StringName &p_class, List<MethodInfo> *p_methods, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
431431
static void get_method_list_with_compatibility(const StringName &p_class, List<Pair<MethodInfo, uint32_t>> *p_methods_with_hash, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
432432
static bool get_method_info(const StringName &p_class, const StringName &p_method, MethodInfo *r_info, bool p_no_inheritance = false, bool p_exclude_from_properties = false);
433+
static int get_method_argument_count(const StringName &p_class, const StringName &p_method, bool *r_is_valid = nullptr, bool p_no_inheritance = false);
433434
static MethodBind *get_method(const StringName &p_class, const StringName &p_name);
434435
static MethodBind *get_method_with_compatibility(const StringName &p_class, const StringName &p_name, uint64_t p_hash, bool *r_method_exists = nullptr, bool *r_is_deprecated = nullptr);
435436
static Vector<uint32_t> get_method_compatibility_hashes(const StringName &p_class, const StringName &p_name);

core/object/object.cpp

+55
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,59 @@ bool Object::has_method(const StringName &p_method) const {
688688
return false;
689689
}
690690

691+
int Object::_get_method_argument_count_bind(const StringName &p_method) const {
692+
return get_method_argument_count(p_method);
693+
}
694+
695+
int Object::get_method_argument_count(const StringName &p_method, bool *r_is_valid) const {
696+
if (p_method == CoreStringNames::get_singleton()->_free) {
697+
if (r_is_valid) {
698+
*r_is_valid = true;
699+
}
700+
return 0;
701+
}
702+
703+
if (script_instance) {
704+
bool valid = false;
705+
int ret = script_instance->get_method_argument_count(p_method, &valid);
706+
if (valid) {
707+
if (r_is_valid) {
708+
*r_is_valid = true;
709+
}
710+
return ret;
711+
}
712+
}
713+
714+
{
715+
bool valid = false;
716+
int ret = ClassDB::get_method_argument_count(get_class_name(), p_method, &valid);
717+
if (valid) {
718+
if (r_is_valid) {
719+
*r_is_valid = true;
720+
}
721+
return ret;
722+
}
723+
}
724+
725+
const Script *scr = Object::cast_to<Script>(this);
726+
while (scr != nullptr) {
727+
bool valid = false;
728+
int ret = scr->get_script_method_argument_count(p_method, &valid);
729+
if (valid) {
730+
if (r_is_valid) {
731+
*r_is_valid = true;
732+
}
733+
return ret;
734+
}
735+
scr = scr->get_base_script().ptr();
736+
}
737+
738+
if (r_is_valid) {
739+
*r_is_valid = false;
740+
}
741+
return 0;
742+
}
743+
691744
Variant Object::getvar(const Variant &p_key, bool *r_valid) const {
692745
if (r_valid) {
693746
*r_valid = false;
@@ -1644,6 +1697,8 @@ void Object::_bind_methods() {
16441697

16451698
ClassDB::bind_method(D_METHOD("has_method", "method"), &Object::has_method);
16461699

1700+
ClassDB::bind_method(D_METHOD("get_method_argument_count", "method"), &Object::_get_method_argument_count_bind);
1701+
16471702
ClassDB::bind_method(D_METHOD("has_signal", "signal"), &Object::has_signal);
16481703
ClassDB::bind_method(D_METHOD("get_signal_list"), &Object::_get_signal_list);
16491704
ClassDB::bind_method(D_METHOD("get_signal_connection_list", "signal"), &Object::_get_signal_connection_list);

core/object/object.h

+2
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,7 @@ class Object {
654654
Variant _get_bind(const StringName &p_name) const;
655655
void _set_indexed_bind(const NodePath &p_name, const Variant &p_value);
656656
Variant _get_indexed_bind(const NodePath &p_name) const;
657+
int _get_method_argument_count_bind(const StringName &p_name) const;
657658

658659
_FORCE_INLINE_ void _construct_object(bool p_reference);
659660

@@ -865,6 +866,7 @@ class Object {
865866
Variant property_get_revert(const StringName &p_name) const;
866867

867868
bool has_method(const StringName &p_method) const;
869+
int get_method_argument_count(const StringName &p_method, bool *r_is_valid = nullptr) const;
868870
void get_method_list(List<MethodInfo> *p_list) const;
869871
Variant callv(const StringName &p_method, const Array &p_args);
870872
virtual Variant callp(const StringName &p_method, const Variant **p_args, int p_argcount, Callable::CallError &r_error);

0 commit comments

Comments
 (0)