Browse Source

Merge pull request #2873 from icsharpcode/net-7.0

pull/2993/head
Siegfried Pammer 2 years ago committed by GitHub
parent
commit
83f4fdcc47
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
  1. 2
      ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj
  2. 7
      ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
  3. 11
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  4. 13
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  5. 31
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs
  6. 18
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ConstantsTests.cs
  7. 7
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DynamicTests.cs
  8. 14
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/FunctionPointers.cs
  9. 4
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  10. 36
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/NativeInts.cs
  11. 7
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/PInvoke.cs
  12. 17
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/UnsafeCode.cs
  13. 25
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  14. 15
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  15. 21
      ICSharpCode.Decompiler/DecompilerSettings.cs
  16. 17
      ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs
  17. 2
      ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs
  18. 14
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  19. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  20. 5
      ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs
  21. 2
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs
  22. 9
      ILSpy/Properties/Resources.Designer.cs
  23. 3
      ILSpy/Properties/Resources.resx
  24. 6
      README.md
  25. 2
      global.json

2
ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework> <TargetFramework>net7.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

7
ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs

@ -317,7 +317,7 @@ namespace ICSharpCode.Decompiler.Tests
public async Task StackTests() public async Task StackTests()
{ {
// IL contains .corflags = 32BITREQUIRED // IL contains .corflags = 32BITREQUIRED
await RunIL("StackTests.il", asmOptions: AssemblerOptions.Force32Bit); await RunIL("StackTests.il", CompilerOptions.Force32Bit, AssemblerOptions.Force32Bit);
} }
[Test] [Test]
@ -483,6 +483,11 @@ namespace ICSharpCode.Decompiler.Tests
string outputFile = null; string outputFile = null;
CompilerResults decompiledOutputFile = null; CompilerResults decompiledOutputFile = null;
bool optionsForce32Bit = options.HasFlag(CompilerOptions.Force32Bit);
bool asmOptionsForce32Bit = asmOptions.HasFlag(AssemblerOptions.Force32Bit);
Assert.AreEqual(optionsForce32Bit, asmOptionsForce32Bit, "Inconsistent architecture.");
try try
{ {
options |= CompilerOptions.UseTestRunner; options |= CompilerOptions.UseTestRunner;

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

@ -105,9 +105,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
TesterPath = Path.GetDirectoryName(typeof(Tester).Assembly.Location); TesterPath = Path.GetDirectoryName(typeof(Tester).Assembly.Location);
TestCasePath = Path.Combine(TesterPath, "../../../../TestCases"); TestCasePath = Path.Combine(TesterPath, "../../../../TestCases");
#if DEBUG #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 #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 #endif
packagesPropsFile = Path.Combine(TesterPath, "../../../../../packages.props"); packagesPropsFile = Path.Combine(TesterPath, "../../../../../packages.props");
roslynLatestVersion = XDocument.Load(packagesPropsFile).XPathSelectElement("//RoslynVersion").Value; roslynLatestVersion = XDocument.Load(packagesPropsFile).XPathSelectElement("//RoslynVersion").Value;
@ -270,8 +270,8 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
} }
static readonly string coreRefAsmPath = new DotNetCorePathFinder(TargetFrameworkIdentifier.NET, static readonly string coreRefAsmPath = new DotNetCorePathFinder(TargetFrameworkIdentifier.NET,
new Version(6, 0), "Microsoft.NETCore.App") new Version(7, 0), "Microsoft.NETCore.App")
.GetReferenceAssemblyPath(".NETCoreApp,Version=v6.0"); .GetReferenceAssemblyPath(".NETCoreApp,Version=v7.0");
public static readonly string RefAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86), public static readonly string RefAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2"); @"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2");
@ -308,7 +308,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
const string targetFrameworkAttributeSnippet = @" 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 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
{ {
preprocessorSymbols.Add("NETCORE"); preprocessorSymbols.Add("NETCORE");
preprocessorSymbols.Add("NET60"); preprocessorSymbols.Add("NET60");
preprocessorSymbols.Add("NET70");
} }
preprocessorSymbols.Add("ROSLYN"); preprocessorSymbols.Add("ROSLYN");
preprocessorSymbols.Add("CS60"); preprocessorSymbols.Add("CS60");

13
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -321,12 +321,11 @@ namespace ICSharpCode.Decompiler.Tests
[Test] [Test]
public async Task Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions) public async Task Loops([ValueSource(nameof(defaultOptionsWithMcs))] CompilerOptions cscOptions)
{ {
await RunForLibrary(cscOptions: cscOptions, decompilerSettings: new DecompilerSettings { DecompilerSettings settings = Tester.GetSettings(cscOptions);
// legacy csc generates a dead store in debug builds // legacy csc generates a dead store in debug builds
RemoveDeadStores = (cscOptions == CompilerOptions.None), settings.RemoveDeadStores = (cscOptions == CompilerOptions.None);
UseExpressionBodyForCalculatedGetterOnlyProperties = false, settings.UseExpressionBodyForCalculatedGetterOnlyProperties = false;
FileScopedNamespaces = false, await RunForLibrary(cscOptions: cscOptions, decompilerSettings: settings);
});
} }
[Test] [Test]
@ -486,7 +485,7 @@ namespace ICSharpCode.Decompiler.Tests
} }
[Test] [Test]
public async Task NativeInts([ValueSource(nameof(roslyn3OrNewerOptions))] CompilerOptions cscOptions) public async Task NativeInts([ValueSource(nameof(roslyn3OrNewerWithNet40Options))] CompilerOptions cscOptions)
{ {
await RunForLibrary(cscOptions: cscOptions); await RunForLibrary(cscOptions: cscOptions);
} }

31
ICSharpCode.Decompiler.Tests/TestCases/Correctness/OverloadResolution.cs

@ -36,6 +36,9 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Issue1747(); Issue1747();
CallAmbiguousOutParam(); CallAmbiguousOutParam();
CallWithInParam(); CallWithInParam();
#if CS90
NativeIntTests(new IntPtr(1), 2);
#endif
Issue2444.M2(); Issue2444.M2();
Issue2741.B.Test(new Issue2741.C()); Issue2741.B.Test(new Issue2741.C());
} }
@ -337,6 +340,34 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
#endif #endif
#endregion #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 #region #2444
public struct Issue2444 public struct Issue2444
{ {

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

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

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

@ -436,10 +436,17 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
return true.Equals(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) private static IntPtr NewIntPtr(dynamic a)
{ {
return new IntPtr(a); return new IntPtr(a);
} }
#endif
private static dynamic GetDynamic(int i) private static dynamic GetDynamic(int i)
{ {

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

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

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

@ -844,10 +844,10 @@ namespace LocalFunctions
#if CS90 #if CS90
public void Issue2196() public void Issue2196()
{ {
EnumWindows(IntPtr.Zero, IntPtr.Zero); EnumWindows(0L, 0L);
[DllImport("user32.dll", CallingConvention = CallingConvention.StdCall, EntryPoint = "EnumWindows")] [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 #endif
} }

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

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

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

@ -89,9 +89,14 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
} }
#if CS110 && NET70
[DllImport("ws2_32.dll", SetLastError = true)] [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() public void CallMethodWithInOutParameter()
{ {
int argp = 0; int argp = 0;

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

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

25
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -1406,6 +1406,7 @@ namespace ICSharpCode.Decompiler.CSharp
attr.Remove(); attr.Remove();
} }
} }
RemoveCompilerFeatureRequiredAttribute(typeDecl, "RefStructs");
} }
if (settings.RequiredMembers) if (settings.RequiredMembers)
{ {
@ -1851,6 +1852,30 @@ namespace ICSharpCode.Decompiler.CSharp
return found; 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) bool FindAttribute(EntityDeclaration entityDecl, KnownAttribute attributeType, out Syntax.Attribute attribute)
{ {
attribute = null; attribute = null;

15
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1553,12 +1553,25 @@ namespace ICSharpCode.Decompiler.CSharp
CastArguments(argumentList.Arguments, argumentList.ExpectedParameters); CastArguments(argumentList.Arguments, argumentList.ExpectedParameters);
break; // make sure that we don't not end up in an infinite loop 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( return new ObjectCreateExpression(
expressionBuilder.ConvertType(method.DeclaringType), expressionBuilder.ConvertType(method.DeclaringType),
argumentList.GetArgumentExpressions() argumentList.GetArgumentExpressions()
).WithRR(new CSharpInvocationResolveResult( ).WithRR(new CSharpInvocationResolveResult(
target, method, argumentList.GetArgumentResolveResults().ToArray(), target, method, argumentList.GetArgumentResolveResults().ToArray(),
isExpandedForm: argumentList.IsExpandedForm, argumentToParameterMap: argumentList.ArgumentToParameterMap isExpandedForm: argumentList.IsExpandedForm,
argumentToParameterMap: argumentList.ArgumentToParameterMap,
returnTypeOverride: returnTypeOverride
)); ));
} }
} }

21
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -152,12 +152,13 @@ namespace ICSharpCode.Decompiler
parameterNullCheck = false; parameterNullCheck = false;
lifetimeAnnotations = false; lifetimeAnnotations = false;
requiredMembers = false; requiredMembers = false;
numericIntPtr = false;
} }
} }
public CSharp.LanguageVersion GetMinimumRequiredVersion() public CSharp.LanguageVersion GetMinimumRequiredVersion()
{ {
if (parameterNullCheck || lifetimeAnnotations || requiredMembers) if (parameterNullCheck || lifetimeAnnotations || requiredMembers || numericIntPtr)
return CSharp.LanguageVersion.CSharp11_0; return CSharp.LanguageVersion.CSharp11_0;
if (fileScopedNamespaces || recordStructs) if (fileScopedNamespaces || recordStructs)
return CSharp.LanguageVersion.CSharp10_0; return CSharp.LanguageVersion.CSharp10_0;
@ -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; bool covariantReturns = true;
/// <summary> /// <summary>

17
ICSharpCode.Decompiler/IL/Transforms/UsingTransform.cs

@ -388,7 +388,22 @@ namespace ICSharpCode.Decompiler.IL.Transforms
isInlinedIsInst = false; isInlinedIsInst = false;
if (condition.MatchCompNotEquals(out var left, out var right)) 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; isInlinedIsInst = true;
left = arg; left = arg;

2
ICSharpCode.Decompiler/TypeSystem/ApplyAttributeTypeVisitor.cs

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

14
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -125,11 +125,17 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary> /// </summary>
LifetimeAnnotations = 0x4000, LifetimeAnnotations = 0x4000,
/// <summary> /// <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. /// Default settings: typical options for the decompiler, with all C# languages features enabled.
/// </summary> /// </summary>
Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters Default = Dynamic | Tuple | ExtensionMethods | DecimalConstants | ReadOnlyStructsAndParameters
| RefStructs | UnmanagedConstraints | NullabilityAnnotations | ReadOnlyMethods | RefStructs | UnmanagedConstraints | NullabilityAnnotations | ReadOnlyMethods
| NativeIntegers | FunctionPointers | LifetimeAnnotations | NativeIntegers | FunctionPointers | LifetimeAnnotations | NativeIntegersWithoutAttribute
} }
/// <summary> /// <summary>
@ -167,6 +173,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
typeSystemOptions |= TypeSystemOptions.FunctionPointers; typeSystemOptions |= TypeSystemOptions.FunctionPointers;
if (settings.LifetimeAnnotations) if (settings.LifetimeAnnotations)
typeSystemOptions |= TypeSystemOptions.LifetimeAnnotations; typeSystemOptions |= TypeSystemOptions.LifetimeAnnotations;
if (settings.NumericIntPtr)
typeSystemOptions |= TypeSystemOptions.NativeIntegersWithoutAttribute;
return typeSystemOptions; return typeSystemOptions;
} }
@ -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 mainModuleWithOptions = mainModule.WithOptions(typeSystemOptions);
var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(typeSystemOptions)); var referencedAssembliesWithOptions = referencedAssemblies.Select(file => file.WithOptions(typeSystemOptions));
// Primitive types are necessary to avoid assertions in ILReader. // Primitive types are necessary to avoid assertions in ILReader.

2
ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs

@ -33,6 +33,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
None, None,
CompilerGenerated, CompilerGenerated,
CompilerFeatureRequired,
/// <summary> /// <summary>
/// Marks a method as extension method; or a class as containing extension methods. /// Marks a method as extension method; or a class as containing extension methods.
/// </summary> /// </summary>
@ -119,6 +120,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{ static readonly TopLevelTypeName[] typeNames = new TopLevelTypeName[Count]{
default, default,
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(CompilerGeneratedAttribute)), 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(ExtensionAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(DynamicAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(DynamicAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(TupleElementNamesAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(TupleElementNamesAttribute)),

5
ICSharpCode.Decompiler/TypeSystem/MetadataModule.cs

@ -402,8 +402,9 @@ namespace ICSharpCode.Decompiler.TypeSystem
IType ResolveDeclaringType(EntityHandle declaringTypeReference, GenericContext context) IType ResolveDeclaringType(EntityHandle declaringTypeReference, GenericContext context)
{ {
// resolve without substituting dynamic/tuple types // resolve without substituting dynamic/tuple types
var ty = ResolveType(declaringTypeReference, context, const TypeSystemOptions removedOptions = TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple
options & ~(TypeSystemOptions.Dynamic | TypeSystemOptions.Tuple | TypeSystemOptions.NullabilityAnnotations)); | TypeSystemOptions.NullabilityAnnotations | TypeSystemOptions.NativeIntegers | TypeSystemOptions.NativeIntegersWithoutAttribute;
var ty = ResolveType(declaringTypeReference, context, options & ~removedOptions);
// but substitute tuple types in type arguments: // but substitute tuple types in type arguments:
ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true); ty = ApplyAttributeTypeVisitor.ApplyAttributesToType(ty, Compilation, null, metadata, options, Nullability.Oblivious, typeChildrenOnly: true);
return ty; return ty;

2
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -239,7 +239,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
bool IsUnmanagedTypeInternal(IType type) 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; return true;
} }

9
ILSpy/Properties/Resources.Designer.cs generated

@ -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> /// <summary>
/// Looks up a localized string similar to Object/collection initializer expressions. /// Looks up a localized string similar to Object/collection initializer expressions.
/// </summary> /// </summary>

3
ILSpy/Properties/Resources.resx

@ -393,6 +393,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve"> <data name="DecompilerSettings.NullableReferenceTypes" xml:space="preserve">
<value>Nullable reference types</value> <value>Nullable reference types</value>
</data> </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"> <data name="DecompilerSettings.ObjectCollectionInitializerExpressions" xml:space="preserve">
<value>Object/collection initializer expressions</value> <value>Object/collection initializer expressions</value>
</data> </data>

6
README.md

@ -24,7 +24,7 @@ Features
------- -------
* Decompilation to C# (check out the [language support status](https://github.com/icsharpcode/ILSpy/issues/829)) * 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)) * Search for types/methods/properties (learn about the [options](https://github.com/icsharpcode/ILSpy/wiki/Search-Options))
* Hyperlink-based type/method/property navigation * Hyperlink-based type/method/property navigation
* Base/Derived types navigation, history * 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. - 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). - 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: - 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_ - 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) - 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. - _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.XPlat.slnf: for the cross-platform CLI or PowerShell cmdlets
- ILSpy.AddIn.slnf: for the Visual Studio plugin - 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). 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). If this problem occurs, please manually install the .NET 6.0 SDK from [here](https://dotnet.microsoft.com/download/dotnet/6.0).

2
global.json

@ -1,6 +1,6 @@
{ {
"sdk": { "sdk": {
"version": "6.0.200", "version": "7.0.100",
"rollForward": "major", "rollForward": "major",
"allowPrerelease": true "allowPrerelease": true
} }

Loading…
Cancel
Save