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:
@@ -92,28 +92,22 @@ namespace Il2CppInspector.Reflection
|
|||||||
|
|
||||||
// Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP)
|
// Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP)
|
||||||
foreach (var spec in Package.MethodSpecs) {
|
foreach (var spec in Package.MethodSpecs) {
|
||||||
TypeInfo declaringType;
|
var methodDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex];
|
||||||
|
var declaringType = methodDefinition.DeclaringType;
|
||||||
|
|
||||||
// Concrete instance of a generic class
|
// 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 the class index is not specified, we will later create a generic method in a non-generic class
|
||||||
if (spec.classIndexIndex != -1) {
|
if (spec.classIndexIndex != -1) {
|
||||||
var genericTypeDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
|
|
||||||
var genericInstance = Package.GenericInstances[spec.classIndexIndex];
|
var genericInstance = Package.GenericInstances[spec.classIndexIndex];
|
||||||
var genericArguments = ResolveGenericArguments(genericInstance);
|
var genericArguments = ResolveGenericArguments(genericInstance);
|
||||||
declaringType = genericTypeDefinition.MakeGenericType(genericArguments);
|
declaringType = declaringType.MakeGenericType(genericArguments);
|
||||||
}
|
}
|
||||||
else
|
|
||||||
declaringType = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
|
|
||||||
|
|
||||||
// Concrete instance of a generic method
|
// Concrete instance of a generic method
|
||||||
if (spec.methodIndexIndex != -1) {
|
if (methodDefinition is MethodInfo)
|
||||||
// Method or constructor
|
GenericMethods[spec] = new MethodInfo(this, spec, declaringType);
|
||||||
var concreteMethod = new MethodInfo(this, spec, declaringType);
|
|
||||||
if (concreteMethod.Name == ConstructorInfo.ConstructorName || concreteMethod.Name == ConstructorInfo.TypeConstructorName)
|
|
||||||
GenericMethods.Add(spec, new ConstructorInfo(this, spec, declaringType));
|
|
||||||
else
|
else
|
||||||
GenericMethods.Add(spec, concreteMethod);
|
GenericMethods[spec] = new ConstructorInfo(this, spec, declaringType);
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Find all custom attribute generators (populate AttributesByIndices) (use ToList() to force evaluation)
|
// 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
|
// Get the method used in a metadata usage
|
||||||
public MethodBase GetMetadataUsageMethod(MetadataUsage usage) => usage.Type switch {
|
public MethodBase GetMetadataUsageMethod(MetadataUsage usage) => usage.Type switch {
|
||||||
MetadataUsageType.MethodDef => MethodsByDefinitionIndex[usage.SourceIndex],
|
MetadataUsageType.MethodDef => MethodsByDefinitionIndex[usage.SourceIndex],
|
||||||
MetadataUsageType.MethodRef => Package.MethodSpecs[usage.SourceIndex].methodIndexIndex != -1?
|
MetadataUsageType.MethodRef => GenericMethods[Package.MethodSpecs[usage.SourceIndex]],
|
||||||
GenericMethods[Package.MethodSpecs[usage.SourceIndex]] :
|
|
||||||
MethodsByDefinitionIndex[Package.MethodSpecs[usage.SourceIndex].methodDefinitionIndex],
|
|
||||||
_ => throw new InvalidOperationException("Incorrect metadata usage type to retrieve referenced type")
|
_ => throw new InvalidOperationException("Incorrect metadata usage type to retrieve referenced type")
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -152,16 +152,19 @@ namespace Il2CppInspector.Reflection
|
|||||||
Name = methodDef.Name;
|
Name = methodDef.Name;
|
||||||
Attributes = methodDef.Attributes;
|
Attributes = methodDef.Attributes;
|
||||||
|
|
||||||
|
if (spec.methodIndexIndex >= 0) {
|
||||||
IsGenericMethod = true;
|
IsGenericMethod = true;
|
||||||
genericArguments = model.ResolveGenericArguments(model.Package.GenericInstances[spec.methodIndexIndex]);
|
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
|
// Substitute matching generic type parameters with concrete type arguments
|
||||||
foreach (var p in methodDef.DeclaredParameters) {
|
DeclaredParameters = methodDef.DeclaredParameters
|
||||||
if (!p.ParameterType.IsGenericMethodParameter)
|
.Select(p => p.SubstituteGenericArguments(genericTypeArguments, genericArguments))
|
||||||
DeclaredParameters.Add(p);
|
.ToList();
|
||||||
else
|
|
||||||
DeclaredParameters.Add(new ParameterInfo(model, p, genericArguments[p.ParameterType.GenericParameterPosition]));
|
|
||||||
}
|
|
||||||
|
|
||||||
VirtualAddress = model.Package.GetGenericMethodPointer(spec);
|
VirtualAddress = model.Package.GetGenericMethodPointer(spec);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -17,8 +17,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
public ParameterInfo ReturnParameter { get; }
|
public ParameterInfo ReturnParameter { get; }
|
||||||
|
|
||||||
// Return type of the method
|
// Return type of the method
|
||||||
private readonly TypeRef returnTypeReference;
|
public TypeInfo ReturnType => ReturnParameter.ParameterType;
|
||||||
public TypeInfo ReturnType => returnTypeReference.Value;
|
|
||||||
|
|
||||||
public override bool RequiresUnsafeContext => base.RequiresUnsafeContext || ReturnType.RequiresUnsafeContext;
|
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) {
|
public MethodInfo(Il2CppInspector pkg, int methodIndex, TypeInfo declaringType) : base(pkg, methodIndex, declaringType) {
|
||||||
// Add return parameter
|
// Add return parameter
|
||||||
returnTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.returnType);
|
|
||||||
ReturnParameter = new ParameterInfo(pkg, -1, this);
|
ReturnParameter = new ParameterInfo(pkg, -1, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
public MethodInfo(Il2CppModel model, Il2CppMethodSpec spec, TypeInfo declaringType) : base(model, spec, declaringType) {
|
public MethodInfo(Il2CppModel model, Il2CppMethodSpec spec, TypeInfo declaringType) : base(model, spec, declaringType) {
|
||||||
var methodDef = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex];
|
var methodDef = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex];
|
||||||
// Add return parameter (TODO substitute type)
|
ReturnParameter = ((MethodInfo)methodDef).ReturnParameter.SubstituteGenericArguments(declaringType.GetGenericArguments(), GetGenericArguments());
|
||||||
returnTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, methodDef.Definition.returnType);
|
|
||||||
ReturnParameter = ((MethodInfo) methodDef).ReturnParameter;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public override string ToString() => ReturnType.Name + " " + Name + GetFullTypeParametersString() + "(" + string.Join(", ",
|
public override string ToString() => ReturnType.Name + " " + Name + GetFullTypeParametersString() + "(" + string.Join(", ",
|
||||||
|
|||||||
@@ -97,20 +97,29 @@ namespace Il2CppInspector.Reflection
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create a concrete type parameter from a generic type parameter
|
// 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;
|
DeclaringMethod = generic.DeclaringMethod;
|
||||||
Name = generic.Name;
|
Name = generic.Name;
|
||||||
Position = generic.Position;
|
Position = generic.Position;
|
||||||
Attributes = generic.Attributes;
|
Attributes = generic.Attributes;
|
||||||
|
|
||||||
// TODO substitute concrete params?
|
|
||||||
paramTypeReference = TypeRef.FromTypeInfo(concrete);
|
paramTypeReference = TypeRef.FromTypeInfo(concrete);
|
||||||
|
|
||||||
DefaultValue = generic.DefaultValue;
|
DefaultValue = generic.DefaultValue;
|
||||||
DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress;
|
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
|
// ref will be handled as part of the type name
|
||||||
public string GetModifierString() =>
|
public string GetModifierString() =>
|
||||||
(IsIn && !IsOut ? "in " : "")
|
(IsIn && !IsOut ? "in " : "")
|
||||||
|
|||||||
Reference in New Issue
Block a user