Model: Implement various generic method properties

This commit is contained in:
Katy Coe
2020-02-01 23:42:51 +01:00
parent f04604edc7
commit e60f1ef89b
3 changed files with 34 additions and 25 deletions

View File

@@ -607,8 +607,7 @@ namespace Il2CppInspector
writer.Append("(" + method.GetParametersString(scope, !SuppressMetadata) + ")"); writer.Append("(" + method.GetParametersString(scope, !SuppressMetadata) + ")");
// Generic type constraints // Generic type constraints
if (method.GenericTypeParameters != null) foreach (var gp in method.GetGenericArguments()) {
foreach (var gp in method.GenericTypeParameters) {
var constraint = gp.GetTypeConstraintsString(scope); var constraint = gp.GetTypeConstraintsString(scope);
if (constraint != string.Empty) if (constraint != string.Empty)
writer.Append($"\n{prefix}\t\t{constraint}"); writer.Append($"\n{prefix}\t\t{constraint}");

View File

@@ -1,5 +1,5 @@
/* /*
Copyright 2017-2019 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com Copyright 2017-2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
All rights reserved. All rights reserved.
*/ */
@@ -9,7 +9,6 @@ using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Text; using System.Text;
using System.Text.RegularExpressions;
namespace Il2CppInspector.Reflection namespace Il2CppInspector.Reflection
{ {
@@ -23,13 +22,9 @@ namespace Il2CppInspector.Reflection
// Information/flags about the method // Information/flags about the method
public MethodAttributes Attributes { get; protected set; } public MethodAttributes Attributes { get; protected set; }
// True if the method contains unresolved generic type parameters
public bool ContainsGenericParameters { get; }
// Custom attributes for this member // Custom attributes for this member
public override IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(this); public override IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(this);
public List<TypeInfo> GenericTypeParameters { get; } // System.Reflection.MethodInfo.GetGenericArguments()
public List<ParameterInfo> DeclaredParameters { get; } = new List<ParameterInfo>(); public List<ParameterInfo> DeclaredParameters { get; } = new List<ParameterInfo>();
public bool IsAbstract => (Attributes & MethodAttributes.Abstract) == MethodAttributes.Abstract; public bool IsAbstract => (Attributes & MethodAttributes.Abstract) == MethodAttributes.Abstract;
@@ -39,8 +34,6 @@ namespace Il2CppInspector.Reflection
public bool IsFamilyAndAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem; public bool IsFamilyAndAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamANDAssem;
public bool IsFamilyOrAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem; public bool IsFamilyOrAssembly => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.FamORAssem;
public bool IsFinal => (Attributes & MethodAttributes.Final) == MethodAttributes.Final; public bool IsFinal => (Attributes & MethodAttributes.Final) == MethodAttributes.Final;
public bool IsGenericMethod { get; }
public bool IsGenericMethodDefinition { get; }
public bool IsHideBySig => (Attributes & MethodAttributes.HideBySig) == MethodAttributes.HideBySig; public bool IsHideBySig => (Attributes & MethodAttributes.HideBySig) == MethodAttributes.HideBySig;
public bool IsPrivate => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private; public bool IsPrivate => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Private;
public bool IsPublic => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public; public bool IsPublic => (Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public;
@@ -50,6 +43,25 @@ namespace Il2CppInspector.Reflection
public virtual bool RequiresUnsafeContext => DeclaredParameters.Any(p => p.ParameterType.RequiresUnsafeContext); public virtual bool RequiresUnsafeContext => DeclaredParameters.Any(p => p.ParameterType.RequiresUnsafeContext);
// True if the method contains unresolved generic type parameters, or if it is a non-generic method in an open ganeric type
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.containsgenericparameters?view=netframework-4.8
public bool ContainsGenericParameters => DeclaringType.ContainsGenericParameters || genericArguments.Any(ga => ga.ContainsGenericParameters);
// For a generic method definition: the list of generic type parameters
// For an open generic method: a mix of generic type parameters and generic type arguments
// For a closed generic method: the list of generic type arguments
private readonly List<TypeInfo> genericArguments = new List<TypeInfo>();
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.getgenericarguments?view=netframework-4.8
public List<TypeInfo> GetGenericArguments() => genericArguments;
// This was added in .NET Core 2.1 and isn't properly documented yet
public bool IsConstructedGenericMethod => genericArguments.All(ga => !ga.ContainsGenericParameters);
// See: https://docs.microsoft.com/en-us/dotnet/api/system.reflection.methodbase.isgenericmethod?view=netframework-4.8
public bool IsGenericMethod { get; }
public bool IsGenericMethodDefinition => genericArguments.Any() && genericArguments.All(a => a.IsGenericTypeParameter);
// TODO: GetMethodBody() // TODO: GetMethodBody()
public string CSharpName => public string CSharpName =>
@@ -85,13 +97,11 @@ namespace Il2CppInspector.Reflection
// Generic method definition? // Generic method definition?
if (Definition.genericContainerIndex >= 0) { if (Definition.genericContainerIndex >= 0) {
IsGenericMethod = true; IsGenericMethod = true;
IsGenericMethodDefinition = true;
ContainsGenericParameters = true;
// Store the generic type parameters for later instantiation // Store the generic type parameters for later instantiation
var container = pkg.GenericContainers[Definition.genericContainerIndex]; var container = pkg.GenericContainers[Definition.genericContainerIndex];
GenericTypeParameters = pkg.GenericParameters.Skip((int)container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToList(); genericArguments = pkg.GenericParameters.Skip((int)container.genericParameterStart).Take(container.type_argc).Select(p => new TypeInfo(this, p)).ToList();
} }
// Set method attributes // Set method attributes
@@ -191,11 +201,11 @@ namespace Il2CppInspector.Reflection
public string GetParametersString(Scope usingScope, bool emitPointer = false, bool commentAttributes = false) public string GetParametersString(Scope usingScope, bool emitPointer = false, bool commentAttributes = false)
=> string.Join(", ", DeclaredParameters.Select(p => p.GetParameterString(usingScope, emitPointer, commentAttributes))); => string.Join(", ", DeclaredParameters.Select(p => p.GetParameterString(usingScope, emitPointer, commentAttributes)));
public string GetTypeParametersString(Scope usingScope) => GenericTypeParameters == null? "" : public string GetTypeParametersString(Scope usingScope) => !GetGenericArguments().Any()? "" :
"<" + string.Join(", ", GenericTypeParameters.Select(p => p.GetScopedCSharpName(usingScope))) + ">"; "<" + string.Join(", ", GetGenericArguments().Select(p => p.GetScopedCSharpName(usingScope))) + ">";
public string GetFullTypeParametersString() => GenericTypeParameters == null? "" : public string GetFullTypeParametersString() => !GetGenericArguments().Any()? "" :
"[" + string.Join(",", GenericTypeParameters.Select(p => p.FullName ?? p.Name)) + "]"; "[" + string.Join(",", GetGenericArguments().Select(p => p.FullName ?? p.Name)) + "]";
public abstract string GetSignatureString(); public abstract string GetSignatureString();

View File

@@ -773,8 +773,8 @@ namespace Il2CppInspector.Reflection {
refs.UnionWith(DeclaredMethods.SelectMany(m => m.DeclaredParameters).Select(p => p.ParameterType)); refs.UnionWith(DeclaredMethods.SelectMany(m => m.DeclaredParameters).Select(p => p.ParameterType));
// Method generic type parameters and constraints // Method generic type parameters and constraints
refs.UnionWith(DeclaredMethods.SelectMany(m => m.GenericTypeParameters ?? new List<TypeInfo>())); refs.UnionWith(DeclaredMethods.SelectMany(m => m.GetGenericArguments()));
refs.UnionWith(DeclaredMethods.SelectMany(m => m.GenericTypeParameters ?? new List<TypeInfo>()) refs.UnionWith(DeclaredMethods.SelectMany(m => m.GetGenericArguments())
.SelectMany(p => p.GetGenericParameterConstraints())); .SelectMany(p => p.GetGenericParameterConstraints()));
// Type declaration attributes // Type declaration attributes
@@ -898,7 +898,7 @@ namespace Il2CppInspector.Reflection {
// Find nearest ancestor base method which has us as a generic type parameter // Find nearest ancestor base method which has us as a generic type parameter
var sig = DeclaringMethod.GetSignatureString(); var sig = DeclaringMethod.GetSignatureString();
var method = DeclaringMethod.DeclaringType.BaseType.GetAllMethods() var method = DeclaringMethod.DeclaringType.BaseType.GetAllMethods()
.FirstOrDefault(m => m.IsHideBySig && m.IsVirtual && m.GetSignatureString() == sig && (m.GenericTypeParameters?.Any(p => p.Name == Name) ?? false)); .FirstOrDefault(m => m.IsHideBySig && m.IsVirtual && m.GetSignatureString() == sig && m.GetGenericArguments().Any(p => p.Name == Name));
// Stop if we are inherited from a base method // Stop if we are inherited from a base method
if (method != null) if (method != null)