Add non-generic methods in generic types to GenericMethods

GenericMethods should contain all MethodSpec-referenced methods,
including those which are non-generic methods inside generic types. This
patch adds those methods, and also implements parameter substitution for
type arguments in parameters & return types.
This commit is contained in:
Robert Xiao
2020-04-11 17:57:46 -07:00
committed by Katy
parent 50ea6dac36
commit c73aad08b8
4 changed files with 32 additions and 32 deletions

View File

@@ -92,28 +92,22 @@ namespace Il2CppInspector.Reflection
// Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP)
foreach (var spec in Package.MethodSpecs) {
TypeInfo declaringType;
var methodDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex];
var declaringType = methodDefinition.DeclaringType;
// Concrete instance of a generic class
// If the class index is not specified, we will later create a generic method in a non-generic class
if (spec.classIndexIndex != -1) {
var genericTypeDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
var genericInstance = Package.GenericInstances[spec.classIndexIndex];
var genericArguments = ResolveGenericArguments(genericInstance);
declaringType = genericTypeDefinition.MakeGenericType(genericArguments);
declaringType = declaringType.MakeGenericType(genericArguments);
}
else
declaringType = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
// Concrete instance of a generic method
if (spec.methodIndexIndex != -1) {
// Method or constructor
var concreteMethod = new MethodInfo(this, spec, declaringType);
if (concreteMethod.Name == ConstructorInfo.ConstructorName || concreteMethod.Name == ConstructorInfo.TypeConstructorName)
GenericMethods.Add(spec, new ConstructorInfo(this, spec, declaringType));
if (methodDefinition is MethodInfo)
GenericMethods[spec] = new MethodInfo(this, spec, declaringType);
else
GenericMethods.Add(spec, concreteMethod);
}
GenericMethods[spec] = new ConstructorInfo(this, spec, declaringType);
}
// Find all custom attribute generators (populate AttributesByIndices) (use ToList() to force evaluation)
@@ -245,9 +239,7 @@ namespace Il2CppInspector.Reflection
// Get the method used in a metadata usage
public MethodBase GetMetadataUsageMethod(MetadataUsage usage) => usage.Type switch {
MetadataUsageType.MethodDef => MethodsByDefinitionIndex[usage.SourceIndex],
MetadataUsageType.MethodRef => Package.MethodSpecs[usage.SourceIndex].methodIndexIndex != -1?
GenericMethods[Package.MethodSpecs[usage.SourceIndex]] :
MethodsByDefinitionIndex[Package.MethodSpecs[usage.SourceIndex].methodDefinitionIndex],
MetadataUsageType.MethodRef => GenericMethods[Package.MethodSpecs[usage.SourceIndex]],
_ => throw new InvalidOperationException("Incorrect metadata usage type to retrieve referenced type")
};
}

View File

@@ -152,16 +152,19 @@ namespace Il2CppInspector.Reflection
Name = methodDef.Name;
Attributes = methodDef.Attributes;
if (spec.methodIndexIndex >= 0) {
IsGenericMethod = true;
genericArguments = model.ResolveGenericArguments(model.Package.GenericInstances[spec.methodIndexIndex]);
} else {
IsGenericMethod = methodDef.IsGenericMethod;
genericArguments = methodDef.GetGenericArguments();
}
var genericTypeArguments = declaringType.GetGenericArguments();
// Substitute matching generic type parameters with concrete type arguments
foreach (var p in methodDef.DeclaredParameters) {
if (!p.ParameterType.IsGenericMethodParameter)
DeclaredParameters.Add(p);
else
DeclaredParameters.Add(new ParameterInfo(model, p, genericArguments[p.ParameterType.GenericParameterPosition]));
}
DeclaredParameters = methodDef.DeclaredParameters
.Select(p => p.SubstituteGenericArguments(genericTypeArguments, genericArguments))
.ToList();
VirtualAddress = model.Package.GetGenericMethodPointer(spec);
}

View File

@@ -17,8 +17,7 @@ namespace Il2CppInspector.Reflection
public ParameterInfo ReturnParameter { get; }
// Return type of the method
private readonly TypeRef returnTypeReference;
public TypeInfo ReturnType => returnTypeReference.Value;
public TypeInfo ReturnType => ReturnParameter.ParameterType;
public override bool RequiresUnsafeContext => base.RequiresUnsafeContext || ReturnType.RequiresUnsafeContext;
@@ -26,15 +25,12 @@ namespace Il2CppInspector.Reflection
public MethodInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(pkg, methodIndex, declaringType) {
// Add return parameter
returnTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.returnType);
ReturnParameter = new ParameterInfo(pkg, -1, this);
}
public MethodInfo(Il2CppModel model, Il2CppMethodSpec spec, TypeInfo declaringType) : base(model, spec, declaringType) {
var methodDef = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex];
// Add return parameter (TODO substitute type)
returnTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, methodDef.Definition.returnType);
ReturnParameter = ((MethodInfo) methodDef).ReturnParameter;
ReturnParameter = ((MethodInfo)methodDef).ReturnParameter.SubstituteGenericArguments(declaringType.GetGenericArguments(), GetGenericArguments());
}
public override string ToString() => ReturnType.Name + " " + Name + GetFullTypeParametersString() + "(" + string.Join(", ",

View File

@@ -97,20 +97,29 @@ namespace Il2CppInspector.Reflection
}
// Create a concrete type parameter from a generic type parameter
public ParameterInfo(Il2CppModel model, ParameterInfo generic, TypeInfo concrete) {
public ParameterInfo(ParameterInfo generic, TypeInfo concrete) {
DeclaringMethod = generic.DeclaringMethod;
Name = generic.Name;
Position = generic.Position;
Attributes = generic.Attributes;
// TODO substitute concrete params?
paramTypeReference = TypeRef.FromTypeInfo(concrete);
DefaultValue = generic.DefaultValue;
DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress;
}
public ParameterInfo SubstituteGenericArguments(TypeInfo[] typeArguments, TypeInfo[] methodArguments) {
/* TODO: Deep substitution */
if (ParameterType.IsGenericTypeParameter)
return new ParameterInfo(this, typeArguments[ParameterType.GenericParameterPosition]);
else if (ParameterType.IsGenericMethodParameter)
return new ParameterInfo(this, methodArguments[ParameterType.GenericParameterPosition]);
else
return this;
}
// ref will be handled as part of the type name
public string GetModifierString() =>
(IsIn && !IsOut ? "in " : "")