Implement constructors & methods on constructed generics.

We adopt roughly the same approach as the C# Reflection API: a
GenericMethodDefinition is a method which has no method parameters
substituted, but lives in a open or closed type with some or all
type parameters substituted. To ensure the uniqueness of the MethodInfo,
we cache by the method type arguments, and also cache generated
DeclaredConstructors/DeclaredMethods in the TypeInfo.

This also enables MakeGenericMethod, albeit in a slightly different form
than the Reflection API: MakeGenericMethod lives in MethodBase, so it's
callable from a constructor (even though in C# constructors cannot be
generic). This slight violation of the spec reduces code duplication, so
it's probably worth it.

Finally, VirtualAddress gets set when populating GenericMethods, and so
it'll work whether or not the methods get cached/generated ahead of
time.
This commit is contained in:
Robert Xiao
2020-04-13 04:21:30 -07:00
committed by Katy
parent 867f559f18
commit 652d76d6fe
6 changed files with 167 additions and 38 deletions

View File

@@ -18,11 +18,14 @@ namespace Il2CppInspector.Reflection
public int Index { get; }
public ulong DefaultValueMetadataAddress { get; }
// Root definition: the parameter with Definition != null
private readonly ParameterInfo rootDefinition;
// Information/flags about the parameter
public ParameterAttributes Attributes { get; }
// Custom attributes for this parameter
public IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(this);
public IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(rootDefinition);
// True if the parameter has a default value
public bool HasDefaultValue => (Attributes & ParameterAttributes.HasDefault) != 0;
@@ -63,6 +66,7 @@ namespace Il2CppInspector.Reflection
Definition = pkg.Params[Index];
Name = pkg.Strings[Definition.nameIndex];
rootDefinition = this;
// Handle unnamed/obfuscated parameter names
if (string.IsNullOrEmpty(Name))
@@ -97,9 +101,10 @@ namespace Il2CppInspector.Reflection
}
// Create a concrete type parameter from a generic type parameter
public ParameterInfo(ParameterInfo generic, TypeInfo concrete) {
private ParameterInfo(ParameterInfo generic, MethodBase declaringMethod, TypeInfo concrete) {
rootDefinition = generic.rootDefinition;
DeclaringMethod = generic.DeclaringMethod;
DeclaringMethod = declaringMethod;
Name = generic.Name;
Position = generic.Position;
Attributes = generic.Attributes;
@@ -110,11 +115,11 @@ namespace Il2CppInspector.Reflection
DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress;
}
public ParameterInfo SubstituteGenericArguments(TypeInfo[] typeArguments, TypeInfo[] methodArguments = null) {
public ParameterInfo SubstituteGenericArguments(MethodBase declaringMethod, TypeInfo[] typeArguments, TypeInfo[] methodArguments = null) {
TypeInfo t = ParameterType.SubstituteGenericArguments(typeArguments, methodArguments);
if (t == ParameterType)
return this;
return new ParameterInfo(this, t);
return new ParameterInfo(this, declaringMethod, t);
}
// ref will be handled as part of the type name