diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index c8e8d2721..34a3c4406 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -92,6 +92,7 @@ + diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs index c5687aa85..fdfc29d62 100644 --- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs +++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs @@ -493,6 +493,12 @@ namespace ICSharpCode.Decompiler.Tests RunForLibrary(cscOptions: cscOptions); } + [Test] + public void DeconstructionTests([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) + { + RunForLibrary(cscOptions: cscOptions); + } + void RunForLibrary([CallerMemberName] string testName = null, AssemblerOptions asmOptions = AssemblerOptions.None, CompilerOptions cscOptions = CompilerOptions.None, DecompilerSettings decompilerSettings = null) { Run(testName, asmOptions | AssemblerOptions.Library, cscOptions | CompilerOptions.Library, decompilerSettings); diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs new file mode 100644 index 000000000..8d834ef7b --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DeconstructionTests.cs @@ -0,0 +1,101 @@ +// Copyright (c) 2020 Siegfried Pammer +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Runtime.InteropServices; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty +{ + internal class DeconstructionTests + { + private class CustomDeconstructionAndConversion + { + [StructLayout(LayoutKind.Sequential, Size = 1)] + public struct MyInt + { + public static implicit operator int(MyInt x) + { + return 0; + } + + public static implicit operator MyInt(int x) + { + return default(MyInt); + } + } + + public int IntField; + + public int? NullableIntField; + + public MyInt MyIntField; + + public MyInt? NullableMyIntField; + + public int Int { + get; + set; + } + + public int? NInt { + get; + set; + } + + public MyInt My { + get; + set; + } + + public MyInt? NMy { + get; + set; + } + + public void Deconstruct(out MyInt? x, out MyInt y) + { + x = null; + y = default(MyInt); + } + + public CustomDeconstructionAndConversion GetValue() + { + return null; + } + + public CustomDeconstructionAndConversion Get(int i) + { + return null; + } + + private MyInt? GetNullableMyInt() + { + throw new NotImplementedException(); + } + + public void Test7() + { + MyInt? myInt3; + MyInt x; + (myInt3, x) = GetValue(); + Console.WriteLine(myInt3); + Console.WriteLine(x); + } + } + } +} diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index e1b158b0a..36bd2534a 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -93,6 +93,7 @@ namespace ICSharpCode.Decompiler tupleConversions = false; discards = false; localFunctions = false; + deconstruction = false; } if (languageVersion < CSharp.LanguageVersion.CSharp7_2) { introduceReadonlyAndInModifiers = false; @@ -1106,6 +1107,23 @@ namespace ICSharpCode.Decompiler } } + bool deconstruction = true; + + /// + /// Gets/Sets whether C# 7.0 deconstruction should be detected. + /// + [Category("C# 7.0 / VS 2017")] + [Description("DecompilerSettings.Deconstruction")] + public bool Deconstruction { + get { return deconstruction; } + set { + if (deconstruction != value) { + deconstruction = value; + OnPropertyChanged(); + } + } + } + bool staticLocalFunctions = true; /// @@ -1126,7 +1144,7 @@ namespace ICSharpCode.Decompiler bool ranges = true; /// - /// Gets/Sets whether C# 8.0 static local functions should be transformed. + /// Gets/Sets whether C# 8.0 index and range syntax should be used. /// [Category("C# 8.0 / VS 2019")] [Description("DecompilerSettings.Ranges")] diff --git a/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs index b3322f31e..3a33a5b02 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/DeconstructionTransform.cs @@ -18,12 +18,6 @@ using System; using System.Collections.Generic; -using System.Diagnostics; -using System.Linq; -using System.Linq.Expressions; -using System.Text; - -using ICSharpCode.Decompiler.CSharp.Syntax.PatternMatching; using ICSharpCode.Decompiler.TypeSystem; namespace ICSharpCode.Decompiler.IL.Transforms @@ -62,8 +56,8 @@ namespace ICSharpCode.Decompiler.IL.Transforms * */ void IStatementTransform.Run(Block block, int pos, StatementTransformContext context) { - //if (!context.Settings.Deconstruction) - // return; + if (!context.Settings.Deconstruction) + return; try { this.context = context; diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs index 84a05cf4c..6ede5d22a 100644 --- a/ILSpy/Properties/Resources.Designer.cs +++ b/ILSpy/Properties/Resources.Designer.cs @@ -765,6 +765,15 @@ namespace ICSharpCode.ILSpy.Properties { } } + /// + /// Looks up a localized string similar to Detect deconstruction assignments. + /// + public static string DecompilerSettings_Deconstruction { + get { + return ResourceManager.GetString("DecompilerSettings.Deconstruction", resourceCulture); + } + } + /// /// Looks up a localized string similar to Detect awaited using and foreach statements. /// diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx index 62a8ffa83..6a979b29d 100644 --- a/ILSpy/Properties/Resources.resx +++ b/ILSpy/Properties/Resources.resx @@ -879,4 +879,7 @@ Do you want to continue? Base Types + + Detect deconstruction assignments + \ No newline at end of file