Skip to content

Commit

Permalink
Merge pull request #55564 from raulsntos/csharp-delegates-for-generic…
Browse files Browse the repository at this point in the history
…-class-3.x

[3.x] Fix C# `get_all_delegates` method for generic classes
  • Loading branch information
akien-mga authored Dec 4, 2021
2 parents 8cedf91 + 613751a commit c42e9bd
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 c42e9bd

Please sign in to comment.