From 4ba48b9c75be65c3b77fd6d90126cd7434f4964f Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Mon, 20 Apr 2020 00:11:31 -0700 Subject: [PATCH] Add generics support to TypeInfo.GetVTable This patch fixes TypeInfo.GetVTable so that it specializes the vtable for generic type instances. Also fix a minor bug in PropertyInfo that would pass null pointers to GetMethodByDefinition. --- .../Reflection/MethodBase.cs | 1 + .../Reflection/PropertyInfo.cs | 6 ++-- Il2CppInspector.Common/Reflection/TypeInfo.cs | 34 +++++++++++++------ 3 files changed, 29 insertions(+), 12 deletions(-) diff --git a/Il2CppInspector.Common/Reflection/MethodBase.cs b/Il2CppInspector.Common/Reflection/MethodBase.cs index 98e26a9..c860d1d 100644 --- a/Il2CppInspector.Common/Reflection/MethodBase.cs +++ b/Il2CppInspector.Common/Reflection/MethodBase.cs @@ -76,6 +76,7 @@ namespace Il2CppInspector.Reflection return this; throw new InvalidOperationException("This method can only be called on generic methods"); } + public MethodBase RootDefinition => rootDefinition; // See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.isgenericmethod?view=netframework-4.8 public bool IsGenericMethod { get; } diff --git a/Il2CppInspector.Common/Reflection/PropertyInfo.cs b/Il2CppInspector.Common/Reflection/PropertyInfo.cs index 4c770fb..4105aef 100644 --- a/Il2CppInspector.Common/Reflection/PropertyInfo.cs +++ b/Il2CppInspector.Common/Reflection/PropertyInfo.cs @@ -77,8 +77,10 @@ namespace Il2CppInspector.Reflection { rootDefinition = propertyDef; Name = propertyDef.Name; - GetMethod = declaringType.GetMethodByDefinition(propertyDef.GetMethod); - SetMethod = declaringType.GetMethodByDefinition(propertyDef.SetMethod); + if (propertyDef.GetMethod != null) + GetMethod = declaringType.GetMethodByDefinition(propertyDef.GetMethod); + if (propertyDef.SetMethod != null) + SetMethod = declaringType.GetMethodByDefinition(propertyDef.SetMethod); } } } \ No newline at end of file diff --git a/Il2CppInspector.Common/Reflection/TypeInfo.cs b/Il2CppInspector.Common/Reflection/TypeInfo.cs index f60b0bc..387614c 100644 --- a/Il2CppInspector.Common/Reflection/TypeInfo.cs +++ b/Il2CppInspector.Common/Reflection/TypeInfo.cs @@ -210,7 +210,7 @@ namespace Il2CppInspector.Reflection if (genericTypeDefinition != null) { var collection = genericTypeDefinition.DeclaredConstructors; for (int i = 0; i < collection.Count; i++) { - if (collection[i] == definition) + if (collection[i].RootDefinition == definition.RootDefinition) return DeclaredConstructors[i]; } } @@ -222,7 +222,7 @@ namespace Il2CppInspector.Reflection if (genericTypeDefinition != null) { var collection = genericTypeDefinition.DeclaredMethods; for (int i = 0; i < collection.Count; i++) { - if (collection[i] == definition) + if (collection[i].RootDefinition == definition.RootDefinition) return DeclaredMethods[i]; } } @@ -250,15 +250,29 @@ namespace Il2CppInspector.Reflection public PropertyInfo GetProperty(string name) => DeclaredProperties.FirstOrDefault(p => p.Name == name); public MethodBase[] GetVTable() { - var definition = Definition; - - MetadataUsage[] vt = Assembly.Model.Package.GetVTable(definition); - MethodBase[] res = new MethodBase[vt.Length]; - for (int i = 0; i < vt.Length; i++) { - if (vt[i] != null) - res[i] = Assembly.Model.GetMetadataUsageMethod(vt[i]); + if (Definition != null) { + MetadataUsage[] vt = Assembly.Model.Package.GetVTable(Definition); + MethodBase[] res = new MethodBase[vt.Length]; + for (int i = 0; i < vt.Length; i++) { + if (vt[i] != null) + res[i] = Assembly.Model.GetMetadataUsageMethod(vt[i]); + } + return res; + } else if (genericTypeDefinition != null) { + MethodBase[] baseVt = genericTypeDefinition.GetVTable(); + MethodBase[] res = new MethodBase[baseVt.Length]; + for (int i = 0; i < baseVt.Length; i++) { + if (baseVt[i] == null) + continue; + var declaringType = baseVt[i].DeclaringType.SubstituteGenericArguments(genericArguments); + if (baseVt[i] is ConstructorInfo ci) + res[i] = declaringType.GetConstructorByDefinition(ci); + else + res[i] = declaringType.GetMethodByDefinition((MethodInfo)baseVt[i]); + } + return res; } - return res; + return null; } // Method that the type is declared in if this is a type parameter of a generic method