Browse Source

Fix #2763: Improve decompilation of switch-on-enum by preserving enum type information when inlining local variables into SwitchInstruction.Value.

pull/2789/head
Siegfried Pammer 3 years ago
parent
commit
a3191f19e2
  1. 35
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 4
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
  4. 11
      ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs
  5. 6
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

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

@ -74,6 +74,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -74,6 +74,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
Null
}
public enum KnownColor
{
DarkBlue,
DarkCyan,
DarkGoldenrod,
DarkGray,
DarkGreen,
DarkKhaki
}
private static char ch1767;
#if !ROSLYN
@ -1474,5 +1484,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -1474,5 +1484,30 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
break;
}
}
public static void Issue2763(int value)
{
switch ((KnownColor)value)
{
case KnownColor.DarkBlue:
Console.WriteLine("DarkBlue");
break;
case KnownColor.DarkCyan:
Console.WriteLine("DarkCyan");
break;
case KnownColor.DarkGoldenrod:
Console.WriteLine("DarkGoldenrod");
break;
case KnownColor.DarkGray:
Console.WriteLine("DarkGray");
break;
case KnownColor.DarkGreen:
Console.WriteLine("DarkGreen");
break;
case KnownColor.DarkKhaki:
Console.WriteLine("DarkKhaki");
break;
}
}
}
}

4
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -3819,6 +3819,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3819,6 +3819,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
strToInt = null;
value = Translate(inst.Value);
if (inst.Type != null)
{
value = value.ConvertTo(inst.Type, this, allowImplicitConversion: true);
}
type = value.Type;
}

4
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -226,6 +226,10 @@ namespace ICSharpCode.Decompiler.CSharp @@ -226,6 +226,10 @@ namespace ICSharpCode.Decompiler.CSharp
{
strToInt = null;
value = exprBuilder.Translate(inst.Value);
if (inst.Type != null)
{
value = value.ConvertTo(inst.Type, exprBuilder, allowImplicitConversion: true);
}
type = value.Type;
}

11
ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs

@ -20,6 +20,7 @@ @@ -20,6 +20,7 @@
using System.Diagnostics;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
namespace ICSharpCode.Decompiler.IL
@ -42,6 +43,12 @@ namespace ICSharpCode.Decompiler.IL @@ -42,6 +43,12 @@ namespace ICSharpCode.Decompiler.IL
/// </summary>
public bool IsLifted;
/// <summary>
/// Additional type information used to interpret the value instruction.
/// Set by ILInlining to preserve stack information that would otherwise be lost.
/// </summary>
public IType? Type;
public SwitchInstruction(ILInstruction value)
: base(OpCode.SwitchInstruction)
{
@ -82,7 +89,9 @@ namespace ICSharpCode.Decompiler.IL @@ -82,7 +89,9 @@ namespace ICSharpCode.Decompiler.IL
output.Write("switch");
if (IsLifted)
output.Write(".lifted");
output.Write(" (");
output.Write(' ');
Type?.WriteTo(output);
output.Write('(');
value.WriteTo(output, options);
output.Write(") ");
output.MarkFoldStart("{...}");

6
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -600,6 +600,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -600,6 +600,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
case OpCode.YieldReturn:
return true;
case OpCode.SwitchInstruction:
// Preserve type info on switch instruction, if we're inlining a local variable into the switch-value slot.
if (v.Kind != VariableKind.StackSlot && loadInst.SlotInfo == SwitchInstruction.ValueSlot)
{
((SwitchInstruction)parent).Type ??= v.Type;
}
return true;
//case OpCode.BinaryNumericInstruction when parent.SlotInfo == SwitchInstruction.ValueSlot:
case OpCode.StringToInt when parent.SlotInfo == SwitchInstruction.ValueSlot:
return true;

Loading…
Cancel
Save