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

SamboyCoding / Cpp2IL / 20488056168

24 Dec 2025 02:19PM UTC coverage: 34.361% (+0.05%) from 34.31%
20488056168

Pull #499

github

web-flow
Merge 482cdd13f into 3a72c253a
Pull Request #499: Add ResolveContextForMethod overload taking Cpp2IlMethodRef as a parameter

1811 of 6624 branches covered (27.34%)

Branch coverage included in aggregate %.

0 of 3 new or added lines in 1 file covered. (0.0%)

187 existing lines in 10 files now uncovered.

4208 of 10893 relevant lines covered (38.63%)

201355.63 hits per line

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

38.84
/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
    /// <summary>
22
    /// The context for the assembly this type was defined in.
23
    /// </summary>
24
    public readonly AssemblyAnalysisContext DeclaringAssembly;
25

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

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

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

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

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

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

56
    protected override int CustomAttributeIndex => Definition!.CustomAttributeIndex;
73,150✔
57

58
    public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringAssembly;
197,458✔
59

60
    public override string DefaultName => Definition?.Name! ?? throw new("Subclasses of TypeAnalysisContext must override DefaultName");
232,718!
61

62
    public virtual string DefaultNamespace => Definition?.Namespace ?? throw new("Subclasses of TypeAnalysisContext must override DefaultNs");
230,432!
63

64
    public string? OverrideNamespace { get; set; }
231,203✔
65

66
    public string Namespace
67
    {
68
        get => OverrideNamespace ?? DefaultNamespace;
231,203✔
UNCOV
69
        set => OverrideNamespace = value;
×
70
    }
71

72
    public virtual TypeAttributes DefaultAttributes => Definition?.Attributes ?? TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed;
553,874!
73

74
    public virtual TypeAttributes? OverrideAttributes { get; set; }
29,753✔
75

76
    public TypeAttributes Attributes
77
    {
78
        get => OverrideAttributes ?? DefaultAttributes;
29,753!
UNCOV
79
        set => OverrideAttributes = value;
×
80
    }
81

82
    public virtual TypeAnalysisContext? DefaultBaseType => Definition == null || DefaultAttributes.HasFlag(TypeAttributes.Interface) ? null : DeclaringAssembly.ResolveIl2CppType(Definition.RawBaseType);
524,121✔
83

84
    public TypeAnalysisContext? OverrideBaseType { get; set; }
516,022✔
85

86
    public TypeAnalysisContext? BaseType
87
    {
88
        get => OverrideBaseType ?? DefaultBaseType;
516,022✔
UNCOV
89
        set => OverrideBaseType = value;
×
90
    }
91

92
    public TypeAnalysisContext? DeclaringType { get; protected internal set; }
840,340✔
93

UNCOV
94
    public TypeAnalysisContext? EnumUnderlyingType => Definition == null ? null : DeclaringAssembly.ResolveIl2CppType(Definition.EnumUnderlyingType);
×
95

96
    private List<TypeAnalysisContext>? _interfaceContexts;
97
    public List<TypeAnalysisContext> InterfaceContexts
98
    {
99
        get
100
        {
101
            // Lazy load the interface contexts
102
            _interfaceContexts ??= (Definition?.RawInterfaces.Select(DeclaringAssembly.ResolveIl2CppType).ToList() ?? [])!;
14,420!
103
            return _interfaceContexts;
14,420✔
104
        }
105
    }
106

107
    private List<GenericParameterTypeAnalysisContext>? _genericParameters;
108
    public override List<GenericParameterTypeAnalysisContext> GenericParameters
109
    {
110
        get
111
        {
112
            // Lazy load the generic parameters
113
            _genericParameters ??= Definition?.GenericContainer?.GenericParameters.Select(g => new GenericParameterTypeAnalysisContext(g, this)).ToList() ?? [];
380,690!
114
            return _genericParameters;
373,956✔
115
        }
116
    }
117

118
    public virtual Il2CppTypeEnum Type
119
    {
120
        get
121
        {
UNCOV
122
            if (AppContext.SystemTypes.TryGetIl2CppTypeEnum(this, out var value))
×
UNCOV
123
                return value;
×
124

UNCOV
125
            if (IsEnumType)
×
UNCOV
126
                return Il2CppTypeEnum.IL2CPP_TYPE_ENUM;
×
127

128
            if (IsValueType)
×
UNCOV
129
                return Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE;
×
130

131
            return Il2CppTypeEnum.IL2CPP_TYPE_CLASS;
×
132
        }
133
    }
134

135
    public string DefaultFullName
136
    {
137
        get
138
        {
UNCOV
139
            if (DeclaringType != null)
×
UNCOV
140
                return DeclaringType.DefaultFullName + "+" + DefaultName;
×
141

UNCOV
142
            if (string.IsNullOrEmpty(DefaultNamespace))
×
UNCOV
143
                return DefaultName;
×
144

UNCOV
145
            return $"{DefaultNamespace}.{DefaultName}";
×
146
        }
147
    }
148

149
    public string FullName
150
    {
151
        get
152
        {
153
            if (DeclaringType != null)
134,116✔
154
                return DeclaringType.FullName + "+" + Name;
24,761✔
155

156
            if (string.IsNullOrEmpty(Namespace))
109,355✔
157
                return Name;
1,928✔
158

159
            return $"{Namespace}.{Name}";
107,427✔
160
        }
161
    }
162

163
    public TypeAttributes Visibility
164
    {
165
        get
166
        {
167
            return Attributes & TypeAttributes.VisibilityMask;
7✔
168
        }
169
        set
170
        {
UNCOV
171
            Attributes = (Attributes & ~TypeAttributes.VisibilityMask) | (value & TypeAttributes.VisibilityMask);
×
UNCOV
172
        }
×
173
    }
174

175
    public bool IsInterface => (Attributes & TypeAttributes.Interface) != default;
11,944✔
176
    public bool IsAbstract => (Attributes & TypeAttributes.Abstract) != default;
2,926✔
177
    public bool IsSealed => (Attributes & TypeAttributes.Sealed) != default;
456✔
178
    public bool IsStatic => IsAbstract && IsSealed;
2,926✔
179

180
    /// <summary>
181
    /// Returns the namespace of this type expressed as a folder hierarchy, with each sub-namespace becoming a sub-directory.
182
    /// If this type is in the global namespace, this will return an empty string.
183
    /// </summary>
184
    public string NamespaceAsSubdirs
185
    {
186
        get
187
        {
UNCOV
188
            var ns = Namespace;
×
UNCOV
189
            return string.IsNullOrEmpty(ns) ? "" : Path.Combine(MiscUtils.CleanPathElement(ns).Split('.'));
×
190
        }
191
    }
192

193
    /// <summary>
194
    /// Returns the top-level type this type is nested inside. If this type is not nested, will return this type.
195
    /// </summary>
UNCOV
196
    public TypeAnalysisContext UltimateDeclaringType => DeclaringType ?? this;
×
197

198
    public TypeAnalysisContext(Il2CppTypeDefinition? il2CppTypeDefinition, AssemblyAnalysisContext containingAssembly) : base(il2CppTypeDefinition?.Token ?? 0, containingAssembly.AppContext)
722,600✔
199
    {
200
        DeclaringAssembly = containingAssembly;
722,600✔
201
        Definition = il2CppTypeDefinition;
722,600✔
202

203
        if (Definition != null)
722,600✔
204
        {
205
            InitCustomAttributeData();
87,958✔
206

207
            Methods = Definition.Methods!.Select(m => new MethodAnalysisContext(m, this)).ToList();
597,562✔
208
            Properties = Definition.Properties!.Select(p => new PropertyAnalysisContext(p, this)).ToList();
176,218✔
209
            Events = Definition.Events!.Select(e => new EventAnalysisContext(e, this)).ToList();
88,363✔
210
            Fields = Definition.FieldInfos!.ToList().Select(f => new FieldAnalysisContext(f, this)).ToList();
435,395✔
211
        }
212
        else
213
        {
214
            Methods = [];
634,642✔
215
            Properties = [];
634,642✔
216
            Events = [];
634,642✔
217
            Fields = [];
634,642✔
218
        }
219
    }
634,642✔
220

221
    public MethodAnalysisContext? GetMethod(Il2CppMethodDefinition? methodDefinition)
222
    {
223
        if (methodDefinition == null)
531,663✔
224
            return null;
66,807✔
225

226
        return Methods.Find(m => m.Definition == methodDefinition);
8,957,431✔
227
    }
228

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

UNCOV
231
    public override string ToString() => $"Type: {FullName}";
×
232

233
    public virtual string GetCSharpSourceString()
234
    {
UNCOV
235
        if (Definition != null)
×
UNCOV
236
            return Definition.FullName!;
×
237

UNCOV
238
        var ret = new StringBuilder();
×
UNCOV
239
        if (OverrideNamespace != null)
×
UNCOV
240
            ret.Append(OverrideNamespace).Append('.');
×
241

UNCOV
242
        ret.Append(Name);
×
243

UNCOV
244
        return ret.ToString();
×
245
    }
246

247
    public ArrayTypeAnalysisContext MakeArrayType(int rank)
248
    {
UNCOV
249
        return new(this, rank, DeclaringAssembly);
×
250
    }
251

252
    public ByRefTypeAnalysisContext MakeByReferenceType()
253
    {
254
        return new(this, DeclaringAssembly);
18,944✔
255
    }
256

257
    public GenericInstanceTypeAnalysisContext MakeGenericInstanceType(params IEnumerable<TypeAnalysisContext> genericArguments)
258
    {
259
        return new(this, genericArguments, DeclaringAssembly);
87,611✔
260
    }
261

262
    public PointerTypeAnalysisContext MakePointerType()
263
    {
UNCOV
264
        return new(this, DeclaringAssembly);
×
265
    }
266

267
    public SzArrayTypeAnalysisContext MakeSzArrayType()
268
    {
UNCOV
269
        return new(this, DeclaringAssembly);
×
270
    }
271

272
    public PinnedTypeAnalysisContext MakePinnedType()
273
    {
UNCOV
274
        return new(this, DeclaringAssembly);
×
275
    }
276

277
    public BoxedTypeAnalysisContext MakeBoxedType()
278
    {
UNCOV
279
        return new(this, DeclaringAssembly);
×
280
    }
281

282
    public CustomModifierTypeAnalysisContext MakeCustomModifierType(TypeAnalysisContext modifierType, bool required)
283
    {
UNCOV
284
        return new(this, modifierType, required, DeclaringAssembly);
×
285
    }
286

287
    public InjectedTypeAnalysisContext InjectNestedType(string name, TypeAnalysisContext? baseType, TypeAttributes typeAttributes = TypeAttributes.NestedPublic | TypeAttributes.Sealed)
288
    {
289
        if (this is ReferencedTypeAnalysisContext)
43!
UNCOV
290
            throw new InvalidOperationException("Cannot inject nested types into a non type definition");
×
291

292
        var ret = new InjectedTypeAnalysisContext(DeclaringAssembly, "", name, baseType, typeAttributes);
43✔
293
        ret.DeclaringType = this;
43✔
294
        NestedTypes.Add(ret);
43✔
295
        DeclaringAssembly.InjectType(ret);
43✔
296
        return ret;
43✔
297
    }
298

299
    #region StableNameDotNet implementation
300

301
    public IEnumerable<ITypeInfoProvider> GetBaseTypeHierarchy()
302
    {
UNCOV
303
        if (IsInjected)
×
UNCOV
304
            throw new("Type hierarchy for injected types is not supported");
×
305

UNCOV
306
        var baseType = Definition!.RawBaseType;
×
307
        while (baseType != null)
×
308
        {
UNCOV
309
            yield return GetSndnProviderForType(AppContext, baseType);
×
310

UNCOV
311
            baseType = baseType.CoerceToUnderlyingTypeDefinition().RawBaseType;
×
312
        }
UNCOV
313
    }
×
314

315
    public static ITypeInfoProvider GetSndnProviderForType(ApplicationAnalysisContext appContext, Il2CppType type)
316
    {
UNCOV
317
        if (type.Type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
×
318
        {
UNCOV
319
            var genericClass = type.GetGenericClass();
×
UNCOV
320
            var elementType = appContext.ResolveContextForType(genericClass.TypeDefinition)!;
×
321

322
            var genericParamTypes = genericClass.Context.ClassInst.Types;
×
323

324
            if (genericParamTypes.Any(t => t.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR))
×
325
                //Discard non-fixed generic instances
UNCOV
326
                return elementType;
×
327

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

330
            return new GenericInstanceTypeInfoProviderWrapper(elementType, genericArguments);
×
331
        }
332

333
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
×
UNCOV
334
            return new GenericParameterTypeInfoProviderWrapper(type.GetGenericParameterDef().Name!);
×
335

336
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY or Il2CppTypeEnum.IL2CPP_TYPE_PTR)
×
337
            return GetSndnProviderForType(appContext, type.GetEncapsulatedType());
×
338

339
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
×
340
            return GetSndnProviderForType(appContext, type.GetArrayElementType());
×
341

342
        if (type.Type.IsIl2CppPrimitive())
×
UNCOV
343
            return appContext.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type])!;
×
344

UNCOV
345
        return appContext.ResolveContextForType(type.AsClass())!;
×
346
    }
347

UNCOV
348
    IEnumerable<ITypeInfoProvider> ITypeInfoProvider.Interfaces => Definition!.RawInterfaces!.Select(t => GetSndnProviderForType(AppContext, t));
×
UNCOV
349
    TypeAttributes ITypeInfoProvider.TypeAttributes => Attributes;
×
350
    int ITypeInfoProvider.GenericParameterCount => GenericParameters.Count;
×
351
    string ITypeInfoProvider.OriginalTypeName => DefaultName;
×
UNCOV
352
    string ITypeInfoProvider.RewrittenTypeName => Name;
×
353
    string ITypeInfoProvider.TypeNamespace => Namespace;
×
UNCOV
354
    public virtual bool IsGenericInstance => false;
×
355
    public virtual bool IsValueType
356
    {
357
        get
358
        {
359
            if (Definition is not null)
8,920!
360
                return Definition.IsValueType;
8,920✔
361

362
            if (BaseType is { Namespace: "System", Name: "ValueType" })
×
UNCOV
363
                return Namespace is not "System" || Name is not "Enum"; // Enum is a reference type
×
364

UNCOV
365
            return IsEnumType;
×
366
        }
367
    }
368

UNCOV
369
    public bool IsEnumType => Definition?.IsEnumType ?? BaseType is { Namespace: "System", Name: "Enum" };
×
UNCOV
370
    IEnumerable<ITypeInfoProvider> ITypeInfoProvider.GenericArgumentInfoProviders => [];
×
UNCOV
371
    IEnumerable<IFieldInfoProvider> ITypeInfoProvider.FieldInfoProviders => Fields;
×
UNCOV
372
    IEnumerable<IMethodInfoProvider> ITypeInfoProvider.MethodInfoProviders => Methods;
×
UNCOV
373
    IEnumerable<IPropertyInfoProvider> ITypeInfoProvider.PropertyInfoProviders => Properties;
×
UNCOV
374
    ITypeInfoProvider? ITypeInfoProvider.DeclaringTypeInfoProvider => DeclaringType;
×
375

376
    #endregion
377
}
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