diff --git a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj index a0026ced3..c4b541875 100644 --- a/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj +++ b/ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj @@ -42,8 +42,8 @@ - - + + diff --git a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs index 3b369e3fc..2a1b99130 100644 --- a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs +++ b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs @@ -88,39 +88,65 @@ namespace ICSharpCode.Decompiler.Tests [Test] public void ExplicitConversions() { - RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe"); + RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe", LanguageVersion.CSharp8_0); } [Test] public void ExplicitConversions_32() { - RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe"); + RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe", LanguageVersion.CSharp8_0); + } + + [Test] + [Ignore("Waiting for https://github.com/dotnet/roslyn/issues/45929")] + public void ExplicitConversions_With_NativeInts() + { + RunWithOutput("Random Tests\\TestCases", "ExplicitConversions.exe", LanguageVersion.Preview); + } + + [Test] + [Ignore("Waiting for https://github.com/dotnet/roslyn/issues/45929")] + public void ExplicitConversions_32_With_NativeInts() + { + RunWithOutput("Random Tests\\TestCases", "ExplicitConversions_32.exe", LanguageVersion.Preview); } [Test] public void Random_TestCase_1() { - RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe"); + RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe", LanguageVersion.CSharp8_0); + } + + [Test] + [Ignore("Waiting for https://github.com/dotnet/roslyn/issues/45929")] + public void Random_TestCase_1_With_NativeInts() + { + RunWithOutput("Random Tests\\TestCases", "TestCase-1.exe", LanguageVersion.Preview); } - void RunWithTest(string dir, string fileToRoundtrip, string fileToTest, string keyFile = null, bool useOldProjectFormat = false) + // Let's limit the roundtrip tests to C# 8.0 for now; because 9.0 is still in preview + // and the generated project doesn't build as-is. + const LanguageVersion defaultLanguageVersion = LanguageVersion.CSharp8_0; + + void RunWithTest(string dir, string fileToRoundtrip, string fileToTest, LanguageVersion languageVersion = defaultLanguageVersion, string keyFile = null, bool useOldProjectFormat = false) { - RunInternal(dir, fileToRoundtrip, outputDir => RunTest(outputDir, fileToTest), keyFile, useOldProjectFormat); + RunInternal(dir, fileToRoundtrip, outputDir => RunTest(outputDir, fileToTest), languageVersion, snkFilePath: keyFile, useOldProjectFormat: useOldProjectFormat); } - void RunWithOutput(string dir, string fileToRoundtrip) + void RunWithOutput(string dir, string fileToRoundtrip, LanguageVersion languageVersion = defaultLanguageVersion) { string inputDir = Path.Combine(TestDir, dir); RunInternal(dir, fileToRoundtrip, - outputDir => Tester.RunAndCompareOutput(fileToRoundtrip, Path.Combine(inputDir, fileToRoundtrip), Path.Combine(outputDir, fileToRoundtrip))); + outputDir => Tester.RunAndCompareOutput(fileToRoundtrip, Path.Combine(inputDir, fileToRoundtrip), Path.Combine(outputDir, fileToRoundtrip)), + languageVersion); } - void RunOnly(string dir, string fileToRoundtrip) + void RunOnly(string dir, string fileToRoundtrip, LanguageVersion languageVersion = defaultLanguageVersion) { - RunInternal(dir, fileToRoundtrip, outputDir => { }); + RunInternal(dir, fileToRoundtrip, outputDir => { }, languageVersion); } - void RunInternal(string dir, string fileToRoundtrip, Action testAction, string snkFilePath = null, bool useOldProjectFormat = false) + void RunInternal(string dir, string fileToRoundtrip, Action testAction, LanguageVersion languageVersion, string snkFilePath = null, bool useOldProjectFormat = false) { if (!Directory.Exists(TestDir)) { Assert.Ignore($"Assembly-roundtrip test ignored: test directory '{TestDir}' needs to be checked out separately." + Environment.NewLine + @@ -131,8 +157,8 @@ namespace ICSharpCode.Decompiler.Tests string outputDir = inputDir + "-output"; if (inputDir.EndsWith("TestCases")) { // make sure output dir names are unique so that we don't get trouble due to parallel test execution - decompiledDir += Path.GetFileNameWithoutExtension(fileToRoundtrip); - outputDir += Path.GetFileNameWithoutExtension(fileToRoundtrip); + decompiledDir += Path.GetFileNameWithoutExtension(fileToRoundtrip) + "_" + languageVersion.ToString(); + outputDir += Path.GetFileNameWithoutExtension(fileToRoundtrip) + "_" + languageVersion.ToString(); } ClearDirectory(decompiledDir); ClearDirectory(outputDir); @@ -155,9 +181,7 @@ namespace ICSharpCode.Decompiler.Tests // use a fixed GUID so that we can diff the output between different ILSpy runs without spurious changes var projectGuid = Guid.Parse("{127C83E4-4587-4CF9-ADCA-799875F3DFE6}"); - // Let's limit the roundtrip tests to C# 7.3 for now; because 8.0 is still in preview - // and the generated project doesn't build as-is. - var settings = new DecompilerSettings(LanguageVersion.CSharp7_3); + var settings = new DecompilerSettings(languageVersion); if (useOldProjectFormat) { settings.UseSdkStyleProjectFormat = false; } diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs new file mode 100644 index 000000000..ce295a371 --- /dev/null +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs @@ -0,0 +1,77 @@ +// Copyright (c) 2020 Daniel Grunwald +// +// 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.Collections.Generic; + +namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty +{ + internal class NativeInts + { + private const nint nint_const = 42; + private const nuint nuint_const = 99u; + + private IntPtr intptr; + private UIntPtr uintptr; + private nint i; + private nuint u; + private int i32; + private uint u32; + private long i64; + private ulong u64; + private (IntPtr, nint, UIntPtr, nuint) tuple_field; + private Dictionary dict1; + private Dictionary dict2; + + public void Convert() + { + intptr = i; + intptr = (nint)u; + intptr = (nint)(nuint)uintptr; + + uintptr = (nuint)i; + uintptr = u; + uintptr = (nuint)(nint)intptr; + + i = intptr; + i = (nint)u; + i = (nint)(nuint)uintptr; + + u = (nuint)i; + u = uintptr; + u = (nuint)(nint)intptr; + } + + public void Convert2() + { + i32 = (int)i; + i = i32; + intptr = (IntPtr)i32; + + i64 = (long)intptr; + i64 = i; + i = (nint)i64; + + u32 = (uint)i; + i = (nint)u32; + + u64 = (uint)i; + i = (nint)u64; + } + } +} diff --git a/ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs b/ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs index 037af83be..530f5aa48 100644 --- a/ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs +++ b/ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs @@ -17,7 +17,7 @@ namespace ICSharpCode.Decompiler.CSharp CSharp7_2 = 702, CSharp7_3 = 703, CSharp8_0 = 800, - CSharp9_0 = 900, + Preview = 900, Latest = 0x7FFFFFFF } } diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs index 5ff0113f8..7e5e90d09 100644 --- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs @@ -1650,8 +1650,15 @@ namespace ICSharpCode.Decompiler.CSharp IType GetType(KnownTypeCode typeCode) { IType type = compilation.FindType(typeCode); - if (inst.IsLifted) + // Prefer n(u)int over (U)IntPtr + if (typeCode == KnownTypeCode.IntPtr && settings.NativeIntegers && !type.Equals(context.TypeHint)) { + type = SpecialType.NInt; + } else if (typeCode == KnownTypeCode.UIntPtr && settings.NativeIntegers && !type.Equals(context.TypeHint)) { + type = SpecialType.NUInt; + } + if (inst.IsLifted) { type = NullableType.Create(compilation, type); + } return type; } diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs index 29a790d66..e1b158b0a 100644 --- a/ICSharpCode.Decompiler/DecompilerSettings.cs +++ b/ICSharpCode.Decompiler/DecompilerSettings.cs @@ -114,7 +114,7 @@ namespace ICSharpCode.Decompiler staticLocalFunctions = false; ranges = false; } - if (languageVersion < CSharp.LanguageVersion.CSharp9_0) { + if (languageVersion < CSharp.LanguageVersion.Preview) { nativeIntegers = false; } } @@ -122,7 +122,7 @@ namespace ICSharpCode.Decompiler public CSharp.LanguageVersion GetMinimumRequiredVersion() { if (nativeIntegers) - return CSharp.LanguageVersion.CSharp9_0; + return CSharp.LanguageVersion.Preview; if (nullableReferenceTypes || readOnlyMethods || asyncEnumerator || asyncUsingAndForEachStatement || staticLocalFunctions || ranges) return CSharp.LanguageVersion.CSharp8_0; if (introduceUnmanagedConstraint || tupleComparisons || stackAllocInitializers || patternBasedFixedStatement) diff --git a/ILSpy.Tests/ILSpy.Tests.csproj b/ILSpy.Tests/ILSpy.Tests.csproj index ec0e6bf79..6027ba7aa 100644 --- a/ILSpy.Tests/ILSpy.Tests.csproj +++ b/ILSpy.Tests/ILSpy.Tests.csproj @@ -46,8 +46,8 @@ - - + + diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index 0e0b95a38..8b0253026 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -107,7 +107,7 @@ namespace ICSharpCode.ILSpy new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp7_2.ToString(), "C# 7.2 / VS 2017.4"), new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp7_3.ToString(), "C# 7.3 / VS 2017.7"), new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp8_0.ToString(), "C# 8.0 / VS 2019"), - new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp9_0.ToString(), "C# 9.0 (experimental)"), + new LanguageVersion(Decompiler.CSharp.LanguageVersion.Preview.ToString(), "C# 9.0 (experimental)"), }; } return versions;