• 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

39.07
/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; } = [];
655,867✔
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");
232,714!
63

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

66
    public string? OverrideNs { get; set; }
231,195✔
67

68
    public string Namespace => OverrideNs ?? DefaultNs;
231,195✔
69

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

72
    public TypeAnalysisContext? DeclaringType { get; protected internal set; }
190,346✔
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() ?? [];
228,310!
96
            return _genericParameters;
222,416✔
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 (IsEnumType)
×
108
                return Il2CppTypeEnum.IL2CPP_TYPE_ENUM;
×
109

110
            if (IsValueType)
×
111
                return Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE;
×
112

113
            return Il2CppTypeEnum.IL2CPP_TYPE_CLASS;
×
114
        }
115
    }
116

117
    public string FullName
118
    {
119
        get
120
        {
121
            if (DeclaringType != null)
134,112✔
122
                return DeclaringType.FullName + "+" + Name;
24,761✔
123

124
            if (string.IsNullOrEmpty(Namespace))
109,351✔
125
                return Name;
1,928✔
126

127
            return $"{Namespace}.{Name}";
107,423✔
128
        }
129
    }
130

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

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

149
    public TypeAnalysisContext(Il2CppTypeDefinition? il2CppTypeDefinition, AssemblyAnalysisContext containingAssembly) : base(il2CppTypeDefinition?.Token ?? 0, containingAssembly.AppContext)
634,986✔
150
    {
151
        DeclaringAssembly = containingAssembly;
634,986✔
152
        Definition = il2CppTypeDefinition;
634,986✔
153

154
        if (Definition != null)
634,986✔
155
        {
156
            InitCustomAttributeData();
76,254✔
157

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

172
    public MethodAnalysisContext? GetMethod(Il2CppMethodDefinition? methodDefinition)
173
    {
174
        if (methodDefinition == null)
451,299✔
175
            return null;
57,795✔
176

177
        return Methods.Find(m => m.Definition == methodDefinition);
7,564,371✔
178
    }
179

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

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

184
    public virtual string GetCSharpSourceString()
185
    {
186
        if (Definition != null)
×
187
            return Definition.FullName!;
×
188

189
        var ret = new StringBuilder();
×
190
        if (OverrideNs != null)
×
191
            ret.Append(OverrideNs).Append('.');
×
192

193
        ret.Append(Name);
×
194

195
        return ret.ToString();
×
196
    }
197

198
    public ArrayTypeAnalysisContext MakeArrayType(int rank)
199
    {
200
        return new(this, rank, DeclaringAssembly);
×
201
    }
202

203
    public ByRefTypeAnalysisContext MakeByReferenceType()
204
    {
205
        return new(this, DeclaringAssembly);
16,856✔
206
    }
207

208
    public GenericInstanceTypeAnalysisContext MakeGenericInstanceType(IEnumerable<TypeAnalysisContext> genericArguments)
209
    {
210
        return new(this, genericArguments, DeclaringAssembly);
330✔
211
    }
212

213
    public PointerTypeAnalysisContext MakePointerType()
214
    {
215
        return new(this, DeclaringAssembly);
×
216
    }
217

218
    public SzArrayTypeAnalysisContext MakeSzArrayType()
219
    {
220
        return new(this, DeclaringAssembly);
×
221
    }
222

223
    public PinnedTypeAnalysisContext MakePinnedType()
224
    {
225
        return new(this, DeclaringAssembly);
×
226
    }
227

228
    public BoxedTypeAnalysisContext MakeBoxedType()
229
    {
230
        return new(this, DeclaringAssembly);
×
231
    }
232

233
    public CustomModifierTypeAnalysisContext MakeCustomModifierType(TypeAnalysisContext modifierType, bool required)
234
    {
235
        return new(this, modifierType, required, DeclaringAssembly);
×
236
    }
237

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

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

250
    #region StableNameDotNet implementation
251

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

257
        var baseType = Definition!.RawBaseType;
×
258
        while (baseType != null)
×
259
        {
260
            yield return GetSndnProviderForType(AppContext, baseType);
×
261

262
            baseType = baseType.CoerceToUnderlyingTypeDefinition().RawBaseType;
×
263
        }
264
    }
×
265

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

273
            var genericParamTypes = genericClass.Context.ClassInst.Types;
×
274

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

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

281
            return new GenericInstanceTypeInfoProviderWrapper(elementType, genericArguments);
×
282
        }
283

284
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
×
285
            return new GenericParameterTypeInfoProviderWrapper(type.GetGenericParameterDef().Name!);
×
286

287
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY or Il2CppTypeEnum.IL2CPP_TYPE_PTR)
×
288
            return GetSndnProviderForType(appContext, type.GetEncapsulatedType());
×
289

290
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
×
291
            return GetSndnProviderForType(appContext, type.GetArrayElementType());
×
292

293
        if (type.Type.IsIl2CppPrimitive())
×
294
            return appContext.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type])!;
×
295

296
        return appContext.ResolveContextForType(type.AsClass())!;
×
297
    }
298

299
    public IEnumerable<ITypeInfoProvider> Interfaces => Definition!.RawInterfaces!.Select(t => GetSndnProviderForType(AppContext, t));
×
300
    public virtual TypeAttributes TypeAttributes => Definition?.Attributes ?? DefaultTypeAttributes;
14,754!
301
    public virtual int GenericParameterCount => GenericParameters.Count;
330✔
302
    public string OriginalTypeName => DefaultName;
×
303
    public string RewrittenTypeName => Name;
×
304
    public string TypeNamespace => Namespace;
×
305
    public virtual bool IsGenericInstance => false;
×
306
    public virtual bool IsValueType => Definition?.IsValueType ?? BaseType is { Namespace: "System", Name: "ValueType" };
8,920!
307
    public bool IsEnumType => Definition?.IsEnumType ?? BaseType is { Namespace: "System", Name: "Enum" };
×
308
    public bool IsInterface => Definition?.IsInterface ?? ((TypeAttributes & TypeAttributes.Interface) != default);
3,166✔
NEW
309
    public bool IsAbstract => (TypeAttributes & TypeAttributes.Abstract) != default;
×
NEW
310
    public bool IsSealed => (TypeAttributes & TypeAttributes.Sealed) != default;
×
NEW
311
    public bool IsStatic => IsAbstract && IsSealed;
×
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

© 2025 Coveralls, Inc