Browse Source

Merge pull request #3422 from ds5678/fix-issue-3421

Improve null case handling in MatchLegacySwitchOnStringWithDict
pull/3427/head
Siegfried Pammer 2 months ago committed by GitHub
parent
commit
a264217952
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 2
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  2. 6
      ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs
  3. 26
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3421.cs
  4. 116
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3421.il
  5. 16
      ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs

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

@ -104,6 +104,7 @@ @@ -104,6 +104,7 @@
<None Include="TestCases\ILPretty\Issue1922.il" />
<None Include="TestCases\ILPretty\Issue1918.il" />
<None Include="TestCases\ILPretty\Issue2104.il" />
<None Include="TestCases\ILPretty\Issue3421.il" />
<None Include="TestCases\ILPretty\WeirdEnums.il" />
<None Include="TestCases\ILPretty\ConstantBlobs.il" />
<None Include="TestCases\ILPretty\CS1xSwitch_Debug.il" />
@ -129,6 +130,7 @@ @@ -129,6 +130,7 @@
<Compile Include="Output\InsertParenthesesVisitorTests.cs" />
<Compile Include="ProjectDecompiler\TargetFrameworkTests.cs" />
<Compile Include="TestAssemblyResolver.cs" />
<Compile Include="TestCases\ILPretty\Issue3421.cs" />
<Compile Include="TestCases\ILPretty\MonoFixed.cs" />
<Compile Include="TestCases\Pretty\Comparisons.cs" />
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />

6
ICSharpCode.Decompiler.Tests/ILPrettyTestRunner.cs

@ -207,6 +207,12 @@ namespace ICSharpCode.Decompiler.Tests @@ -207,6 +207,12 @@ namespace ICSharpCode.Decompiler.Tests
await Run();
}
[Test]
public async Task Issue3421()
{
await Run();
}
[Test]
public async Task Issue2260SwitchString()
{

26
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3421.cs

@ -0,0 +1,26 @@ @@ -0,0 +1,26 @@
internal class Issue3421
{
private string name;
private object value;
public virtual void SetValue(object value)
{
switch (name)
{
case "##Name##":
return;
case "##Value##":
this.value = value;
return;
case "##InnerText##":
this.value = value.ToString();
return;
case null:
return;
}
if (this.value == null)
{
this.value = "";
}
}
}

116
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue3421.il

@ -0,0 +1,116 @@ @@ -0,0 +1,116 @@
#define CORE_ASSEMBLY "System.Runtime"
.assembly extern CORE_ASSEMBLY
{
.publickeytoken = (B0 3F 5F 7F 11 D5 0A 3A ) // .?_....:
.ver 4:0:0:0
}
.class private auto ansi beforefieldinit Issue3421
extends [CORE_ASSEMBLY]System.Object
{
// Fields
.field private string name
.field private object 'value'
.field private static class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> '<>f__switch$map1D'
.custom instance void [CORE_ASSEMBLY]System.Runtime.CompilerServices.CompilerGeneratedAttribute::.ctor() = (
01 00 00 00
)
// Methods
.method public hidebysig virtual
instance void SetValue (
object 'value'
) cil managed
{
// Method begins at RVA 0x2050
// Header size: 12
// Code size: 180 (0xb4)
.maxstack 27
.locals init (
[0] string,
[1] class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>,
[2] int32
)
IL_0000: ldarg.0
IL_0001: ldfld string Issue3421::name
IL_0006: stloc.0
IL_0007: ldloc.0
IL_0008: brfalse IL_0093
IL_000d: ldsfld class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> Issue3421::'<>f__switch$map1D'
IL_0012: brtrue IL_0048
IL_0017: ldc.i4.3
IL_0018: newobj instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::.ctor(int32)
IL_001d: stloc.1
IL_001e: ldloc.1
IL_001f: ldstr "##Name##"
IL_0024: ldc.i4.0
IL_0025: callvirt instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
IL_002a: ldloc.1
IL_002b: ldstr "##Value##"
IL_0030: ldc.i4.1
IL_0031: callvirt instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
IL_0036: ldloc.1
IL_0037: ldstr "##InnerText##"
IL_003c: ldc.i4.2
IL_003d: callvirt instance void class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::Add(!0, !1)
IL_0042: ldloc.1
IL_0043: stsfld class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> Issue3421::'<>f__switch$map1D'
IL_0048: ldsfld class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32> Issue3421::'<>f__switch$map1D'
IL_004d: ldloc.0
IL_004e: ldloca.s 2
IL_0050: callvirt instance bool class [CORE_ASSEMBLY]System.Collections.Generic.Dictionary`2<string, int32>::TryGetValue(!0, !1&)
IL_0055: brfalse IL_0098
IL_005a: ldloc.2
IL_005b: switch (IL_0071, IL_0076, IL_0082)
IL_006c: br IL_0098
IL_0071: br IL_00b3
IL_0076: ldarg.0
IL_0077: ldarg.1
IL_0078: stfld object Issue3421::'value'
IL_007d: br IL_00b3
IL_0082: ldarg.0
IL_0083: ldarg.1
IL_0084: callvirt instance string [CORE_ASSEMBLY]System.Object::ToString()
IL_0089: stfld object Issue3421::'value'
IL_008e: br IL_00b3
IL_0093: br IL_00b3
IL_0098: ldarg.0
IL_0099: ldfld object Issue3421::'value'
IL_009e: brtrue IL_00ae
IL_00a3: ldarg.0
IL_00a4: ldstr ""
IL_00a9: stfld object Issue3421::'value'
IL_00ae: br IL_00b3
IL_00b3: ret
} // end of method Issue3421::SetValue
.method public hidebysig specialname rtspecialname
instance void .ctor () cil managed
{
// Method begins at RVA 0x2110
// Header size: 1
// Code size: 8 (0x8)
.maxstack 8
IL_0000: ldarg.0
IL_0001: call instance void [CORE_ASSEMBLY]System.Object::.ctor()
IL_0006: nop
IL_0007: ret
} // end of method Issue3421::.ctor
} // end of class Issue3421

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

@ -668,13 +668,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -668,13 +668,20 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (!FixCasesWithoutValue(sections, stringValues))
return false;
// switch contains case null:
if (nullValueCaseBlock != defaultBlock)
if (nullValueCaseBlock != null && nullValueCaseBlock != defaultBlock)
{
if (!AddNullSection(sections, stringValues, nullValueCaseBlock))
{
return false;
}
}
else if (leaveContainer != null && !defaultBlockJump.MatchLeave(leaveContainer))
{
if (!AddNullSection(sections, stringValues, (Leave)exitBlockJump))
{
return false;
}
}
context.Step(nameof(MatchLegacySwitchOnStringWithDict), instructions[i]);
bool keepAssignmentBefore = false;
if (switchValueVar.LoadCount > 2 || switchValue == null)
@ -741,6 +748,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -741,6 +748,11 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
bool AddNullSection(List<SwitchSection> sections, List<(string Value, int Index)> stringValues, Block nullValueCaseBlock)
{
return AddNullSection(sections, stringValues, new Branch(nullValueCaseBlock));
}
bool AddNullSection(List<SwitchSection> sections, List<(string Value, int Index)> stringValues, ILInstruction body)
{
var label = new LongSet(stringValues.Max(item => item.Index) + 1);
var possibleConflicts = sections.Where(sec => sec.Labels.Overlaps(label)).ToArray();
@ -753,7 +765,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -753,7 +765,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
possibleConflicts[0].Labels = possibleConflicts[0].Labels.ExceptWith(label);
}
stringValues.Add((null, (int)label.Values.First()));
sections.Add(new SwitchSection() { Labels = label, Body = new Branch(nullValueCaseBlock) });
sections.Add(new SwitchSection() { Labels = label, Body = body });
return true;
}

Loading…
Cancel
Save