diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs index f49d3ea68..374752ba3 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs @@ -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 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; + } + } } } diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 0c167800b..e96407395 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -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; } diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 32d46b643..1db19abe8 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -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; } diff --git a/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs b/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs index aa3a55a56..ad0d0a9a4 100644 --- a/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs +++ b/ICSharpCode.Decompiler/IL/Instructions/SwitchInstruction.cs @@ -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 /// public bool IsLifted; + /// + /// Additional type information used to interpret the value instruction. + /// Set by ILInlining to preserve stack information that would otherwise be lost. + /// + public IType? Type; + public SwitchInstruction(ILInstruction value) : base(OpCode.SwitchInstruction) { @@ -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("{...}"); diff --git a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs index d9326c841..b77494f46 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs @@ -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;