Model and Output: Dramatically improve handling of byref types
This commit is contained in:
@@ -52,11 +52,14 @@ namespace Il2CppInspector.Reflection
|
|||||||
public Assembly GetAssembly(string name) => Assemblies.FirstOrDefault(a => a.ShortName == name);
|
public Assembly GetAssembly(string name) => Assemblies.FirstOrDefault(a => a.ShortName == name);
|
||||||
|
|
||||||
private TypeInfo getNewTypeUsage(Il2CppType usage, MemberTypes memberType) {
|
private TypeInfo getNewTypeUsage(Il2CppType usage, MemberTypes memberType) {
|
||||||
|
TypeInfo underlyingType;
|
||||||
|
|
||||||
switch (usage.type) {
|
switch (usage.type) {
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
case Il2CppTypeEnum.IL2CPP_TYPE_CLASS:
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
case Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE:
|
||||||
// Classes defined in the metadata
|
// Classes defined in the metadata
|
||||||
return TypesByDefinitionIndex[usage.datapoint]; // klassIndex
|
underlyingType = TypesByDefinitionIndex[usage.datapoint]; // klassIndex
|
||||||
|
break;
|
||||||
|
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
case Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST:
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
case Il2CppTypeEnum.IL2CPP_TYPE_ARRAY:
|
||||||
@@ -65,12 +68,17 @@ namespace Il2CppInspector.Reflection
|
|||||||
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
case Il2CppTypeEnum.IL2CPP_TYPE_VAR:
|
||||||
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
case Il2CppTypeEnum.IL2CPP_TYPE_MVAR:
|
||||||
// Everything that requires special handling
|
// Everything that requires special handling
|
||||||
return new TypeInfo(this, usage, memberType);
|
underlyingType = new TypeInfo(this, usage, memberType);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Primitive types
|
// Primitive types
|
||||||
return GetTypeFromTypeEnum(usage.type);
|
underlyingType = GetTypeFromTypeEnum(usage.type);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Create a reference type if necessary
|
||||||
|
return usage.byref? underlyingType.MakeByRefType() : underlyingType;
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get or generate a type from its IL2CPP binary type usage reference
|
// Get or generate a type from its IL2CPP binary type usage reference
|
||||||
|
|||||||
@@ -31,7 +31,8 @@ namespace Il2CppInspector.Reflection
|
|||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Generic arguments (and on ConstructorInfo)
|
// TODO: Generic arguments (and on ConstructorInfo)
|
||||||
public override string ToString() => ReturnType.Name + " " + Name + "(" + string.Join(", ", DeclaredParameters.Select(x => x.ParameterType.Name)) + ")";
|
public override string ToString() => ReturnType.Name + " " + Name + "(" + string.Join(", ",
|
||||||
|
DeclaredParameters.Select(x => x.ParameterType.IsByRef? x.ParameterType.Name.TrimEnd('&') + " ByRef" : x.ParameterType.Name)) + ")";
|
||||||
|
|
||||||
public override string GetSignatureString() => ReturnParameter.GetSignatureString() + " " + Name + GetFullTypeParametersString()
|
public override string GetSignatureString() => ReturnParameter.GetSignatureString() + " " + Name + GetFullTypeParametersString()
|
||||||
+ "(" + string.Join(",", DeclaredParameters.Select(x => x.GetSignatureString())) + ")";
|
+ "(" + string.Join(",", DeclaredParameters.Select(x => x.GetSignatureString())) + ")";
|
||||||
|
|||||||
@@ -30,8 +30,6 @@ namespace Il2CppInspector.Reflection
|
|||||||
// Default value for the parameter
|
// Default value for the parameter
|
||||||
public object DefaultValue { get; }
|
public object DefaultValue { get; }
|
||||||
|
|
||||||
public bool IsByRef => !ParameterType.ContainsGenericParameters && paramTypeUsage == ParameterType.Definition.byrefTypeIndex;
|
|
||||||
|
|
||||||
public bool IsIn => (Attributes & ParameterAttributes.In) != 0;
|
public bool IsIn => (Attributes & ParameterAttributes.In) != 0;
|
||||||
public bool IsOptional => (Attributes & ParameterAttributes.Optional) != 0;
|
public bool IsOptional => (Attributes & ParameterAttributes.Optional) != 0;
|
||||||
public bool IsOut => (Attributes & ParameterAttributes.Out) != 0;
|
public bool IsOut => (Attributes & ParameterAttributes.Out) != 0;
|
||||||
@@ -96,12 +94,13 @@ namespace Il2CppInspector.Reflection
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// ref will be handled as part of the type name
|
||||||
public string GetModifierString() =>
|
public string GetModifierString() =>
|
||||||
(IsIn ? "in " : "")
|
(IsIn ? "in " : "")
|
||||||
+ (IsByRef? "ref " : "")
|
+ (IsOut ? "out " : "")
|
||||||
+ (IsOut? "out " : "");
|
+ (!IsIn && !IsOut && ParameterType.IsByRef ? "ref " : "");
|
||||||
|
|
||||||
private string getCSharpSignatureString(Scope scope) => $"{GetModifierString()}{ParameterType.GetScopedCSharpName(scope)}";
|
private string getCSharpSignatureString(Scope scope) => $"{GetModifierString()}{ParameterType.GetScopedCSharpName(scope, omitRef: true)}";
|
||||||
public string GetSignatureString() => $"{GetModifierString()}{ParameterType.FullName}";
|
public string GetSignatureString() => $"{GetModifierString()}{ParameterType.FullName}";
|
||||||
|
|
||||||
public string GetParameterString(Scope usingScope, bool emitPointer = false, bool compileAttributes = false) => IsRetval? null :
|
public string GetParameterString(Scope usingScope, bool emitPointer = false, bool compileAttributes = false) => IsRetval? null :
|
||||||
@@ -112,5 +111,7 @@ namespace Il2CppInspector.Reflection
|
|||||||
+ (emitPointer && !(DefaultValue is null)? $" /* Metadata: 0x{(uint) DefaultValueMetadataAddress:X8} */" : "") : "");
|
+ (emitPointer && !(DefaultValue is null)? $" /* Metadata: 0x{(uint) DefaultValueMetadataAddress:X8} */" : "") : "");
|
||||||
|
|
||||||
public string GetReturnParameterString(Scope scope) => !IsRetval? null : getCSharpSignatureString(scope);
|
public string GetReturnParameterString(Scope scope) => !IsRetval? null : getCSharpSignatureString(scope);
|
||||||
|
|
||||||
|
public override string ToString() => ParameterType.Name + " " + Name;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -59,13 +59,16 @@ namespace Il2CppInspector.Reflection {
|
|||||||
n = "out " + n;
|
n = "out " + n;
|
||||||
if ((GenericParameterAttributes & GenericParameterAttributes.Contravariant) == GenericParameterAttributes.Contravariant)
|
if ((GenericParameterAttributes & GenericParameterAttributes.Contravariant) == GenericParameterAttributes.Contravariant)
|
||||||
n = "in " + n;
|
n = "in " + n;
|
||||||
|
if (IsByRef)
|
||||||
|
n = "ref " + n;
|
||||||
return n + (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "") + (IsPointer ? "*" : "");
|
return n + (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "") + (IsPointer ? "*" : "");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// C# name as it would be written in a type declaration
|
// C# name as it would be written in a type declaration
|
||||||
public string CSharpTypeDeclarationName =>
|
public string CSharpTypeDeclarationName =>
|
||||||
(HasElementType?
|
(IsByRef? "ref " : "")
|
||||||
|
+ (HasElementType?
|
||||||
ElementType.CSharpTypeDeclarationName :
|
ElementType.CSharpTypeDeclarationName :
|
||||||
((GenericParameterAttributes & GenericParameterAttributes.Contravariant) == GenericParameterAttributes.Contravariant? "in " : "")
|
((GenericParameterAttributes & GenericParameterAttributes.Contravariant) == GenericParameterAttributes.Contravariant? "in " : "")
|
||||||
+ ((GenericParameterAttributes & GenericParameterAttributes.Covariant) == GenericParameterAttributes.Covariant? "out ":"")
|
+ ((GenericParameterAttributes & GenericParameterAttributes.Covariant) == GenericParameterAttributes.Covariant? "out ":"")
|
||||||
@@ -144,14 +147,16 @@ namespace Il2CppInspector.Reflection {
|
|||||||
// Type name including namespace
|
// Type name including namespace
|
||||||
public string FullName =>
|
public string FullName =>
|
||||||
IsGenericParameter? null :
|
IsGenericParameter? null :
|
||||||
|
HasElementType && ElementType.IsGenericParameter? null :
|
||||||
(HasElementType? ElementType.FullName :
|
(HasElementType? ElementType.FullName :
|
||||||
(DeclaringType != null? DeclaringType.FullName + "+" : Namespace + (Namespace.Length > 0? "." : ""))
|
(DeclaringType != null? DeclaringType.FullName + "+" : Namespace + (Namespace.Length > 0? "." : ""))
|
||||||
+ base.Name)
|
+ base.Name)
|
||||||
+ (IsArray? "[" + new string(',', GetArrayRank() - 1) + "]" : "")
|
+ (IsArray? "[" + new string(',', GetArrayRank() - 1) + "]" : "")
|
||||||
|
+ (IsByRef? "&" : "")
|
||||||
+ (IsPointer? "*" : "");
|
+ (IsPointer? "*" : "");
|
||||||
|
|
||||||
// Returns the minimally qualified type name required to refer to this type within the specified scope
|
// Returns the minimally qualified type name required to refer to this type within the specified scope
|
||||||
public string GetScopedFullName(Scope scope) {
|
private string getScopedFullName(Scope scope) {
|
||||||
// This is the type to be used (generic type parameters have a null FullName)
|
// This is the type to be used (generic type parameters have a null FullName)
|
||||||
var usedType = FullName?.Replace('+', '.') ?? Name;
|
var usedType = FullName?.Replace('+', '.') ?? Name;
|
||||||
|
|
||||||
@@ -299,7 +304,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// C#-friendly type name as it should be used in the scope of a given type
|
// C#-friendly type name as it should be used in the scope of a given type
|
||||||
public string GetScopedCSharpName(Scope usingScope = null) {
|
public string GetScopedCSharpName(Scope usingScope = null, bool omitRef = false) {
|
||||||
// Unscoped name if no using scope specified
|
// Unscoped name if no using scope specified
|
||||||
if (usingScope == null)
|
if (usingScope == null)
|
||||||
return CSharpName;
|
return CSharpName;
|
||||||
@@ -308,7 +313,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
|
|
||||||
// Built-in keyword type names do not require a scope
|
// Built-in keyword type names do not require a scope
|
||||||
var i = Il2CppConstants.FullNameTypeString.IndexOf(s);
|
var i = Il2CppConstants.FullNameTypeString.IndexOf(s);
|
||||||
var n = i != -1 ? Il2CppConstants.CSharpTypeString[i] : GetScopedFullName(usingScope);
|
var n = i != -1 ? Il2CppConstants.CSharpTypeString[i] : getScopedFullName(usingScope);
|
||||||
|
|
||||||
// Unmangle generic type names
|
// Unmangle generic type names
|
||||||
if (n?.IndexOf("`", StringComparison.Ordinal) != -1)
|
if (n?.IndexOf("`", StringComparison.Ordinal) != -1)
|
||||||
@@ -327,7 +332,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
if (HasElementType)
|
if (HasElementType)
|
||||||
n = ElementType.GetScopedCSharpName(usingScope);
|
n = ElementType.GetScopedCSharpName(usingScope);
|
||||||
|
|
||||||
return n + (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "") + (IsPointer ? "*" : "");
|
return (IsByRef && !omitRef? "ref " : "") + n + (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "") + (IsPointer ? "*" : "");
|
||||||
}
|
}
|
||||||
|
|
||||||
// Get the generic type parameters for a specific usage of this type based on its scope,
|
// Get the generic type parameters for a specific usage of this type based on its scope,
|
||||||
@@ -375,7 +380,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
|
|
||||||
public bool IsAbstract => (Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract;
|
public bool IsAbstract => (Attributes & TypeAttributes.Abstract) == TypeAttributes.Abstract;
|
||||||
public bool IsArray { get; }
|
public bool IsArray { get; }
|
||||||
public bool IsByRef => throw new NotImplementedException();
|
public bool IsByRef { get; }
|
||||||
public bool IsClass => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class;
|
public bool IsClass => (Attributes & TypeAttributes.ClassSemanticsMask) == TypeAttributes.Class;
|
||||||
public bool IsEnum => enumUnderlyingTypeUsage != -1;
|
public bool IsEnum => enumUnderlyingTypeUsage != -1;
|
||||||
public bool IsGenericParameter { get; }
|
public bool IsGenericParameter { get; }
|
||||||
@@ -504,6 +509,10 @@ namespace Il2CppInspector.Reflection {
|
|||||||
if (((Definition.bitfield >> 1) & 1) == 1)
|
if (((Definition.bitfield >> 1) & 1) == 1)
|
||||||
enumUnderlyingTypeUsage = Definition.elementTypeIndex;
|
enumUnderlyingTypeUsage = Definition.elementTypeIndex;
|
||||||
|
|
||||||
|
// Pass-by-reference type
|
||||||
|
// NOTE: This should actually always evaluate to false in the current implementation
|
||||||
|
IsByRef = Index == Definition.byrefTypeIndex;
|
||||||
|
|
||||||
// Add all implemented interfaces
|
// Add all implemented interfaces
|
||||||
implementedInterfaceUsages = new int[Definition.interfaces_count];
|
implementedInterfaceUsages = new int[Definition.interfaces_count];
|
||||||
for (var i = 0; i < Definition.interfaces_count; i++)
|
for (var i = 0; i < Definition.interfaces_count; i++)
|
||||||
@@ -692,6 +701,23 @@ namespace Il2CppInspector.Reflection {
|
|||||||
public TypeInfo(MethodBase declaringMethod, Il2CppGenericParameter param) : this(declaringMethod.DeclaringType, param)
|
public TypeInfo(MethodBase declaringMethod, Il2CppGenericParameter param) : this(declaringMethod.DeclaringType, param)
|
||||||
=> DeclaringMethod = declaringMethod;
|
=> DeclaringMethod = declaringMethod;
|
||||||
|
|
||||||
|
// Initialize a type that is a reference to the specified type
|
||||||
|
private TypeInfo(TypeInfo underlyingType) {
|
||||||
|
ElementType = underlyingType;
|
||||||
|
IsByRef = true;
|
||||||
|
|
||||||
|
// No base type or declaring type for reference types
|
||||||
|
Assembly = ElementType.Assembly;
|
||||||
|
Definition = ElementType.Definition;
|
||||||
|
Index = ElementType.Index;
|
||||||
|
Namespace = ElementType.Namespace;
|
||||||
|
Name = ElementType.Name;
|
||||||
|
|
||||||
|
Attributes = ElementType.Attributes;
|
||||||
|
}
|
||||||
|
|
||||||
|
public TypeInfo MakeByRefType() => new TypeInfo(this);
|
||||||
|
|
||||||
// Get all the other types directly referenced by this type (single level depth; no recursion)
|
// Get all the other types directly referenced by this type (single level depth; no recursion)
|
||||||
public List<TypeInfo> GetAllTypeReferences() {
|
public List<TypeInfo> GetAllTypeReferences() {
|
||||||
var refs = new HashSet<TypeInfo>();
|
var refs = new HashSet<TypeInfo>();
|
||||||
@@ -797,6 +823,7 @@ namespace Il2CppInspector.Reflection {
|
|||||||
+ (GenericTypeParameters != null ? "[" + string.Join(",", GenericTypeParameters.Select(x => x.Namespace != Namespace? x.FullName ?? x.Name : x.Name)) + "]" : "")
|
+ (GenericTypeParameters != null ? "[" + string.Join(",", GenericTypeParameters.Select(x => x.Namespace != Namespace? x.FullName ?? x.Name : x.Name)) + "]" : "")
|
||||||
+ (GenericTypeArguments != null ? "[" + string.Join(",", GenericTypeArguments.Select(x => x.Namespace != Namespace? x.FullName ?? x.Name : x.Name)) + "]" : ""))
|
+ (GenericTypeArguments != null ? "[" + string.Join(",", GenericTypeArguments.Select(x => x.Namespace != Namespace? x.FullName ?? x.Name : x.Name)) + "]" : ""))
|
||||||
+ (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "")
|
+ (IsArray ? "[" + new string(',', GetArrayRank() - 1) + "]" : "")
|
||||||
|
+ (IsByRef ? "&" : "")
|
||||||
+ (IsPointer ? "*" : "");
|
+ (IsPointer ? "*" : "");
|
||||||
|
|
||||||
public string GetAccessModifierString() => this switch {
|
public string GetAccessModifierString() => this switch {
|
||||||
|
|||||||
Reference in New Issue
Block a user