Skip to content

Commit d25980b

Browse files
Fix #3069: Reuse SwitchAnalysis instead of MatchIfElseOnCharBlock
1 parent 0cdac3f commit d25980b

File tree

2 files changed

+27
-52
lines changed

2 files changed

+27
-52
lines changed

ICSharpCode.Decompiler/IL/ControlFlow/SwitchAnalysis.cs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -32,7 +32,7 @@ class SwitchAnalysis
3232
public ILVariable SwitchVariable => switchVar;
3333

3434
/// <summary>
35-
/// Whether at least one the analyzed blocks contained an IL switch constructors.
35+
/// Whether at least one of the analyzed blocks contained an IL switch constructors.
3636
/// </summary>
3737
public bool ContainsILSwitch { get; private set; }
3838

ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

Lines changed: 26 additions & 51 deletions
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
3434
public class SwitchOnStringTransform : IILTransform
3535
{
3636
ILTransformContext context;
37+
private readonly SwitchAnalysis analysis = new SwitchAnalysis();
3738

3839
public void Run(ILFunction function, ILTransformContext context)
3940
{
@@ -1191,8 +1192,7 @@ private bool MatchRoslynSwitchOnStringUsingLengthAndChar(InstructionCollection<I
11911192
else
11921193
{
11931194
int length = (int)block.Length.Intervals[0].Start;
1194-
if (MatchSwitchOnCharBlock(block.TargetBlock, length, switchValueVar, out var mapping)
1195-
|| MatchIfElseOnCharBlock(block.TargetBlock, length, switchValueVar, out mapping))
1195+
if (MatchSwitchOnCharBlock(block.TargetBlock, length, switchValueVar, out var mapping))
11961196
{
11971197
foreach (var item in mapping)
11981198
{
@@ -1277,6 +1277,7 @@ bool MatchSwitchOnCharBlock(Block block, int length, ILVariable switchValueVar,
12771277
if (block.IncomingEdgeCount != 1)
12781278
return false;
12791279
SwitchInstruction @switch;
1280+
List<KeyValuePair<LongSet, ILInstruction>> sections;
12801281
int index;
12811282
switch (block.Instructions.Count)
12821283
{
@@ -1286,6 +1287,7 @@ bool MatchSwitchOnCharBlock(Block block, int length, ILVariable switchValueVar,
12861287
return false;
12871288
if (!MatchGetChars(@switch.Value, switchValueVar, out index))
12881289
return false;
1290+
sections = @switch.Sections.SelectList(s => new KeyValuePair<LongSet, ILInstruction>(s.Labels, s.Body));
12891291
break;
12901292
case 2:
12911293
if (!block.Instructions[0].MatchStLoc(out var charTempVar, out var getCharsCall))
@@ -1299,19 +1301,33 @@ bool MatchSwitchOnCharBlock(Block block, int length, ILVariable switchValueVar,
12991301
return false;
13001302
if (!@switch.Value.MatchLdLoc(charTempVar))
13011303
return false;
1304+
sections = @switch.Sections.SelectList(s => new KeyValuePair<LongSet, ILInstruction>(s.Labels, s.Body));
13021305
break;
13031306
default:
1304-
return false;
1307+
if (!analysis.AnalyzeBlock(block))
1308+
{
1309+
return false;
1310+
}
1311+
if (!block.Instructions[0].MatchStLoc(out charTempVar, out getCharsCall))
1312+
return false;
1313+
if (!MatchGetChars(getCharsCall, switchValueVar, out index))
1314+
return false;
1315+
if (index < 0)
1316+
return false;
1317+
if (analysis.SwitchVariable != charTempVar)
1318+
return false;
1319+
sections = analysis.Sections;
1320+
break;
13051321
}
13061322
if (index >= length)
13071323
return false;
1308-
SwitchSection defaultSection = null;
1309-
foreach (var section in @switch.Sections)
1324+
bool hasDefaultSection = false;
1325+
foreach (var (labels, body) in sections)
13101326
{
1311-
if (section.Labels.Count() == 1)
1327+
if (labels.Count() == 1)
13121328
{
1313-
char ch = unchecked((char)section.Labels.Values.Single());
1314-
if (!section.Body.MatchBranch(out var targetBlock))
1329+
char ch = unchecked((char)labels.Values.Single());
1330+
if (!body.MatchBranch(out var targetBlock))
13151331
return false;
13161332
if (length == 1)
13171333
{
@@ -1332,9 +1348,9 @@ bool MatchSwitchOnCharBlock(Block block, int length, ILVariable switchValueVar,
13321348
}
13331349
}
13341350
}
1335-
else if (defaultSection == null)
1351+
else if (!hasDefaultSection)
13361352
{
1337-
defaultSection = section;
1353+
hasDefaultSection = true;
13381354
}
13391355
else
13401356
{
@@ -1344,47 +1360,6 @@ bool MatchSwitchOnCharBlock(Block block, int length, ILVariable switchValueVar,
13441360
return results?.Count > 0;
13451361
}
13461362

1347-
bool MatchIfElseOnCharBlock(Block startOfChainBlock, int length, ILVariable switchValueVar, out List<(string StringValue, ILInstruction BodyOrLeave)> results)
1348-
{
1349-
results = null;
1350-
if (startOfChainBlock.IncomingEdgeCount != 1)
1351-
return false;
1352-
if (startOfChainBlock.Instructions.Count != 3)
1353-
return false;
1354-
if (!startOfChainBlock.Instructions[0].MatchStLoc(out var charTempVar, out var getCharsCall))
1355-
return false;
1356-
if (!MatchGetChars(getCharsCall, switchValueVar, out int index))
1357-
return false;
1358-
if (index < 0)
1359-
return false;
1360-
if (index >= length)
1361-
return false;
1362-
var currentBlock = startOfChainBlock;
1363-
int offset = 1;
1364-
while (true)
1365-
{
1366-
if (!currentBlock.Instructions[offset].MatchIfInstruction(out var condition, out var gotoHead))
1367-
break;
1368-
if (!condition.MatchCompEquals(out var left, out var right))
1369-
break;
1370-
if (!left.MatchLdLoc(charTempVar) || !right.MatchLdcI4(out int i))
1371-
break;
1372-
if (!currentBlock.Instructions[offset + 1].MatchBranch(out var nextBlock))
1373-
break;
1374-
if (!gotoHead.MatchBranch(out var headBlock))
1375-
break;
1376-
if (!MatchRoslynCaseBlockHead(headBlock, switchValueVar, out var bodyOrLeave, out var exit, out var stringValue, out _))
1377-
break;
1378-
if (exit != nullCase)
1379-
return false;
1380-
results ??= new();
1381-
results.Add((stringValue, bodyOrLeave));
1382-
offset = 0;
1383-
currentBlock = nextBlock;
1384-
}
1385-
return true;
1386-
}
1387-
13881363
bool MatchSwitchOnLengthBlock(ILVariable switchValueVar, Block switchOnLengthBlock, out List<(LongSet Length, Block TargetBlock)> blocks)
13891364
{
13901365
blocks = null;

0 commit comments

Comments
 (0)