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

SamboyCoding / Cpp2IL / 25641285720

10 May 2026 10:18PM UTC coverage: 35.104% (-0.2%) from 35.33%
25641285720

Pull #542

github

web-flow
Merge 9249bcb5b into 6af99f218
Pull Request #542: Remove static mutable state from LibCpp2IL 2: Electric Boogaloo

1877 of 6693 branches covered (28.04%)

Branch coverage included in aggregate %.

303 of 569 new or added lines in 66 files covered. (53.25%)

12 existing lines in 11 files now uncovered.

4394 of 11171 relevant lines covered (39.33%)

268486.35 hits per line

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

44.37
/LibCpp2IL/Reflection/LibCpp2IlReflectionCache.cs
1
using System;
2
using System.Collections.Concurrent;
3
using System.Collections.Generic;
4
using System.Diagnostics.CodeAnalysis;
5
using System.Linq;
6
using LibCpp2IL.BinaryStructures;
7
using LibCpp2IL.Metadata;
8

9
namespace LibCpp2IL.Reflection;
10

11
/// <summary>
12
/// Per-context reflection caches. This is the non-static equivalent of <see cref="LibCpp2IlReflection"/>.
13
/// </summary>
14
public sealed class LibCpp2IlReflectionCache
15
{
16
    private readonly ConcurrentDictionary<(string, string?), Il2CppTypeDefinition?> _cachedTypes = new();
37✔
17
    private readonly ConcurrentDictionary<string, Il2CppTypeDefinition?> _cachedTypesByFullName = new();
37✔
18

19
    private readonly Dictionary<Il2CppTypeDefinition, Il2CppVariableWidthIndex<Il2CppTypeDefinition>> _typeIndices = new();
37✔
20
    private readonly Dictionary<Il2CppMethodDefinition, Il2CppVariableWidthIndex<Il2CppMethodDefinition>> _methodIndices = new();
37✔
21
    private readonly Dictionary<Il2CppFieldDefinition, Il2CppVariableWidthIndex<Il2CppFieldDefinition>> _fieldIndices = new();
37✔
22
    private readonly Dictionary<Il2CppPropertyDefinition, int> _propertyIndices = new();
37✔
23

24
    private readonly Dictionary<Il2CppFieldDefinition, Il2CppTypeDefinition> _fieldDeclaringTypes = new();
37✔
25

26
    private readonly Dictionary<Il2CppTypeEnum, Il2CppType> _primitiveTypeCache = new();
37✔
27
    public Dictionary<Il2CppTypeEnum, Il2CppTypeDefinition> PrimitiveTypeDefinitions { get; } = new();
1,028,350✔
28
    private readonly Dictionary<Il2CppVariableWidthIndex<Il2CppTypeDefinition>, Il2CppType> _il2CppTypeCache = new();
37✔
29

30
    private LibCpp2IlContext? _context;
31

32
    private LibCpp2IlContext Context =>
33
        _context ?? throw new InvalidOperationException("LibCpp2IlReflectionCache must be initialized before use");
1,915,510!
34

35
    public void Reset()
36
    {
37
        _context = null;
37✔
38
        _cachedTypes.Clear();
37✔
39
        _cachedTypesByFullName.Clear();
37✔
40

41
        lock (_typeIndices)
37✔
42
            _typeIndices.Clear();
37✔
43

44
        _methodIndices.Clear();
37✔
45
        _fieldIndices.Clear();
37✔
46
        _propertyIndices.Clear();
37✔
47
        _fieldDeclaringTypes.Clear();
37✔
48
        _primitiveTypeCache.Clear();
37✔
49
        PrimitiveTypeDefinitions.Clear();
37✔
50
        _il2CppTypeCache.Clear();
37✔
51
    }
37✔
52

53
    internal void Init(LibCpp2IlContext context)
54
    {
55
        Reset();
37✔
56
        _context = context;
37✔
57

58
        for (var e = Il2CppTypeEnum.IL2CPP_TYPE_VOID; e <= Il2CppTypeEnum.IL2CPP_TYPE_STRING; e++)
1,110✔
59
            _primitiveTypeCache[e] = context.Binary.AllTypes.First(t => t.Type == e && t.Byref == 0);
1,961,196✔
60

61
        _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF] = context.Binary.AllTypes.FirstOrDefault(t => t.Type == Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF && t.Byref == 0)
729,307!
62
            ?? context.Metadata.typeDefs.First(t => t.DeclaringAssembly?.Name is "mscorlib.dll" && t.Namespace is "System" && t.Name is "TypedReference").RawType;
37!
63

64
        for (var e = Il2CppTypeEnum.IL2CPP_TYPE_I; e <= Il2CppTypeEnum.IL2CPP_TYPE_U; e++)
222✔
65
            _primitiveTypeCache[e] = context.Binary.AllTypes.First(t => t.Type == e && t.Byref == 0);
300,895✔
66

67
        _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_OBJECT] = context.Binary.AllTypes.First(t => t.Type == Il2CppTypeEnum.IL2CPP_TYPE_OBJECT && t.Byref == 0);
83,289✔
68

69
        for (var i = 0; i < context.Metadata.TypeDefinitionCount; i++)
325,250✔
70
        {
71
            var typeDefinition = context.Metadata.typeDefs[i];
162,588✔
72

73
            _typeIndices[typeDefinition] = Il2CppVariableWidthIndex<Il2CppTypeDefinition>.MakeTemporaryForFixedWidthUsage(i);
162,588✔
74

75
            var type = typeDefinition.RawType;
162,588✔
76

77
            if (type.Type.IsIl2CppPrimitive())
162,588✔
78
                PrimitiveTypeDefinitions[type.Type] = typeDefinition;
666✔
79
        }
80

81
        foreach (var type in context.Binary.AllTypes)
2,264,258✔
82
        {
83
            if (type.Type is not Il2CppTypeEnum.IL2CPP_TYPE_CLASS and not Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
1,132,092✔
84
                continue;
85

86
            if (type.Byref == 0)
375,941✔
87
                _il2CppTypeCache[type.Data.ClassIndex] = type;
257,686✔
88
        }
89
    }
37✔
90

91
    public Il2CppTypeDefinition? GetType(string name, string? @namespace = null)
92
    {
93
        var key = (name, @namespace);
843,256✔
94
        if (!_cachedTypes.ContainsKey(key))
843,256✔
95
        {
96
            var typeDef = Context.Metadata.typeDefs.FirstOrDefault(td => td.Name == name && (@namespace == null || @namespace == td.Namespace));
95,628!
97
            _cachedTypes[key] = typeDef;
419✔
98
        }
99

100
        return _cachedTypes[key];
843,256✔
101
    }
102

103
    public Il2CppTypeDefinition? GetTypeByFullName(string fullName)
104
    {
105
        if (!_cachedTypesByFullName.ContainsKey(fullName))
×
106
        {
NEW
107
            var typeDef = Context.Metadata.typeDefs.FirstOrDefault(td => td.FullName == fullName);
×
108
            _cachedTypesByFullName[fullName] = typeDef;
×
109
        }
110

111
        return _cachedTypesByFullName[fullName];
×
112
    }
113

114
    public Il2CppTypeDefinition? GetTypeDefinitionByTypeIndex(Il2CppVariableWidthIndex<Il2CppType> index)
115
    {
116
        if (index.IsNull) return null;
×
117

NEW
118
        var type = Context.Binary.GetType(index);
×
119
        return type.CoerceToUnderlyingTypeDefinition();
×
120
    }
121

122
    [SuppressMessage("ReSharper", "InconsistentlySynchronizedField")]
123
    public Il2CppVariableWidthIndex<Il2CppTypeDefinition> GetTypeIndexFromType(Il2CppTypeDefinition typeDefinition)
124
        => _typeIndices.GetOrDefault(typeDefinition, Il2CppVariableWidthIndex<Il2CppTypeDefinition>.Null);
402,793✔
125

126
    public Il2CppVariableWidthIndex<Il2CppMethodDefinition> GetMethodIndexFromMethod(Il2CppMethodDefinition methodDefinition)
127
    {
128
        if (_methodIndices.Count == 0)
571,885✔
129
        {
130
            lock (_methodIndices)
32✔
131
            {
132
                if (_methodIndices.Count == 0)
32✔
133
                {
134
                    for (var i = 0; i < Context.Metadata.MethodDefinitionCount; i++)
1,143,834✔
135
                    {
136
                        var def = Context.Metadata.methodDefs[i];
571,885✔
137
                        _methodIndices[def] = Il2CppVariableWidthIndex<Il2CppMethodDefinition>.MakeTemporaryForFixedWidthUsage(i);
571,885✔
138
                    }
139
                }
140
            }
32✔
141
        }
142

143
        return _methodIndices.GetOrDefault(methodDefinition, Il2CppVariableWidthIndex<Il2CppMethodDefinition>.Null);
571,885✔
144
    }
145

146
    public Il2CppVariableWidthIndex<Il2CppFieldDefinition> GetFieldIndexFromField(Il2CppFieldDefinition fieldDefinition)
147
    {
148
        if (_fieldIndices.Count == 0)
771,781✔
149
        {
150
            lock (_fieldIndices)
32✔
151
            {
152
                if (_fieldIndices.Count == 0)
32✔
153
                {
154
                    for (var i = 0; i < Context.Metadata.fieldDefs.Length; i++)
771,320✔
155
                    {
156
                        var def = Context.Metadata.fieldDefs[i];
385,628✔
157
                        _fieldIndices[def] = Il2CppVariableWidthIndex<Il2CppFieldDefinition>.MakeTemporaryForFixedWidthUsage(i);
385,628✔
158
                    }
159
                }
160
            }
32✔
161
        }
162

163
        return _fieldIndices[fieldDefinition];
771,781✔
164
    }
165

166
    public int GetPropertyIndexFromProperty(Il2CppPropertyDefinition propertyDefinition)
167
    {
168
        if (_propertyIndices.Count == 0)
×
169
        {
170
            lock (_propertyIndices)
×
171
            {
172
                if (_propertyIndices.Count == 0)
×
173
                {
NEW
174
                    for (var i = 0; i < Context.Metadata.propertyDefs.Length; i++)
×
NEW
175
                        _propertyIndices[Context.Metadata.propertyDefs[i]] = i;
×
176
                }
177
            }
×
178
        }
179

180
        return _propertyIndices[propertyDefinition];
×
181
    }
182

183
    public Il2CppTypeDefinition GetDeclaringTypeFromField(Il2CppFieldDefinition fieldDefinition)
184
    {
185
        if (_fieldDeclaringTypes.Count == 0)
1✔
186
        {
187
            lock (_fieldDeclaringTypes)
1✔
188
            {
189
                if (_fieldDeclaringTypes.Count == 0)
1✔
190
                {
191
                    foreach (var declaringType in Context.Metadata.typeDefs)
5,854✔
192
                    foreach (var field in declaringType.Fields ?? [])
29,410!
193
                        _fieldDeclaringTypes[field] = declaringType;
11,779✔
194
                }
195
            }
1✔
196
        }
197

198
        return _fieldDeclaringTypes[fieldDefinition];
1✔
199
    }
200

201
    public Il2CppType? GetTypeFromDefinition(Il2CppTypeDefinition definition)
202
    {
203
        switch (definition.FullName)
×
204
        {
205
            case "System.SByte": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_I1];
×
206
            case "System.Int16": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_I2];
×
207
            case "System.Int32": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_I4];
×
208
            case "System.Int64": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_I8];
×
209
            case "System.Byte": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_U1];
×
210
            case "System.UInt16": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_U2];
×
211
            case "System.UInt32": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_U4];
×
212
            case "System.UInt64": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_U8];
×
213
            case "System.IntPtr": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_I];
×
214
            case "System.UIntPtr": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_U];
×
215
            case "System.Single": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_R4];
×
216
            case "System.Double": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_R8];
×
217
            case "System.Boolean": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_BOOLEAN];
×
218
            case "System.Char": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_CHAR];
×
219
            case "System.String": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_STRING];
×
220
            case "System.Void": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_VOID];
×
221
            case "System.TypedReference": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_TYPEDBYREF];
×
222
            case "System.Object": return _primitiveTypeCache[Il2CppTypeEnum.IL2CPP_TYPE_OBJECT];
×
223
        }
224

225
        var index = definition.TypeIndex;
×
226

227
        if (_il2CppTypeCache.TryGetValue(index, out var cachedType))
×
228
            return cachedType;
×
229

NEW
230
        foreach (var type in Context.Binary.AllTypes)
×
231
        {
232
            if (type.Type is not Il2CppTypeEnum.IL2CPP_TYPE_CLASS and not Il2CppTypeEnum.IL2CPP_TYPE_VALUETYPE)
×
233
                continue;
234

235
            if (type.Data.ClassIndex.Value == index.Value && type.Byref == 0)
×
236
            {
237
                lock (_il2CppTypeCache)
×
238
                    _il2CppTypeCache[index] = type;
×
239

240
                return type;
×
241
            }
242
        }
243

244
        return null;
×
245
    }
246
}
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