Refactor TypeInfo constructors
This patch replaces Il2CppModel.resolveTypeReference by a static TypeInfo constructor, and simultaneously refactors the TypeInfo constructors to eliminate duplication between resolveTypeReference and the original constructors. This will make future refactoring much easier.
This commit is contained in:
@@ -74,7 +74,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
// Note that you can't resolve any TypeRefs until all the TypeDefs have been processed
|
// Note that you can't resolve any TypeRefs until all the TypeDefs have been processed
|
||||||
for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Count; typeRefIndex++) {
|
for (int typeRefIndex = 0; typeRefIndex < package.TypeReferences.Count; typeRefIndex++) {
|
||||||
var typeRef = Package.TypeReferences[typeRefIndex];
|
var typeRef = Package.TypeReferences[typeRefIndex];
|
||||||
var referencedType = resolveTypeReference(typeRef);
|
var referencedType = TypeInfo.FromTypeReference(this, typeRef);
|
||||||
|
|
||||||
TypesByReferenceIndex[typeRefIndex] = referencedType;
|
TypesByReferenceIndex[typeRefIndex] = referencedType;
|
||||||
}
|
}
|
||||||
@@ -86,8 +86,11 @@ namespace Il2CppInspector.Reflection
|
|||||||
// 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) {
|
||||||
if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex))
|
if (!TypesByMethodSpecClassIndex.ContainsKey(spec.classIndexIndex)) {
|
||||||
TypesByMethodSpecClassIndex.Add(spec.classIndexIndex, new TypeInfo(this, spec));
|
var genericTypeDefinition = MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
|
||||||
|
var genericInstance = Package.GenericInstances[spec.classIndexIndex];
|
||||||
|
TypesByMethodSpecClassIndex.Add(spec.classIndexIndex, new TypeInfo(genericTypeDefinition, genericInstance));
|
||||||
|
}
|
||||||
|
|
||||||
declaringType = TypesByMethodSpecClassIndex[spec.classIndexIndex];
|
declaringType = TypesByMethodSpecClassIndex[spec.classIndexIndex];
|
||||||
}
|
}
|
||||||
@@ -147,48 +150,6 @@ namespace Il2CppInspector.Reflection
|
|||||||
return genericTypeArguments.Select(a => GetTypeFromVirtualAddress((ulong) a)).ToList();
|
return genericTypeArguments.Select(a => GetTypeFromVirtualAddress((ulong) a)).ToList();
|
||||||
}
|
}
|
||||||
|
|
||||||
private TypeInfo resolveTypeReference(Il2CppType typeRef) {
|
|
||||||
TypeInfo underlyingType;
|
|
||||||
|
|
||||||
switch (typeRef.type) {
|
|
||||||
// Classes defined in the metadata (reference to a TypeDef)
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
|
||||||
underlyingType = TypesByDefinitionIndex[typeRef.datapoint]; // klassIndex
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Constructed types
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
|
|
||||||
|
|
||||||
// Generic type and generic method parameters
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
|
||||||
|
|
||||||
underlyingType = new TypeInfo(this, typeRef);
|
|
||||||
break;
|
|
||||||
|
|
||||||
// Primitive types
|
|
||||||
default:
|
|
||||||
underlyingType = getTypeDefinitionFromTypeEnum(typeRef.type);
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Create a reference type if necessary
|
|
||||||
return typeRef.byref ? underlyingType.MakeByRefType() : underlyingType;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Basic primitive types are specified via a flag value
|
|
||||||
private TypeInfo getTypeDefinitionFromTypeEnum(Il2CppTypeEnum t) {
|
|
||||||
if ((int) t >= Il2CppConstants.FullNameTypeString.Count)
|
|
||||||
return null;
|
|
||||||
|
|
||||||
var fqn = Il2CppConstants.FullNameTypeString[(int) t];
|
|
||||||
return TypesByFullName[fqn];
|
|
||||||
}
|
|
||||||
|
|
||||||
// Get a TypeRef by its virtual address
|
// Get a TypeRef by its virtual address
|
||||||
// These are always nested types from references within another TypeRef
|
// These are always nested types from references within another TypeRef
|
||||||
public TypeInfo GetTypeFromVirtualAddress(ulong ptr) {
|
public TypeInfo GetTypeFromVirtualAddress(ulong ptr) {
|
||||||
@@ -198,7 +159,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
return TypesByReferenceIndex[typeRefIndex];
|
return TypesByReferenceIndex[typeRefIndex];
|
||||||
|
|
||||||
var type = Package.TypeReferences[typeRefIndex];
|
var type = Package.TypeReferences[typeRefIndex];
|
||||||
var referencedType = resolveTypeReference(type);
|
var referencedType = TypeInfo.FromTypeReference(this, type);
|
||||||
|
|
||||||
TypesByReferenceIndex[typeRefIndex] = referencedType;
|
TypesByReferenceIndex[typeRefIndex] = referencedType;
|
||||||
return referencedType;
|
return referencedType;
|
||||||
|
|||||||
@@ -597,121 +597,85 @@ namespace Il2CppInspector.Reflection {
|
|||||||
|
|
||||||
// Initialize type from type reference (TypeRef)
|
// Initialize type from type reference (TypeRef)
|
||||||
// Much of the following is adapted from il2cpp::vm::Class::FromIl2CppType
|
// Much of the following is adapted from il2cpp::vm::Class::FromIl2CppType
|
||||||
public TypeInfo(Il2CppModel model, Il2CppType pType) {
|
internal static TypeInfo FromTypeReference(Il2CppModel model, Il2CppType typeRef) {
|
||||||
var image = model.Package.BinaryImage;
|
var image = model.Package.BinaryImage;
|
||||||
|
TypeInfo underlyingType;
|
||||||
|
|
||||||
// Open and closed generic types
|
switch (typeRef.type) {
|
||||||
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST) {
|
// Classes defined in the metadata (reference to a TypeDef)
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
||||||
|
underlyingType = model.TypesByDefinitionIndex[typeRef.datapoint]; // klassIndex
|
||||||
|
break;
|
||||||
|
|
||||||
// TODO: Replace with array load from Il2CppMetadataRegistration.genericClasses
|
// Constructed types
|
||||||
var generic = image.ReadMappedObject<Il2CppGenericClass>(pType.datapoint); // Il2CppGenericClass *
|
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
||||||
|
// TODO: Replace with array load from Il2CppMetadataRegistration.genericClasses
|
||||||
|
var generic = image.ReadMappedObject<Il2CppGenericClass>(typeRef.datapoint); // Il2CppGenericClass *
|
||||||
|
|
||||||
// We have seen one test case where the TypeRef can point to no generic instance
|
// We have seen one test case where the TypeRef can point to no generic instance
|
||||||
// This is going to leave the TypeInfo in an undefined state
|
// This is going to leave the TypeInfo in an undefined state
|
||||||
if (generic.typeDefinitionIndex == 0x0000_0000_ffff_ffff)
|
if (generic.typeDefinitionIndex == 0x0000_0000_ffff_ffff)
|
||||||
return;
|
return null;
|
||||||
|
|
||||||
var genericTypeDef = model.TypesByDefinitionIndex[generic.typeDefinitionIndex];
|
var genericTypeDef = model.TypesByDefinitionIndex[generic.typeDefinitionIndex];
|
||||||
|
|
||||||
Assembly = genericTypeDef.Assembly;
|
// Get the instantiation
|
||||||
Namespace = genericTypeDef.Namespace;
|
// TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts
|
||||||
Name = genericTypeDef.BaseName;
|
var genericInstance = image.ReadMappedObject<Il2CppGenericInst>(generic.context.class_inst);
|
||||||
Attributes |= TypeAttributes.Class;
|
|
||||||
|
|
||||||
// Derived type?
|
underlyingType = new TypeInfo(genericTypeDef, genericInstance);
|
||||||
if (genericTypeDef.Definition.parentIndex >= 0)
|
break;
|
||||||
baseTypeReference = genericTypeDef.Definition.parentIndex;
|
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||||
|
var descriptor = image.ReadMappedObject<Il2CppArrayType>(typeRef.datapoint);
|
||||||
|
var elementType = model.GetTypeFromVirtualAddress(descriptor.etype);
|
||||||
|
underlyingType = new TypeInfo(elementType, descriptor.rank);
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY:
|
||||||
|
elementType = model.GetTypeFromVirtualAddress(typeRef.datapoint);
|
||||||
|
underlyingType = new TypeInfo(elementType, 1);
|
||||||
|
break;
|
||||||
|
case Il2CppTypeEnum.IL2CPP_TYPE_PTR:
|
||||||
|
elementType = model.GetTypeFromVirtualAddress(typeRef.datapoint);
|
||||||
|
underlyingType = new TypeInfo(elementType, isPointer: true);
|
||||||
|
break;
|
||||||
|
|
||||||
// Nested type?
|
// Generic type and generic method parameters
|
||||||
if (genericTypeDef.Definition.declaringTypeIndex >= 0) {
|
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
||||||
declaringTypeDefinitionIndex = (int)model.Package.TypeReferences[genericTypeDef.Definition.declaringTypeIndex].datapoint;
|
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
||||||
MemberType |= MemberTypes.NestedType;
|
var paramType = model.Package.GenericParameters[typeRef.datapoint]; // genericParameterIndex
|
||||||
}
|
var container = model.Package.GenericContainers[paramType.ownerIndex];
|
||||||
|
|
||||||
IsGenericType = true;
|
if(container.is_method == 1) {
|
||||||
IsGenericParameter = false;
|
var owner = model.MethodsByDefinitionIndex[container.ownerIndex];
|
||||||
|
underlyingType = new TypeInfo(owner, paramType);
|
||||||
|
} else {
|
||||||
|
var owner = model.TypesByDefinitionIndex[container.ownerIndex];
|
||||||
|
underlyingType = new TypeInfo(owner, paramType);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
// Get the instantiation
|
// Primitive types
|
||||||
// TODO: Replace with array load from Il2CppMetadataRegistration.genericInsts
|
default:
|
||||||
var genericInstance = image.ReadMappedObject<Il2CppGenericInst>(generic.context.class_inst);
|
underlyingType = FromTypeEnum(model, typeRef.type);
|
||||||
|
break;
|
||||||
if (generic.context.method_inst != 0)
|
|
||||||
throw new InvalidOperationException("Generic method instance cannot be non-null when processing a generic class instance");
|
|
||||||
|
|
||||||
// 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
|
// Create a reference type if necessary
|
||||||
|
return typeRef.byref ? underlyingType.MakeByRefType() : underlyingType;
|
||||||
// Array with known dimensions and bounds
|
|
||||||
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_ARRAY) {
|
|
||||||
var descriptor = image.ReadMappedObject<Il2CppArrayType>(pType.datapoint);
|
|
||||||
ElementType = model.GetTypeFromVirtualAddress(descriptor.etype);
|
|
||||||
|
|
||||||
Assembly = ElementType.Assembly;
|
|
||||||
Namespace = ElementType.Namespace;
|
|
||||||
Name = ElementType.Name;
|
|
||||||
|
|
||||||
IsArray = true;
|
|
||||||
arrayRank = descriptor.rank;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Dynamically allocated array or pointer type
|
|
||||||
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_PTR) {
|
|
||||||
ElementType = model.GetTypeFromVirtualAddress(pType.datapoint);
|
|
||||||
|
|
||||||
Assembly = ElementType.Assembly;
|
|
||||||
Namespace = ElementType.Namespace;
|
|
||||||
Name = ElementType.Name;
|
|
||||||
|
|
||||||
IsPointer = (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_PTR);
|
|
||||||
IsArray = !IsPointer;
|
|
||||||
|
|
||||||
// Heap arrays always have one dimension
|
|
||||||
arrayRank = 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
// Generic type parameter
|
|
||||||
if (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_VAR || pType.type == Il2CppTypeEnum.IL2CPP_TYPE_MVAR) {
|
|
||||||
var paramType = model.Package.GenericParameters[pType.datapoint]; // genericParameterIndex
|
|
||||||
var container = model.Package.GenericContainers[paramType.ownerIndex];
|
|
||||||
|
|
||||||
var ownerType = model.TypesByDefinitionIndex[
|
|
||||||
container.is_method == 1
|
|
||||||
? model.Package.Methods[container.ownerIndex].declaringType
|
|
||||||
: container.ownerIndex];
|
|
||||||
|
|
||||||
Assembly = ownerType.Assembly;
|
|
||||||
Namespace = "";
|
|
||||||
Name = model.Package.Strings[paramType.nameIndex];
|
|
||||||
Attributes |= TypeAttributes.Class;
|
|
||||||
|
|
||||||
// Derived type?
|
|
||||||
if (ownerType.Definition.parentIndex >= 0)
|
|
||||||
baseTypeReference = ownerType.Definition.parentIndex;
|
|
||||||
|
|
||||||
// Nested type always - sets DeclaringType used below
|
|
||||||
declaringTypeDefinitionIndex = ownerType.Index;
|
|
||||||
MemberType |= MemberTypes.NestedType;
|
|
||||||
|
|
||||||
// All generic method type parameters have a declared method
|
|
||||||
if (container.is_method == 1)
|
|
||||||
DeclaringMethod = model.MethodsByDefinitionIndex[container.ownerIndex];
|
|
||||||
|
|
||||||
// Set position in argument list
|
|
||||||
GenericParameterPosition = paramType.num;
|
|
||||||
|
|
||||||
IsGenericParameter = true;
|
|
||||||
IsGenericType = false;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a type from a concrete generic instance (TypeSpec)
|
// Basic primitive types are specified via a flag value
|
||||||
public TypeInfo(Il2CppModel model, Il2CppMethodSpec spec) {
|
internal static TypeInfo FromTypeEnum(Il2CppModel model, Il2CppTypeEnum t) {
|
||||||
var genericTypeDefinition = model.MethodsByDefinitionIndex[spec.methodDefinitionIndex].DeclaringType;
|
if ((int)t >= Il2CppConstants.FullNameTypeString.Count)
|
||||||
|
return null;
|
||||||
|
|
||||||
|
var fqn = Il2CppConstants.FullNameTypeString[(int)t];
|
||||||
|
return model.TypesByFullName[fqn];
|
||||||
|
}
|
||||||
|
|
||||||
|
// Initialize a type from a concrete generic instance
|
||||||
|
public TypeInfo(TypeInfo genericTypeDefinition, Il2CppGenericInst instance) : base(genericTypeDefinition.Assembly) {
|
||||||
// Same visibility attributes as generic type definition
|
// Same visibility attributes as generic type definition
|
||||||
Attributes = genericTypeDefinition.Attributes;
|
Attributes = genericTypeDefinition.Attributes;
|
||||||
|
|
||||||
@@ -719,15 +683,24 @@ namespace Il2CppInspector.Reflection {
|
|||||||
Index = genericTypeDefinition.Index;
|
Index = genericTypeDefinition.Index;
|
||||||
|
|
||||||
// Same name as generic type definition
|
// Same name as generic type definition
|
||||||
Assembly = genericTypeDefinition.Assembly;
|
|
||||||
Namespace = genericTypeDefinition.Namespace;
|
Namespace = genericTypeDefinition.Namespace;
|
||||||
Name = genericTypeDefinition.BaseName; // use BaseName to exclude the type parameters so we can supply our own
|
Name = genericTypeDefinition.BaseName; // use BaseName to exclude the type parameters so we can supply our own
|
||||||
|
|
||||||
|
// Derived type?
|
||||||
|
if (genericTypeDefinition.Definition.parentIndex >= 0)
|
||||||
|
baseTypeReference = genericTypeDefinition.Definition.parentIndex;
|
||||||
|
|
||||||
|
// Nested type?
|
||||||
|
if (genericTypeDefinition.Definition.declaringTypeIndex >= 0) {
|
||||||
|
declaringTypeDefinitionIndex = (int)Assembly.Model.Package.TypeReferences[genericTypeDefinition.Definition.declaringTypeIndex].datapoint;
|
||||||
|
MemberType |= MemberTypes.NestedType;
|
||||||
|
}
|
||||||
|
|
||||||
IsGenericParameter = false;
|
IsGenericParameter = false;
|
||||||
IsGenericType = true;
|
IsGenericType = true;
|
||||||
|
|
||||||
// Resolve type arguments
|
// Resolve type arguments
|
||||||
genericArguments = model.ResolveGenericArguments(spec.classIndexIndex);
|
genericArguments = Assembly.Model.ResolveGenericArguments(instance);
|
||||||
|
|
||||||
/* TODO: This is a bare definition at the moment. We need to iterate over all the members of genericTypeDefinition
|
/* 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,
|
* and replace the matching generic type parameters with our concrete type parameters,
|
||||||
@@ -769,22 +742,30 @@ namespace Il2CppInspector.Reflection {
|
|||||||
public TypeInfo(MethodBase declaringMethod, Il2CppGenericParameter param) : this(declaringMethod.DeclaringType, param)
|
public TypeInfo(MethodBase declaringMethod, Il2CppGenericParameter param) : this(declaringMethod.DeclaringType, param)
|
||||||
=> DeclaringMethod = declaringMethod;
|
=> DeclaringMethod = declaringMethod;
|
||||||
|
|
||||||
// Initialize a type that is a reference to the specified type
|
// Initialize a type that is an array of the specified type
|
||||||
private TypeInfo(TypeInfo underlyingType) {
|
private TypeInfo(TypeInfo elementType, int rank) : base(elementType.Assembly) {
|
||||||
ElementType = underlyingType;
|
ElementType = elementType;
|
||||||
IsByRef = true;
|
IsArray = true;
|
||||||
|
|
||||||
// No base type or declaring type for reference types
|
|
||||||
Assembly = ElementType.Assembly;
|
|
||||||
Definition = ElementType.Definition;
|
|
||||||
Index = ElementType.Index;
|
|
||||||
Namespace = ElementType.Namespace;
|
Namespace = ElementType.Namespace;
|
||||||
Name = ElementType.Name;
|
Name = ElementType.Name;
|
||||||
|
arrayRank = rank;
|
||||||
Attributes = ElementType.Attributes;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
public TypeInfo MakeByRefType() => new TypeInfo(this);
|
// Initialize a type that is a reference or pointer to the specified type
|
||||||
|
private TypeInfo(TypeInfo underlyingType, bool isPointer) : base(underlyingType.Assembly) {
|
||||||
|
ElementType = underlyingType;
|
||||||
|
if(isPointer) {
|
||||||
|
IsPointer = true;
|
||||||
|
} else {
|
||||||
|
IsByRef = true;
|
||||||
|
}
|
||||||
|
|
||||||
|
Namespace = ElementType.Namespace;
|
||||||
|
Name = ElementType.Name;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInfo MakeByRefType() => new TypeInfo(this, isPointer: false);
|
||||||
|
|
||||||
// Get all the other types directly referenced by this type (single level depth; no recursion)
|
// Get all the other types directly referenced by this type (single level depth; no recursion)
|
||||||
public List<TypeInfo> GetAllTypeReferences() {
|
public List<TypeInfo> GetAllTypeReferences() {
|
||||||
|
|||||||
Reference in New Issue
Block a user