Add events, fields and properties to concrete generics.
This basically finishes the concrete generics implementation. We can now enumerate all members of a concrete generic type with full type substitution implemented. Also add a simple test to verify that we can obtain the correct type for a field of a concrete generic type.
This commit is contained in:
@@ -15,12 +15,14 @@ namespace Il2CppInspector.Reflection
|
|||||||
// IL2CPP-specific data
|
// IL2CPP-specific data
|
||||||
public Il2CppEventDefinition Definition { get; }
|
public Il2CppEventDefinition Definition { get; }
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
// Root definition: the event with Definition != null
|
||||||
|
protected readonly EventInfo rootDefinition;
|
||||||
|
|
||||||
// Information/flags about the event
|
// Information/flags about the event
|
||||||
public EventAttributes Attributes { get; }
|
public EventAttributes Attributes { 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(rootDefinition);
|
||||||
|
|
||||||
// Methods for the event
|
// Methods for the event
|
||||||
public MethodInfo AddMethod { get; }
|
public MethodInfo AddMethod { get; }
|
||||||
@@ -41,6 +43,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
Definition = pkg.Events[eventIndex];
|
Definition = pkg.Events[eventIndex];
|
||||||
Index = eventIndex;
|
Index = eventIndex;
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.nameIndex];
|
||||||
|
rootDefinition = this;
|
||||||
|
|
||||||
eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
eventTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
||||||
var eventType = pkg.TypeReferences[Definition.typeIndex];
|
var eventType = pkg.TypeReferences[Definition.typeIndex];
|
||||||
@@ -57,5 +60,17 @@ namespace Il2CppInspector.Reflection
|
|||||||
if (Definition.raise >= 0)
|
if (Definition.raise >= 0)
|
||||||
RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.raise);
|
RaiseMethod = declaringType.DeclaredMethods.First(x => x.Index == declaringType.Definition.methodStart + Definition.raise);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public EventInfo(EventInfo eventDef, TypeInfo declaringType) : base(declaringType) {
|
||||||
|
rootDefinition = eventDef;
|
||||||
|
|
||||||
|
Name = eventDef.Name;
|
||||||
|
Attributes = eventDef.Attributes;
|
||||||
|
eventTypeReference = TypeRef.FromTypeInfo(eventDef.EventHandlerType.SubstituteGenericArguments(declaringType.GetGenericArguments()));
|
||||||
|
|
||||||
|
AddMethod = declaringType.GetMethodByDefinition(eventDef.AddMethod);
|
||||||
|
RemoveMethod = declaringType.GetMethodByDefinition(eventDef.RemoveMethod);
|
||||||
|
RaiseMethod = declaringType.GetMethodByDefinition(eventDef.RaiseMethod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -4,6 +4,7 @@
|
|||||||
All rights reserved.
|
All rights reserved.
|
||||||
*/
|
*/
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Collections.Generic;
|
using System.Collections.Generic;
|
||||||
using System.Linq;
|
using System.Linq;
|
||||||
using System.Reflection;
|
using System.Reflection;
|
||||||
@@ -15,6 +16,8 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// IL2CPP-specific data
|
// IL2CPP-specific data
|
||||||
public Il2CppFieldDefinition Definition { get; }
|
public Il2CppFieldDefinition Definition { get; }
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
// Root definition: the field with Definition != null
|
||||||
|
protected readonly FieldInfo rootDefinition;
|
||||||
|
|
||||||
// Offsets for reference types start at 0x8 or 0x10 due to Il2CppObject "header" containing 2 pointers
|
// Offsets for reference types start at 0x8 or 0x10 due to Il2CppObject "header" containing 2 pointers
|
||||||
// Value types don't have this header but the offsets are still stored as starting at 0x8 or 0x10, so we have to subtract this
|
// Value types don't have this header but the offsets are still stored as starting at 0x8 or 0x10, so we have to subtract this
|
||||||
@@ -26,7 +29,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
public ulong DefaultValueMetadataAddress { get; }
|
public ulong DefaultValueMetadataAddress { 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(rootDefinition);
|
||||||
|
|
||||||
public bool HasDefaultValue => (Attributes & FieldAttributes.HasDefault) != 0;
|
public bool HasDefaultValue => (Attributes & FieldAttributes.HasDefault) != 0;
|
||||||
public object DefaultValue { get; }
|
public object DefaultValue { get; }
|
||||||
@@ -89,6 +92,8 @@ namespace Il2CppInspector.Reflection {
|
|||||||
|
|
||||||
rawOffset = pkg.FieldOffsets[fieldIndex];
|
rawOffset = pkg.FieldOffsets[fieldIndex];
|
||||||
|
|
||||||
|
rootDefinition = this;
|
||||||
|
|
||||||
fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
fieldTypeReference = TypeRef.FromReferenceIndex(Assembly.Model, Definition.typeIndex);
|
||||||
var fieldType = pkg.TypeReferences[Definition.typeIndex];
|
var fieldType = pkg.TypeReferences[Definition.typeIndex];
|
||||||
|
|
||||||
@@ -126,6 +131,20 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public FieldInfo(FieldInfo fieldDef, TypeInfo declaringType) : base(declaringType) {
|
||||||
|
if (fieldDef.Definition == null)
|
||||||
|
throw new ArgumentException("Argument must be a bare field definition");
|
||||||
|
|
||||||
|
rootDefinition = fieldDef;
|
||||||
|
|
||||||
|
Name = fieldDef.Name;
|
||||||
|
Attributes = fieldDef.Attributes;
|
||||||
|
fieldTypeReference = TypeRef.FromTypeInfo(fieldDef.FieldType.SubstituteGenericArguments(declaringType.GetGenericArguments()));
|
||||||
|
|
||||||
|
DefaultValue = fieldDef.DefaultValue;
|
||||||
|
DefaultValueMetadataAddress = fieldDef.DefaultValueMetadataAddress;
|
||||||
|
}
|
||||||
|
|
||||||
public string GetAccessModifierString() => this switch {
|
public string GetAccessModifierString() => this switch {
|
||||||
{ IsPrivate: true } => "private ",
|
{ IsPrivate: true } => "private ",
|
||||||
{ IsPublic: true } => "public ",
|
{ IsPublic: true } => "public ",
|
||||||
|
|||||||
@@ -15,12 +15,14 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// IL2CPP-specific data
|
// IL2CPP-specific data
|
||||||
public Il2CppPropertyDefinition Definition { get; }
|
public Il2CppPropertyDefinition Definition { get; }
|
||||||
public int Index { get; }
|
public int Index { get; }
|
||||||
|
// Root definition: the property with Definition != null
|
||||||
|
protected readonly PropertyInfo rootDefinition;
|
||||||
|
|
||||||
public bool CanRead => GetMethod != null;
|
public bool CanRead => GetMethod != null;
|
||||||
public bool CanWrite => SetMethod != null;
|
public bool CanWrite => SetMethod != null;
|
||||||
|
|
||||||
// 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(rootDefinition);
|
||||||
|
|
||||||
public MethodInfo GetMethod { get; }
|
public MethodInfo GetMethod { get; }
|
||||||
public MethodInfo SetMethod { get; }
|
public MethodInfo SetMethod { get; }
|
||||||
@@ -50,6 +52,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
Index = propIndex;
|
Index = propIndex;
|
||||||
Definition = pkg.Properties[propIndex];
|
Definition = pkg.Properties[propIndex];
|
||||||
Name = pkg.Strings[Definition.nameIndex];
|
Name = pkg.Strings[Definition.nameIndex];
|
||||||
|
rootDefinition = this;
|
||||||
|
|
||||||
// prop.get and prop.set are method indices from the first method of the declaring type
|
// prop.get and prop.set are method indices from the first method of the declaring type
|
||||||
if (Definition.get >= 0)
|
if (Definition.get >= 0)
|
||||||
@@ -63,10 +66,19 @@ namespace Il2CppInspector.Reflection {
|
|||||||
base(declaringType) {
|
base(declaringType) {
|
||||||
Index = -1;
|
Index = -1;
|
||||||
Definition = null;
|
Definition = null;
|
||||||
|
rootDefinition = this;
|
||||||
|
|
||||||
Name = (getter ?? setter).Name.Replace(".get_", ".").Replace(".set_", ".");
|
Name = (getter ?? setter).Name.Replace(".get_", ".").Replace(".set_", ".");
|
||||||
GetMethod = getter;
|
GetMethod = getter;
|
||||||
SetMethod = setter;
|
SetMethod = setter;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public PropertyInfo(PropertyInfo propertyDef, TypeInfo declaringType) : base(declaringType) {
|
||||||
|
rootDefinition = propertyDef;
|
||||||
|
|
||||||
|
Name = propertyDef.Name;
|
||||||
|
GetMethod = declaringType.GetMethodByDefinition(propertyDef.GetMethod);
|
||||||
|
SetMethod = declaringType.GetMethodByDefinition(propertyDef.SetMethod);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -109,8 +109,33 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<EventInfo> DeclaredEvents { get; } = new List<EventInfo>();
|
private List<EventInfo> declaredEvents;
|
||||||
public List<FieldInfo> DeclaredFields { get; } = new List<FieldInfo>();
|
public ReadOnlyCollection<EventInfo> DeclaredEvents {
|
||||||
|
get {
|
||||||
|
if (declaredEvents != null)
|
||||||
|
return declaredEvents.AsReadOnly();
|
||||||
|
if (genericTypeDefinition != null) {
|
||||||
|
var result = genericTypeDefinition.DeclaredEvents.Select(c => new EventInfo(c, this)).ToList();
|
||||||
|
declaredEvents = result;
|
||||||
|
return result.AsReadOnly();
|
||||||
|
}
|
||||||
|
return new List<EventInfo>().AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private List<FieldInfo> declaredFields;
|
||||||
|
public ReadOnlyCollection<FieldInfo> DeclaredFields {
|
||||||
|
get {
|
||||||
|
if (declaredFields != null)
|
||||||
|
return declaredFields.AsReadOnly();
|
||||||
|
if (genericTypeDefinition != null) {
|
||||||
|
var result = genericTypeDefinition.DeclaredFields.Select(c => new FieldInfo(c, this)).ToList();
|
||||||
|
declaredFields = result;
|
||||||
|
return result.AsReadOnly();
|
||||||
|
}
|
||||||
|
return new List<FieldInfo>().AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public List<MemberInfo> DeclaredMembers => new IEnumerable<MemberInfo>[] {
|
public List<MemberInfo> DeclaredMembers => new IEnumerable<MemberInfo>[] {
|
||||||
DeclaredConstructors, DeclaredEvents, DeclaredFields, DeclaredMethods,
|
DeclaredConstructors, DeclaredEvents, DeclaredFields, DeclaredMethods,
|
||||||
@@ -147,7 +172,19 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
public List<PropertyInfo> DeclaredProperties { get; } = new List<PropertyInfo>();
|
private List<PropertyInfo> declaredProperties;
|
||||||
|
public ReadOnlyCollection<PropertyInfo> DeclaredProperties {
|
||||||
|
get {
|
||||||
|
if (declaredProperties != null)
|
||||||
|
return declaredProperties.AsReadOnly();
|
||||||
|
if (genericTypeDefinition != null) {
|
||||||
|
var result = genericTypeDefinition.DeclaredProperties.Select(c => new PropertyInfo(c, this)).ToList();
|
||||||
|
declaredProperties = result;
|
||||||
|
return result.AsReadOnly();
|
||||||
|
}
|
||||||
|
return new List<PropertyInfo>().AsReadOnly();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// 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);
|
||||||
@@ -737,8 +774,9 @@ namespace Il2CppInspector.Reflection {
|
|||||||
declaredNestedTypes[n] = TypeRef.FromDefinitionIndex(Assembly.Model, pkg.NestedTypeIndices[Definition.nestedTypesStart + n]);
|
declaredNestedTypes[n] = TypeRef.FromDefinitionIndex(Assembly.Model, pkg.NestedTypeIndices[Definition.nestedTypesStart + n]);
|
||||||
|
|
||||||
// Add all fields
|
// Add all fields
|
||||||
|
declaredFields = new List<FieldInfo>();
|
||||||
for (var f = Definition.fieldStart; f < Definition.fieldStart + Definition.field_count; f++)
|
for (var f = Definition.fieldStart; f < Definition.fieldStart + Definition.field_count; f++)
|
||||||
DeclaredFields.Add(new FieldInfo(pkg, f, this));
|
declaredFields.Add(new FieldInfo(pkg, f, this));
|
||||||
|
|
||||||
// Add all methods
|
// Add all methods
|
||||||
declaredConstructors = new List<ConstructorInfo>();
|
declaredConstructors = new List<ConstructorInfo>();
|
||||||
@@ -752,8 +790,9 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Add all properties
|
// Add all properties
|
||||||
|
declaredProperties = new List<PropertyInfo>();
|
||||||
for (var p = Definition.propertyStart; p < Definition.propertyStart + Definition.property_count; p++)
|
for (var p = Definition.propertyStart; p < Definition.propertyStart + Definition.property_count; p++)
|
||||||
DeclaredProperties.Add(new PropertyInfo(pkg, p, this));
|
declaredProperties.Add(new PropertyInfo(pkg, p, this));
|
||||||
|
|
||||||
// There are rare cases when explicitly implemented interface properties
|
// There are rare cases when explicitly implemented interface properties
|
||||||
// are only given as methods in the metadata. Find these and add them as properties
|
// are only given as methods in the metadata. Find these and add them as properties
|
||||||
@@ -787,11 +826,12 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
foreach (var prop in pairedEip)
|
foreach (var prop in pairedEip)
|
||||||
DeclaredProperties.Add(new PropertyInfo(prop.get, prop.set, this));
|
declaredProperties.Add(new PropertyInfo(prop.get, prop.set, this));
|
||||||
|
|
||||||
// Add all events
|
// Add all events
|
||||||
|
declaredEvents = new List<EventInfo>();
|
||||||
for (var e = Definition.eventStart; e < Definition.eventStart + Definition.event_count; e++)
|
for (var e = Definition.eventStart; e < Definition.eventStart + Definition.event_count; e++)
|
||||||
DeclaredEvents.Add(new EventInfo(pkg, e, this));
|
declaredEvents.Add(new EventInfo(pkg, e, this));
|
||||||
}
|
}
|
||||||
|
|
||||||
// Initialize a type from a concrete generic instance
|
// Initialize a type from a concrete generic instance
|
||||||
@@ -816,11 +856,6 @@ namespace Il2CppInspector.Reflection {
|
|||||||
IsGenericType = true;
|
IsGenericType = true;
|
||||||
|
|
||||||
genericArguments = genericArgs;
|
genericArguments = genericArgs;
|
||||||
|
|
||||||
/* TODO: This is a bare definition at the moment. We need to iterate over all the members of genericTypeDefinition
|
|
||||||
* and replace the matching generic type parameters with our concrete type parameters,
|
|
||||||
* as well as setting the various TypeInfo properties here
|
|
||||||
*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// Substitutes the elements of an array of types for the type parameters of the current generic type definition
|
// Substitutes the elements of an array of types for the type parameters of the current generic type definition
|
||||||
|
|||||||
@@ -41,6 +41,7 @@ namespace Il2CppInspector
|
|||||||
TypeInfo tT = tBase.GenericTypeParameters[0];
|
TypeInfo tT = tBase.GenericTypeParameters[0];
|
||||||
TypeInfo tU = tBase.GenericTypeParameters[1];
|
TypeInfo tU = tBase.GenericTypeParameters[1];
|
||||||
TypeInfo tF = tDerived.GetField("F").FieldType;
|
TypeInfo tF = tDerived.GetField("F").FieldType;
|
||||||
|
TypeInfo tF_closed = tDerived_closed.GetField("F").FieldType;
|
||||||
TypeInfo tNested = asm.GetType("Il2CppTests.TestSources.Derived`1+Nested");
|
TypeInfo tNested = asm.GetType("Il2CppTests.TestSources.Derived`1+Nested");
|
||||||
|
|
||||||
TypeInfo tNG = asm.GetType("Il2CppTests.TestSources.NonGeneric");
|
TypeInfo tNG = asm.GetType("Il2CppTests.TestSources.NonGeneric");
|
||||||
@@ -87,6 +88,7 @@ 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),
|
||||||
|
(tF_closed, "G`1[Derived`1[System.Int32]]", true, false, false, 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, "B", false, false, true, true, 0),
|
||||||
(tB.BaseType, "Derived`1[R]", true, false, true, false, -1),
|
(tB.BaseType, "Derived`1[R]", true, false, true, false, -1),
|
||||||
|
|||||||
Reference in New Issue
Block a user