Support BaseType and ImplementedInterfaces on generic params

This has been a little TODO for a while, and happily it's easy enough to
implement with TypeRef arrays.

Also implement ImplementedInterfaces for generic type instances via
substitution.
This commit is contained in:
Robert Xiao
2020-04-13 01:35:51 -07:00
committed by Katy
parent a36c93514d
commit 867f559f18
2 changed files with 40 additions and 17 deletions

View File

@@ -55,6 +55,11 @@ namespace Il2CppInspector.Reflection {
if (genericTypeDefinition != null) { if (genericTypeDefinition != null) {
return genericTypeDefinition.BaseType.SubstituteGenericArguments(genericArguments); return genericTypeDefinition.BaseType.SubstituteGenericArguments(genericArguments);
} }
if (IsGenericParameter) {
var res = GetGenericParameterConstraints().Where(t => !t.IsInterface).FirstOrDefault();
if (res != null)
return res;
}
if (Namespace != "System" || BaseName != "Object") if (Namespace != "System" || BaseName != "Object")
return Assembly.Model.TypesByFullName["System.Object"]; return Assembly.Model.TypesByFullName["System.Object"];
return null; return null;
@@ -87,7 +92,7 @@ namespace Il2CppInspector.Reflection {
public bool ContainsGenericParameters => (HasElementType && ElementType.ContainsGenericParameters) || IsGenericParameter || genericArguments.Any(ga => ga.ContainsGenericParameters); public bool ContainsGenericParameters => (HasElementType && ElementType.ContainsGenericParameters) || IsGenericParameter || genericArguments.Any(ga => ga.ContainsGenericParameters);
// 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(genericTypeDefinition ?? this);
public List<ConstructorInfo> DeclaredConstructors { get; } = new List<ConstructorInfo>(); public List<ConstructorInfo> DeclaredConstructors { get; } = new List<ConstructorInfo>();
public List<EventInfo> DeclaredEvents { get; } = new List<EventInfo>(); public List<EventInfo> DeclaredEvents { get; } = new List<EventInfo>();
@@ -121,22 +126,21 @@ namespace Il2CppInspector.Reflection {
// Get a field by its name // Get a field by its name
public FieldInfo GetField(string name) => DeclaredFields.FirstOrDefault(f => f.Name == name); public FieldInfo GetField(string name) => DeclaredFields.FirstOrDefault(f => f.Name == name);
private readonly int genericConstraintIndex; private TypeRef[] genericParameterConstraints;
private readonly int genericConstraintCount;
// Get type constraints on a generic parameter // Get type constraints on a generic parameter
public TypeInfo[] GetGenericParameterConstraints() { public TypeInfo[] GetGenericParameterConstraints() => genericParameterConstraints?.Select(t => t.Value)?.ToArray() ?? Array.Empty<TypeInfo>();
var types = new TypeInfo[genericConstraintCount];
for (int c = 0; c < genericConstraintCount; c++)
types[c] = Assembly.Model.TypesByReferenceIndex[Assembly.Model.Package.GenericConstraintIndices[genericConstraintIndex + c]];
return types;
}
private readonly TypeInfo genericTypeDefinition; private readonly TypeInfo genericTypeDefinition;
/* https://docs.microsoft.com/en-us/dotnet/api/system.type.getgenerictypedefinition?view=netframework-4.8 */ /* https://docs.microsoft.com/en-us/dotnet/api/system.type.getgenerictypedefinition?view=netframework-4.8 */
public TypeInfo GetGenericTypeDefinition() => genericTypeDefinition; public TypeInfo GetGenericTypeDefinition() {
if (genericTypeDefinition != null)
return genericTypeDefinition;
if (IsGenericTypeDefinition)
return this;
throw new InvalidOperationException("This method can only be called on generic types");
}
// Get a method by its name // Get a method by its name
public MethodInfo GetMethod(string name) => DeclaredMethods.FirstOrDefault(m => m.Name == name); public MethodInfo GetMethod(string name) => DeclaredMethods.FirstOrDefault(m => m.Name == name);
@@ -530,7 +534,17 @@ namespace Il2CppInspector.Reflection {
public bool HasElementType => ElementType != null; public bool HasElementType => ElementType != null;
private readonly TypeRef[] implementedInterfaceReferences; private readonly TypeRef[] implementedInterfaceReferences;
public IEnumerable<TypeInfo> ImplementedInterfaces => implementedInterfaceReferences.Select(x => x.Value); public IEnumerable<TypeInfo> ImplementedInterfaces {
get {
if (Definition != null)
return implementedInterfaceReferences.Select(x => x.Value);
if (genericTypeDefinition != null)
return genericTypeDefinition.ImplementedInterfaces.Select(t => t.SubstituteGenericArguments(genericArguments));
if (IsGenericParameter)
return GetGenericParameterConstraints().Where(t => t.IsInterface);
return Enumerable.Empty<TypeInfo>();
}
}
public bool IsAbstract => (Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract; public bool IsAbstract => (Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract;
public bool IsArray { get; } public bool IsArray { get; }
@@ -809,14 +823,14 @@ namespace Il2CppInspector.Reflection {
Namespace = declaringType.Namespace; Namespace = declaringType.Namespace;
// Special constraints // Special constraints
GenericParameterAttributes = (GenericParameterAttributes) param.flags; GenericParameterAttributes = (GenericParameterAttributes)param.flags;
// Type constraints // Type constraints
genericConstraintIndex = param.constraintsStart; genericParameterConstraints = new TypeRef[param.constraintsCount];
genericConstraintCount = param.constraintsCount; for (int c = 0; c < param.constraintsCount; c++)
genericParameterConstraints[c] = TypeRef.FromReferenceIndex(Assembly.Model, Assembly.Model.Package.GenericConstraintIndices[param.constraintsStart + c]);
// Base type of object (set by default) // Base type of object (set by default)
// TODO: BaseType should be set to base type constraint
// TODO: ImplementedInterfaces should be set to interface types constraints // TODO: ImplementedInterfaces should be set to interface types constraints
// Name of parameter // Name of parameter

View File

@@ -52,6 +52,11 @@ namespace Il2CppInspector
MethodInfo mGMDIGC = tGCWM.GetMethod("GenericMethodDefinitionInGenericClass"); MethodInfo mGMDIGC = tGCWM.GetMethod("GenericMethodDefinitionInGenericClass");
MethodInfo mGMDIGC2 = tGCWM.GetMethod("GenericMethodDefinitionInGenericClass2"); MethodInfo mGMDIGC2 = tGCWM.GetMethod("GenericMethodDefinitionInGenericClass2");
TypeInfo tConstrainedRefType = asm.GetType("Il2CppTests.TestSources.ConstrainedRefType`1");
MethodInfo mMAMCM = tConstrainedRefType.GetMethod("MultipleArgumentsMultipleConstraintsMethod");
TypeInfo tB = mMAMCM.GetGenericArguments()[0];
TypeInfo tI = mMAMCM.GetGenericArguments()[1];
MethodBase mGMDINGC_closed = model.GetGenericMethod( MethodBase mGMDINGC_closed = model.GetGenericMethod(
"Il2CppTests.TestSources.NonGeneric.GenericMethodDefinitionInNonGenericClass", model.GetType("System.Single")); "Il2CppTests.TestSources.NonGeneric.GenericMethodDefinitionInNonGenericClass", model.GetType("System.Single"));
MethodBase mNGMIGC_closed = model.GetGenericMethod( MethodBase mNGMIGC_closed = model.GetGenericMethod(
@@ -82,7 +87,11 @@ namespace Il2CppInspector
(tT, "T", false, false, true, true, 0), (tT, "T", false, false, true, true, 0),
(tU, "U", false, false, true, true, 1), (tU, "U", false, false, true, true, 1),
(tF, "G`1[Derived`1[V]]", true, false, true, false, -1), (tF, "G`1[Derived`1[V]]", true, false, true, false, -1),
(tNested, "Derived`1[V]+Nested[V]", true, true, true, false, -1) (tNested, "Derived`1[V]+Nested[V]", true, true, true, false, -1),
(tB, "B", false, false, true, true, 0),
(tB.BaseType, "Derived`1[R]", true, false, true, false, -1),
(tI, "I", false, false, true, true, 1),
(tI.ImplementedInterfaces.ElementAt(1), "IEnumerable`1[R]", true, false, true, false, -1),
}; };
var methodChecks = new[] { var methodChecks = new[] {