Skip to content

Commit a264217

Browse files
Merge pull request #3422 from ds5678/fix-issue-3421
Improve null case handling in MatchLegacySwitchOnStringWithDict
2 parents 412b513 + e4000c8 commit a264217

File tree

5 files changed

+164
-2
lines changed

5 files changed

+164
-2
lines changed

ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -104,6 +104,7 @@
104104
<None Include="TestCases\ILPretty\Issue1922.il" />
105105
<None Include="TestCases\ILPretty\Issue1918.il" />
106106
<None Include="TestCases\ILPretty\Issue2104.il" />
107+
<None Include="TestCases\ILPretty\Issue3421.il" />
107108
<None Include="TestCases\ILPretty\WeirdEnums.il" />
108109
<None Include="TestCases\ILPretty\ConstantBlobs.il" />
109110
<None Include="TestCases\ILPretty\CS1xSwitch_Debug.il" />
@@ -129,6 +130,7 @@
129130
<Compile Include="Output\InsertParenthesesVisitorTests.cs" />
130131
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
131132
<Compile Include="TestAssemblyResolver.cs" />
133+
<Compile Include="TestCases\ILPretty\Issue3421.cs" />
132134
<Compile Include="TestCases\ILPretty\MonoFixed.cs" />
133135
<Compile Include="TestCases\Pretty\Comparisons.cs" />
134136
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />

ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,12 @@ public async Task Issue2443()
207207
await Run();
208208
}
209209

210+
[Test]
211+
public async Task Issue3421()
212+
{
213+
await Run();
214+
}
215+
210216
[Test]
211217
public async Task Issue2260SwitchString()
212218
{
Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
internal class Issue3421
2+
{
3+
private string name;
4+
private object value;
5+
6+
public virtual void SetValue(object value)
7+
{
8+
switch (name)
9+
{
10+
case "##Name##":
11+
return;
12+
case "##Value##":
13+
this.value = value;
14+
return;
15+
case "##InnerText##":
16+
this.value = value.ToString();
17+
return;
18+
case null:
19+
return;
20+
}
21+
if (this.value == null)
22+
{
23+
this.value = "";
24+
}
25+
}
26+
}
Lines changed: 116 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,116 @@
1+
#define CORE_ASSEMBLY "System.Runtime"
2+
3+
.assembly extern CORE_ASSEMBLY
4+
{
5+
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
6+
.ver 4:0:0:0
7+
}
8+
9+
.class private auto ansi beforefieldinit Issue3421
10+
extends [CORE_ASSEMBLY]System.Object
11+
{
12+
// Fields
13+
.field private string name
14+
.field private object 'value'
15+
.field private static class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> '<>f__switch$map1D'
16+
.custom instance void [CORE_ASSEMBLY]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
17+
01 00 00 00
18+
)
19+
20+
// Methods
21+
.method public hidebysig virtual
22+
instance void SetValue (
23+
object 'value'
24+
) cil managed
25+
{
26+
// Method begins at RVA 0x2050
27+
// Header size: 12
28+
// Code size: 180 (0xb4)
29+
.maxstack 27
30+
.locals init (
31+
[0] string,
32+
[1] class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>,
33+
[2] int32
34+
)
35+
36+
IL_0000: ldarg.0
37+
IL_0001: ldfld string Issue3421::name
38+
IL_0006: stloc.0
39+
IL_0007: ldloc.0
40+
IL_0008: brfalse IL_0093
41+
42+
IL_000d: ldsfld class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> Issue3421::'<>f__switch$map1D'
43+
IL_0012: brtrue IL_0048
44+
45+
IL_0017: ldc.i4.3
46+
IL_0018: newobj instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::.ctor(int32)
47+
IL_001d: stloc.1
48+
IL_001e: ldloc.1
49+
IL_001f: ldstr "##Name##"
50+
IL_0024: ldc.i4.0
51+
IL_0025: callvirt instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
52+
IL_002a: ldloc.1
53+
IL_002b: ldstr "##Value##"
54+
IL_0030: ldc.i4.1
55+
IL_0031: callvirt instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
56+
IL_0036: ldloc.1
57+
IL_0037: ldstr "##InnerText##"
58+
IL_003c: ldc.i4.2
59+
IL_003d: callvirt instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
60+
IL_0042: ldloc.1
61+
IL_0043: stsfld class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> Issue3421::'<>f__switch$map1D'
62+
63+
IL_0048: ldsfld class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> Issue3421::'<>f__switch$map1D'
64+
IL_004d: ldloc.0
65+
IL_004e: ldloca.s 2
66+
IL_0050: callvirt instance bool class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::TryGetValue(!0, !1&)
67+
IL_0055: brfalse IL_0098
68+
69+
IL_005a: ldloc.2
70+
IL_005b: switch (IL_0071, IL_0076, IL_0082)
71+
72+
IL_006c: br IL_0098
73+
74+
IL_0071: br IL_00b3
75+
76+
IL_0076: ldarg.0
77+
IL_0077: ldarg.1
78+
IL_0078: stfld object Issue3421::'value'
79+
IL_007d: br IL_00b3
80+
81+
IL_0082: ldarg.0
82+
IL_0083: ldarg.1
83+
IL_0084: callvirt instance string [CORE_ASSEMBLY]System.Object::ToString()
84+
IL_0089: stfld object Issue3421::'value'
85+
IL_008e: br IL_00b3
86+
87+
IL_0093: br IL_00b3
88+
89+
IL_0098: ldarg.0
90+
IL_0099: ldfld object Issue3421::'value'
91+
IL_009e: brtrue IL_00ae
92+
93+
IL_00a3: ldarg.0
94+
IL_00a4: ldstr ""
95+
IL_00a9: stfld object Issue3421::'value'
96+
97+
IL_00ae: br IL_00b3
98+
99+
IL_00b3: ret
100+
} // end of method Issue3421::SetValue
101+
102+
.method public hidebysig specialname rtspecialname
103+
instance void .ctor () cil managed
104+
{
105+
// Method begins at RVA 0x2110
106+
// Header size: 1
107+
// Code size: 8 (0x8)
108+
.maxstack 8
109+
110+
IL_0000: ldarg.0
111+
IL_0001: call instance void [CORE_ASSEMBLY]System.Object::.ctor()
112+
IL_0006: nop
113+
IL_0007: ret
114+
} // end of method Issue3421::.ctor
115+
116+
} // end of class Issue3421

ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -668,13 +668,20 @@ bool MatchLegacySwitchOnStringWithDict(InstructionCollection<ILInstruction> inst
668668
if (!FixCasesWithoutValue(sections, stringValues))
669669
return false;
670670
// switch contains case null:
671-
if (nullValueCaseBlock != defaultBlock)
671+
if (nullValueCaseBlock != null && nullValueCaseBlock != defaultBlock)
672672
{
673673
if (!AddNullSection(sections, stringValues, nullValueCaseBlock))
674674
{
675675
return false;
676676
}
677677
}
678+
else if (leaveContainer != null && !defaultBlockJump.MatchLeave(leaveContainer))
679+
{
680+
if (!AddNullSection(sections, stringValues, (Leave)exitBlockJump))
681+
{
682+
return false;
683+
}
684+
}
678685
context.Step(nameof(MatchLegacySwitchOnStringWithDict), instructions[i]);
679686
bool keepAssignmentBefore = false;
680687
if (switchValueVar.LoadCount > 2 || switchValue == null)
@@ -741,6 +748,11 @@ bool HasLabel(SwitchSection section)
741748
}
742749

743750
bool AddNullSection(List<SwitchSection> sections, List<(string Value, int Index)> stringValues, Block nullValueCaseBlock)
751+
{
752+
return AddNullSection(sections, stringValues, new Branch(nullValueCaseBlock));
753+
}
754+
755+
bool AddNullSection(List<SwitchSection> sections, List<(string Value, int Index)> stringValues, ILInstruction body)
744756
{
745757
var label = new LongSet(stringValues.Max(item => item.Index) + 1);
746758
var possibleConflicts = sections.Where(sec => sec.Labels.Overlaps(label)).ToArray();
@@ -753,7 +765,7 @@ bool AddNullSection(List<SwitchSection> sections, List<(string Value, int Index)
753765
possibleConflicts[0].Labels = possibleConflicts[0].Labels.ExceptWith(label);
754766
}
755767
stringValues.Add((null, (int)label.Values.First()));
756-
sections.Add(new SwitchSection() { Labels = label, Body = new Branch(nullValueCaseBlock) });
768+
sections.Add(new SwitchSection() { Labels = label, Body = body });
757769
return true;
758770
}
759771

0 commit comments

Comments
 (0)