Skip to content

Commit

Permalink
Fix get_all_delegates method for generic classes
Browse files Browse the repository at this point in the history
If the class is generic, we must get its generic type definition and use
it to retrieve the delegates.
  • Loading branch information
raulsntos committed Dec 4, 2021
1 parent 144e3cd commit 613751a
Show file tree
Hide file tree
Showing 6 changed files with 38 additions and 2 deletions.
12 changes: 12 additions & 0 deletions modules/mono/glue/GodotSharp/GodotSharp/Core/MarshalUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,18 @@ private static bool TypeIsSystemGenericDictionary(Type type) =>
/// </exception>
private static bool TypeIsGenericIDictionary(Type type) => type.GetGenericTypeDefinition() == typeof(IDictionary<,>);

/// <summary>
/// Returns the generic type definition of <paramref name="type"/>.
/// </summary>
/// <exception cref="InvalidOperationException">
/// Thrown when the given <paramref name="type"/> is not a generic type.
/// That is, <see cref="Type.IsGenericType"/> returns <see langword="false"/>.
/// </exception>
private static void GetGenericTypeDefinition(Type type, out Type genericTypeDefinition)
{
genericTypeDefinition = type.GetGenericTypeDefinition();
}

/// <summary>
/// Gets the element type for the given <paramref name="arrayType"/>.
/// </summary>
Expand Down
4 changes: 4 additions & 0 deletions modules/mono/mono_gd/gd_mono_cache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,8 @@ void CachedData::clear_godot_api_cache() {
methodthunk_MarshalUtils_TypeIsGenericICollection.nullify();
methodthunk_MarshalUtils_TypeIsGenericIDictionary.nullify();

methodthunk_MarshalUtils_GetGenericTypeDefinition.nullify();

methodthunk_MarshalUtils_ArrayGetElementType.nullify();
methodthunk_MarshalUtils_DictionaryGetKeyValueTypes.nullify();

Expand Down Expand Up @@ -279,6 +281,8 @@ void update_godot_api_cache() {
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericICollection, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericICollection", 1));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, TypeIsGenericIDictionary, GODOT_API_CLASS(MarshalUtils)->get_method("TypeIsGenericIDictionary", 1));

CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, GetGenericTypeDefinition, GODOT_API_CLASS(MarshalUtils)->get_method("GetGenericTypeDefinition", 2));

CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, ArrayGetElementType, GODOT_API_CLASS(MarshalUtils)->get_method("ArrayGetElementType", 2));
CACHE_METHOD_THUNK_AND_CHECK(MarshalUtils, DictionaryGetKeyValueTypes, GODOT_API_CLASS(MarshalUtils)->get_method("DictionaryGetKeyValueTypes", 3));

Expand Down
2 changes: 2 additions & 0 deletions modules/mono/mono_gd/gd_mono_cache.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,8 @@ struct CachedData {
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericICollection;
GDMonoMethodThunkR<MonoBoolean, MonoReflectionType *> methodthunk_MarshalUtils_TypeIsGenericIDictionary;

GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_GetGenericTypeDefinition;

GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **> methodthunk_MarshalUtils_ArrayGetElementType;
GDMonoMethodThunk<MonoReflectionType *, MonoReflectionType **, MonoReflectionType **> methodthunk_MarshalUtils_DictionaryGetKeyValueTypes;

Expand Down
14 changes: 12 additions & 2 deletions modules/mono/mono_gd/gd_mono_class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -438,12 +438,22 @@ const Vector<GDMonoProperty *> &GDMonoClass::get_all_properties() {
}

const Vector<GDMonoClass *> &GDMonoClass::get_all_delegates() {
if (delegates_fetched)
if (delegates_fetched) {
return delegates_list;
}

// If the class is generic we must use the generic type definition.
MonoClass *klass = mono_class;
if (mono_type_get_type(get_mono_type()) == MONO_TYPE_GENERICINST) {
MonoReflectionType *reftype = mono_type_get_object(mono_domain_get(), get_mono_type());
GDMonoUtils::Marshal::get_generic_type_definition(reftype, &reftype);
MonoType *type = mono_reflection_type_get_type(reftype);
klass = mono_class_from_mono_type(type);
}

void *iter = NULL;
MonoClass *raw_class = NULL;
while ((raw_class = mono_class_get_nested_types(mono_class, &iter)) != NULL) {
while ((raw_class = mono_class_get_nested_types(klass, &iter)) != NULL) {
if (mono_class_is_delegate(raw_class)) {
StringName name = String::utf8(mono_class_get_name(raw_class));

Expand Down
6 changes: 6 additions & 0 deletions modules/mono/mono_gd/gd_mono_utils.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -587,6 +587,12 @@ bool type_is_generic_idictionary(MonoReflectionType *p_reftype) {
return (bool)res;
}

void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype) {
MonoException *exc = nullptr;
CACHED_METHOD_THUNK(MarshalUtils, GetGenericTypeDefinition).invoke(p_reftype, r_generic_reftype, &exc);
UNHANDLED_EXCEPTION(exc);
}

void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype) {
MonoException *exc = NULL;
CACHED_METHOD_THUNK(MarshalUtils, ArrayGetElementType).invoke(p_array_reftype, r_elem_reftype, &exc);
Expand Down
2 changes: 2 additions & 0 deletions modules/mono/mono_gd/gd_mono_utils.h
Original file line number Diff line number Diff line change
Expand Up @@ -62,6 +62,8 @@ bool type_is_generic_ienumerable(MonoReflectionType *p_reftype);
bool type_is_generic_icollection(MonoReflectionType *p_reftype);
bool type_is_generic_idictionary(MonoReflectionType *p_reftype);

void get_generic_type_definition(MonoReflectionType *p_reftype, MonoReflectionType **r_generic_reftype);

void array_get_element_type(MonoReflectionType *p_array_reftype, MonoReflectionType **r_elem_reftype);
void dictionary_get_key_value_types(MonoReflectionType *p_dict_reftype, MonoReflectionType **r_key_reftype, MonoReflectionType **r_value_reftype);

Expand Down

0 comments on commit 613751a

Please sign in to comment.