Files
Il2CppInspectorRedux/Il2CppInspector.Common/Reflection/ParameterInfo.cs
Robert Xiao a9f6e7b4e0 Generify reference indices to prepare for generic instances
We use indices into the TypesByReferenceIndex table to defer type lookup
during model construction. However, this won't support fully generic
instances (which might not be in the type table at all). This patch
introduces a new TypeRef abstraction which can either represent a fixed
index or an instantiated generic type.
2020-06-20 10:17:48 +02:00

135 lines
6.1 KiB
C#

/*
Copyright 2017-2020 Katy Coe - http://www.hearthcode.org - http://www.djkaty.com
All rights reserved.
*/
using System;
using System.Collections.Generic;
using System.Linq;
using System.Reflection;
namespace Il2CppInspector.Reflection
{
public class ParameterInfo
{
// IL2CPP-specific data
public Il2CppParameterDefinition Definition { get; }
public int Index { get; }
public ulong DefaultValueMetadataAddress { get; }
// Information/flags about the parameter
public ParameterAttributes Attributes { get; }
// Custom attributes for this parameter
public IEnumerable<CustomAttributeData> CustomAttributes => CustomAttributeData.GetCustomAttributes(this);
// True if the parameter has a default value
public bool HasDefaultValue => (Attributes & ParameterAttributes.HasDefault) != 0;
// Default value for the parameter
public object DefaultValue { get; }
public bool IsIn => (Attributes & ParameterAttributes.In) != 0;
public bool IsOptional => (Attributes & ParameterAttributes.Optional) != 0;
public bool IsOut => (Attributes & ParameterAttributes.Out) != 0;
public bool IsRetval => (Attributes & ParameterAttributes.Retval) != 0;
// The method in which the parameter is defined
public MethodBase DeclaringMethod { get; }
// Name of parameter
public string Name { get; }
public string CSharpSafeName => Constants.Keywords.Contains(Name) ? "@" + Name : Name;
// Type of this parameter
private readonly TypeRef paramTypeReference;
public TypeInfo ParameterType => paramTypeReference.Value;
// Zero-indexed position of the parameter in parameter list
public int Position { get; }
// Create a parameter. Specify paramIndex == -1 for a return type parameter
public ParameterInfo(Il2CppInspector pkg, int paramIndex, MethodBase declaringMethod) {
Index = paramIndex;
DeclaringMethod = declaringMethod;
if (paramIndex == -1) {
Position = -1;
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, declaringMethod.Definition.returnType);
Attributes |= ParameterAttributes.Retval;
return;
}
Definition = pkg.Params[Index];
Name = pkg.Strings[Definition.nameIndex];
// Handle unnamed/obfuscated parameter names
if (string.IsNullOrEmpty(Name))
Name = string.Format($"param_{Index:x8}");
Position = paramIndex - declaringMethod.Definition.parameterStart;
paramTypeReference = TypeRef.FromReferenceIndex(declaringMethod.Assembly.Model, Definition.typeIndex);
var paramType = pkg.TypeReferences[Definition.typeIndex];
if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_HAS_DEFAULT) != 0)
Attributes |= ParameterAttributes.HasDefault;
if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_OPTIONAL) != 0)
Attributes |= ParameterAttributes.Optional;
if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_IN) != 0)
Attributes |= ParameterAttributes.In;
if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_OUT) != 0)
Attributes |= ParameterAttributes.Out;
if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_RESERVED_MASK) != 0)
Attributes |= ParameterAttributes.ReservedMask;
if ((paramType.attrs & Il2CppConstants.PARAM_ATTRIBUTE_HAS_FIELD_MARSHAL) != 0)
Attributes |= ParameterAttributes.HasFieldMarshal;
if (Position == -1)
Attributes |= ParameterAttributes.Retval;
// Default initialization value if present
if (pkg.ParameterDefaultValue.TryGetValue(paramIndex, out (ulong address, object variant) value)) {
DefaultValue = value.variant;
DefaultValueMetadataAddress = value.address;
}
}
// Create a concrete type parameter from a generic type parameter
public ParameterInfo(Il2CppModel model, ParameterInfo generic, TypeInfo concrete) {
DeclaringMethod = generic.DeclaringMethod;
Name = generic.Name;
Position = generic.Position;
Attributes = generic.Attributes;
// TODO substitute concrete params?
paramTypeReference = TypeRef.FromTypeInfo(concrete);
DefaultValue = generic.DefaultValue;
DefaultValueMetadataAddress = generic.DefaultValueMetadataAddress;
}
// ref will be handled as part of the type name
public string GetModifierString() =>
(IsIn && !IsOut ? "in " : "")
+ (IsOut && !IsIn ? "out " : "")
+ (IsIn && IsOut ? "[In, Out] " : "")
+ (!IsIn && !IsOut && ParameterType.IsByRef ? "ref " : "");
private string getCSharpSignatureString(Scope scope) => $"{GetModifierString()}{ParameterType.GetScopedCSharpName(scope, omitRef: true)}";
public string GetSignatureString() => $"{GetModifierString()}{ParameterType.FullName}";
public string GetParameterString(Scope usingScope, bool emitPointer = false, bool compileAttributes = false) => IsRetval? null :
$"{CustomAttributes.ToString(usingScope, inline: true, emitPointer: emitPointer, mustCompile: compileAttributes).Replace("[ParamArray]", "params")}"
+ (Position == 0 && DeclaringMethod.GetCustomAttributes("System.Runtime.CompilerServices.ExtensionAttribute").Any()? "this ":"")
+ $"{getCSharpSignatureString(usingScope)} {CSharpSafeName}"
+ (IsOptional? " = " + DefaultValue.ToCSharpValue(ParameterType, usingScope)
+ (emitPointer && !(DefaultValue is null)? $" /* Metadata: 0x{(uint) DefaultValueMetadataAddress:X8} */" : "") : "");
public string GetReturnParameterString(Scope scope) => !IsRetval? null : getCSharpSignatureString(scope);
public override string ToString() => ParameterType.Name + " " + Name;
}
}