From 63ca748b9a1d39deee27c2bbc9cdb51aeb0229c5 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Mon, 25 Jan 2021 18:48:00 +0100 Subject: [PATCH] Fix #2283: string.to.int instruction entails a conversion to string of the input value --- .../TestCases/Pretty/Switch.cs | 92 +++++++++++++++++++ .../CSharp/ExpressionBuilder.cs | 5 +- .../CSharp/StatementBuilder.cs | 9 +- 3 files changed, 103 insertions(+), 3 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs index 4a10965a7..1b4de4422 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs @@ -37,6 +37,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + public class ImplicitString + { + private readonly string s; + + public ImplicitString(string s) + { + this.s = s; + } + + public static implicit operator string(ImplicitString v) + { + return v.s; + } + } + + public class ExplicitString + { + private readonly string s; + + public ExplicitString(string s) + { + this.s = s; + } + + public static explicit operator string(ExplicitString v) + { + return v.s; + } + } + public enum State { False, @@ -379,6 +409,68 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty } } + public static string SwitchOverImplicitString(ImplicitString s) + { + switch (s) + { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case "Seventh case": + return "Text7"; + case "Eighth case": + return "Text8"; + case "Ninth case": + return "Text9"; + case "Tenth case": + return "Text10"; + case "Eleventh case": + return "Text11"; + default: + return "Default"; + } + } + + public static string SwitchOverExplicitString(ExplicitString s) + { + switch ((string)s) + { + case "First case": + return "Text1"; + case "Second case": + return "Text2"; + case "Third case": + return "Text3"; + case "Fourth case": + return "Text4"; + case "Fifth case": + return "Text5"; + case "Sixth case": + return "Text6"; + case "Seventh case": + return "Text7"; + case "Eighth case": + return "Text8"; + case "Ninth case": + return "Text9"; + case "Tenth case": + return "Text10"; + case "Eleventh case": + return "Text11"; + default: + return "Default"; + } + } + #if !ROSLYN public static string SwitchOverBool(bool b) { diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 9a723cead..e37343051 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -3642,6 +3642,7 @@ namespace ICSharpCode.Decompiler.CSharp protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context) { TranslatedExpression value; + IType type; if (inst.Value is StringToInt strToInt) { value = Translate(strToInt.Argument) @@ -3650,11 +3651,13 @@ namespace ICSharpCode.Decompiler.CSharp this, allowImplicitConversion: false // switch-expression does not support implicit conversions ); + type = compilation.FindType(KnownTypeCode.String); } else { strToInt = null; value = Translate(inst.Value); + type = value.Type; } IL.SwitchSection defaultSection = inst.GetDefaultSection(); @@ -3683,7 +3686,7 @@ namespace ICSharpCode.Decompiler.CSharp else { long val = section.Labels.Values.Single(); - var rr = statementBuilder.CreateTypedCaseLabel(val, value.Type, strToInt?.Map).Single(); + var rr = statementBuilder.CreateTypedCaseLabel(val, type, strToInt?.Map).Single(); ses.Pattern = astBuilder.ConvertConstantValue(rr); } ses.Body = TranslateSectionBody(section); diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index 7464a6358..bd9cbe5ed 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -144,12 +144,14 @@ namespace ICSharpCode.Decompiler.CSharp // unpack nullable type, if necessary: // we need to do this in all cases, because there are nullable bools and enum types as well. type = NullableType.GetUnderlyingType(type); + if (type.IsKnownType(KnownTypeCode.Boolean)) { value = i != 0; } - else if (type.IsKnownType(KnownTypeCode.String) && map != null) + else if (map != null) { + Debug.Assert(type.IsKnownType(KnownTypeCode.String)); var keys = map.Where(entry => entry.Value == i).Select(entry => entry.Key); foreach (var key in keys) yield return new ConstantResolveResult(type, key); @@ -196,6 +198,7 @@ namespace ICSharpCode.Decompiler.CSharp caseLabelMapping = new Dictionary(); TranslatedExpression value; + IType type; if (inst.Value is StringToInt strToInt) { value = exprBuilder.Translate(strToInt.Argument) @@ -204,11 +207,13 @@ namespace ICSharpCode.Decompiler.CSharp exprBuilder, allowImplicitConversion: true ); + type = exprBuilder.compilation.FindType(KnownTypeCode.String); } else { strToInt = null; value = exprBuilder.Translate(inst.Value); + type = value.Type; } IL.SwitchSection defaultSection = inst.GetDefaultSection(); @@ -229,7 +234,7 @@ namespace ICSharpCode.Decompiler.CSharp } else { - var values = section.Labels.Values.SelectMany(i => CreateTypedCaseLabel(i, value.Type, strToInt?.Map)).ToArray(); + var values = section.Labels.Values.SelectMany(i => CreateTypedCaseLabel(i, type, strToInt?.Map)).ToArray(); if (section.HasNullLabel) { astSection.CaseLabels.Add(new CaseLabel(new NullReferenceExpression()));