Browse Source

Add feature: C#11 nint without NativeIntegerAttribute

Because it is no longer possible to distinguish IntPtr from nint, this required a lot of testcase adjustment.
pull/2873/head
Daniel Grunwald 2 years ago
parent
commit
efeaf1356f
  1. 1
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  2. 3
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  3. 18
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs
  4. 7
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
  5. 14
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs
  6. 4
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  7. 36
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs
  8. 11
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs
  9. 17
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  10. 21
      ICSharpCode.Decompiler/DecompilerSettings.cs
  11. 2
      ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
  12. 14
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  13. 9
      ILSpy/Properties/Resources.Designer.cs
  14. 3
      ILSpy/Properties/Resources.resx
  15. 4
      README.md

1
ICSharpCode.Decompiler.Tests/Helpers/Tester.cs

@ -343,6 +343,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers @@ -343,6 +343,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
{
preprocessorSymbols.Add("NETCORE");
preprocessorSymbols.Add("NET60");
preprocessorSymbols.Add("NET70");
}
preprocessorSymbols.Add("ROSLYN");
preprocessorSymbols.Add("CS60");

3
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -326,6 +326,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -326,6 +326,7 @@ namespace ICSharpCode.Decompiler.Tests
RemoveDeadStores = (cscOptions == CompilerOptions.None),
UseExpressionBodyForCalculatedGetterOnlyProperties = false,
FileScopedNamespaces = false,
NumericIntPtr = false,
});
}
@ -486,7 +487,7 @@ namespace ICSharpCode.Decompiler.Tests @@ -486,7 +487,7 @@ namespace ICSharpCode.Decompiler.Tests
}
[Test]
public async Task NativeInts([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions)
public async Task NativeInts([ValueSource(nameof(roslyn3OrNewerWithNet40Options))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}

18
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs

@ -1,10 +1,25 @@ @@ -1,10 +1,25 @@
using System;
#if !(CS110 && NET70)
using System;
#endif
using System.Threading.Tasks;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
internal class ConstantsTests
{
#if CS90
public nint? NullableNInt()
{
return null;
}
public nuint? NullableNUInt()
{
return null;
}
#endif
#if !(CS110 && NET70)
public IntPtr? NullableIntPtr()
{
return null;
@ -14,6 +29,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -14,6 +29,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return null;
}
#endif
public ulong Issue1308(ulong u = 8uL)
{

7
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs

@ -436,10 +436,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -436,10 +436,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return true.Equals(a);
}
#if CS110 && NET70
private static nint NewIntPtr(dynamic a)
{
return new nint(a);
}
#else
private static IntPtr NewIntPtr(dynamic a)
{
return new IntPtr(a);
}
#endif
private static dynamic GetDynamic(int i)
{

14
ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs

@ -1,4 +1,6 @@ @@ -1,4 +1,6 @@
using System;
#if !(CS110 && NET70)
using System;
#endif
using System.Text;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
@ -17,10 +19,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -17,10 +19,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return &Overloaded;
}
#if !(CS110 && NET70)
public unsafe IntPtr GetAddressAsIntPtr()
{
return (IntPtr)(delegate*<void>)(&Overloaded);
}
#endif
public unsafe nint GetAddressAsNInt()
{
return (nint)(delegate*<void>)(&Overloaded);
}
public unsafe void* GetAddressAsVoidPtr()
{
@ -93,6 +102,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -93,6 +102,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
internal class FunctionPointersWithNativeIntegerTypes
{
public unsafe delegate*<nint, nint, nint> F1;
#if !(CS110 && NET70)
public unsafe delegate*<IntPtr, IntPtr, nint> F2;
public unsafe delegate*<nint, IntPtr, IntPtr> F3;
public unsafe delegate*<IntPtr, nint, IntPtr> F4;
@ -100,6 +110,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -100,6 +110,8 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public unsafe delegate*<nint, delegate*<IntPtr, IntPtr, IntPtr>> F6;
public unsafe delegate*<delegate*<IntPtr, IntPtr, nint>, IntPtr> F7;
public unsafe delegate*<IntPtr, delegate*<IntPtr, nint, IntPtr>> F8;
public unsafe delegate*<IntPtr, delegate*<IntPtr, IntPtr, IntPtr>> F9;
#endif
}
internal class FunctionPointersWithRefParams

4
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -844,10 +844,10 @@ namespace LocalFunctions @@ -844,10 +844,10 @@ namespace LocalFunctions
#if CS90
public void Issue2196()
{
EnumWindows(IntPtr.Zero, IntPtr.Zero);
EnumWindows(0L, 0L);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "EnumWindows")]
static extern int EnumWindows(IntPtr hWnd, IntPtr lParam);
static extern int EnumWindows(long hWnd, long lParam);
}
#endif
}

36
ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs

@ -26,23 +26,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -26,23 +26,36 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
private const nint nint_const = 42;
private const nuint nuint_const = 99u;
#if CS110 && NET70
// C#11 on .NET7 no longer uses NativeIntegerAttribute,
// instead nint+IntPtr are considered to be the same type.
private nint intptr;
private nuint uintptr;
#else
private IntPtr intptr;
private UIntPtr uintptr;
#endif
private nint i;
private nuint u;
private int i32;
private uint u32;
private long i64;
private ulong u64;
#if !(CS110 && NET70)
private (IntPtr, nint, UIntPtr, nuint) tuple_field;
private (object, int, IntPtr, nint, UIntPtr, nuint) tuple_field2;
private Dictionary<nint, IntPtr> dict1;
private Dictionary<IntPtr, nint> dict2;
private Dictionary<IntPtr?, nint?> dict3;
private Dictionary<IntPtr, nint[]> dict4;
#endif
private Dictionary<nuint, nint[]> dict5;
public void Convert()
{
i = (nint)u;
u = (nuint)i;
#if !(CS110 && NET70)
intptr = i;
intptr = (nint)u;
intptr = (nint)(nuint)uintptr;
@ -58,15 +71,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -58,15 +71,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
u = (nuint)i;
u = uintptr;
u = (nuint)(nint)intptr;
#endif
}
public void Convert2()
{
i32 = (int)i;
i = i32;
#if !(CS110 && NET70)
intptr = (IntPtr)i32;
i64 = (long)intptr;
#endif
i64 = i;
i = (nint)i64;
@ -79,7 +95,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -79,7 +95,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public void Arithmetic()
{
#if !(CS110 && NET70)
Console.WriteLine((nint)intptr * 2);
#endif
Console.WriteLine(i * 2);
Console.WriteLine(i + (nint)u);
@ -155,6 +173,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -155,6 +173,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
GetInstance(3).u *= 2u;
}
#if !(CS110 && NET70)
GetInstance(4).intptr += (nint)i32;
checked
{
@ -164,10 +183,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -164,10 +183,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
// multiplication results in compiler-error without the cast
GetInstance(6).intptr *= (nint)2;
#endif
GetInstance(7).i <<= i32;
GetInstance(7).i += i32;
GetInstance(8).i <<= i32;
}
#if !(CS110 && NET70)
public void LocalTypeFromStore()
{
nint num = 42;
@ -188,10 +210,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -188,10 +210,19 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
intptr = num3;
intptr = intPtr;
}
#endif
public void LocalTypeFromUse()
{
#if CS110 && NET70
nint num = intptr;
nint num2 = intptr;
Console.WriteLine();
intptr = num;
i = num2 + 1;
#else
IntPtr intPtr = intptr;
nint num = intptr;
@ -199,6 +230,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -199,6 +230,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
intptr = intPtr;
i = num + 1;
#endif
}
public nint NegateUnsigned(nuint x)

11
ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs

@ -89,6 +89,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -89,6 +89,16 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
}
#if CS110 && NET70
[DllImport("ws2_32.dll", SetLastError = true)]
internal static extern nint ioctlsocket([In] nint socketHandle, [In] int cmd, [In][Out] ref int argp);
public void CallMethodWithInOutParameter()
{
int argp = 0;
ioctlsocket(nint.Zero, 0, ref argp);
}
#else
[DllImport("ws2_32.dll", SetLastError = true)]
internal static extern IntPtr ioctlsocket([In] IntPtr socketHandle, [In] int cmd, [In][Out] ref int argp);
@ -97,5 +107,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -97,5 +107,6 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
int argp = 0;
ioctlsocket(IntPtr.Zero, 0, ref argp);
}
#endif
}
}

17
ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs

@ -30,7 +30,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -30,7 +30,11 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public static object StaticObj;
#if CS110 && NET70
public nint A;
#else
public IntPtr A;
#endif
}
private struct UnmanagedStruct
@ -605,6 +609,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -605,6 +609,18 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return value.Integers[(int)s];
}
#if CS90
private unsafe static void* CastNIntToVoidPtr(nint intptr)
{
return (void*)intptr;
}
private unsafe static void* CastNIntToVoidPtr(nuint intptr)
{
return (void*)intptr;
}
#endif
#if !(CS110 && NET70)
private unsafe static void* CastToVoidPtr(IntPtr intptr)
{
return (void*)intptr;
@ -614,6 +630,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty @@ -614,6 +630,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
return (void*)intptr;
}
#endif
private unsafe static void* CastToVoidPtr(int* intptr)
{

21
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -152,12 +152,13 @@ namespace ICSharpCode.Decompiler @@ -152,12 +152,13 @@ namespace ICSharpCode.Decompiler
parameterNullCheck = false;
lifetimeAnnotations = false;
requiredMembers = false;
numericIntPtr = false;
}
}
public CSharp.LanguageVersion GetMinimumRequiredVersion()
{
if (parameterNullCheck || lifetimeAnnotations || requiredMembers)
if (parameterNullCheck || lifetimeAnnotations || requiredMembers || numericIntPtr)
return CSharp.LanguageVersion.CSharp11_0;
if (fileScopedNamespaces || recordStructs)
return CSharp.LanguageVersion.CSharp10_0;
@ -211,6 +212,24 @@ namespace ICSharpCode.Decompiler @@ -211,6 +212,24 @@ namespace ICSharpCode.Decompiler
}
}
bool numericIntPtr = true;
/// <summary>
/// Treat <c>IntPtr</c>/<c>UIntPtr</c> as <c>nint</c>/<c>nuint</c>.
/// </summary>
[Category("C# 11.0 / VS 2022.4")]
[Description("DecompilerSettings.NumericIntPtr")]
public bool NumericIntPtr {
get { return numericIntPtr; }
set {
if (numericIntPtr != value)
{
numericIntPtr = value;
OnPropertyChanged();
}
}
}
bool covariantReturns = true;
/// <summary>

2
ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs

@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -44,7 +44,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
{
bool hasDynamicAttribute = false;
bool[] dynamicAttributeData = null;
bool hasNativeIntegersAttribute = false;
bool hasNativeIntegersAttribute = (options & TypeSystemOptions.NativeIntegersWithoutAttribute) != 0;
bool[] nativeIntegersAttributeData = null;
string[] tupleElementNames = null;
Nullability nullability;

14
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -125,11 +125,17 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -125,11 +125,17 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary>
LifetimeAnnotations = 0x4000,
/// <summary>
/// Replace 'IntPtr' types with the 'nint' type even in absence of [NativeIntegerAttribute].
/// Note: DecompilerTypeSystem constructor removes this setting from the options if
/// not targeting .NET 7 or later.
/// </summary>
NativeIntegersWithoutAttribute = 0x8000,
/// <summary>
/// Default settings: typical options for the decompiler, with all C# languages features enabled.
/// </summary>
Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters
| RefStructs | UnmanagedConstraints | NullabilityAnnotations | ReadOnlyMethods
| NativeIntegers | FunctionPointers | LifetimeAnnotations
| NativeIntegers | FunctionPointers | LifetimeAnnotations | NativeIntegersWithoutAttribute
}
/// <summary>
@ -167,6 +173,8 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -167,6 +173,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
typeSystemOptions |= TypeSystemOptions.FunctionPointers;
if (settings.LifetimeAnnotations)
typeSystemOptions |= TypeSystemOptions.LifetimeAnnotations;
if (settings.NumericIntPtr)
typeSystemOptions |= TypeSystemOptions.NativeIntegersWithoutAttribute;
return typeSystemOptions;
}
@ -304,6 +312,10 @@ namespace ICSharpCode.Decompiler.TypeSystem @@ -304,6 +312,10 @@ namespace ICSharpCode.Decompiler.TypeSystem
}
}
if (!(identifier == TargetFrameworkIdentifier.NET && version >= new Version(7, 0)))
{
typeSystemOptions &= ~TypeSystemOptions.NativeIntegersWithoutAttribute;
}
var mainModuleWithOptions = mainModule.WithOptions(typeSystemOptions);
var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(typeSystemOptions));
// Primitive types are necessary to avoid assertions in ILReader.

9
ILSpy/Properties/Resources.Designer.cs generated

@ -1108,6 +1108,15 @@ namespace ICSharpCode.ILSpy.Properties { @@ -1108,6 +1108,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
/// <summary>
/// Looks up a localized string similar to Treat (U)IntPtr as n(u)int.
/// </summary>
public static string DecompilerSettings_NumericIntPtr {
get {
return ResourceManager.GetString("DecompilerSettings.NumericIntPtr", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to Object/collection initializer expressions.
/// </summary>

3
ILSpy/Properties/Resources.resx

@ -393,6 +393,9 @@ Are you sure you want to continue?</value> @@ -393,6 +393,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve">
<value>Nullable reference types</value>
</data>
<data name="DecompilerSettings.NumericIntPtr" xml:space="preserve">
<value>Treat (U)IntPtr as n(u)int</value>
</data>
<data name="DecompilerSettings.ObjectCollectionInitializerExpressions" xml:space="preserve">
<value>Object/collection initializer expressions</value>
</data>

4
README.md

@ -24,7 +24,7 @@ Features @@ -24,7 +24,7 @@ Features
-------
* Decompilation to C# (check out the [language support status](https://github.com/icsharpcode/ILSpy/issues/829))
* Whole-project decompilation (csproj, not sln!)
* Whole-project decompilation
* Search for types/methods/properties (learn about the [options](https://github.com/icsharpcode/ILSpy/wiki/Search-Options))
* Hyperlink-based type/method/property navigation
* Base/Derived types navigation, history
@ -65,7 +65,7 @@ How to build @@ -65,7 +65,7 @@ How to build
- ILSpy.XPlat.slnf: for the cross-platform CLI or PowerShell cmdlets
- ILSpy.AddIn.slnf: for the Visual Studio plugin
**Note:** Visual Studio 16.3 and later include a version of the .NET (Core) SDK that is managed by the Visual Studio installer - once you update, it may get upgraded too.
**Note:** Visual Studio includes a version of the .NET SDK that is managed by the Visual Studio installer - once you update, it may get upgraded too.
Please note that ILSpy is only compatible with the .NET 6.0 SDK and Visual Studio will refuse to load some projects in the solution (and unit tests will fail).
If this problem occurs, please manually install the .NET 6.0 SDK from [here](https://dotnet.microsoft.com/download/dotnet/6.0).

Loading…
Cancel
Save