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.
This commit is contained in:
Robert Xiao
2020-04-20 00:11:31 -07:00
committed by Katy
parent 359b99fded
commit 4ba48b9c75
3 changed files with 29 additions and 12 deletions

View File

@@ -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; }

View File

@@ -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);
}
}
}

View File

@@ -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