diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs index 3bb096a87..eadb55bc9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs @@ -543,6 +543,35 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + public static void SwitchInTryBlock(string value) + { + try { + switch (value.Substring(5)) { + case "Name1": + Console.WriteLine("1"); + break; + case "Name2": + Console.WriteLine("Name_2"); + break; + case "Name3": + Console.WriteLine("Name_3"); + break; + case "Name4": + Console.WriteLine("No. 4"); + break; + case "Name5": + case "Name6": + Console.WriteLine("5+6"); + break; + default: + Console.WriteLine("default"); + break; + } + } catch (Exception) { + Console.WriteLine("catch block"); + } + } + public static void SwitchWithComplexCondition(string[] args) { switch ((args.Length == 0) ? "dummy" : args[0]) { diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il index 5f70f6ec0..5ce76195f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il @@ -1915,6 +1915,128 @@ IL_014b: ret } // end of method Switch::SwitchOnStringInForLoop + .method public hidebysig static void SwitchInTryBlock(string 'value') cil managed + { + // Code size 258 (0x102) + .maxstack 4 + .locals init (string V_0, + int32 V_1) + IL_0000: nop + .try + { + IL_0001: nop + IL_0002: ldarg.0 + IL_0003: ldc.i4.5 + IL_0004: callvirt instance string [mscorlib]System.String::Substring(int32) + IL_0009: stloc.0 + IL_000a: ldloc.0 + IL_000b: brfalse IL_00e0 + + IL_0010: volatile. + IL_0012: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2 ''::'$$method0x6000019-1' + IL_0017: brtrue.s IL_006e + + IL_0019: ldc.i4.6 + IL_001a: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2::.ctor(int32) + IL_001f: dup + IL_0020: ldstr "Name1" + IL_0025: ldc.i4.0 + IL_0026: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_002b: dup + IL_002c: ldstr "Name2" + IL_0031: ldc.i4.1 + IL_0032: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0037: dup + IL_0038: ldstr "Name3" + IL_003d: ldc.i4.2 + IL_003e: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0043: dup + IL_0044: ldstr "Name4" + IL_0049: ldc.i4.3 + IL_004a: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_004f: dup + IL_0050: ldstr "Name5" + IL_0055: ldc.i4.4 + IL_0056: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_005b: dup + IL_005c: ldstr "Name6" + IL_0061: ldc.i4.5 + IL_0062: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0067: volatile. + IL_0069: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2 ''::'$$method0x6000019-1' + IL_006e: volatile. + IL_0070: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2 ''::'$$method0x6000019-1' + IL_0075: ldloc.0 + IL_0076: ldloca.s V_1 + IL_0078: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2::TryGetValue(!0, + !1&) + IL_007d: brfalse.s IL_00e0 + + IL_007f: ldloc.1 + IL_0080: switch ( + IL_009f, + IL_00ac, + IL_00b9, + IL_00c6, + IL_00d3, + IL_00d3) + IL_009d: br.s IL_00e0 + + IL_009f: ldstr "1" + IL_00a4: call void [mscorlib]System.Console::WriteLine(string) + IL_00a9: nop + IL_00aa: br.s IL_00ed + + IL_00ac: ldstr "Name_2" + IL_00b1: call void [mscorlib]System.Console::WriteLine(string) + IL_00b6: nop + IL_00b7: br.s IL_00ed + + IL_00b9: ldstr "Name_3" + IL_00be: call void [mscorlib]System.Console::WriteLine(string) + IL_00c3: nop + IL_00c4: br.s IL_00ed + + IL_00c6: ldstr "No. 4" + IL_00cb: call void [mscorlib]System.Console::WriteLine(string) + IL_00d0: nop + IL_00d1: br.s IL_00ed + + IL_00d3: ldstr "5+6" + IL_00d8: call void [mscorlib]System.Console::WriteLine(string) + IL_00dd: nop + IL_00de: br.s IL_00ed + + IL_00e0: ldstr "default" + IL_00e5: call void [mscorlib]System.Console::WriteLine(string) + IL_00ea: nop + IL_00eb: br.s IL_00ed + + IL_00ed: nop + IL_00ee: leave.s IL_0100 + + } // end .try + catch [mscorlib]System.Exception + { + IL_00f0: pop + IL_00f1: nop + IL_00f2: ldstr "catch block" + IL_00f7: call void [mscorlib]System.Console::WriteLine(string) + IL_00fc: nop + IL_00fd: nop + IL_00fe: leave.s IL_0100 + + } // end handler + IL_0100: nop + IL_0101: ret + } // end of method Switch::SwitchInTryBlock + .method public hidebysig static void SwitchWithComplexCondition(string[] args) cil managed { // Code size 139 (0x8b) @@ -3776,6 +3898,7 @@ .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000015-1' .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000016-1' .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000018-1' + .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000019-1' } // end of class '' diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il index c17a273e4..d694960e9 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il @@ -1629,6 +1629,113 @@ IL_0134: ret } // end of method Switch::SwitchOnStringInForLoop + .method public hidebysig static void SwitchInTryBlock(string 'value') cil managed + { + // Code size 243 (0xf3) + .maxstack 4 + .locals init (string V_0, + int32 V_1) + .try + { + IL_0000: ldarg.0 + IL_0001: ldc.i4.5 + IL_0002: callvirt instance string [mscorlib]System.String::Substring(int32) + IL_0007: dup + IL_0008: stloc.0 + IL_0009: brfalse IL_00d9 + + IL_000e: volatile. + IL_0010: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2 ''::'$$method0x6000019-1' + IL_0015: brtrue.s IL_006c + + IL_0017: ldc.i4.6 + IL_0018: newobj instance void class [mscorlib]System.Collections.Generic.Dictionary`2::.ctor(int32) + IL_001d: dup + IL_001e: ldstr "Name1" + IL_0023: ldc.i4.0 + IL_0024: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0029: dup + IL_002a: ldstr "Name2" + IL_002f: ldc.i4.1 + IL_0030: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0035: dup + IL_0036: ldstr "Name3" + IL_003b: ldc.i4.2 + IL_003c: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0041: dup + IL_0042: ldstr "Name4" + IL_0047: ldc.i4.3 + IL_0048: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_004d: dup + IL_004e: ldstr "Name5" + IL_0053: ldc.i4.4 + IL_0054: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0059: dup + IL_005a: ldstr "Name6" + IL_005f: ldc.i4.5 + IL_0060: call instance void class [mscorlib]System.Collections.Generic.Dictionary`2::Add(!0, + !1) + IL_0065: volatile. + IL_0067: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2 ''::'$$method0x6000019-1' + IL_006c: volatile. + IL_006e: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2 ''::'$$method0x6000019-1' + IL_0073: ldloc.0 + IL_0074: ldloca.s V_1 + IL_0076: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2::TryGetValue(!0, + !1&) + IL_007b: brfalse.s IL_00d9 + + IL_007d: ldloc.1 + IL_007e: switch ( + IL_009d, + IL_00a9, + IL_00b5, + IL_00c1, + IL_00cd, + IL_00cd) + IL_009b: br.s IL_00d9 + + IL_009d: ldstr "1" + IL_00a2: call void [mscorlib]System.Console::WriteLine(string) + IL_00a7: br.s IL_00e3 + + IL_00a9: ldstr "Name_2" + IL_00ae: call void [mscorlib]System.Console::WriteLine(string) + IL_00b3: br.s IL_00e3 + + IL_00b5: ldstr "Name_3" + IL_00ba: call void [mscorlib]System.Console::WriteLine(string) + IL_00bf: br.s IL_00e3 + + IL_00c1: ldstr "No. 4" + IL_00c6: call void [mscorlib]System.Console::WriteLine(string) + IL_00cb: br.s IL_00e3 + + IL_00cd: ldstr "5+6" + IL_00d2: call void [mscorlib]System.Console::WriteLine(string) + IL_00d7: br.s IL_00e3 + + IL_00d9: ldstr "default" + IL_00de: call void [mscorlib]System.Console::WriteLine(string) + IL_00e3: leave.s IL_00f2 + + } // end .try + catch [mscorlib]System.Exception + { + IL_00e5: pop + IL_00e6: ldstr "catch block" + IL_00eb: call void [mscorlib]System.Console::WriteLine(string) + IL_00f0: leave.s IL_00f2 + + } // end handler + IL_00f2: ret + } // end of method Switch::SwitchInTryBlock + .method public hidebysig static void SwitchWithComplexCondition(string[] args) cil managed { // Code size 130 (0x82) @@ -2829,6 +2936,7 @@ .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000015-1' .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000016-1' .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000018-1' + .field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2 '$$method0x6000019-1' } // end of class '' diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il index a5c1af55f..892871a82 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il @@ -1813,6 +1813,91 @@ IL_00f3: ret } // end of method Switch::SwitchOnStringInForLoop + .method public hidebysig static void SwitchInTryBlock(string 'value') cil managed + { + // Code size 174 (0xae) + .maxstack 2 + .locals init (string V_0) + .try + { + IL_0000: ldarg.0 + IL_0001: ldc.i4.5 + IL_0002: callvirt instance string [mscorlib]System.String::Substring(int32) + IL_0007: stloc.0 + IL_0008: ldloc.0 + IL_0009: ldstr "Name1" + IL_000e: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0013: brtrue.s IL_0058 + + IL_0015: ldloc.0 + IL_0016: ldstr "Name2" + IL_001b: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0020: brtrue.s IL_0064 + + IL_0022: ldloc.0 + IL_0023: ldstr "Name3" + IL_0028: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_002d: brtrue.s IL_0070 + + IL_002f: ldloc.0 + IL_0030: ldstr "Name4" + IL_0035: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_003a: brtrue.s IL_007c + + IL_003c: ldloc.0 + IL_003d: ldstr "Name5" + IL_0042: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0047: brtrue.s IL_0088 + + IL_0049: ldloc.0 + IL_004a: ldstr "Name6" + IL_004f: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0054: brtrue.s IL_0088 + + IL_0056: br.s IL_0094 + + IL_0058: ldstr "1" + IL_005d: call void [mscorlib]System.Console::WriteLine(string) + IL_0062: br.s IL_009e + + IL_0064: ldstr "Name_2" + IL_0069: call void [mscorlib]System.Console::WriteLine(string) + IL_006e: br.s IL_009e + + IL_0070: ldstr "Name_3" + IL_0075: call void [mscorlib]System.Console::WriteLine(string) + IL_007a: br.s IL_009e + + IL_007c: ldstr "No. 4" + IL_0081: call void [mscorlib]System.Console::WriteLine(string) + IL_0086: br.s IL_009e + + IL_0088: ldstr "5+6" + IL_008d: call void [mscorlib]System.Console::WriteLine(string) + IL_0092: br.s IL_009e + + IL_0094: ldstr "default" + IL_0099: call void [mscorlib]System.Console::WriteLine(string) + IL_009e: leave.s IL_00ad + + } // end .try + catch [mscorlib]System.Exception + { + IL_00a0: pop + IL_00a1: ldstr "catch block" + IL_00a6: call void [mscorlib]System.Console::WriteLine(string) + IL_00ab: leave.s IL_00ad + + } // end handler + IL_00ad: ret + } // end of method Switch::SwitchInTryBlock + .method public hidebysig static void SwitchWithComplexCondition(string[] args) cil managed { // Code size 126 (0x7e) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il index c08307c3d..9da40e40f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il @@ -2261,6 +2261,105 @@ IL_0109: ret } // end of method Switch::SwitchOnStringInForLoop + .method public hidebysig static void SwitchInTryBlock(string 'value') cil managed + { + // Code size 188 (0xbc) + .maxstack 2 + .locals init (string V_0) + IL_0000: nop + .try + { + IL_0001: nop + IL_0002: ldarg.0 + IL_0003: ldc.i4.5 + IL_0004: callvirt instance string [mscorlib]System.String::Substring(int32) + IL_0009: stloc.0 + IL_000a: ldloc.0 + IL_000b: ldstr "Name1" + IL_0010: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0015: brtrue.s IL_005a + + IL_0017: ldloc.0 + IL_0018: ldstr "Name2" + IL_001d: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0022: brtrue.s IL_0067 + + IL_0024: ldloc.0 + IL_0025: ldstr "Name3" + IL_002a: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_002f: brtrue.s IL_0074 + + IL_0031: ldloc.0 + IL_0032: ldstr "Name4" + IL_0037: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_003c: brtrue.s IL_0081 + + IL_003e: ldloc.0 + IL_003f: ldstr "Name5" + IL_0044: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0049: brtrue.s IL_008e + + IL_004b: ldloc.0 + IL_004c: ldstr "Name6" + IL_0051: call bool [mscorlib]System.String::op_Equality(string, + string) + IL_0056: brtrue.s IL_008e + + IL_0058: br.s IL_009b + + IL_005a: ldstr "1" + IL_005f: call void [mscorlib]System.Console::WriteLine(string) + IL_0064: nop + IL_0065: br.s IL_00a8 + + IL_0067: ldstr "Name_2" + IL_006c: call void [mscorlib]System.Console::WriteLine(string) + IL_0071: nop + IL_0072: br.s IL_00a8 + + IL_0074: ldstr "Name_3" + IL_0079: call void [mscorlib]System.Console::WriteLine(string) + IL_007e: nop + IL_007f: br.s IL_00a8 + + IL_0081: ldstr "No. 4" + IL_0086: call void [mscorlib]System.Console::WriteLine(string) + IL_008b: nop + IL_008c: br.s IL_00a8 + + IL_008e: ldstr "5+6" + IL_0093: call void [mscorlib]System.Console::WriteLine(string) + IL_0098: nop + IL_0099: br.s IL_00a8 + + IL_009b: ldstr "default" + IL_00a0: call void [mscorlib]System.Console::WriteLine(string) + IL_00a5: nop + IL_00a6: br.s IL_00a8 + + IL_00a8: nop + IL_00a9: leave.s IL_00bb + + } // end .try + catch [mscorlib]System.Exception + { + IL_00ab: pop + IL_00ac: nop + IL_00ad: ldstr "catch block" + IL_00b2: call void [mscorlib]System.Console::WriteLine(string) + IL_00b7: nop + IL_00b8: nop + IL_00b9: leave.s IL_00bb + + } // end handler + IL_00bb: ret + } // end of method Switch::SwitchInTryBlock + .method public hidebysig static void SwitchWithComplexCondition(string[] args) cil managed { // Code size 134 (0x86) diff --git a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs index d35d2533c..527f9ad9f 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs @@ -399,7 +399,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms if (!switchValueVar.Type.IsKnownType(KnownTypeCode.String)) return false; // either br nullCase or leave container - if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock) && !exitBlockJump.MatchLeave((BlockContainer)instructions[i].Parent.Parent)) + var leaveContainer = BlockContainer.FindClosestContainer(instructions[i]); + if (leaveContainer.Parent is TryInstruction) { + leaveContainer = BlockContainer.FindClosestContainer(leaveContainer.Parent); + } + if (!exitBlockJump.MatchBranch(out var nullValueCaseBlock) && !exitBlockJump.MatchLeave(leaveContainer)) return false; var nextBlockJump = instructions.ElementAtOrDefault(i + 1) as Branch; if (nextBlockJump == null || nextBlockJump.TargetBlock.IncomingEdgeCount != 1) @@ -436,7 +440,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) && !defaultBlockJump.MatchLeave((BlockContainer)tryGetValueBlock.Parent)) + if (!defaultBlockJump.MatchBranch(out var defaultBlock) && !defaultBlockJump.MatchLeave(leaveContainer)) 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)))