Browse Source

Fix #1076; improve detection of mcs switch-on-string pattern

pull/1087/head
Siegfried Pammer 8 years ago
parent
commit
b400d89f57
  1. 4
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Switch.cs
  2. 36
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

4
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Switch.cs

@ -25,9 +25,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -25,9 +25,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
public static void Main()
{
TestCase(SparseIntegerSwitch, -100, 1, 2, 3, 4);
#if !MCS
TestCase(ShortSwitchOverString, "First case", "Else");
#endif
TestCase(ShortSwitchOverString2, "First case", "Second case", "Third case", "Else");
TestCase(ShortSwitchOverStringNoExplicitDefault, "First case", "Second case", "Third case", "Else");
TestCase(SwitchOverString1, "First case", "Second case", "2nd case", "Third case", "Fourth case", "Fifth case", "Sixth case", null, "default", "else");
@ -67,7 +65,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -67,7 +65,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
}
}
#if !MCS
public static string ShortSwitchOverString(string text)
{
Console.WriteLine("ShortSwitchOverString: " + text);
@ -78,7 +75,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness @@ -78,7 +75,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
return "Default";
}
}
#endif
public static string ShortSwitchOverString2(string text)
{

36
ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

@ -205,7 +205,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -205,7 +205,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!switchValueVar.IsSingleDefinition)
return false;
if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock))
// either br nullCase or leave container
if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock) && !exitBlockJump.MatchLeave((BlockContainer)instructions[i].Parent.Parent))
return false;
if (!(condition.MatchCompEquals(out var left, out var right) && right.MatchLdNull()
&& ((SemanticHelper.IsPure(switchValue.Flags) && left.Match(switchValue).Success) || left.MatchLdLoc(switchValueVar))))
@ -243,7 +244,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -243,7 +244,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (!tryGetValueBlock.Instructions[0].MatchIfInstruction(out condition, out var defaultBlockJump))
return false;
if (!defaultBlockJump.MatchBranch(out var defaultBlock))
if (!defaultBlockJump.MatchBranch(out var defaultBlock) && !defaultBlockJump.MatchLeave((BlockContainer)tryGetValueBlock.Parent))
return false;
if (!(condition.MatchLogicNot(out var arg) && arg is CallInstruction c && c.Method.Name == "TryGetValue" &&
MatchDictionaryFieldLoad(c.Arguments[0], IsStringToIntDictionary, out var dictField2, out _) && dictField2.Equals(dictField)))
@ -258,11 +259,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -258,11 +259,32 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// ... more cases ...
// case [long.MinValue..0),[13..long.MaxValue]: br defaultBlock
// }
if (switchBlock.IncomingEdgeCount != 1 || switchBlock.Instructions.Count != 1)
return false;
if (!(switchBlock.Instructions[0] is SwitchInstruction switchInst && switchInst.Value.MatchLdLoc(switchIndexVar)))
return false;
var sections = new List<SwitchSection>(switchInst.Sections);
// mcs has a bug: when there is only one case it still generates the full-blown Dictionary<string, int> pattern,
// but uses only a simple if statement instead of the switch instruction.
if (switchBlock.IncomingEdgeCount != 1 || switchBlock.Instructions.Count == 0)
return false;
var sections = new List<SwitchSection>();
switch (switchBlock.Instructions[0]) {
case SwitchInstruction switchInst:
if (switchBlock.Instructions.Count != 1)
return false;
if (!switchInst.Value.MatchLdLoc(switchIndexVar))
return false;
sections.AddRange(switchInst.Sections);
break;
case IfInstruction ifInst:
if (switchBlock.Instructions.Count != 2)
return false;
if (!ifInst.Condition.MatchCompEquals(out left, out right))
return false;
if (!left.MatchLdLoc(switchIndexVar))
return false;
if (!right.MatchLdcI4(0))
return false;
sections.Add(new SwitchSection() { Body = ifInst.TrueInst, Labels = new LongSet(0), ILRange = ifInst.ILRange });
sections.Add(new SwitchSection() { Body = switchBlock.Instructions[1], Labels = new LongSet(0).Invert(), ILRange = switchBlock.Instructions[1].ILRange });
break;
}
// switch contains case null:
if (nullValueCaseBlock != defaultBlock) {
if (!AddNullSection(sections, stringValues, nullValueCaseBlock)) {

Loading…
Cancel
Save