From c73aad08b85156e322aa486988d9f20bf5ca3bb9 Mon Sep 17 00:00:00 2001 From: Robert Xiao Date: Sat, 11 Apr 2020 17:57:46 -0700 Subject: [PATCH] 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. --- .../Reflection/Il2CppModel.cs | 24 +++++++------------ .../Reflection/MethodBase.cs | 19 ++++++++------- .../Reflection/MethodInfo.cs | 8 ++----- .../Reflection/ParameterInfo.cs | 13 ++++++++-- 4 files changed, 32 insertions(+), 32 deletions(-) diff --git a/Il2CppInspector.Common/Reflection/Il2CppModel.cs b/Il2CppInspector.Common/Reflection/Il2CppModel.cs index 265beec..c10034f 100644 --- a/Il2CppInspector.Common/Reflection/Il2CppModel.cs +++ b/Il2CppInspector.Common/Reflection/Il2CppModel.cs @@ -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)); - else - GenericMethods.Add(spec, concreteMethod); - } + if (methodDefinition is MethodInfo) + GenericMethods[spec] = new MethodInfo(this, spec, declaringType); + else + 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") }; } diff --git a/Il2CppInspector.Common/Reflection/MethodBase.cs b/Il2CppInspector.Common/Reflection/MethodBase.cs index f301ba4..c61948e 100644 --- a/Il2CppInspector.Common/Reflection/MethodBase.cs +++ b/Il2CppInspector.Common/Reflection/MethodBase.cs @@ -152,16 +152,19 @@ namespace Il2CppInspector.Reflection Name = methodDef.Name; Attributes = methodDef.Attributes; - IsGenericMethod = true; - genericArguments = model.ResolveGenericArguments(model.Package.GenericInstances[spec.methodIndexIndex]); + 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); } diff --git a/Il2CppInspector.Common/Reflection/MethodInfo.cs b/Il2CppInspector.Common/Reflection/MethodInfo.cs index 3864a1d..a2a1750 100644 --- a/Il2CppInspector.Common/Reflection/MethodInfo.cs +++ b/Il2CppInspector.Common/Reflection/MethodInfo.cs @@ -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(", ", diff --git a/Il2CppInspector.Common/Reflection/ParameterInfo.cs b/Il2CppInspector.Common/Reflection/ParameterInfo.cs index 6261ec5..2b339cd 100644 --- a/Il2CppInspector.Common/Reflection/ParameterInfo.cs +++ b/Il2CppInspector.Common/Reflection/ParameterInfo.cs @@ -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 " : "")