Browse Source

Fix part 1 of #1292: switch on string inside try-block not recognized.

pull/1347/head
Siegfried Pammer 7 years ago
parent
commit
b9f179465d
  1. 29
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
  2. 123
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il
  3. 108
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il
  4. 85
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il
  5. 99
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il
  6. 8
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

29
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs

@ -543,6 +543,35 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -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]) {

123
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.il

@ -1915,6 +1915,128 @@ @@ -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<string,int32> '<PrivateImplementationDetails>'::'$$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<string,int32>::.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<string,int32>::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<string,int32>::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<string,int32>::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<string,int32>::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<string,int32>::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<string,int32>::Add(!0,
!1)
IL_0067: volatile.
IL_0069: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>'::'$$method0x6000019-1'
IL_006e: volatile.
IL_0070: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>'::'$$method0x6000019-1'
IL_0075: ldloc.0
IL_0076: ldloca.s V_1
IL_0078: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::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 @@ @@ -3776,6 +3898,7 @@
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000015-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000016-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000018-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000019-1'
} // end of class '<PrivateImplementationDetails>'

108
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.il

@ -1629,6 +1629,113 @@ @@ -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<string,int32> '<PrivateImplementationDetails>'::'$$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<string,int32>::.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<string,int32>::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<string,int32>::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<string,int32>::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<string,int32>::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<string,int32>::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<string,int32>::Add(!0,
!1)
IL_0065: volatile.
IL_0067: stsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>'::'$$method0x6000019-1'
IL_006c: volatile.
IL_006e: ldsfld class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '<PrivateImplementationDetails>'::'$$method0x6000019-1'
IL_0073: ldloc.0
IL_0074: ldloca.s V_1
IL_0076: call instance bool class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32>::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 @@ @@ -2829,6 +2936,7 @@
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000015-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000016-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000018-1'
.field static assembly class [mscorlib]System.Collections.Generic.Dictionary`2<string,int32> '$$method0x6000019-1'
} // end of class '<PrivateImplementationDetails>'

85
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.opt.roslyn.il

@ -1813,6 +1813,91 @@ @@ -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)

99
ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.roslyn.il

@ -2261,6 +2261,105 @@ @@ -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)

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

@ -399,7 +399,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -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 @@ -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)))

Loading…
Cancel
Save