Browse Source

Fix #3361: switch-value conversion was losing its target type.

pull/3362/head
Siegfried Pammer 4 months ago
parent
commit
efbefd0d3b
  1. 86
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
  2. 19
      ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
  3. 25
      ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

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

@ -67,6 +67,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -67,6 +67,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
public class ImplicitInt
{
private readonly int s;
public ImplicitInt(int s)
{
this.s = s;
}
public static implicit operator int(ImplicitInt v)
{
return v.s;
}
}
public class ExplicitInt
{
private readonly int s;
public ExplicitInt(int s)
{
this.s = s;
}
public static explicit operator int(ExplicitInt v)
{
return v.s;
}
}
public enum State
{
False,
@ -310,6 +340,62 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -310,6 +340,62 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
public static void SwitchOverExplicitInt(ExplicitInt i)
{
switch ((int)i)
{
case 0:
Console.WriteLine("zero");
break;
case 5:
Console.WriteLine("five");
break;
case 10:
Console.WriteLine("ten");
break;
case 15:
Console.WriteLine("fifteen");
break;
case 20:
Console.WriteLine("twenty");
break;
case 25:
Console.WriteLine("twenty-five");
break;
case 30:
Console.WriteLine("thirty");
break;
}
}
public static void SwitchOverImplicitInt(ImplicitInt i)
{
switch (i)
{
case 0:
Console.WriteLine("zero");
break;
case 5:
Console.WriteLine("five");
break;
case 10:
Console.WriteLine("ten");
break;
case 15:
Console.WriteLine("fifteen");
break;
case 20:
Console.WriteLine("twenty");
break;
case 25:
Console.WriteLine("twenty-five");
break;
case 30:
Console.WriteLine("thirty");
break;
}
}
// SwitchDetection.UseCSharpSwitch requires more complex heuristic to identify this when compiled with Roslyn
public static void CompactSwitchOverInt(int i)
{

19
ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

@ -3900,17 +3900,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3900,17 +3900,20 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context)
internal (TranslatedExpression, IType) TranslateSwitchValue(SwitchInstruction inst, bool allowImplicitConversion)
{
TranslatedExpression value;
IType type;
if (inst.Value is StringToInt strToInt)
{
// switch-expression does not support implicit conversions at all,
// switch-statement does support implicit conversions in general, however, the rules are
// not very intuitive and in order to prevent bugs, we emit an explicit cast.
value = Translate(strToInt.Argument)
.ConvertTo(
strToInt.ExpectedType,
this,
allowImplicitConversion: false // switch-expression does not support implicit conversions
allowImplicitConversion: false
);
type = compilation.FindType(KnownTypeCode.String);
}
@ -3918,12 +3921,20 @@ namespace ICSharpCode.Decompiler.CSharp @@ -3918,12 +3921,20 @@ namespace ICSharpCode.Decompiler.CSharp
{
strToInt = null;
value = Translate(inst.Value);
type = value.Type;
if (inst.Type != null)
{
value = value.ConvertTo(inst.Type, this, allowImplicitConversion: true);
value = value.ConvertTo(inst.Type, this, allowImplicitConversion: allowImplicitConversion);
type = inst.Type;
}
type = value.Type;
}
return (value, type);
}
protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context)
{
// switch-expression does not support implicit conversions
var (value, type) = TranslateSwitchValue(inst, allowImplicitConversion: false);
IL.SwitchSection defaultSection = inst.GetDefaultSection();
SwitchExpression switchExpr = new SwitchExpression();

25
ICSharpCode.Decompiler/CSharp/StatementBuilder.cs

@ -210,30 +210,7 @@ namespace ICSharpCode.Decompiler.CSharp @@ -210,30 +210,7 @@ namespace ICSharpCode.Decompiler.CSharp
var oldCaseLabelMapping = caseLabelMapping;
caseLabelMapping = new Dictionary<Block, ConstantResolveResult>();
TranslatedExpression value;
IType type;
if (inst.Value is StringToInt strToInt)
{
value = exprBuilder.Translate(strToInt.Argument)
.ConvertTo(
strToInt.ExpectedType,
exprBuilder,
// switch statement does support implicit conversions in general, however, the rules are
// not very intuitive and in order to prevent bugs, we emit an explicit cast.
allowImplicitConversion: false
);
type = exprBuilder.compilation.FindType(KnownTypeCode.String);
}
else
{
strToInt = null;
value = exprBuilder.Translate(inst.Value);
if (inst.Type != null)
{
value = value.ConvertTo(inst.Type, exprBuilder, allowImplicitConversion: true);
}
type = value.Type;
}
var (value, type) = exprBuilder.TranslateSwitchValue(inst, allowImplicitConversion: true);
IL.SwitchSection defaultSection = inst.GetDefaultSection();

Loading…
Cancel
Save