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

SamboyCoding / Cpp2IL / 28923306611

08 Jul 2026 06:47AM UTC coverage: 36.169% (+0.04%) from 36.132%
28923306611

Pull #578

github

web-flow
Merge 8e28f8d3b into 5ef1a1957
Pull Request #578: Wrap default values in a struct

2678 of 8470 branches covered (31.62%)

Branch coverage included in aggregate %.

45 of 50 new or added lines in 15 files covered. (90.0%)

5061 of 12927 relevant lines covered (39.15%)

166823.12 hits per line

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

0.58
/Cpp2IL.Core/ProcessingLayers/StableRenamingProcessingLayer.cs
1
using System;
2
using System.Collections.Generic;
3
using System.Linq;
4
using System.Reflection;
5
using Cpp2IL.Core.Api;
6
using Cpp2IL.Core.Logging;
7
using Cpp2IL.Core.Model.Contexts;
8
using StableNameDotNet;
9

10
namespace Cpp2IL.Core.ProcessingLayers;
11

12
/// <summary>
13
/// This class is functionally adapted from parts of Il2CppAssemblyUnhollower
14
/// </summary>
15
public class StableRenamingProcessingLayer : Cpp2IlProcessingLayer
16
{
17
    public override string Name => "Stable (Unhollower-Style) Renaming";
×
18
    public override string Id => "stablenamer";
1✔
19

20
    private DeobfuscationMapProcessingLayer? _deobfuscationMapProcessingLayer;
21

22
    public override void PreProcess(ApplicationAnalysisContext context, List<Cpp2IlProcessingLayer> layers)
23
    {
24
        for (var i = 0; i < layers.Count; i++)
×
25
        {
26
            if (layers[i] is not DeobfuscationMapProcessingLayer deobf)
×
27
                continue;
28

29
            //Save this for manual invocation later
30
            Logger.InfoNewline("Found DeobfuscationMapProcessingLayer. It will be run at the correct time", "StableRenamingProcessingLayer");
×
31
            _deobfuscationMapProcessingLayer = deobf;
×
32
            layers.RemoveAt(i);
×
33
            return;
×
34
        }
35
    }
×
36

37
    public override void Process(ApplicationAnalysisContext appContext, Action<int, int>? progressCallback = null)
38
    {
39
        var stableNameStemCounts = new Dictionary<string, int>();
×
40

41
        var typesToProcess = appContext.AllTypes.Where(t => t is not InjectedTypeAnalysisContext).ToArray();
×
42

43
        //Initial pass through, to find types which can be renamed trivially
44
        foreach (var typeAnalysisContext in typesToProcess)
×
45
        {
46
            var stableName = StableNameGenerator.GetStableNameForTypeIfNeeded(typeAnalysisContext, false);
×
47

48
            if (stableName == null)
×
49
                //No rename needed
50
                continue;
51

52
            stableNameStemCounts[stableName] = stableNameStemCounts.GetOrCreate(stableName, () => 0) + 1;
×
53
            typeAnalysisContext.OverrideName = stableName;
×
54
        }
55

56
        StableNameGenerator.RenamedTypes.Clear();
×
57

58
        //Remove all types which got a non-unique name
59
        foreach (var typeAnalysisContext in typesToProcess)
×
60
        {
61
            if (typeAnalysisContext.OverrideName == null)
×
62
                //Wasn't renamed
63
                continue;
64

65
            var dupeCount = stableNameStemCounts[typeAnalysisContext.OverrideName];
×
66
            if (dupeCount > 1)
×
67
                //Clear rename, we'll try again with methods included
68
                typeAnalysisContext.OverrideName = null;
×
69
            else
70
                //Inform name generator of the rename so it can use them later
71
                StableNameGenerator.RenamedTypes[typeAnalysisContext] = typeAnalysisContext.OverrideName;
×
72
        }
73

74
        //Second pass, including method params this time
75
        foreach (var typeAnalysisContext in typesToProcess)
×
76
        {
77
            if (typeAnalysisContext.OverrideName != null)
×
78
                //Already renamed
79
                continue;
80

81
            var stableName = StableNameGenerator.GetStableNameForTypeIfNeeded(typeAnalysisContext, true);
×
82

83
            if (stableName == null)
×
84
                //No rename needed
85
                continue;
86

87
            stableNameStemCounts[stableName] = stableNameStemCounts.GetOrCreate(stableName, () => 0) + 1;
×
88
            typeAnalysisContext.OverrideName = stableName;
×
89
        }
90

91
        //Now we rename duplicates to add a numerical suffix, and rename non-duplicates to add a Unique suffix.
92
        var stableNameRenameCount = new Dictionary<string, int>();
×
93

94
        foreach (var typeAnalysisContext in typesToProcess)
×
95
        {
96
            if (typeAnalysisContext.OverrideName == null || !stableNameStemCounts.TryGetValue(typeAnalysisContext.OverrideName, out var count))
×
97
                continue;
98

99
            //Handle generic type backtick suffixes
100
            string? backTickSuffix = null;
×
101
            if (typeAnalysisContext.OverrideName.Length > 2 && typeAnalysisContext.OverrideName[^2] == '`')
×
102
            {
103
                backTickSuffix = typeAnalysisContext.OverrideName[^2..];
×
104
                typeAnalysisContext.OverrideName = typeAnalysisContext.OverrideName[..^2];
×
105
            }
106

107
            if (count == 1)
×
108
                typeAnalysisContext.OverrideName += "Unique";
×
109
            else
110
            {
111
                var thisCount = stableNameRenameCount[typeAnalysisContext.OverrideName] = stableNameRenameCount.GetOrCreate(typeAnalysisContext.OverrideName, () => -1) + 1;
×
112
                typeAnalysisContext.OverrideName += thisCount;
×
113
            }
114

115
            if (backTickSuffix != null)
×
116
                typeAnalysisContext.OverrideName += backTickSuffix;
×
117
        }
118

119
        //Now rename enum values
120
        foreach (var type in typesToProcess)
×
121
        {
122
            if (!type.IsEnumType)
×
123
                continue;
124

125
            //All static fields
126
            foreach (var field in type.Fields)
×
127
            {
128
                if (!field.IsStatic || !field.Attributes.HasFlag(FieldAttributes.HasDefault))
×
129
                    continue;
130

131
                if (!StableNameGenerator.IsObfuscated(field.Name))
×
132
                    continue;
133

NEW
134
                field.OverrideName = $"EnumValue{field.ConstantValue}";
×
135
            }
136
        }
137

138
        //If the user wants to rename types using a deobfuscation map, do that now
139
        if (_deobfuscationMapProcessingLayer != null)
×
140
        {
141
            Logger.InfoNewline("Running Deobfuscation Map Processing Layer Now...", "StableRenamingProcessingLayer");
×
142
            _deobfuscationMapProcessingLayer.Process(appContext);
×
143
            Logger.InfoNewline("Deobfuscation Map Processing Layer Finished.", "StableRenamingProcessingLayer");
×
144
        }
145

146
        //Now (post deobf), rename all methods
147
        foreach (var typeAnalysisContext in typesToProcess)
×
148
        {
149
            var typeMethodNames = new Dictionary<string, int>();
×
150
            foreach (var methodAnalysisContext in typeAnalysisContext.Methods)
×
151
            {
152
                if (methodAnalysisContext is InjectedMethodAnalysisContext)
×
153
                    continue;
154

155
                var stableName = StableNameGenerator.GetStableNameForMethodIfNeeded(methodAnalysisContext);
×
156

157
                //Params first
158
                for (var i = 0; i < methodAnalysisContext.Parameters.Count; i++)
×
159
                {
160
                    var param = methodAnalysisContext.Parameters[i];
×
161

162
                    if (StableNameGenerator.IsObfuscated(param.Name))
×
163
                        param.OverrideName = $"param_{i}";
×
164
                }
165

166
                if (stableName == null)
×
167
                    //No rename needed
168
                    continue;
169

170
                var occurenceCount = typeMethodNames.GetOrCreate(stableName, () => 0);
×
171
                typeMethodNames[stableName]++;
×
172
                methodAnalysisContext.OverrideName = $"{stableName}_{occurenceCount}";
×
173
            }
174
        }
175

176
        //Rename all fields
177
        foreach (var typeAnalysisContext in typesToProcess)
×
178
        {
179
            var typeFieldNames = new Dictionary<string, int>();
×
180
            foreach (var fieldAnalysisContext in typeAnalysisContext.Fields)
×
181
            {
182
                if (fieldAnalysisContext is InjectedFieldAnalysisContext)
×
183
                    continue;
184

185
                var stableName = StableNameGenerator.GetStableNameForFieldIfNeeded(fieldAnalysisContext);
×
186

187
                if (stableName == null)
×
188
                    //No rename needed
189
                    continue;
190

191
                var occurenceCount = typeFieldNames.GetOrCreate(stableName, () => 0);
×
192
                typeFieldNames[stableName]++;
×
193
                fieldAnalysisContext.OverrideName = $"{stableName}_{occurenceCount}";
×
194
            }
195
        }
196

197
        //Rename all props
198
        foreach (var typeAnalysisContext in typesToProcess)
×
199
        {
200
            var typePropNames = new Dictionary<string, int>();
×
201
            foreach (var propAnalysisContext in typeAnalysisContext.Properties)
×
202
            {
203
                var stableName = StableNameGenerator.GetStableNameForPropertyIfNeeded(propAnalysisContext);
×
204

205
                if (stableName == null)
×
206
                    //No rename needed
207
                    continue;
208

209
                var occurenceCount = typePropNames.GetOrCreate(stableName, () => 0);
×
210
                typePropNames[stableName]++;
×
211
                propAnalysisContext.OverrideName = $"{stableName}_{occurenceCount}";
×
212
            }
213
        }
214

215
        //Rename all events. This isn't done by unhollower because it doesn't generate events, but it's arguably useful
216
        foreach (var typeAnalysisContext in typesToProcess)
×
217
        {
218
            var typeEventNames = new Dictionary<string, int>();
×
219
            foreach (var eventAnalysisContext in typeAnalysisContext.Events)
×
220
            {
221
                var stableName = StableNameGenerator.GetStableNameForEventIfNeeded(eventAnalysisContext);
×
222

223
                if (stableName == null)
×
224
                    //No rename needed
225
                    continue;
226

227
                var occurenceCount = typeEventNames.GetOrCreate(stableName, () => 0);
×
228
                typeEventNames[stableName]++;
×
229
                eventAnalysisContext.OverrideName = $"{stableName}_{occurenceCount}";
×
230
            }
231
        }
232
    }
×
233
}
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