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) {
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")
return Assembly.Model.TypesByFullName["System.Object"];
return null;
@@ -87,7 +92,7 @@ namespace Il2CppInspector.Reflection {
public bool ContainsGenericParameters => (HasElementType && ElementType.ContainsGenericParameters) || IsGenericParameter || genericArguments.Any(ga => ga.ContainsGenericParameters);
// 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<EventInfo> DeclaredEvents { get; } = new List<EventInfo>();
@@ -121,22 +126,21 @@ namespace Il2CppInspector.Reflection {
// Get a field by its name
public FieldInfo GetField(string name) => DeclaredFields.FirstOrDefault(f => f.Name == name);
private readonly int genericConstraintIndex;
private readonly int genericConstraintCount;
private TypeRef[] genericParameterConstraints;
// Get type constraints on a generic parameter
public TypeInfo[] GetGenericParameterConstraints() {
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;
}
public TypeInfo[] GetGenericParameterConstraints() => genericParameterConstraints?.Select(t => t.Value)?.ToArray() ?? Array.Empty<TypeInfo>();
private readonly TypeInfo genericTypeDefinition;
/* 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
public MethodInfo GetMethod(string name) => DeclaredMethods.FirstOrDefault(m => m.Name == name);
@@ -530,7 +534,17 @@ namespace Il2CppInspector.Reflection {
public bool HasElementType => ElementType != null;
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 IsArray { get; }
@@ -812,11 +826,11 @@ namespace Il2CppInspector.Reflection {
GenericParameterAttributes = (GenericParameterAttributes)param.flags;
// Type constraints
genericConstraintIndex = param.constraintsStart;
genericConstraintCount = param.constraintsCount;
genericParameterConstraints = new TypeRef[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)
// TODO: BaseType should be set to base type constraint
// TODO: ImplementedInterfaces should be set to interface types constraints
// Name of parameter

View File

@@ -52,6 +52,11 @@ namespace Il2CppInspector
MethodInfo mGMDIGC = tGCWM.GetMethod("GenericMethodDefinitionInGenericClass");
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(
"Il2CppTests.TestSources.NonGeneric.GenericMethodDefinitionInNonGenericClass", model.GetType("System.Single"));
MethodBase mNGMIGC_closed = model.GetGenericMethod(
@@ -82,7 +87,11 @@ namespace Il2CppInspector
(tT, "T", false, false, true, true, 0),
(tU, "U", false, false, true, true, 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[] {