diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
index a6f551686..874769b9b 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
@@ -1168,5 +1168,29 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
throw new Exception();
}
}
+
+ public static int Issue1602(string x)
+ {
+ switch (x) {
+ case null:
+ return 0;
+ case "":
+ return -1;
+ case "A":
+ return 65;
+ case "B":
+ return 66;
+ case "C":
+ return 67;
+ case "D":
+ return 68;
+ case "E":
+ return 69;
+ case "F":
+ return 70;
+ default:
+ throw new ArgumentOutOfRangeException();
+ }
+ }
}
}
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
index f1d1f126c..7c8575c20 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
@@ -820,8 +820,13 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// extract target block
if (!section.Body.MatchBranch(out Block target))
return false;
- if (!MatchRoslynCaseBlockHead(target, switchValueLoad.Variable, out ILInstruction targetOrLeave, out Block currentExitBlock, out string stringValue))
+ string stringValue;
+ if (MatchRoslynEmptyStringCaseBlockHead(target, switchValueLoad.Variable, out ILInstruction targetOrLeave, out Block currentExitBlock)) {
+ stringValue = "";
+ } else if (!MatchRoslynCaseBlockHead(target, switchValueLoad.Variable, out targetOrLeave, out currentExitBlock, out stringValue)) {
return false;
+ }
+
if (exitOrDefaultBlock != null && exitOrDefaultBlock != currentExitBlock)
return false;
exitOrDefaultBlock = currentExitBlock;
@@ -902,7 +907,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
///
/// Matches (and the negated version):
- /// if (call op_Equality(ldloc V_0, ldstr "Fifth case")) br body
+ /// if (call op_Equality(ldloc switchValueVar, stringValue)) br body
/// br exit
///
bool MatchRoslynCaseBlockHead(Block target, ILVariable switchValueVar, out ILInstruction bodyOrLeave, out Block defaultOrExitBlock, out string stringValue)
@@ -938,6 +943,72 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
}
+ ///
+ /// Block target(incoming: 1) {
+ /// if (comp.o(ldloc switchValueVar == ldnull)) br exit
+ /// br lengthCheckBlock
+ /// }
+ ///
+ /// Block lengthCheckBlock(incoming: 1) {
+ /// if (logic.not(call get_Length(ldloc switchValueVar))) br body
+ /// br exit
+ /// }
+ ///
+ bool MatchRoslynEmptyStringCaseBlockHead(Block target, ILVariable switchValueVar, out ILInstruction bodyOrLeave, out Block defaultOrExitBlock)
+ {
+ bodyOrLeave = null;
+ defaultOrExitBlock = null;
+ if (target.Instructions.Count != 2 || target.IncomingEdgeCount != 1)
+ return false;
+ if (!target.Instructions[0].MatchIfInstruction(out var nullComparisonCondition, out var exitBranch))
+ return false;
+ if (!nullComparisonCondition.MatchCompEqualsNull(out var arg) || !arg.MatchLdLoc(switchValueVar))
+ return false;
+ if (!target.Instructions[1].MatchBranch(out Block lengthCheckBlock))
+ return false;
+ if (lengthCheckBlock.Instructions.Count != 2 || lengthCheckBlock.IncomingEdgeCount != 1)
+ return false;
+ if (!lengthCheckBlock.Instructions[0].MatchIfInstruction(out var lengthCheckCondition, out var exitBranch2))
+ return false;
+ ILInstruction bodyBranch;
+ if (lengthCheckCondition.MatchLogicNot(out arg)) {
+ bodyBranch = exitBranch2;
+ exitBranch2 = lengthCheckBlock.Instructions[1];
+ lengthCheckCondition = arg;
+ } else {
+ bodyBranch = lengthCheckBlock.Instructions[1];
+ }
+ if (!(exitBranch2.MatchBranch(out defaultOrExitBlock) || exitBranch2.MatchLeave(out _)))
+ return false;
+ if (!MatchStringLengthCall(lengthCheckCondition, switchValueVar))
+ return false;
+ if (!(exitBranch.MatchBranch(out defaultOrExitBlock) && exitBranch2.MatchBranch(defaultOrExitBlock)))
+ return false;
+ if (bodyBranch.MatchLeave(out _)) {
+ bodyOrLeave = bodyBranch;
+ return true;
+ }
+ if (bodyBranch.MatchBranch(out var bodyBlock)) {
+ bodyOrLeave = bodyBlock;
+ return true;
+ }
+ return false;
+ }
+
+ ///
+ /// call get_Length(ldloc switchValueVar)
+ ///
+ bool MatchStringLengthCall(ILInstruction inst, ILVariable switchValueVar)
+ {
+ return inst is Call call
+ && call.Method.DeclaringType.IsKnownType(KnownTypeCode.String)
+ && call.Method.IsAccessor
+ && call.Method.AccessorKind == System.Reflection.MethodSemanticsAttributes.Getter
+ && call.Method.AccessorOwner.Name == "Length"
+ && call.Arguments.Count == 1
+ && call.Arguments[0].MatchLdLoc(switchValueVar);
+ }
+
///
/// Matches 'stloc(targetVar, call ComputeStringHash(ldloc switchValue))'
///