diff --git a/ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj b/ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj
index c60a25481a..8c8d40ddc3 100644
--- a/ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj
+++ b/ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj
@@ -2,7 +2,7 @@
Exe
- net6.0-windows
+ net7.0
enable
diff --git a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
index d06c6768e7..ed4a3f2bb2 100644
--- a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
@@ -317,7 +317,7 @@ public async Task Jmp()
public async Task StackTests()
{
// IL contains .corflags = 32BITREQUIRED
- await RunIL("StackTests.il", asmOptions: AssemblerOptions.Force32Bit);
+ await RunIL("StackTests.il", CompilerOptions.Force32Bit, AssemblerOptions.Force32Bit);
}
[Test]
@@ -483,6 +483,11 @@ async Task RunIL(string testFileName, CompilerOptions options = CompilerOptions.
string outputFile = null;
CompilerResults decompiledOutputFile = null;
+ bool optionsForce32Bit = options.HasFlag(CompilerOptions.Force32Bit);
+ bool asmOptionsForce32Bit = asmOptions.HasFlag(AssemblerOptions.Force32Bit);
+
+ Assert.AreEqual(optionsForce32Bit, asmOptionsForce32Bit, "Inconsistent architecture.");
+
try
{
options |= CompilerOptions.UseTestRunner;
diff --git a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
index 3d35779e1b..6219c2a1af 100644
--- a/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
+++ b/ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
@@ -105,9 +105,9 @@ static Tester()
TesterPath = Path.GetDirectoryName(typeof(Tester).Assembly.Location);
TestCasePath = Path.Combine(TesterPath, "../../../../TestCases");
#if DEBUG
- testRunnerBasePath = Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/bin/Debug/net6.0-windows");
+ testRunnerBasePath = Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/bin/Debug/net7.0");
#else
- testRunnerBasePath = Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/bin/Release/net6.0-windows");
+ testRunnerBasePath = Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/bin/Release/net7.0");
#endif
packagesPropsFile = Path.Combine(TesterPath, "../../../../../packages.props");
roslynLatestVersion = XDocument.Load(packagesPropsFile).XPathSelectElement("//RoslynVersion").Value;
@@ -270,8 +270,8 @@ private static string ReplacePrivImplDetails(string il)
}
static readonly string coreRefAsmPath = new DotNetCorePathFinder(TargetFrameworkIdentifier.NET,
- new Version(6, 0), "Microsoft.NETCore.App")
- .GetReferenceAssemblyPath(".NETCoreApp,Version=v6.0");
+ new Version(7, 0), "Microsoft.NETCore.App")
+ .GetReferenceAssemblyPath(".NETCoreApp,Version=v7.0");
public static readonly string RefAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2");
@@ -308,7 +308,7 @@ private static string ReplacePrivImplDetails(string il)
const string targetFrameworkAttributeSnippet = @"
-[assembly: System.Runtime.Versioning.TargetFramework("".NETCoreApp,Version=v6.0"", FrameworkDisplayName = """")]
+[assembly: System.Runtime.Versioning.TargetFramework("".NETCoreApp,Version=v7.0"", FrameworkDisplayName = """")]
";
@@ -343,6 +343,7 @@ public static List GetPreprocessorSymbols(CompilerOptions flags)
{
preprocessorSymbols.Add("NETCORE");
preprocessorSymbols.Add("NET60");
+ preprocessorSymbols.Add("NET70");
}
preprocessorSymbols.Add("ROSLYN");
preprocessorSymbols.Add("CS60");
diff --git a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
index d1dfd07747..c4027fc39c 100644
--- a/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
@@ -321,12 +321,11 @@ public async Task Generics([ValueSource(nameof(defaultOptions))] CompilerOptions
[Test]
public async Task Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
{
- await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings {
- // legacy csc generates a dead store in debug builds
- RemoveDeadStores = (cscOptions == CompilerOptions.None),
- UseExpressionBodyForCalculatedGetterOnlyProperties = false,
- FileScopedNamespaces = false,
- });
+ DecompilerSettings settings = Tester.GetSettings(cscOptions);
+ // legacy csc generates a dead store in debug builds
+ settings.RemoveDeadStores = (cscOptions == CompilerOptions.None);
+ settings.UseExpressionBodyForCalculatedGetterOnlyProperties = false;
+ await RunForLibrary(cscOptions: cscOptions, decompilerSettings: settings);
}
[Test]
@@ -486,7 +485,7 @@ public async Task NullableRefTypes([ValueSource(nameof(roslyn3OrNewerOptions))]
}
[Test]
- public async Task NativeInts([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions)
+ public async Task NativeInts([ValueSource(nameof(roslyn3OrNewerWithNet40Options))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
index 6d829ce95b..e206872a5f 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
@@ -36,6 +36,9 @@ static void Main()
Issue1747();
CallAmbiguousOutParam();
CallWithInParam();
+#if CS90
+ NativeIntTests(new IntPtr(1), 2);
+#endif
Issue2444.M2();
Issue2741.B.Test(new Issue2741.C());
}
@@ -337,6 +340,34 @@ static void InVsRegularParam(int i)
#endif
#endregion
+#if CS90
+ static void NativeIntTests(IntPtr i1, nint i2)
+ {
+ Console.WriteLine("NativeIntTests(i1):");
+ ObjectOrLong((object)i1);
+ ObjectOrLong((long)i1);
+ Console.WriteLine("NativeIntTests(i2):");
+ ObjectOrLong((object)i2);
+ ObjectOrLong((long)i2);
+ Console.WriteLine("NativeIntTests(new IntPtr):");
+ ObjectOrLong((object)new IntPtr(3));
+ ObjectOrLong((long)new IntPtr(3));
+ Console.WriteLine("NativeIntTests(IntPtr.Zero):");
+ ObjectOrLong((object)IntPtr.Zero);
+ ObjectOrLong((long)IntPtr.Zero);
+ }
+
+ static void ObjectOrLong(object o)
+ {
+ Console.WriteLine("object " + o);
+ }
+
+ static void ObjectOrLong(long l)
+ {
+ Console.WriteLine("long " + l);
+ }
+#endif
+
#region #2444
public struct Issue2444
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs
index 8032484ce7..5df746cc0c 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs
@@ -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 @@ internal class ConstantsTests
{
return null;
}
+#endif
public ulong Issue1308(ulong u = 8uL)
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
index c56524281a..01edd50d21 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
@@ -436,10 +436,17 @@ private static bool ConstantTarget(dynamic a)
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)
{
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs
index faa752bcfe..9423c42542 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs
@@ -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 @@ public static void Overloaded(int a)
return &Overloaded;
}
+#if !(CS110 && NET70)
public unsafe IntPtr GetAddressAsIntPtr()
{
return (IntPtr)(delegate*)(&Overloaded);
}
+#endif
+
+ public unsafe nint GetAddressAsNInt()
+ {
+ return (nint)(delegate*)(&Overloaded);
+ }
public unsafe void* GetAddressAsVoidPtr()
{
@@ -93,6 +102,7 @@ public class B
internal class FunctionPointersWithNativeIntegerTypes
{
public unsafe delegate* F1;
+ #if !(CS110 && NET70)
public unsafe delegate* F2;
public unsafe delegate* F3;
public unsafe delegate* F4;
@@ -100,6 +110,8 @@ internal class FunctionPointersWithNativeIntegerTypes
public unsafe delegate*> F6;
public unsafe delegate*, IntPtr> F7;
public unsafe delegate*> F8;
+ public unsafe delegate*> F9;
+ #endif
}
internal class FunctionPointersWithRefParams
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
index c4d784fd46..677f6ebafe 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
@@ -844,10 +844,10 @@ int ZZZ_1()
#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
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs
index 69d3a3e0ce..4267944bbc 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs
@@ -26,23 +26,36 @@ internal class NativeInts
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 dict1;
private Dictionary dict2;
private Dictionary dict3;
private Dictionary dict4;
+#endif
+ private Dictionary 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 @@ public void Convert()
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 @@ public void Convert2()
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 @@ public void CompoundAssign()
{
GetInstance(3).u *= 2u;
}
+#if !(CS110 && NET70)
GetInstance(4).intptr += (nint)i32;
checked
{
@@ -164,10 +183,13 @@ public void CompoundAssign()
}
// 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 @@ public void LocalTypeFromStore()
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 @@ public void LocalTypeFromUse()
intptr = intPtr;
i = num + 1;
+#endif
}
public nint NegateUnsigned(nuint x)
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs
index b8483ecc10..877c8e3938 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs
@@ -89,9 +89,14 @@ public void CustomMarshal2([MarshalAs(UnmanagedType.CustomMarshaler, MarshalType
{
}
+#if CS110 && NET70
[DllImport("ws2_32.dll", SetLastError = true)]
- internal static extern IntPtr ioctlsocket([In] IntPtr socketHandle, [In] int cmd, [In][Out] ref int argp);
+ internal static extern nint ioctlsocket([In] nint socketHandle, [In] int cmd, [In][Out] ref int argp);
+#else
+ [DllImport("ws2_32.dll", SetLastError = true)]
+ internal static extern IntPtr ioctlsocket([In] IntPtr socketHandle, [In] int cmd, [In][Out] ref int argp);
+#endif
public void CallMethodWithInOutParameter()
{
int argp = 0;
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
index 2bb122eb3e..9901fd69e1 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
@@ -30,7 +30,11 @@ private struct StructWithStaticField
{
public static object StaticObj;
+#if CS110 && NET70
+ public nint A;
+#else
public IntPtr A;
+#endif
}
private struct UnmanagedStruct
@@ -605,6 +609,18 @@ private unsafe static int Issue2305(StructWithFixedSizeMembers value, StringComp
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 @@ private unsafe static int Issue2305(StructWithFixedSizeMembers value, StringComp
{
return (void*)intptr;
}
+#endif
private unsafe static void* CastToVoidPtr(int* intptr)
{
diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index d89d776485..86ae6bf22e 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -1406,6 +1406,7 @@ EntityDeclaration DoDecompile(ITypeDefinition typeDef, DecompileRun decompileRun
attr.Remove();
}
}
+ RemoveCompilerFeatureRequiredAttribute(typeDecl, "RefStructs");
}
if (settings.RequiredMembers)
{
@@ -1851,6 +1852,30 @@ internal static bool RemoveAttribute(EntityDeclaration entityDecl, KnownAttribut
return found;
}
+ internal static bool RemoveCompilerFeatureRequiredAttribute(EntityDeclaration entityDecl, string feature)
+ {
+ bool found = false;
+ foreach (var section in entityDecl.Attributes)
+ {
+ foreach (var attr in section.Attributes)
+ {
+ var symbol = attr.Type.GetSymbol();
+ if (symbol is ITypeDefinition td && td.FullTypeName == KnownAttribute.CompilerFeatureRequired.GetTypeName()
+ && attr.Arguments.Count == 1 && attr.Arguments.SingleOrDefault() is PrimitiveExpression pe
+ && pe.Value is string s && s == feature)
+ {
+ attr.Remove();
+ found = true;
+ }
+ }
+ if (section.Attributes.Count == 0)
+ {
+ section.Remove();
+ }
+ }
+ return found;
+ }
+
bool FindAttribute(EntityDeclaration entityDecl, KnownAttribute attributeType, out Syntax.Attribute attribute)
{
attribute = null;
diff --git a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
index 3d53263cdb..d256cf6259 100644
--- a/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/CallBuilder.cs
@@ -1553,12 +1553,25 @@ ExpressionWithResolveResult HandleConstructorCall(ExpectedTargetDetails expected
CastArguments(argumentList.Arguments, argumentList.ExpectedParameters);
break; // make sure that we don't not end up in an infinite loop
}
+ IType returnTypeOverride = null;
+ if (typeSystem.MainModule.TypeSystemOptions.HasFlag(TypeSystemOptions.NativeIntegersWithoutAttribute))
+ {
+ // For DeclaringType, we don't use nint/nuint (so that DeclaringType.GetConstructors etc. works),
+ // but in NativeIntegersWithoutAttribute mode we must use nint/nuint for expression types,
+ // so that the appropriate set of conversions is used for further overload resolution.
+ if (method.DeclaringType.IsKnownType(KnownTypeCode.IntPtr))
+ returnTypeOverride = SpecialType.NInt;
+ else if (method.DeclaringType.IsKnownType(KnownTypeCode.UIntPtr))
+ returnTypeOverride = SpecialType.NUInt;
+ }
return new ObjectCreateExpression(
expressionBuilder.ConvertType(method.DeclaringType),
argumentList.GetArgumentExpressions()
).WithRR(new CSharpInvocationResolveResult(
target, method, argumentList.GetArgumentResolveResults().ToArray(),
- isExpandedForm: argumentList.IsExpandedForm, argumentToParameterMap: argumentList.ArgumentToParameterMap
+ isExpandedForm: argumentList.IsExpandedForm,
+ argumentToParameterMap: argumentList.ArgumentToParameterMap,
+ returnTypeOverride: returnTypeOverride
));
}
}
diff --git a/ICSharpCode.Decompiler/DecompilerSettings.cs b/ICSharpCode.Decompiler/DecompilerSettings.cs
index 4ce0c44c04..fe47894221 100644
--- a/ICSharpCode.Decompiler/DecompilerSettings.cs
+++ b/ICSharpCode.Decompiler/DecompilerSettings.cs
@@ -152,12 +152,13 @@ public void SetLanguageVersion(CSharp.LanguageVersion languageVersion)
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 @@ public bool NativeIntegers {
}
}
+ bool numericIntPtr = true;
+
+ ///
+ /// Treat IntPtr/UIntPtr as nint/nuint.
+ ///
+ [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;
///
diff --git a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
index c2a84f46cd..ee3b705ea5 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
@@ -388,7 +388,22 @@ bool MatchNullCheckOrTypeCheck(ILInstruction condition, ref ILVariable objVar, K
isInlinedIsInst = false;
if (condition.MatchCompNotEquals(out var left, out var right))
{
- if (left.MatchIsInst(out var arg, out var type) && type.IsKnownType(disposeType))
+ if (left.MatchStLoc(out var inlineAssignVar, out var inlineAssignVal))
+ {
+ if (!inlineAssignVal.MatchIsInst(out var arg, out var type) && type.IsKnownType(disposeType))
+ return false;
+ if (!inlineAssignVar.IsSingleDefinition || inlineAssignVar.LoadCount != 1)
+ return false;
+ if (!inlineAssignVar.Type.IsKnownType(disposeType))
+ return false;
+ isInlinedIsInst = true;
+ left = arg;
+ if (!left.MatchLdLoc(objVar) || !right.MatchLdNull())
+ return false;
+ objVar = inlineAssignVar;
+ return true;
+ }
+ else if (left.MatchIsInst(out var arg, out var type) && type.IsKnownType(disposeType))
{
isInlinedIsInst = true;
left = arg;
diff --git a/ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs b/ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
index 5235da4701..a6ba7ef15d 100644
--- a/ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
@@ -44,7 +44,7 @@ public static IType ApplyAttributesToType(
{
bool hasDynamicAttribute = false;
bool[] dynamicAttributeData = null;
- bool hasNativeIntegersAttribute = false;
+ bool hasNativeIntegersAttribute = (options & TypeSystemOptions.NativeIntegersWithoutAttribute) != 0;
bool[] nativeIntegersAttributeData = null;
string[] tupleElementNames = null;
Nullability nullability;
diff --git a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
index b20d1bb0ee..5898fa32ec 100644
--- a/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
@@ -125,11 +125,17 @@ public enum TypeSystemOptions
///
LifetimeAnnotations = 0x4000,
///
+ /// 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.
+ ///
+ NativeIntegersWithoutAttribute = 0x8000,
+ ///
/// Default settings: typical options for the decompiler, with all C# languages features enabled.
///
Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters
| RefStructs | UnmanagedConstraints | NullabilityAnnotations | ReadOnlyMethods
- | NativeIntegers | FunctionPointers | LifetimeAnnotations
+ | NativeIntegers | FunctionPointers | LifetimeAnnotations | NativeIntegersWithoutAttribute
}
///
@@ -167,6 +173,8 @@ public static TypeSystemOptions GetOptions(DecompilerSettings settings)
typeSystemOptions |= TypeSystemOptions.FunctionPointers;
if (settings.LifetimeAnnotations)
typeSystemOptions |= TypeSystemOptions.LifetimeAnnotations;
+ if (settings.NumericIntPtr)
+ typeSystemOptions |= TypeSystemOptions.NativeIntegersWithoutAttribute;
return typeSystemOptions;
}
@@ -304,6 +312,10 @@ private async Task InitializeAsync(PEFile mainModule, IAssemblyResolver assembly
}
}
+ 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.
diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
index d6d99977ab..31fba0891b 100644
--- a/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
@@ -33,6 +33,7 @@ public enum KnownAttribute
None,
CompilerGenerated,
+ CompilerFeatureRequired,
///
/// Marks a method as extension method; or a class as containing extension methods.
///
@@ -119,6 +120,7 @@ public static class KnownAttributes
static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{
default,
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(CompilerGeneratedAttribute)),
+ new TopLevelTypeName("System.Runtime.CompilerServices", "CompilerFeatureRequiredAttribute"),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(ExtensionAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(DynamicAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(TupleElementNamesAttribute)),
diff --git a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
index cf6ae1be57..3481ac1c82 100644
--- a/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
@@ -402,8 +402,9 @@ public IType ResolveType(EntityHandle typeRefDefSpec, GenericContext context, Ty
IType ResolveDeclaringType(EntityHandle declaringTypeReference, GenericContext context)
{
// resolve without substituting dynamic/tuple types
- var ty = ResolveType(declaringTypeReference, context,
- options & ~(TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations));
+ const TypeSystemOptions removedOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple
+ | TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers | TypeSystemOptions.NativeIntegersWithoutAttribute;
+ var ty = ResolveType(declaringTypeReference, context, options & ~removedOptions);
// but substitute tuple types in type arguments:
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true);
return ty;
diff --git a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs
index 9da26dbe70..3ce5d01805 100644
--- a/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs
@@ -239,7 +239,7 @@ public static bool IsUnmanagedType(this IType type, bool allowGenerics)
bool IsUnmanagedTypeInternal(IType type)
{
- if (type.Kind is TypeKind.Enum or TypeKind.Pointer or TypeKind.FunctionPointer)
+ if (type.Kind is TypeKind.Enum or TypeKind.Pointer or TypeKind.FunctionPointer or TypeKind.NInt or TypeKind.NUInt)
{
return true;
}
diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs
index 94c50345bc..60123a44fb 100644
--- a/ILSpy/Properties/Resources.Designer.cs
+++ b/ILSpy/Properties/Resources.Designer.cs
@@ -1108,6 +1108,15 @@ public static string DecompilerSettings_NullPropagation {
}
}
+ ///
+ /// Looks up a localized string similar to Treat (U)IntPtr as n(u)int.
+ ///
+ public static string DecompilerSettings_NumericIntPtr {
+ get {
+ return ResourceManager.GetString("DecompilerSettings.NumericIntPtr", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Object/collection initializer expressions.
///
diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx
index 82d434c12e..186665d73b 100644
--- a/ILSpy/Properties/Resources.resx
+++ b/ILSpy/Properties/Resources.resx
@@ -393,6 +393,9 @@ Are you sure you want to continue?
Nullable reference types
+
+ Treat (U)IntPtr as n(u)int
+
Object/collection initializer expressions
diff --git a/README.md b/README.md
index 19d4a4dc81..92b843aaf3 100644
--- a/README.md
+++ b/README.md
@@ -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
@@ -52,7 +52,7 @@ How to build
- Follow Microsoft's instructions for [importing a configuration](https://docs.microsoft.com/en-us/visualstudio/install/import-export-installation-configurations?view=vs-2022#import-a-configuration), and import the .vsconfig file located at the root of the solution.
- Alternatively, you can open the ILSpy solution (ILSpy.sln) and Visual Studio will [prompt you to install the missing components](https://docs.microsoft.com/en-us/visualstudio/install/import-export-installation-configurations?view=vs-2022#automatically-install-missing-components).
- Finally, you can manually install the necessary components via the Visual Studio Installer. The workloads/components are as follows:
- - Workload ".NET Desktop Development". This workload includes the .NET Framework 4.8 SDK and the .NET Framework 4.7.2 targeting pack, as well as the [.NET 6.0 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) (ILSpy.csproj targets .NET 6.0, but we have net472 projects too). _Note: The optional components of this workload are not required for ILSpy_
+ - Workload ".NET Desktop Development". This workload includes the .NET Framework 4.8 SDK and the .NET Framework 4.7.2 targeting pack, as well as the [.NET 6.0 SDK](https://dotnet.microsoft.com/download/dotnet/6.0) and [.NET 7.0 SDK](https://dotnet.microsoft.com/download/dotnet/7.0) (ILSpy.csproj targets .NET 6.0, but we have net472+net70 projects too). _Note: The optional components of this workload are not required for ILSpy_
- Workload "Visual Studio extension development" (ILSpy.sln contains a VS extension project) _Note: The optional components of this workload are not required for ILSpy_
- Individual Component "MSVC v143 - VS 2022 C++ x64/x86 build tools" (or similar)
- _The VC++ toolset is optional_; if present it is used for `editbin.exe` to modify the stack size used by ILSpy.exe from 1MB to 16MB, because the decompiler makes heavy use of recursion, where small stack sizes lead to problems in very complex methods.
@@ -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).
diff --git a/global.json b/global.json
index 68d9ecef8c..1fcfe4feea 100644
--- a/global.json
+++ b/global.json
@@ -1,6 +1,6 @@
{
"sdk": {
- "version": "6.0.200",
+ "version": "7.0.100",
"rollForward": "major",
"allowPrerelease": true
}