diff --git a/Il2CppInspector/Reflection/Il2CppModel.cs b/Il2CppInspector/Reflection/Il2CppModel.cs index cc492a6..0d55449 100644 --- a/Il2CppInspector/Reflection/Il2CppModel.cs +++ b/Il2CppInspector/Reflection/Il2CppModel.cs @@ -20,9 +20,15 @@ namespace Il2CppInspector.Reflection // List of all types from TypeDefs ordered by their TypeDefinitionIndex public TypeInfo[] TypesByDefinitionIndex { get; } - // List of all types from TypeRefs ordered by index + // List of all types from TypeRefs ordered by instanceIndex public TypeInfo[] TypesByReferenceIndex { get; } + // List of all types from MethodSpecs (closed generic types that can be instantiated) + public Dictionary TypesByMethodSpecClassIndex { get; } = new Dictionary(); + + // List of all methods from MethodSpecs (closed generic methods that can be called; does not need to be in a generic class) + public Dictionary> GenericMethods { get; } = new Dictionary>(); + // List of all type definitions by fully qualified name (TypeDefs only) public Dictionary TypesByFullName { get; } = new Dictionary(); @@ -36,7 +42,7 @@ namespace Il2CppInspector.Reflection // List of all methods ordered by their MethodDefinitionIndex public MethodBase[] MethodsByDefinitionIndex { get; } - // List of all generated CustomAttributeData objects by their index into AttributeTypeIndices + // List of all generated CustomAttributeData objects by their instanceIndex into AttributeTypeIndices public ConcurrentDictionary AttributesByIndices { get; } = new ConcurrentDictionary(); // Get an assembly by its image name @@ -62,6 +68,45 @@ namespace Il2CppInspector.Reflection TypesByReferenceIndex[typeRefIndex] = referencedType; } + + // Create types and methods from MethodSpec (which incorporates TypeSpec in IL2CPP) + foreach (var spec in Package.MethodSpecs) { + TypeInfo 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) { + if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex)) + TypesByMethodSpecClassIndex.Add(spec.classIndexIndex, new TypeInfo(this, spec)); + + declaringType = TypesByMethodSpecClassIndex[spec.classIndexIndex]; + } + else + declaringType = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType; + + // Concrete instance of a generic method + if (spec.methodIndexIndex != -1) { + + // First generic method declaration in this class? + if (!GenericMethods.ContainsKey(declaringType)) + GenericMethods.Add(declaringType, new List()); + + // TODO: Add generic method resolver here + + // Get list of pointers to type parameters (both unresolved and concrete) + var genericTypeArguments = ResolveGenericArguments(spec.methodIndexIndex); + } + } + } + + // Get generic arguments from either a type or method instanceIndex from a MethodSpec + public List ResolveGenericArguments(int instanceIndex) => ResolveGenericArguments(Package.GenericInstances[instanceIndex]); + public List ResolveGenericArguments(Il2CppGenericInst inst) { + + // Get list of pointers to type parameters (both unresolved and concrete) + var genericTypeArguments = Package.BinaryImage.ReadMappedWordArray(inst.type_argv, (int)inst.type_argc); + + return genericTypeArguments.Select(a => GetTypeFromVirtualAddress((ulong) a)).ToList(); } private TypeInfo resolveTypeReference(Il2CppType typeRef) { diff --git a/Il2CppInspector/Reflection/TypeInfo.cs b/Il2CppInspector/Reflection/TypeInfo.cs index f8f7ba7..321506a 100644 --- a/Il2CppInspector/Reflection/TypeInfo.cs +++ b/Il2CppInspector/Reflection/TypeInfo.cs @@ -613,13 +613,9 @@ namespace Il2CppInspector.Reflection { if (generic.context.method_inst != 0) throw new InvalidOperationException("Generic method instance cannot be non-null when processing a generic class instance"); - // Get list of pointers to type parameters (both unresolved and concrete) - var genericTypeArguments = image.ReadMappedWordArray(genericInstance.type_argv, (int)genericInstance.type_argc); - - foreach (var pArg in genericTypeArguments) { - var argType = model.GetTypeFromVirtualAddress((ulong) pArg); - genericArguments.Add(argType); - } + // Find all the type parameters (both unresolved and concrete) + // This will cause new types to be generated with the VAR and MVAR types below + genericArguments = model.ResolveGenericArguments(genericInstance); } // TODO: Set DeclaringType for the two below @@ -687,6 +683,30 @@ namespace Il2CppInspector.Reflection { } } + // Initialize a type from a concrete generic instance (TypeSpec) + public TypeInfo(Il2CppModel model, Il2CppMethodSpec spec) { + var genericTypeDefinition = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType; + + // Same visibility attributes as generic type definition + Attributes = genericTypeDefinition.Attributes; + + // Same name as generic type definition + Assembly = genericTypeDefinition.Assembly; + Namespace = genericTypeDefinition.Namespace; + Name = genericTypeDefinition.BaseName; // use BaseName to exclude the type parameters so we can supply our own + + IsGenericParameter = false; + IsGenericType = true; + + // Resolve type arguments + genericArguments = model.ResolveGenericArguments(spec.classIndexIndex); + + /* TODO: This is a bare definition at the moment. We need to iterate over all the members of genericTypeDefinition + * and replace the matching generic type parameters with our concrete type parameters, + * as well as setting the various TypeInfo properties here + */ + } + // Initialize a type that is a generic parameter of a generic type // See: https://docs.microsoft.com/en-us/dotnet/api/system.type.isgenerictype?view=netframework-4.8 public TypeInfo(TypeInfo declaringType, Il2CppGenericParameter param) : base(declaringType) {