Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add Type field to AttributeAttribute #393

Merged
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 2 additions & 1 deletion Cpp2IL.Core/Model/Contexts/ReferencedTypeAnalysisContext.cs
Original file line number Diff line number Diff line change
@@ -1,3 +1,4 @@
using System;
using LibCpp2IL.BinaryStructures;

namespace Cpp2IL.Core.Model.Contexts;
Expand All @@ -8,7 +9,7 @@ namespace Cpp2IL.Core.Model.Contexts;
public abstract class ReferencedTypeAnalysisContext(AssemblyAnalysisContext referencedFrom)
: TypeAnalysisContext(null, referencedFrom)
{
public abstract Il2CppTypeEnum Type { get; } //Must be set by derived classes
public override Il2CppTypeEnum Type => throw new NotImplementedException("Type must be set by derived classes");

protected override int CustomAttributeIndex => -1;

Expand Down
50 changes: 49 additions & 1 deletion Cpp2IL.Core/Model/Contexts/SystemTypesContext.cs
Original file line number Diff line number Diff line change
@@ -1,4 +1,6 @@
namespace Cpp2IL.Core.Model.Contexts;
using LibCpp2IL.BinaryStructures;

namespace Cpp2IL.Core.Model.Contexts;

public class SystemTypesContext
{
Expand Down Expand Up @@ -84,4 +86,50 @@ public bool IsPrimitive(TypeAnalysisContext context)
context == SystemIntPtrType ||
context == SystemUIntPtrType;
}

public bool TryGetIl2CppTypeEnum(TypeAnalysisContext context, out Il2CppTypeEnum value)
{
if (context == SystemBooleanType)
value = Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN;
else if (context == SystemCharType)
value = Il2CppTypeEnum.IL2CPP_TYPE_CHAR;
else if (context == SystemSByteType)
value = Il2CppTypeEnum.IL2CPP_TYPE_I1;
else if (context == SystemByteType)
value = Il2CppTypeEnum.IL2CPP_TYPE_U1;
else if (context == SystemInt16Type)
value = Il2CppTypeEnum.IL2CPP_TYPE_I2;
else if (context == SystemUInt16Type)
value = Il2CppTypeEnum.IL2CPP_TYPE_U2;
else if (context == SystemInt32Type)
value = Il2CppTypeEnum.IL2CPP_TYPE_I4;
else if (context == SystemUInt32Type)
value = Il2CppTypeEnum.IL2CPP_TYPE_U4;
else if (context == SystemInt64Type)
value = Il2CppTypeEnum.IL2CPP_TYPE_I8;
else if (context == SystemUInt64Type)
value = Il2CppTypeEnum.IL2CPP_TYPE_U8;
else if (context == SystemSingleType)
value = Il2CppTypeEnum.IL2CPP_TYPE_R4;
else if (context == SystemDoubleType)
value = Il2CppTypeEnum.IL2CPP_TYPE_R8;
else if (context == SystemIntPtrType)
value = Il2CppTypeEnum.IL2CPP_TYPE_I;
else if (context == SystemUIntPtrType)
value = Il2CppTypeEnum.IL2CPP_TYPE_U;
else if (context == SystemStringType)
value = Il2CppTypeEnum.IL2CPP_TYPE_STRING;
else if (context == SystemTypedReferenceType)
value = Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF;
else if (context == SystemObjectType)
value = Il2CppTypeEnum.IL2CPP_TYPE_OBJECT;
else if (context == SystemVoidType)
value = Il2CppTypeEnum.IL2CPP_TYPE_VOID;
else
{
value = default;
return false;
}
return true;
}
}
20 changes: 20 additions & 0 deletions Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs
Original file line number Diff line number Diff line change
Expand Up @@ -92,6 +92,26 @@ public bool IsPrimitive
}
}

public virtual Il2CppTypeEnum Type
{
get
{
if (Definition is { RawBaseType: not null })
return Definition.RawBaseType.Type;

if (AppContext.SystemTypes.TryGetIl2CppTypeEnum(this, out var value))
return value;

if (IsEnumType)
return Il2CppTypeEnum.IL2CPP_TYPE_ENUM;

if (IsValueType)
return Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE;

return Il2CppTypeEnum.IL2CPP_TYPE_CLASS;
}
}

public string FullName
{
get
Expand Down
37 changes: 24 additions & 13 deletions Cpp2IL.Core/Model/CustomAttributes/CustomAttributeTypeParameter.cs
Original file line number Diff line number Diff line change
Expand Up @@ -12,13 +12,25 @@ namespace Cpp2IL.Core.Model.CustomAttributes;
/// </summary>
public class CustomAttributeTypeParameter : BaseCustomAttributeTypeParameter
{
public Il2CppType? Type;
private Il2CppType? _type;
private TypeAnalysisContext? _typeContext;

public override TypeAnalysisContext? TypeContext => Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(Type);
public override TypeAnalysisContext? TypeContext
{
get
{
return _typeContext ??= Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(_type);
}
}

public CustomAttributeTypeParameter(Il2CppType? type, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index)
{
Type = type;
_type = type;
}

public CustomAttributeTypeParameter(TypeAnalysisContext? type, AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index)
{
_typeContext = type;
}

public CustomAttributeTypeParameter(AnalyzedCustomAttribute owner, CustomAttributeParameterKind kind, int index) : base(owner, kind, index)
Expand All @@ -29,29 +41,28 @@ public override void ReadFromV29Blob(BinaryReader reader, ApplicationAnalysisCon
{
var typeIndex = reader.BaseStream.ReadUnityCompressedInt();
if (typeIndex == -1)
Type = null;
_type = null;
else
{
Type = context.Binary.GetType(typeIndex);
_type = context.Binary.GetType(typeIndex);
}
_typeContext = null;
}

public override string ToString()
{
if (Type == null)
if (TypeContext == null)
return "(Type) null";

if (Type.Type.IsIl2CppPrimitive())
return $"typeof({LibCpp2ILUtils.GetTypeName(Owner.Constructor.AppContext.Metadata, Owner.Constructor.AppContext.Binary, Type)}";
if (TypeContext.IsPrimitive)
return $"typeof({LibCpp2ILUtils.GetTypeName(TypeContext.Type)}";

if (Type.Type is not Il2CppTypeEnum.IL2CPP_TYPE_CLASS and not Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
if (TypeContext is ReferencedTypeAnalysisContext)
{
//Some sort of wrapper type, like a generic parameter or a generic instance.
var typeContext = Owner.Constructor.CustomAttributeAssembly.ResolveIl2CppType(Type);
return $"typeof({typeContext.GetCSharpSourceString()})";
return $"typeof({TypeContext.GetCSharpSourceString()})";
}

//Basic class/struct
return $"typeof({Type.AsClass().Name})";
return $"typeof({TypeContext.Name})";
}
}

This file was deleted.

11 changes: 8 additions & 3 deletions Cpp2IL.Core/ProcessingLayers/AttributeInjectorProcessingLayer.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,6 +154,7 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte

var attributeAttributes = appContext.InjectTypeIntoAllAssemblies("Cpp2ILInjected", "AttributeAttribute", appContext.SystemTypes.SystemAttributeType);

var attributeTypeFields = attributeAttributes.InjectFieldToAllAssemblies("Type", appContext.SystemTypes.SystemTypeType, FieldAttributes.Public);
var attributeNameFields = attributeAttributes.InjectFieldToAllAssemblies("Name", appContext.SystemTypes.SystemStringType, FieldAttributes.Public);
var attributeRvaFields = attributeAttributes.InjectFieldToAllAssemblies("RVA", appContext.SystemTypes.SystemStringType, FieldAttributes.Public);
var attributeOffsetFields = attributeAttributes.InjectFieldToAllAssemblies("Offset", appContext.SystemTypes.SystemStringType, FieldAttributes.Public);
Expand All @@ -162,6 +163,9 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte

foreach (var assemblyAnalysisContext in appContext.Assemblies)
{
// Todo: Remove nameField because typeField makes it redundant. It only remains for backwards compatibility with Il2CppInterop.
// https://github.com/BepInEx/Il2CppInterop/blob/9d4599dc78d69ede49a2ee96a1ccf41eec02db5b/Il2CppInterop.Generator/Passes/Pass70GenerateProperties.cs#L46
var typeField = attributeTypeFields[assemblyAnalysisContext];
var nameField = attributeNameFields[assemblyAnalysisContext];
var rvaField = attributeRvaFields[assemblyAnalysisContext];
var offsetField = attributeOffsetFields[assemblyAnalysisContext];
Expand All @@ -176,11 +180,11 @@ private static void InjectAttributeAttribute(ApplicationAnalysisContext appConte
.Append(ctx))
.Append(assemblyAnalysisContext);

MiscUtils.ExecuteParallel(toProcess, c => ProcessCustomAttributesForContext(c, nameField, rvaField, offsetField, attributeConstructor));
MiscUtils.ExecuteParallel(toProcess, c => ProcessCustomAttributesForContext(c, typeField, nameField, rvaField, offsetField, attributeConstructor));
}
}

private static void ProcessCustomAttributesForContext(HasCustomAttributes context, FieldAnalysisContext nameField, FieldAnalysisContext rvaField, FieldAnalysisContext offsetField, MethodAnalysisContext ctor)
private static void ProcessCustomAttributesForContext(HasCustomAttributes context, FieldAnalysisContext typeField, FieldAnalysisContext nameField, FieldAnalysisContext rvaField, FieldAnalysisContext offsetField, MethodAnalysisContext ctor)
{
if (_useEzDiffMode)
context.CustomAttributes = [];
Expand Down Expand Up @@ -210,9 +214,10 @@ private static void ProcessCustomAttributesForContext(HasCustomAttributes contex
offsetInBinary = 0;

//Add the 3 fields to the replacement attribute
replacementAttribute.Fields.Add(new(nameField, new CustomAttributePrimitiveParameter(attribute.Constructor.DeclaringType!.Name, replacementAttribute, CustomAttributeParameterKind.Field, 0)));
replacementAttribute.Fields.Add(new(typeField, new CustomAttributeTypeParameter(attribute.Constructor.DeclaringType, replacementAttribute, CustomAttributeParameterKind.Field, 0)));
replacementAttribute.Fields.Add(new(rvaField, new CustomAttributePrimitiveParameter($"0x{generatorRva:X}", replacementAttribute, CustomAttributeParameterKind.Field, 1)));
replacementAttribute.Fields.Add(new(offsetField, new CustomAttributePrimitiveParameter($"0x{offsetInBinary:X}", replacementAttribute, CustomAttributeParameterKind.Field, 2)));
replacementAttribute.Fields.Add(new(nameField, new CustomAttributePrimitiveParameter(attribute.Constructor.DeclaringType!.Name, replacementAttribute, CustomAttributeParameterKind.Field, 3)));

//Replace the original attribute with the replacement attribute
context.CustomAttributes[index] = replacementAttribute;
Expand Down
4 changes: 2 additions & 2 deletions Cpp2IL.Core/Utils/AttributeInjectionUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -181,8 +181,8 @@ private static BaseCustomAttributeParameter MakeCustomAttributeParameter(object?
return value switch
{
Il2CppType type => new CustomAttributeTypeParameter(type, owner, parameterKind, index),
TypeAnalysisContext type => new InjectedCustomAttributeTypeParameter(type, owner, parameterKind, index),
TypeAnalysisContext?[] types => new CustomAttributeArrayParameter(owner, parameterKind, index) { ArrType = Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX, ArrayElements = types.Select(t => (BaseCustomAttributeParameter)new InjectedCustomAttributeTypeParameter(t, owner, CustomAttributeParameterKind.ArrayElement, index)).ToList() },
TypeAnalysisContext type => new CustomAttributeTypeParameter(type, owner, parameterKind, index),
TypeAnalysisContext?[] types => new CustomAttributeArrayParameter(owner, parameterKind, index) { ArrType = Il2CppTypeEnum.IL2CPP_TYPE_IL2CPP_TYPE_INDEX, ArrayElements = types.Select(t => (BaseCustomAttributeParameter)new CustomAttributeTypeParameter(t, owner, CustomAttributeParameterKind.ArrayElement, index)).ToList() },
object?[] objects => new CustomAttributeArrayParameter(owner, parameterKind, index)
{
ArrType = Il2CppTypeEnum.IL2CPP_TYPE_OBJECT,
Expand Down
47 changes: 24 additions & 23 deletions LibCpp2IL/LibCpp2IlUtils.cs
Original file line number Diff line number Diff line change
Expand Up @@ -11,28 +11,6 @@ namespace LibCpp2IL;

public static class LibCpp2ILUtils
{
private static readonly Dictionary<int, string> TypeString = new Dictionary<int, string>
{
{ 1, "void" },
{ 2, "bool" },
{ 3, "char" },
{ 4, "sbyte" },
{ 5, "byte" },
{ 6, "short" },
{ 7, "ushort" },
{ 8, "int" },
{ 9, "uint" },
{ 10, "long" },
{ 11, "ulong" },
{ 12, "float" },
{ 13, "double" },
{ 14, "string" },
{ 22, "TypedReference" },
{ 24, "IntPtr" },
{ 25, "UIntPtr" },
{ 28, "object" }
};

private static readonly Dictionary<string, ulong> PrimitiveSizes = new()
{
{ "Byte", 1 },
Expand All @@ -51,6 +29,29 @@ public static class LibCpp2ILUtils
{ "UIntPtr", 8 },
};

public static string GetTypeName(Il2CppTypeEnum type) => (int)type switch
{
1 => "void",
2 => "bool",
3 => "char",
4 => "sbyte",
5 => "byte",
6 => "short",
7 => "ushort",
8 => "int",
9 => "uint",
10 => "long",
11 => "ulong",
12 => "float",
13 => "double",
14 => "string",
22 => "TypedReference",
24 => "IntPtr",
25 => "UIntPtr",
28 => "object",
_ => throw new ArgumentOutOfRangeException(nameof(type), type, null)
};

internal static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssembly, Il2CppTypeDefinition typeDef, bool fullName = false)
{
var ret = string.Empty;
Expand Down Expand Up @@ -159,7 +160,7 @@ public static string GetTypeName(Il2CppMetadata metadata, Il2CppBinary cppAssemb
break;
}
default:
ret = TypeString[(int)type.Type];
ret = GetTypeName(type.Type);
break;
}

Expand Down
Loading