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:
@@ -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
|
||||
|
||||
@@ -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[] {
|
||||
|
||||
Reference in New Issue
Block a user