• Home
  • Features
  • Pricing
  • Docs
  • Announcements
  • Sign In

SamboyCoding / Cpp2IL / 15377127841

01 Jun 2025 04:27PM UTC coverage: 34.079% (+0.02%) from 34.056%
15377127841

Pull #461

github

web-flow
Merge e10c9aae2 into 84cff1948
Pull Request #461: Improve Il2CppType handling

1751 of 6534 branches covered (26.8%)

Branch coverage included in aggregate %.

2 of 7 new or added lines in 5 files covered. (28.57%)

21 existing lines in 1 file now uncovered.

4145 of 10767 relevant lines covered (38.5%)

183431.67 hits per line

Source File
Press 'n' to go to next uncovered line, 'b' for previous

0.0
/Cpp2IL.Core/Utils/AttributeInjectionUtils.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Reflection;
5
using Cpp2IL.Core.Model;
6
using Cpp2IL.Core.Model.Contexts;
7
using Cpp2IL.Core.Model.CustomAttributes;
8
using LibCpp2IL.BinaryStructures;
9
using LibCpp2IL.Reflection;
10

11
namespace Cpp2IL.Core.Utils;
12

13
public static class AttributeInjectionUtils
14
{
15
    /// <summary>
16
    /// Inject an attribute with no fields nor properties into the <see cref="ApplicationAnalysisContext"/>.
17
    /// </summary>
18
    /// <returns>A dictionary of assembly contexts to their inject attribute constructors.</returns>
19
    public static Dictionary<AssemblyAnalysisContext, InjectedMethodAnalysisContext> InjectZeroParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple)
20
    {
21
        var multiInjectType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType);
×
22
        ApplyAttributeUsageAttribute(appContext, multiInjectType, attributeTargets, allowMultiple);
×
23
        return multiInjectType.InjectConstructor(false);
×
24
    }
25

26
    public static Dictionary<AssemblyAnalysisContext, (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext)> InjectOneParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, TypeAnalysisContext fieldType, string fieldName)
27
    {
28
        var multiInjectType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType);
×
29
        ApplyAttributeUsageAttribute(appContext, multiInjectType, attributeTargets, allowMultiple);
×
30

31
        var fields = multiInjectType.InjectFieldToAllAssemblies(fieldName, fieldType, FieldAttributes.Public);
×
32

33
        var constructors = multiInjectType.InjectConstructor(false);
×
34

35
        return multiInjectType.InjectedTypes.ToDictionary(t => t.DeclaringAssembly, t => (constructors[t.DeclaringAssembly], fields[t.DeclaringAssembly]));
×
36
    }
37

38
    public static Dictionary<AssemblyAnalysisContext, (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext, InjectedFieldAnalysisContext)> InjectTwoParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, TypeAnalysisContext fieldType1, string fieldName1, TypeAnalysisContext fieldType2, string fieldName2)
39
    {
40
        var multiInjectType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType);
×
41
        ApplyAttributeUsageAttribute(appContext, multiInjectType, attributeTargets, allowMultiple);
×
42

43
        var firstFields = multiInjectType.InjectFieldToAllAssemblies(fieldName1, fieldType1, FieldAttributes.Public);
×
44

45
        var secondFields = multiInjectType.InjectFieldToAllAssemblies(fieldName2, fieldType2, FieldAttributes.Public);
×
46

47
        var constructors = multiInjectType.InjectConstructor(false);
×
48

49
        return multiInjectType.InjectedTypes.ToDictionary(t => t.DeclaringAssembly, t =>
×
50
        {
×
51
            return (constructors[t.DeclaringAssembly], firstFields[t.DeclaringAssembly], secondFields[t.DeclaringAssembly]);
×
52
        });
×
53
    }
54

55
    public static Dictionary<AssemblyAnalysisContext, (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext, InjectedFieldAnalysisContext, InjectedFieldAnalysisContext)> InjectThreeParameterAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, TypeAnalysisContext fieldType1, string fieldName1, TypeAnalysisContext fieldType2, string fieldName2, TypeAnalysisContext fieldType3, string fieldName3)
56
    {
57
        var multiInjectType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType);
×
58
        ApplyAttributeUsageAttribute(appContext, multiInjectType, attributeTargets, allowMultiple);
×
59

60
        var firstFields = multiInjectType.InjectFieldToAllAssemblies(fieldName1, fieldType1, FieldAttributes.Public);
×
61

62
        var secondFields = multiInjectType.InjectFieldToAllAssemblies(fieldName2, fieldType2, FieldAttributes.Public);
×
63

64
        var thirdFields = multiInjectType.InjectFieldToAllAssemblies(fieldName3, fieldType3, FieldAttributes.Public);
×
65

66
        var constructors = multiInjectType.InjectConstructor(false);
×
67

68
        return multiInjectType.InjectedTypes.ToDictionary(t => t.DeclaringAssembly, t =>
×
69
        {
×
70
            return (constructors[t.DeclaringAssembly], firstFields[t.DeclaringAssembly], secondFields[t.DeclaringAssembly], thirdFields[t.DeclaringAssembly]);
×
71
        });
×
72
    }
73

74
    public static Dictionary<AssemblyAnalysisContext, (InjectedMethodAnalysisContext, InjectedFieldAnalysisContext[])> InjectAttribute(ApplicationAnalysisContext appContext, string ns, string name, AttributeTargets attributeTargets, bool allowMultiple, params (TypeAnalysisContext, string)[] fields)
75
    {
76
        var multiInjectType = appContext.InjectTypeIntoAllAssemblies(ns, name, appContext.SystemTypes.SystemAttributeType);
×
77
        ApplyAttributeUsageAttribute(appContext, multiInjectType, attributeTargets, allowMultiple);
×
78

79
        var injectedFields = new Dictionary<AssemblyAnalysisContext, InjectedFieldAnalysisContext>[fields.Length];
×
80
        for (var i = 0; i < fields.Length; i++)
×
81
        {
82
            injectedFields[i] = multiInjectType.InjectFieldToAllAssemblies(fields[i].Item2, fields[i].Item1, FieldAttributes.Public);
×
83
        }
84

85
        var constructors = multiInjectType.InjectConstructor(false);
×
86

87
        return multiInjectType.InjectedTypes.ToDictionary(t => t.DeclaringAssembly, t =>
×
88
        {
×
89
            return (constructors[t.DeclaringAssembly], injectedFields.Select(d => d[t.DeclaringAssembly]).ToArray());
×
90
        });
×
91
    }
92

93
    private static void ApplyAttributeUsageAttribute(ApplicationAnalysisContext appContext, MultiAssemblyInjectedType multiAssemblyInjectedType, AttributeTargets attributeTargets, bool allowMultiple)
94
    {
95
        var mscorlibAssembly = appContext.GetAssemblyByName("mscorlib") ?? throw new("Could not find mscorlib");
×
96
        var targetsEnumType = GetAttributeTargetsType(mscorlibAssembly);
×
97
        var usageAttribute = mscorlibAssembly.GetTypeByFullName($"System.{nameof(AttributeUsageAttribute)}") ?? throw new("Could not find AttributeUsageAttribute");
×
98
        var usageConstructor = usageAttribute.Methods.First(m => (m.Attributes & MethodAttributes.MemberAccessMask) == MethodAttributes.Public && m.Name == ".ctor");
×
99
        var allowMultipleProperty = usageAttribute.Properties.First(p => p.Name == nameof(AttributeUsageAttribute.AllowMultiple));
×
100
        foreach (var injectedType in multiAssemblyInjectedType.InjectedTypes)
×
101
        {
102
            var newAttribute = new AnalyzedCustomAttribute(usageConstructor);
×
103
            var enumParameter = new CustomAttributeEnumParameter(targetsEnumType, appContext, newAttribute, CustomAttributeParameterKind.ConstructorParam, 0);
×
104
            enumParameter.UnderlyingPrimitiveParameter.PrimitiveValue = (int)attributeTargets;
×
105
            newAttribute.ConstructorParameters.Add(enumParameter);
×
106
            newAttribute.Properties.Add(new(allowMultipleProperty, new CustomAttributePrimitiveParameter(allowMultiple, newAttribute, CustomAttributeParameterKind.Property, 1)));
×
107
            injectedType.AnalyzeCustomAttributeData();
×
108
            injectedType.CustomAttributes ??= [];
×
109
            injectedType.CustomAttributes.Add(newAttribute);
×
110
        }
111
    }
×
112

113
    public static void AddZeroParameterAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor)
114
    {
115
        var newAttribute = new AnalyzedCustomAttribute(constructor);
×
116
        customAttributeHolder.CustomAttributes!.Add(newAttribute); //Nullability checked elsewhere
×
117
    }
×
118

119
    public static void AddOneParameterAttribute(HasCustomAttributes customAttributeHolder, (MethodAnalysisContext, FieldAnalysisContext) attributeInfo, object fieldValue)
120
    {
121
        AddOneParameterAttribute(customAttributeHolder, attributeInfo.Item1, attributeInfo.Item2, fieldValue);
×
122
    }
×
123

124
    public static void AddOneParameterAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, FieldAnalysisContext field, object fieldValue)
125
    {
126
        var newAttribute = new AnalyzedCustomAttribute(constructor);
×
127
        newAttribute.Fields.Add(new(field, MakeFieldParameter(fieldValue, newAttribute, 0)));
×
128
        customAttributeHolder.CustomAttributes!.Add(newAttribute); //Nullability checked elsewhere
×
129
    }
×
130

131
    public static void AddTwoParameterAttribute(HasCustomAttributes customAttributeHolder, (MethodAnalysisContext, FieldAnalysisContext, FieldAnalysisContext) attributeInfo, object fieldValue1, object fieldValue2)
132
    {
133
        AddTwoParameterAttribute(customAttributeHolder, attributeInfo.Item1, attributeInfo.Item2, fieldValue1, attributeInfo.Item3, fieldValue2);
×
134
    }
×
135

136
    public static void AddTwoParameterAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, FieldAnalysisContext field1, object fieldValue1, FieldAnalysisContext field2, object fieldValue2)
137
    {
138
        var newAttribute = new AnalyzedCustomAttribute(constructor);
×
139
        newAttribute.Fields.Add(new(field1, MakeFieldParameter(fieldValue1, newAttribute, 0)));
×
140
        newAttribute.Fields.Add(new(field2, MakeFieldParameter(fieldValue2, newAttribute, 1)));
×
141
        customAttributeHolder.CustomAttributes!.Add(newAttribute); //Nullability checked elsewhere
×
142
    }
×
143

144
    public static void AddAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, params (FieldAnalysisContext, object)[] fields)
145
    {
146
        AddAttribute(customAttributeHolder, constructor, fields.AsEnumerable());
×
147
    }
×
148

149
    public static void AddAttribute(HasCustomAttributes customAttributeHolder, MethodAnalysisContext constructor, IEnumerable<(FieldAnalysisContext, object)> fields)
150
    {
151
        var newAttribute = new AnalyzedCustomAttribute(constructor);
×
152
        var i = 0;
×
153
        foreach (var field in fields)
×
154
        {
155
            newAttribute.Fields.Add(new(field.Item1, MakeFieldParameter(field.Item2, newAttribute, i)));
×
156
            i++;
×
157
        }
158

159
        customAttributeHolder.CustomAttributes!.Add(newAttribute); //Nullability checked elsewhere
×
160
    }
×
161

162
    private static Il2CppType GetAttributeTargetsType(AssemblyAnalysisContext mscorlibAssembly)
163
    {
164
        var targetsEnum = mscorlibAssembly.GetTypeByFullName($"System.{nameof(AttributeTargets)}") ?? throw new("Could not find AttributeTargets");
×
165
        if (targetsEnum.Definition == null)
×
166
        {
167
            throw new NullReferenceException("AttributeTargets had a null Definition");
×
168
        }
169
        else
170
        {
NEW
171
            return targetsEnum.Definition.RawType;
×
172
        }
173
    }
174

175
    private static BaseCustomAttributeParameter MakeFieldParameter(object fieldValue, AnalyzedCustomAttribute owner, int index)
176
    {
177
        return MakeCustomAttributeParameter(fieldValue, owner, index, CustomAttributeParameterKind.Field);
×
178
    }
179

180
    private static BaseCustomAttributeParameter MakeCustomAttributeParameter(object? value, AnalyzedCustomAttribute owner, int index, CustomAttributeParameterKind parameterKind)
181
    {
182
        return value switch
×
183
        {
×
184
            Il2CppType type => new CustomAttributeTypeParameter(type, owner, parameterKind, index),
×
185
            TypeAnalysisContext type => new CustomAttributeTypeParameter(type, owner, parameterKind, index),
×
186
            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() },
×
187
            object?[] objects => new CustomAttributeArrayParameter(owner, parameterKind, index)
×
188
            {
×
189
                ArrType = Il2CppTypeEnum.IL2CPP_TYPE_OBJECT,
×
190
                ArrayElements = objects.Select(obj => obj is null
×
191
                    ? new CustomAttributeNullParameter(owner, CustomAttributeParameterKind.ArrayElement, index)
×
192
                    : MakeCustomAttributeParameter(obj, owner, index, CustomAttributeParameterKind.ArrayElement)).ToList()
×
193
            },
×
194
            IConvertible convertible => new CustomAttributePrimitiveParameter(convertible, owner, parameterKind, index),
×
195
            null => new CustomAttributeNullParameter(owner, parameterKind, index),
×
196
            _ => throw new NotSupportedException(),
×
197
        };
×
198
    }
199
}
STATUS · Troubleshooting · Open an Issue · Sales · Support · CAREERS · ENTERPRISE · START FREE · SCHEDULE DEMO
ANNOUNCEMENTS · TWITTER · TOS & SLA · Supported CI Services · What's a CI service? · Automated Testing

© 2025 Coveralls, Inc