Model: Handle generic methods and set DeclaringMethod

This commit is contained in:
Katy Coe
2019-11-02 01:44:09 +01:00
parent a1046d6322
commit fdab846710
4 changed files with 59 additions and 19 deletions

View File

@@ -24,12 +24,16 @@ namespace Il2CppInspector.Reflection
// List of type usages that are initialized via pointers in the image
public Dictionary<ulong, TypeInfo> TypesByVirtualAddress { get; } = new Dictionary<ulong, TypeInfo>();
// List of all methods ordered by their MethodDefinitionIndex
public MethodBase[] MethodsByDefinitionIndex { get; }
// List of all types
public Il2CppModel(Il2CppInspector package) {
Package = package;
TypesByDefinitionIndex = new TypeInfo[package.TypeDefinitions.Length];
TypesByUsageIndex = new TypeInfo[package.TypeUsages.Count];
MethodsByDefinitionIndex = new MethodBase[package.Methods.Length];
// Create Assembly objects from Il2Cpp package
for (var image = 0; image < package.Images.Length; image++)

View File

@@ -22,11 +22,12 @@ namespace Il2CppInspector.Reflection
// Information/flags about the method
public MethodAttributes Attributes { get; protected set; }
// True if the type contains unresolved generic type parameters
public bool ContainsGenericParameters => throw new NotImplementedException();
// True if the method contains unresolved generic type parameters
public bool ContainsGenericParameters { get; }
// TODO: Custom attribute stuff
public List<TypeInfo> GenericTypeParameters { get; } // System.Reflection.MethodInfo.GetGenericArguments()
public List<ParameterInfo> DeclaredParameters { get; } = new List<ParameterInfo>();
public bool IsAbstract => (Attributes & MethodAttributes.Abstract) == MethodAttributes.Abstract;
@@ -36,8 +37,8 @@ namespace Il2CppInspector.Reflection
public bool IsFamilyAndAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem;
public bool IsFamilyOrAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;
public bool IsFinal => (Attributes & MethodAttributes.Final) == MethodAttributes.Final;
public bool IsGenericMethod => throw new NotImplementedException();
public bool IsGenericMethodDefinition => throw new NotImplementedException();
public bool IsGenericMethod { get; }
public bool IsGenericMethodDefinition { get; }
public bool IsHideBySig => (Attributes & MethodAttributes.HideBySig) == MethodAttributes.HideBySig;
public bool IsPrivate => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
public bool IsPublic => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
@@ -59,6 +60,24 @@ namespace Il2CppInspector.Reflection
// Find method pointer
VirtualAddress = pkg.GetMethodPointer(Assembly.Module, Definition);
// Add to global method definition list
Assembly.Model.MethodsByDefinitionIndex[Index] = this;
// Generic method definition?
if (Definition.genericContainerIndex >= 0) {
IsGenericMethod = true;
IsGenericMethodDefinition = true; // TODO: Only if all of the parameters are unresolved generic type parameters
ContainsGenericParameters = true;
// Store the generic type parameters for later instantiation
var container = pkg.GenericContainers[Definition.genericContainerIndex];
GenericTypeParameters = pkg.GenericParameters.Skip((int)container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToList();
// TODO: Constraints
// TODO: Attributes
}
// Set method attributes
if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_MEMBER_ACCESS_MASK) == Il2CppConstants.METHOD_ATTRIBUTE_PRIVATE)
Attributes |= MethodAttributes.Private;
@@ -90,7 +109,7 @@ namespace Il2CppInspector.Reflection
Attributes |= MethodAttributes.SpecialName;
if ((Definition.flags & Il2CppConstants.METHOD_ATTRIBUTE_UNMANAGED_EXPORT) != 0)
Attributes |= MethodAttributes.UnmanagedExport;
// Add arguments
for (var p = Definition.parameterStart; p < Definition.parameterStart + Definition.parameterCount; p++)
DeclaredParameters.Add(new ParameterInfo(pkg, p, this));
@@ -142,6 +161,9 @@ namespace Il2CppInspector.Reflection
public string GetParametersString() =>
string.Join(", ", DeclaredParameters.Select(p => $"{p.GetModifierString()}{p.ParameterType.CSharpName} {p.Name}"));
public string GetTypeParametersString() => GenericTypeParameters == null? "" :
"<" + string.Join(", ", GenericTypeParameters.Select(p => p.CSharpName)) + ">";
// List of operator overload metadata names
// https://docs.microsoft.com/en-us/dotnet/standard/design-guidelines/operator-overloads
public static Dictionary<string, string> OperatorMethodNames = new Dictionary<string, string> {

View File

@@ -28,6 +28,7 @@ namespace Il2CppInspector.Reflection
ReturnParameter = new ParameterInfo(pkg, -1, this);
}
// TODO: Generic arguments (and on ConstructorInfo)
public override string ToString() => ReturnType.Name + " " + Name + "(" + string.Join(", ", DeclaredParameters.Select(x => x.ParameterType.Name)) + ")";
}
}

View File

@@ -30,6 +30,11 @@ namespace Il2CppInspector.Reflection {
// True if the type contains unresolved generic type parameters
public bool ContainsGenericParameters { get; }
public string BaseName => base.Name;
// Get rid of generic backticks
public string UnmangledBaseName => base.Name.IndexOf("`", StringComparison.Ordinal) == -1 ? base.Name : base.Name.Remove(base.Name.IndexOf("`", StringComparison.Ordinal));
// C# colloquial name of the type (if available)
public string CSharpName {
get {
@@ -46,6 +51,14 @@ namespace Il2CppInspector.Reflection {
}
}
// C# name as it would be written in a type declaration
public string CSharpTypeDeclarationName =>
(IsPointer ? "void *" : "")
+ (base.Name.IndexOf("`", StringComparison.Ordinal) == -1 ? base.Name : base.Name.Remove(base.Name.IndexOf("`", StringComparison.Ordinal)))
+ (GenericTypeParameters != null ? "<" + string.Join(", ", GenericTypeParameters.Select(x => x.Name)) + ">" : "")
+ (GenericTypeArguments != null ? "<" + string.Join(", ", GenericTypeArguments.Select(x => x.Name)) + ">" : "")
+ (IsArray ? "[]" : "");
public List<ConstructorInfo> DeclaredConstructors { get; } = new List<ConstructorInfo>();
public List<EventInfo> DeclaredEvents { get; } = new List<EventInfo>();
public List<FieldInfo> DeclaredFields { get; } = new List<FieldInfo>();
@@ -58,7 +71,9 @@ namespace Il2CppInspector.Reflection {
public List<PropertyInfo> DeclaredProperties { get; } = new List<PropertyInfo>();
// Method that the type is declared in if this is a type parameter of a generic method
public MethodBase DeclaringMethod => null; // TODO: Implement for methods
public MethodBase DeclaringMethod;
// IsGenericTypeParameter and IsGenericMethodParameter from https://github.com/dotnet/corefx/issues/23883
public bool IsGenericTypeParameter => IsGenericParameter && DeclaringMethod == null;
public bool IsGenericMethodParameter => IsGenericParameter && DeclaringMethod != null;
@@ -127,17 +142,6 @@ namespace Il2CppInspector.Reflection {
// May get overridden by Il2CppType-based constructor below
public override MemberTypes MemberType { get; } = MemberTypes.TypeInfo;
public string BaseName => base.Name;
public override string Name {
get => (IsPointer ? "void *" : "")
+ (base.Name.IndexOf("`", StringComparison.Ordinal) == -1? base.Name : base.Name.Remove(base.Name.IndexOf("`", StringComparison.Ordinal)))
+ (GenericTypeParameters != null? "<" + string.Join(", ", GenericTypeParameters.Select(x => x.Name)) + ">" : "")
+ (GenericTypeArguments != null ? "<" + string.Join(", ", GenericTypeArguments.Select(x => x.Name)) + ">" : "")
+ (IsArray ? "[]" : "");
protected set => base.Name = value;
}
private string @namespace;
public string Namespace {
get => !string.IsNullOrEmpty(@namespace) ? @namespace : DeclaringType?.Namespace ?? "";
@@ -179,7 +183,7 @@ namespace Il2CppInspector.Reflection {
MemberType |= MemberTypes.NestedType;
}
// Generic type?
// Generic type definition?
if (Definition.genericContainerIndex >= 0) {
IsGenericType = true;
IsGenericParameter = false;
@@ -358,6 +362,10 @@ namespace Il2CppInspector.Reflection {
declaringTypeDefinitionIndex = ownerType.Index;
MemberType = memberType | MemberTypes.NestedType;
// All generic method type parameters have a declared method
if (container.is_method == 1)
DeclaringMethod = model.MethodsByDefinitionIndex[container.ownerIndex];
IsGenericParameter = true;
ContainsGenericParameters = true;
IsGenericType = false;
@@ -369,7 +377,7 @@ namespace Il2CppInspector.Reflection {
IsPointer = (pType.type == Il2CppTypeEnum.IL2CPP_TYPE_PTR);
}
// Initialize a type that is a generic parameter
// 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) {
// Same visibility attributes as declaring type
@@ -389,5 +397,10 @@ namespace Il2CppInspector.Reflection {
IsGenericTypeDefinition = false;
ContainsGenericParameters = true;
}
// Initialize a type that is a generic parameter of a generic method
public TypeInfo(MethodBase declaringMethod, Il2CppGenericParameter param) : this(declaringMethod.DeclaringType, param) {
DeclaringMethod = declaringMethod;
}
}
}