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

SamboyCoding / Cpp2IL / 15032750078

14 May 2025 11:00PM UTC coverage: 34.393% (-0.4%) from 34.826%
15032750078

Pull #451

github

web-flow
Merge d7a22ee91 into e93c0fecc
Pull Request #451: Support injecting anything

1786 of 6584 branches covered (27.13%)

Branch coverage included in aggregate %.

140 of 187 new or added lines in 27 files covered. (74.87%)

53 existing lines in 2 files now uncovered.

4167 of 10725 relevant lines covered (38.85%)

189623.56 hits per line

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

39.44
/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 InjectedTypeAnalysisContext InjectNestedType(string name, TypeAnalysisContext? baseType, TypeAttributes typeAttributes = TypeAttributes.NestedPublic | TypeAttributes.Sealed)
227
    {
228
        if (this is ReferencedTypeAnalysisContext)
43!
NEW
229
            throw new InvalidOperationException("Cannot inject nested types into a non type definition");
×
230

231
        var ret = new InjectedTypeAnalysisContext(DeclaringAssembly, "", name, baseType, typeAttributes);
43✔
232
        ret.DeclaringType = this;
43✔
233
        NestedTypes.Add(ret);
43✔
234
        DeclaringAssembly.InjectType(ret);
43✔
235
        return ret;
43✔
236
    }
237

238
    #region StableNameDotNet implementation
239

240
    public IEnumerable<ITypeInfoProvider> GetBaseTypeHierarchy()
241
    {
242
        if (OverrideBaseType != null)
×
243
            throw new("Type hierarchy for injected types is not supported");
×
244

245
        var baseType = Definition!.RawBaseType;
×
246
        while (baseType != null)
×
247
        {
248
            yield return GetSndnProviderForType(AppContext, baseType);
×
249

250
            baseType = baseType.CoerceToUnderlyingTypeDefinition().RawBaseType;
×
251
        }
252
    }
×
253

254
    public static ITypeInfoProvider GetSndnProviderForType(ApplicationAnalysisContext appContext, Il2CppType type)
255
    {
256
        if (type.Type == Il2CppTypeEnum.IL2CPP_TYPE_GENERICINST)
×
257
        {
258
            var genericClass = type.GetGenericClass();
×
259
            var elementType = appContext.ResolveContextForType(genericClass.TypeDefinition)!;
×
260

261
            var genericParamTypes = genericClass.Context.ClassInst.Types;
×
262

263
            if (genericParamTypes.Any(t => t.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR))
×
264
                //Discard non-fixed generic instances
265
                return elementType;
×
266

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

269
            return new GenericInstanceTypeInfoProviderWrapper(elementType, genericArguments);
×
270
        }
271

272
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_VAR or Il2CppTypeEnum.IL2CPP_TYPE_MVAR)
×
273
            return new GenericParameterTypeInfoProviderWrapper(type.GetGenericParameterDef().Name!);
×
274

275
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_SZARRAY or Il2CppTypeEnum.IL2CPP_TYPE_PTR)
×
276
            return GetSndnProviderForType(appContext, type.GetEncapsulatedType());
×
277

278
        if (type.Type is Il2CppTypeEnum.IL2CPP_TYPE_ARRAY)
×
279
            return GetSndnProviderForType(appContext, type.GetArrayElementType());
×
280

281
        if (type.Type.IsIl2CppPrimitive())
×
282
            return appContext.ResolveContextForType(LibCpp2IlReflection.PrimitiveTypeDefinitions[type.Type])!;
×
283

284
        return appContext.ResolveContextForType(type.AsClass())!;
×
285
    }
286

287
    public IEnumerable<ITypeInfoProvider> Interfaces => Definition!.RawInterfaces!.Select(t => GetSndnProviderForType(AppContext, t));
×
288
    public virtual TypeAttributes TypeAttributes => Definition?.Attributes ?? DefaultTypeAttributes;
14,754!
289
    public virtual int GenericParameterCount => GenericParameters.Count;
330✔
290
    public string OriginalTypeName => DefaultName;
×
291
    public string RewrittenTypeName => Name;
×
292
    public string TypeNamespace => Namespace;
×
293
    public virtual bool IsGenericInstance => false;
×
294
    public virtual bool IsValueType => Definition?.IsValueType ?? BaseType is { Namespace: "System", Name: "ValueType" };
8,920!
295
    public bool IsEnumType => Definition?.IsEnumType ?? BaseType is { Namespace: "System", Name: "Enum" };
×
296
    public bool IsInterface => Definition?.IsInterface ?? ((TypeAttributes & TypeAttributes.Interface) != default);
3,166✔
297
    public IEnumerable<ITypeInfoProvider> GenericArgumentInfoProviders => Array.Empty<ITypeInfoProvider>();
×
298
    public IEnumerable<IFieldInfoProvider> FieldInfoProviders => Fields;
×
299
    public IEnumerable<IMethodInfoProvider> MethodInfoProviders => Methods;
×
300
    public IEnumerable<IPropertyInfoProvider> PropertyInfoProviders => Properties;
×
301
    public ITypeInfoProvider? DeclaringTypeInfoProvider => DeclaringType;
×
302

303
    #endregion
304
}
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