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

SamboyCoding / Cpp2IL / 15953064765

29 Jun 2025 07:58AM UTC coverage: 34.323% (+0.02%) from 34.308%
15953064765

Pull #475

github

web-flow
Merge 2bb66031a into 9ce22e911
Pull Request #475: Expand API functionality

1786 of 6576 branches covered (27.16%)

Branch coverage included in aggregate %.

11 of 21 new or added lines in 5 files covered. (52.38%)

1 existing line in 1 file now uncovered.

4189 of 10832 relevant lines covered (38.67%)

183464.28 hits per line

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

37.12
/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; } = [];
739,310✔
55

56
    protected override int CustomAttributeIndex => Definition!.CustomAttributeIndex;
61,446✔
57

58
    public override AssemblyAnalysisContext CustomAttributeAssembly => DeclaringAssembly;
173,210✔
59

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

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

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

66
    public string Namespace => OverrideNamespace ?? DefaultNamespace;
231,195✔
67

68
    public virtual TypeAttributes DefaultAttributes => Definition?.Attributes ?? TypeAttributes.Public | TypeAttributes.Class | TypeAttributes.Sealed;
17,593!
69

70
    public virtual TypeAttributes? OverrideAttributes { get; set; }
17,593✔
71

72
    public TypeAttributes Attributes => OverrideAttributes ?? DefaultAttributes;
17,593!
73

74
    public virtual TypeAnalysisContext? DefaultBaseType => Definition == null ? null : DeclaringAssembly.ResolveIl2CppType(Definition.RawBaseType);
449,149!
75

76
    public TypeAnalysisContext? OverrideBaseType { get; set; }
449,215✔
77

78
    public TypeAnalysisContext? BaseType => OverrideBaseType ?? DefaultBaseType;
449,215✔
79

80
    public TypeAnalysisContext? DeclaringType { get; protected internal set; }
844,621✔
81

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

84
    private List<TypeAnalysisContext>? _interfaceContexts;
85
    public List<TypeAnalysisContext> InterfaceContexts
86
    {
87
        get
88
        {
89
            // Lazy load the interface contexts
90
            _interfaceContexts ??= (Definition?.RawInterfaces.Select(DeclaringAssembly.ResolveIl2CppType).ToList() ?? [])!;
14,420!
91
            return _interfaceContexts;
14,420✔
92
        }
93
    }
94

95
    private List<GenericParameterTypeAnalysisContext>? _genericParameters;
96
    public override List<GenericParameterTypeAnalysisContext> GenericParameters
97
    {
98
        get
99
        {
100
            // Lazy load the generic parameters
101
            _genericParameters ??= Definition?.GenericContainer?.GenericParameters.Select(g => new GenericParameterTypeAnalysisContext(g, this)).ToList() ?? [];
429,588!
102
            return _genericParameters;
423,694✔
103
        }
104
    }
105

106
    public virtual Il2CppTypeEnum Type
107
    {
108
        get
109
        {
110
            if (AppContext.SystemTypes.TryGetIl2CppTypeEnum(this, out var value))
×
111
                return value;
×
112

113
            if (IsEnumType)
×
114
                return Il2CppTypeEnum.IL2CPP_TYPE_ENUM;
×
115

116
            if (IsValueType)
×
117
                return Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE;
×
118

119
            return Il2CppTypeEnum.IL2CPP_TYPE_CLASS;
×
120
        }
121
    }
122

123
    public string DefaultFullName
124
    {
125
        get
126
        {
NEW
127
            if (DeclaringType != null)
×
NEW
128
                return DeclaringType.DefaultFullName + "+" + DefaultName;
×
129

NEW
130
            if (string.IsNullOrEmpty(DefaultNamespace))
×
NEW
131
                return DefaultName;
×
132

NEW
133
            return $"{DefaultNamespace}.{DefaultName}";
×
134
        }
135
    }
136

137
    public string FullName
138
    {
139
        get
140
        {
141
            if (DeclaringType != null)
134,112✔
142
                return DeclaringType.FullName + "+" + Name;
24,761✔
143

144
            if (string.IsNullOrEmpty(Namespace))
109,351✔
145
                return Name;
1,928✔
146

147
            return $"{Namespace}.{Name}";
107,423✔
148
        }
149
    }
150

151
    public TypeAttributes Visibility
152
    {
153
        get
154
        {
155
            return Attributes & TypeAttributes.VisibilityMask;
7✔
156
        }
157
        set
158
        {
159
            OverrideAttributes = (Attributes & ~TypeAttributes.VisibilityMask) | (value & TypeAttributes.VisibilityMask);
×
160
        }
×
161
    }
162

163
    public bool IsInterface => (Attributes & TypeAttributes.Interface) != default;
3,166✔
164
    public bool IsAbstract => (Attributes & TypeAttributes.Abstract) != default;
×
165
    public bool IsSealed => (Attributes & TypeAttributes.Sealed) != default;
×
166
    public bool IsStatic => IsAbstract && IsSealed;
×
167

168
    /// <summary>
169
    /// Returns the namespace of this type expressed as a folder hierarchy, with each sub-namespace becoming a sub-directory.
170
    /// If this type is in the global namespace, this will return an empty string.
171
    /// </summary>
172
    public string NamespaceAsSubdirs
173
    {
174
        get
175
        {
176
            var ns = Namespace;
×
177
            return string.IsNullOrEmpty(ns) ? "" : Path.Combine(MiscUtils.CleanPathElement(ns).Split('.'));
×
178
        }
179
    }
180

181
    /// <summary>
182
    /// Returns the top-level type this type is nested inside. If this type is not nested, will return this type.
183
    /// </summary>
184
    public TypeAnalysisContext UltimateDeclaringType => DeclaringType ?? this;
×
185

186
    public TypeAnalysisContext(Il2CppTypeDefinition? il2CppTypeDefinition, AssemblyAnalysisContext containingAssembly) : base(il2CppTypeDefinition?.Token ?? 0, containingAssembly.AppContext)
718,429✔
187
    {
188
        DeclaringAssembly = containingAssembly;
718,429✔
189
        Definition = il2CppTypeDefinition;
718,429✔
190

191
        if (Definition != null)
718,429✔
192
        {
193
            InitCustomAttributeData();
76,254✔
194

195
            Methods = Definition.Methods!.Select(m => new MethodAnalysisContext(m, this)).ToList();
516,234✔
196
            Properties = Definition.Properties!.Select(p => new PropertyAnalysisContext(p, this)).ToList();
152,226✔
197
            Events = Definition.Events!.Select(e => new EventAnalysisContext(e, this)).ToList();
76,599✔
198
            Fields = Definition.FieldInfos!.ToList().Select(f => new FieldAnalysisContext(f, this)).ToList();
376,575✔
199
        }
200
        else
201
        {
202
            Methods = [];
642,175✔
203
            Properties = [];
642,175✔
204
            Events = [];
642,175✔
205
            Fields = [];
642,175✔
206
        }
207
    }
642,175✔
208

209
    public MethodAnalysisContext? GetMethod(Il2CppMethodDefinition? methodDefinition)
210
    {
211
        if (methodDefinition == null)
451,299✔
212
            return null;
57,795✔
213

214
        return Methods.Find(m => m.Definition == methodDefinition);
7,564,371✔
215
    }
216

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

219
    public override string ToString() => $"Type: {FullName}";
×
220

221
    public virtual string GetCSharpSourceString()
222
    {
223
        if (Definition != null)
×
224
            return Definition.FullName!;
×
225

226
        var ret = new StringBuilder();
×
227
        if (OverrideNamespace != null)
×
228
            ret.Append(OverrideNamespace).Append('.');
×
229

230
        ret.Append(Name);
×
231

232
        return ret.ToString();
×
233
    }
234

235
    public ArrayTypeAnalysisContext MakeArrayType(int rank)
236
    {
237
        return new(this, rank, DeclaringAssembly);
×
238
    }
239

240
    public ByRefTypeAnalysisContext MakeByReferenceType()
241
    {
242
        return new(this, DeclaringAssembly);
16,856✔
243
    }
244

245
    public GenericInstanceTypeAnalysisContext MakeGenericInstanceType(IEnumerable<TypeAnalysisContext> genericArguments)
246
    {
247
        return new(this, genericArguments, DeclaringAssembly);
77,948✔
248
    }
249

250
    public PointerTypeAnalysisContext MakePointerType()
251
    {
252
        return new(this, DeclaringAssembly);
×
253
    }
254

255
    public SzArrayTypeAnalysisContext MakeSzArrayType()
256
    {
257
        return new(this, DeclaringAssembly);
×
258
    }
259

260
    public PinnedTypeAnalysisContext MakePinnedType()
261
    {
262
        return new(this, DeclaringAssembly);
×
263
    }
264

265
    public BoxedTypeAnalysisContext MakeBoxedType()
266
    {
267
        return new(this, DeclaringAssembly);
×
268
    }
269

270
    public CustomModifierTypeAnalysisContext MakeCustomModifierType(TypeAnalysisContext modifierType, bool required)
271
    {
272
        return new(this, modifierType, required, DeclaringAssembly);
×
273
    }
274

275
    public InjectedTypeAnalysisContext InjectNestedType(string name, TypeAnalysisContext? baseType, TypeAttributes typeAttributes = TypeAttributes.NestedPublic | TypeAttributes.Sealed)
276
    {
277
        if (this is ReferencedTypeAnalysisContext)
43!
278
            throw new InvalidOperationException("Cannot inject nested types into a non type definition");
×
279

280
        var ret = new InjectedTypeAnalysisContext(DeclaringAssembly, "", name, baseType, typeAttributes);
43✔
281
        ret.DeclaringType = this;
43✔
282
        NestedTypes.Add(ret);
43✔
283
        DeclaringAssembly.InjectType(ret);
43✔
284
        return ret;
43✔
285
    }
286

287
    #region StableNameDotNet implementation
288

289
    public IEnumerable<ITypeInfoProvider> GetBaseTypeHierarchy()
290
    {
291
        if (IsInjected)
×
292
            throw new("Type hierarchy for injected types is not supported");
×
293

294
        var baseType = Definition!.RawBaseType;
×
295
        while (baseType != null)
×
296
        {
297
            yield return GetSndnProviderForType(AppContext, baseType);
×
298

299
            baseType = baseType.CoerceToUnderlyingTypeDefinition().RawBaseType;
×
300
        }
301
    }
×
302

303
    public static ITypeInfoProvider GetSndnProviderForType(ApplicationAnalysisContext appContext, Il2CppType type)
304
    {
305
        if (type.Type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
×
306
        {
307
            var genericClass = type.GetGenericClass();
×
308
            var elementType = appContext.ResolveContextForType(genericClass.TypeDefinition)!;
×
309

310
            var genericParamTypes = genericClass.Context.ClassInst.Types;
×
311

312
            if (genericParamTypes.Any(t => t.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR))
×
313
                //Discard non-fixed generic instances
314
                return elementType;
×
315

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

318
            return new GenericInstanceTypeInfoProviderWrapper(elementType, genericArguments);
×
319
        }
320

321
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
×
322
            return new GenericParameterTypeInfoProviderWrapper(type.GetGenericParameterDef().Name!);
×
323

324
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY or Il2CppTypeEnum.IL2CPP_TYPE_PTR)
×
325
            return GetSndnProviderForType(appContext, type.GetEncapsulatedType());
×
326

327
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
×
328
            return GetSndnProviderForType(appContext, type.GetArrayElementType());
×
329

330
        if (type.Type.IsIl2CppPrimitive())
×
331
            return appContext.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type])!;
×
332

333
        return appContext.ResolveContextForType(type.AsClass())!;
×
334
    }
335

336
    IEnumerable<ITypeInfoProvider> ITypeInfoProvider.Interfaces => Definition!.RawInterfaces!.Select(t => GetSndnProviderForType(AppContext, t));
×
337
    TypeAttributes ITypeInfoProvider.TypeAttributes => Attributes;
×
338
    int ITypeInfoProvider.GenericParameterCount => GenericParameters.Count;
×
339
    string ITypeInfoProvider.OriginalTypeName => DefaultName;
×
340
    string ITypeInfoProvider.RewrittenTypeName => Name;
×
341
    string ITypeInfoProvider.TypeNamespace => Namespace;
×
342
    public virtual bool IsGenericInstance => false;
×
343
    public virtual bool IsValueType => Definition?.IsValueType ?? BaseType is { Namespace: "System", Name: "ValueType" };
8,920!
344
    public bool IsEnumType => Definition?.IsEnumType ?? BaseType is { Namespace: "System", Name: "Enum" };
×
345
    IEnumerable<ITypeInfoProvider> ITypeInfoProvider.GenericArgumentInfoProviders => [];
×
346
    IEnumerable<IFieldInfoProvider> ITypeInfoProvider.FieldInfoProviders => Fields;
×
347
    IEnumerable<IMethodInfoProvider> ITypeInfoProvider.MethodInfoProviders => Methods;
×
348
    IEnumerable<IPropertyInfoProvider> ITypeInfoProvider.PropertyInfoProviders => Properties;
×
349
    ITypeInfoProvider? ITypeInfoProvider.DeclaringTypeInfoProvider => DeclaringType;
×
350

351
    #endregion
352
}
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