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

SamboyCoding / Cpp2IL / 15052278841

15 May 2025 06:16PM UTC coverage: 34.038% (-0.4%) from 34.453%
15052278841

push

github

SamboyCoding
Support injecting anything
* Nested types
* Events
* Properties
* Assemblies

Support additional metadata in injected assemblies

Make setter for TypeAnalysisContext::OverrideBaseType public

TypeAnalysisContext::InterfaceContexts as list rather than array

Fix sign bug

Support generic parameters on type contexts and method contexts

Make GenericParameterTypeAnalysisContext instances unique

Revert change to Il2CppGenericParameter::Index

Use attributes to determine if injected methods are static
* Also add hide by sig attribute for injected constructors

Support overrides on injected methods

In ControlFlowGraphOutputFormat, exclude injected assemblies

Ensure injected assemblies can't delete existing assemblies

Backing field on .NET Standard for injected method overrides

Implement requested change

1774 of 6622 branches covered (26.79%)

Branch coverage included in aggregate %.

147 of 196 new or added lines in 27 files covered. (75.0%)

53 existing lines in 2 files now uncovered.

4155 of 10797 relevant lines covered (38.48%)

188267.61 hits per line

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

38.89
/Cpp2IL.Core/Model/Contexts/TypeAnalysisContext.cs
1
using System;
2
using System.Collections.Generic;
3
using System.IO;
4
using System.Linq;
5
using System.Reflection;
6
using System.Text;
7
using Cpp2IL.Core.Api;
8
using Cpp2IL.Core.Utils;
9
using LibCpp2IL.BinaryStructures;
10
using LibCpp2IL.Metadata;
11
using LibCpp2IL.Reflection;
12
using StableNameDotNet.Providers;
13

14
namespace Cpp2IL.Core.Model.Contexts;
15

16
/// <summary>
17
/// Represents one managed type in the application.
18
/// </summary>
19
public class TypeAnalysisContext : HasGenericParameters, ITypeInfoProvider, ICSharpSourceToken
20
{
21
    internal const TypeAttributes DefaultTypeAttributes = TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed;
22

23
    /// <summary>
24
    /// The context for the assembly this type was defined in.
25
    /// </summary>
26
    public readonly AssemblyAnalysisContext DeclaringAssembly;
27

28
    /// <summary>
29
    /// The underlying metadata for this type. Allows access to RGCTX data, the raw bitfield properties, interfaces, etc.
30
    /// </summary>
31
    public readonly Il2CppTypeDefinition? Definition;
32

33
    /// <summary>
34
    /// The analysis contexts for methods contained within this type.
35
    /// </summary>
36
    public readonly List<MethodAnalysisContext> Methods;
37

38
    /// <summary>
39
    /// The analysis contexts for properties contained within this type.
40
    /// </summary>
41
    public readonly List<PropertyAnalysisContext> Properties;
42

43
    /// <summary>
44
    /// The analysis contexts for events contained within this type.
45
    /// </summary>
46
    public readonly List<EventAnalysisContext> Events;
47

48
    /// <summary>
49
    /// The analysis contexts for fields contained within this type.
50
    /// </summary>
51
    public readonly List<FieldAnalysisContext> Fields;
52

53
    /// <summary>
54
    /// The analysis contexts for nested types within this type.
55
    /// </summary>
56
    public List<TypeAnalysisContext> NestedTypes { get; internal set; } = [];
720,789✔
57

58
    protected override int CustomAttributeIndex => Definition!.CustomAttributeIndex;
61,446✔
59

60
    public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringAssembly;
173,210✔
61

62
    public override string DefaultName => Definition?.Name! ?? throw new("Subclasses of TypeAnalysisContext must override DefaultName");
188,514!
63

64
    public virtual string DefaultNs => Definition?.Namespace ?? throw new("Subclasses of TypeAnalysisContext must override DefaultNs");
159,124!
65

66
    public string? OverrideNs { get; set; }
159,895✔
67

68
    public string Namespace => OverrideNs ?? DefaultNs;
159,895✔
69

70
    public TypeAnalysisContext? OverrideBaseType { get; set; }
721,275✔
71

72
    public TypeAnalysisContext? DeclaringType { get; protected internal set; }
137,866✔
73

74
    public TypeAnalysisContext? EnumUnderlyingType => Definition == null ? null : DeclaringAssembly.ResolveIl2CppType(Definition.EnumUnderlyingType);
×
75

76
    public TypeAnalysisContext? BaseType => OverrideBaseType ?? (Definition == null ? null : DeclaringAssembly.ResolveIl2CppType(Definition.RawBaseType));
371,597✔
77

78
    private List<TypeAnalysisContext>? _interfaceContexts;
79
    public List<TypeAnalysisContext> InterfaceContexts
80
    {
81
        get
82
        {
83
            // Lazy load the interface contexts
84
            _interfaceContexts ??= (Definition?.RawInterfaces.Select(DeclaringAssembly.ResolveIl2CppType).ToList() ?? [])!;
14,420!
85
            return _interfaceContexts;
14,420✔
86
        }
87
    }
88

89
    private List<GenericParameterTypeAnalysisContext>? _genericParameters;
90
    public override List<GenericParameterTypeAnalysisContext> GenericParameters
91
    {
92
        get
93
        {
94
            // Lazy load the generic parameters
95
            _genericParameters ??= Definition?.GenericContainer?.GenericParameters.Select(g => new GenericParameterTypeAnalysisContext(g, this)).ToList() ?? [];
330,725!
96
            return _genericParameters;
324,831✔
97
        }
98
    }
99

100
    public virtual Il2CppTypeEnum Type
101
    {
102
        get
103
        {
104
            if (AppContext.SystemTypes.TryGetIl2CppTypeEnum(this, out var value))
×
105
                return value;
×
106
            
107
            if (Definition is { RawType: {} rawType })
×
108
                return rawType.Type;
×
109

110
            if (IsEnumType)
×
111
                return Il2CppTypeEnum.IL2CPP_TYPE_ENUM;
×
112

113
            if (IsValueType)
×
114
                return Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE;
×
115

116
            return Il2CppTypeEnum.IL2CPP_TYPE_CLASS;
×
117
        }
118
    }
119

120
    public string FullName
121
    {
122
        get
123
        {
124
            if (DeclaringType != null)
89,912✔
125
                return DeclaringType.FullName + "." + Name;
16,481✔
126

127
            if (string.IsNullOrEmpty(Namespace))
73,431✔
128
                return Name;
1,388✔
129

130
            return $"{Namespace}.{Name}";
72,043✔
131
        }
132
    }
133

134
    /// <summary>
135
    /// Returns the namespace of this type expressed as a folder hierarchy, with each sub-namespace becoming a sub-directory.
136
    /// If this type is in the global namespace, this will return an empty string.
137
    /// </summary>
138
    public string NamespaceAsSubdirs
139
    {
140
        get
141
        {
142
            var ns = Namespace;
×
143
            return string.IsNullOrEmpty(ns) ? "" : Path.Combine(MiscUtils.CleanPathElement(ns).Split('.'));
×
144
        }
145
    }
146

147
    /// <summary>
148
    /// Returns the top-level type this type is nested inside. If this type is not nested, will return this type.
149
    /// </summary>
150
    public TypeAnalysisContext UltimateDeclaringType => DeclaringType ?? this;
×
151

152
    public TypeAnalysisContext(Il2CppTypeDefinition? il2CppTypeDefinition, AssemblyAnalysisContext containingAssembly) : base(il2CppTypeDefinition?.Token ?? 0, containingAssembly.AppContext)
699,908✔
153
    {
154
        DeclaringAssembly = containingAssembly;
699,908✔
155
        Definition = il2CppTypeDefinition;
699,908✔
156

157
        if (Definition != null)
699,908✔
158
        {
159
            InitCustomAttributeData();
76,254✔
160

161
            Methods = Definition.Methods!.Select(m => new MethodAnalysisContext(m, this)).ToList();
516,234✔
162
            Properties = Definition.Properties!.Select(p => new PropertyAnalysisContext(p, this)).ToList();
152,226✔
163
            Events = Definition.Events!.Select(e => new EventAnalysisContext(e, this)).ToList();
76,599✔
164
            Fields = Definition.FieldInfos!.ToList().Select(f => new FieldAnalysisContext(f, this)).ToList();
376,575✔
165
        }
166
        else
167
        {
168
            Methods = [];
623,654✔
169
            Properties = [];
623,654✔
170
            Events = [];
623,654✔
171
            Fields = [];
623,654✔
172
        }
173
    }
623,654✔
174

175
    public MethodAnalysisContext? GetMethod(Il2CppMethodDefinition? methodDefinition)
176
    {
177
        if (methodDefinition == null)
451,299✔
178
            return null;
57,795✔
179

180
        return Methods.Find(m => m.Definition == methodDefinition);
7,564,371✔
181
    }
182

183
    public List<MethodAnalysisContext> GetConstructors() => Methods.Where(m => m.Definition!.Name == ".ctor").ToList();
×
184

185
    public override string ToString() => $"Type: {Definition?.FullName}";
×
186

187
    public virtual string GetCSharpSourceString()
188
    {
189
        if (Definition != null)
×
190
            return Definition.FullName!;
×
191

192
        var ret = new StringBuilder();
×
193
        if (OverrideNs != null)
×
194
            ret.Append(OverrideNs).Append('.');
×
195

196
        ret.Append(Name);
×
197

198
        return ret.ToString();
×
199
    }
200

201
    public ArrayTypeAnalysisContext MakeArrayType(int rank)
202
    {
203
        return new(this, rank, DeclaringAssembly);
×
204
    }
205

206
    public ByRefTypeAnalysisContext MakeByReferenceType()
207
    {
208
        return new(this, DeclaringAssembly);
28,190✔
209
    }
210

211
    public GenericInstanceTypeAnalysisContext MakeGenericInstanceType(IEnumerable<TypeAnalysisContext> genericArguments)
212
    {
213
        return new(this, genericArguments, DeclaringAssembly);
330✔
214
    }
215

216
    public PointerTypeAnalysisContext MakePointerType()
217
    {
218
        return new(this, DeclaringAssembly);
×
219
    }
220

221
    public SzArrayTypeAnalysisContext MakeSzArrayType()
222
    {
223
        return new(this, DeclaringAssembly);
×
224
    }
225

226
    public PinnedTypeAnalysisContext MakePinnedType()
227
    {
228
        return new(this, DeclaringAssembly);
×
229
    }
230

231
    public BoxedTypeAnalysisContext MakeBoxedType()
232
    {
233
        return new(this, DeclaringAssembly);
×
234
    }
235

236
    public CustomModifierTypeAnalysisContext MakeCustomModifierType(TypeAnalysisContext modifierType, bool required)
237
    {
238
        return new(this, modifierType, required, DeclaringAssembly);
×
239
    }
240

241
    public InjectedTypeAnalysisContext InjectNestedType(string name, TypeAnalysisContext? baseType, TypeAttributes typeAttributes = TypeAttributes.NestedPublic | TypeAttributes.Sealed)
242
    {
243
        if (this is ReferencedTypeAnalysisContext)
43!
NEW
244
            throw new InvalidOperationException("Cannot inject nested types into a non type definition");
×
245

246
        var ret = new InjectedTypeAnalysisContext(DeclaringAssembly, "", name, baseType, typeAttributes);
43✔
247
        ret.DeclaringType = this;
43✔
248
        NestedTypes.Add(ret);
43✔
249
        DeclaringAssembly.InjectType(ret);
43✔
250
        return ret;
43✔
251
    }
252

253
    #region StableNameDotNet implementation
254

255
    public IEnumerable<ITypeInfoProvider> GetBaseTypeHierarchy()
256
    {
257
        if (OverrideBaseType != null)
×
258
            throw new("Type hierarchy for injected types is not supported");
×
259

260
        var baseType = Definition!.RawBaseType;
×
261
        while (baseType != null)
×
262
        {
263
            yield return GetSndnProviderForType(AppContext, baseType);
×
264

265
            baseType = baseType.CoerceToUnderlyingTypeDefinition().RawBaseType;
×
266
        }
267
    }
×
268

269
    public static ITypeInfoProvider GetSndnProviderForType(ApplicationAnalysisContext appContext, Il2CppType type)
270
    {
271
        if (type.Type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
×
272
        {
273
            var genericClass = type.GetGenericClass();
×
274
            var elementType = appContext.ResolveContextForType(genericClass.TypeDefinition)!;
×
275

276
            var genericParamTypes = genericClass.Context.ClassInst.Types;
×
277

278
            if (genericParamTypes.Any(t => t.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR))
×
279
                //Discard non-fixed generic instances
280
                return elementType;
×
281

282
            var genericArguments = genericParamTypes.Select(t => GetSndnProviderForType(appContext, t)).ToArray();
×
283

284
            return new GenericInstanceTypeInfoProviderWrapper(elementType, genericArguments);
×
285
        }
286

287
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
×
288
            return new GenericParameterTypeInfoProviderWrapper(type.GetGenericParameterDef().Name!);
×
289

290
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY or Il2CppTypeEnum.IL2CPP_TYPE_PTR)
×
291
            return GetSndnProviderForType(appContext, type.GetEncapsulatedType());
×
292

293
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
×
294
            return GetSndnProviderForType(appContext, type.GetArrayElementType());
×
295

296
        if (type.Type.IsIl2CppPrimitive())
×
297
            return appContext.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type])!;
×
298

299
        return appContext.ResolveContextForType(type.AsClass())!;
×
300
    }
301

302
    public IEnumerable<ITypeInfoProvider> Interfaces => Definition!.RawInterfaces!.Select(t => GetSndnProviderForType(AppContext, t));
×
303
    public virtual TypeAttributes TypeAttributes => Definition?.Attributes ?? DefaultTypeAttributes;
14,754!
304
    public virtual int GenericParameterCount => GenericParameters.Count;
330✔
305
    public string OriginalTypeName => DefaultName;
×
306
    public string RewrittenTypeName => Name;
×
307
    public string TypeNamespace => Namespace;
×
308
    public virtual bool IsGenericInstance => false;
×
309
    public virtual bool IsValueType => Definition?.IsValueType ?? BaseType is { Namespace: "System", Name: "ValueType" };
8,920!
310
    public bool IsEnumType => Definition?.IsEnumType ?? BaseType is { Namespace: "System", Name: "Enum" };
×
311
    public bool IsInterface => Definition?.IsInterface ?? ((TypeAttributes & TypeAttributes.Interface) != default);
3,166✔
312
    public IEnumerable<ITypeInfoProvider> GenericArgumentInfoProviders => Array.Empty<ITypeInfoProvider>();
×
313
    public IEnumerable<IFieldInfoProvider> FieldInfoProviders => Fields;
×
314
    public IEnumerable<IMethodInfoProvider> MethodInfoProviders => Methods;
×
315
    public IEnumerable<IPropertyInfoProvider> PropertyInfoProviders => Properties;
×
316
    public ITypeInfoProvider? DeclaringTypeInfoProvider => DeclaringType;
×
317

318
    #endregion
319
}
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

© 2026 Coveralls, Inc