Browse Source

Merge pull request #3500 from icsharpcode/net10upgrade-future

Upgrade dotnet target framework to net10
pull/3398/head
Siegfried Pammer 3 weeks ago committed by GitHub
parent
commit
29e5e7df21
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 6
      .github/workflows/build-frontends.yml
  2. 20
      .github/workflows/build-ilspy.yml
  3. 6
      .github/workflows/codeql-analysis.yml
  4. 1
      .gitmodules
  5. 4
      BuildTools/pre-commit
  6. 6
      ICSharpCode.BamlDecompiler/ICSharpCode.BamlDecompiler.csproj
  7. 2
      ICSharpCode.BamlDecompiler/packages.lock.json
  8. 2
      ICSharpCode.Decompiler.TestRunner/ICSharpCode.Decompiler.TestRunner.csproj
  9. 103
      ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs
  10. 24
      ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs
  11. 146
      ICSharpCode.Decompiler.Tests/Helpers/Tester.cs
  12. 6
      ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj
  13. 12
      ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs
  14. 4
      ICSharpCode.Decompiler.Tests/TestCases/Correctness/Conversions.cs
  15. 2
      ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1325.il
  16. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs
  17. 8
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/MetadataAttributes.cs
  18. 21
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/ParamsCollections.cs
  19. 4
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
  20. 2
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs
  21. 4
      ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs
  22. 2
      ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
  23. 3
      ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs
  24. 85
      ICSharpCode.Decompiler/CSharp/CallBuilder.cs
  25. 2
      ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs
  26. 129
      ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs
  27. 21
      ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs
  28. 1
      ICSharpCode.Decompiler/CSharp/Transforms/EscapeInvalidIdentifiers.cs
  29. 12
      ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs
  30. 24
      ICSharpCode.Decompiler/DecompilerSettings.cs
  31. 2
      ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
  32. 4
      ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs
  33. 2
      ICSharpCode.Decompiler/IL/ILTypeExtensions.cs
  34. 16
      ICSharpCode.Decompiler/IL/Instructions/Block.cs
  35. 5
      ICSharpCode.Decompiler/IL/Transforms/DetectCatchWhenConditionBlocks.cs
  36. 15
      ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs
  37. 18
      ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs
  38. 13
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs
  39. 2
      ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs
  40. 6
      ICSharpCode.Decompiler/Properties/DecompilerVersionInfo.template.cs
  41. 11
      ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs
  42. 3
      ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs
  43. 2
      ICSharpCode.Decompiler/TypeSystem/Implementation/KnownAttributes.cs
  44. 18
      ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs
  45. 17
      ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs
  46. 4
      ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj
  47. 11
      ICSharpCode.ILSpyCmd/packages.lock.json
  48. 4
      ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj
  49. 2
      ICSharpCode.ILSpyX/MermaidDiagrammer/html/.vscode/tasks.json
  50. 14
      ICSharpCode.ILSpyX/packages.lock.json
  51. 2
      ILSpy-tests
  52. 4
      ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj
  53. 2
      ILSpy.AddIn/ILSpy.AddIn.csproj
  54. 2
      ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj
  55. 2
      ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj
  56. 2
      ILSpy.Installer/setup.cs
  57. 2
      ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj
  58. 2
      ILSpy.Tests/ILSpy.Tests.csproj
  59. 1
      ILSpy.sln
  60. 2
      ILSpy/ILSpy.csproj
  61. 1
      ILSpy/Languages/CSharpLanguage.cs
  62. 9
      ILSpy/Properties/Resources.Designer.cs
  63. 3
      ILSpy/Properties/Resources.resx
  64. 3
      ILSpy/Properties/Resources.zh-Hans.resx
  65. 2
      TestPlugin/TestPlugin.csproj
  66. 2
      global.json
  67. 6
      publish.ps1
  68. 4
      publishlocaldev.ps1

6
.github/workflows/build-frontends.yml

@ -21,11 +21,11 @@ jobs:
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v4
with: with:
dotnet-version: '8.0.x' dotnet-version: '10.0.x'
dotnet-quality: 'ga' dotnet-quality: 'preview'
- name: Install dependencies - name: Install dependencies
run: dotnet restore ILSpy.XPlat.slnf run: dotnet restore ILSpy.XPlat.slnf -p:RestoreEnablePackagePruning=false
- name: Build Debug - name: Build Debug
run: dotnet msbuild ILSpy.XPlat.slnf -p:Configuration=Debug -bl:Debug.binlog run: dotnet msbuild ILSpy.XPlat.slnf -p:Configuration=Debug -bl:Debug.binlog

20
.github/workflows/build-ilspy.yml

@ -34,8 +34,8 @@ jobs:
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v4
with: with:
dotnet-version: '8.0.x' dotnet-version: '10.0.x'
dotnet-quality: 'ga' dotnet-quality: 'preview'
env: env:
DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet
DOTNET_ROOT: ${{ runner.temp }}/.dotnet DOTNET_ROOT: ${{ runner.temp }}/.dotnet
@ -44,7 +44,7 @@ jobs:
uses: microsoft/setup-msbuild@v2 uses: microsoft/setup-msbuild@v2
- name: Install dotnet-format - name: Install dotnet-format
run: dotnet tool install -g dotnet-format --version "8.3.546805" --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json run: dotnet tool install -g dotnet-format --version "9.0.520307" --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v3/index.json
- name: Install wix (locked version) - name: Install wix (locked version)
run: dotnet tool install --global wix --version 6.0.0 run: dotnet tool install --global wix --version 6.0.0
@ -57,7 +57,7 @@ jobs:
Get-ChildItem Env: | Where-Object {$_.Name -Match "^ILSPY_"} | %{ echo "$($_.Name)=$($_.Value)" } | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append Get-ChildItem Env: | Where-Object {$_.Name -Match "^ILSPY_"} | %{ echo "$($_.Name)=$($_.Value)" } | Out-File -FilePath $Env:GITHUB_OUTPUT -Encoding utf8 -Append
- name: Restore the application - name: Restore the application
run: msbuild ILSpy.sln /t:Restore /p:Configuration=${{ matrix.configuration }} /p:Platform=$env:BuildPlatform run: msbuild ILSpy.sln /t:Restore /p:RestoreEnablePackagePruning=false /p:Configuration=${{ matrix.configuration }} /p:Platform=$env:BuildPlatform
- name: Build - name: Build
run: msbuild ILSpy.sln /p:Configuration=${{ matrix.configuration }} /p:Platform=$env:BuildPlatform /m run: msbuild ILSpy.sln /p:Configuration=${{ matrix.configuration }} /p:Platform=$env:BuildPlatform /m
@ -65,9 +65,9 @@ jobs:
- name: Execute unit tests - name: Execute unit tests
run: dotnet test --logger "trx;LogFileName=${{ matrix.configuration }}.trx" --results-directory test-results $env:Tests1 $env:Tests2 $env:Tests3 run: dotnet test --logger "trx;LogFileName=${{ matrix.configuration }}.trx" --results-directory test-results $env:Tests1 $env:Tests2 $env:Tests3
env: env:
Tests1: ICSharpCode.Decompiler.Tests\bin\${{ matrix.configuration }}\net8.0-windows\win-x64\ICSharpCode.Decompiler.Tests.dll Tests1: ICSharpCode.Decompiler.Tests\bin\${{ matrix.configuration }}\net10.0-windows\win-x64\ICSharpCode.Decompiler.Tests.dll
Tests2: ILSpy.Tests\bin\${{ matrix.configuration }}\net8.0-windows\ILSpy.Tests.dll Tests2: ILSpy.Tests\bin\${{ matrix.configuration }}\net10.0-windows\ILSpy.Tests.dll
Tests3: ILSpy.BamlDecompiler.Tests\bin\${{ matrix.configuration }}\net8.0-windows\win-x64\ILSpy.BamlDecompiler.Tests.dll Tests3: ILSpy.BamlDecompiler.Tests\bin\${{ matrix.configuration }}\net10.0-windows\win-x64\ILSpy.BamlDecompiler.Tests.dll
- name: Upload Test Logs - name: Upload Test Logs
uses: actions/upload-artifact@v4 uses: actions/upload-artifact@v4
@ -94,7 +94,7 @@ jobs:
git diff --exit-code git diff --exit-code
- name: Zip ILSpy (framework-dependent) - name: Zip ILSpy (framework-dependent)
run: 7z a -tzip $env:StagingDirectory\ILSpy_binaries.zip .\ILSpy\bin\${{ matrix.configuration }}\net8.0-windows\*.dll .\ILSpy\bin\${{ matrix.configuration }}\net8.0-windows\*.exe .\ILSpy\bin\${{ matrix.configuration }}\net8.0-windows\*.config .\ILSpy\bin\${{ matrix.configuration }}\net8.0-windows\*.json .\ILSpy\bin\${{ matrix.configuration }}\net8.0-windows\*\ILSpy.resources.dll .\ILSpy\bin\${{ matrix.configuration }}\net8.0-windows\*\ILSpy.ReadyToRun.Plugin.resources.dll run: 7z a -tzip $env:StagingDirectory\ILSpy_binaries.zip .\ILSpy\bin\${{ matrix.configuration }}\net10.0-windows\*.dll .\ILSpy\bin\${{ matrix.configuration }}\net10.0-windows\*.exe .\ILSpy\bin\${{ matrix.configuration }}\net10.0-windows\*.config .\ILSpy\bin\${{ matrix.configuration }}\net10.0-windows\*.json .\ILSpy\bin\${{ matrix.configuration }}\net10.0-windows\*\ILSpy.resources.dll .\ILSpy\bin\${{ matrix.configuration }}\net10.0-windows\*\ILSpy.ReadyToRun.Plugin.resources.dll
- name: Publish x64/arm64 framework-dependent/self-contained - name: Publish x64/arm64 framework-dependent/self-contained
shell: pwsh shell: pwsh
@ -102,11 +102,11 @@ jobs:
- name: Zip ILSpy Release (x64 self-contained) - name: Zip ILSpy Release (x64 self-contained)
if: matrix.configuration == 'release' if: matrix.configuration == 'release'
run: 7z a -tzip $env:StagingDirectory\ILSpy_selfcontained_x64.zip .\ILSpy\bin\Release\net8.0-windows\win-x64\publish\selfcontained\* run: 7z a -tzip $env:StagingDirectory\ILSpy_selfcontained_x64.zip .\ILSpy\bin\Release\net10.0-windows\win-x64\publish\selfcontained\*
- name: Zip ILSpy Release (arm64 framework-dependent) - name: Zip ILSpy Release (arm64 framework-dependent)
if: matrix.configuration == 'release' if: matrix.configuration == 'release'
run: 7z a -tzip $env:StagingDirectory\ILSpy_binaries_arm64.zip .\ILSpy\bin\Release\net8.0-windows\win-arm64\publish\fwdependent\* run: 7z a -tzip $env:StagingDirectory\ILSpy_binaries_arm64.zip .\ILSpy\bin\Release\net10.0-windows\win-arm64\publish\fwdependent\*
- name: Pack NuGets - name: Pack NuGets
if: matrix.configuration == 'release' if: matrix.configuration == 'release'

6
.github/workflows/codeql-analysis.yml

@ -37,11 +37,11 @@ jobs:
- uses: actions/setup-dotnet@v4 - uses: actions/setup-dotnet@v4
with: with:
dotnet-version: '8.0.x' dotnet-version: '10.0.x'
dotnet-quality: 'ga' dotnet-quality: 'preview'
- name: Build - name: Build
run: dotnet build ILSpy.XPlat.slnf --configuration Release run: dotnet build ILSpy.XPlat.slnf --configuration Release -p:RestoreEnablePackagePruning=false
- name: Perform CodeQL Analysis - name: Perform CodeQL Analysis
uses: github/codeql-action/analyze@v3 uses: github/codeql-action/analyze@v3

1
.gitmodules vendored

@ -1,3 +1,4 @@
[submodule "ILSpy-tests"] [submodule "ILSpy-tests"]
path = ILSpy-tests path = ILSpy-tests
url = https://github.com/icsharpcode/ILSpy-tests url = https://github.com/icsharpcode/ILSpy-tests
branch = master

4
BuildTools/pre-commit

@ -5,11 +5,11 @@
set -eu set -eu
DOTNET_FORMAT_VERSION=8.3.546805 DOTNET_FORMAT_VERSION=9.0.520307
DOTNET_PATH="$LOCALAPPDATA/ICSharpCode/ILSpy/dotnet-format-$DOTNET_FORMAT_VERSION" DOTNET_PATH="$LOCALAPPDATA/ICSharpCode/ILSpy/dotnet-format-$DOTNET_FORMAT_VERSION"
if [ ! -d "$DOTNET_PATH" ]; then if [ ! -d "$DOTNET_PATH" ]; then
echo "Downloading dotnet-format $DOTNET_FORMAT_VERSION..." echo "Downloading dotnet-format $DOTNET_FORMAT_VERSION..."
dotnet tool install --tool-path "$DOTNET_PATH" dotnet-format --version "$DOTNET_FORMAT_VERSION" --add-source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json" dotnet tool install --tool-path "$DOTNET_PATH" dotnet-format --version "$DOTNET_FORMAT_VERSION" --add-source "https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet9/nuget/v3/index.json"
fi fi
"$DOTNET_PATH/dotnet-format.exe" --version "$DOTNET_PATH/dotnet-format.exe" --version

6
ICSharpCode.BamlDecompiler/ICSharpCode.BamlDecompiler.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<SignAssembly>True</SignAssembly> <SignAssembly>True</SignAssembly>
<AssemblyOriginatorKeyFile>..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.snk</AssemblyOriginatorKeyFile> <AssemblyOriginatorKeyFile>..\ICSharpCode.Decompiler\ICSharpCode.Decompiler.snk</AssemblyOriginatorKeyFile>
@ -14,7 +14,7 @@
<PropertyGroup> <PropertyGroup>
<PackageId>ICSharpCode.BamlDecompiler</PackageId> <PackageId>ICSharpCode.BamlDecompiler</PackageId>
<PackageVersion>8.0.0.0-noversion</PackageVersion> <PackageVersion>10.0.0.0-noversion</PackageVersion>
<Title>ILSpy BAML Decompiler</Title> <Title>ILSpy BAML Decompiler</Title>
<Authors>ILSpy Contributors</Authors> <Authors>ILSpy Contributors</Authors>
<PackageLicenseExpression>MIT</PackageLicenseExpression> <PackageLicenseExpression>MIT</PackageLicenseExpression>
@ -44,7 +44,7 @@
<!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ --> <!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ -->
<PropertyGroup> <PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(GITHUB_ACTIONS)' == 'true'">true</RestoreLockedMode> <RestoreLockedMode>true</RestoreLockedMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
ICSharpCode.BamlDecompiler/packages.lock.json

@ -1,7 +1,7 @@
{ {
"version": 2, "version": 2,
"dependencies": { "dependencies": {
"net8.0": { "net10.0": {
"Microsoft.Sbom.Targets": { "Microsoft.Sbom.Targets": {
"type": "Direct", "type": "Direct",
"requested": "[3.1.0, )", "requested": "[3.1.0, )",

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

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
</PropertyGroup> </PropertyGroup>

103
ICSharpCode.Decompiler.Tests/Helpers/RoslynToolset.cs

@ -18,12 +18,13 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks; using System.Threading.Tasks;
using ICSharpCode.Decompiler.Util; using ICSharpCode.Decompiler.Metadata;
using NuGet.Common; using NuGet.Common;
using NuGet.Packaging; using NuGet.Packaging;
@ -31,6 +32,8 @@ using NuGet.Protocol;
using NuGet.Protocol.Core.Types; using NuGet.Protocol.Core.Types;
using NuGet.Versioning; using NuGet.Versioning;
using NUnit.Framework;
namespace ICSharpCode.Decompiler.Tests.Helpers namespace ICSharpCode.Decompiler.Tests.Helpers
{ {
abstract class AbstractToolset abstract class AbstractToolset
@ -50,29 +53,45 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
protected async Task FetchPackage(string packageName, string version, string sourcePath, string outputPath) protected async Task FetchPackage(string packageName, string version, string sourcePath, string outputPath)
{ {
if (!Directory.Exists(Path.Combine(Roundtrip.RoundtripAssembly.TestDir, "nuget")))
Assert.Fail("No nuget cache found!");
ILogger logger = NullLogger.Instance; ILogger logger = NullLogger.Instance;
CancellationToken cancellationToken = CancellationToken.None; CancellationToken cancellationToken = CancellationToken.None;
using MemoryStream packageStream = new MemoryStream(); string pathToPackage = Path.Combine(Roundtrip.RoundtripAssembly.TestDir, "nuget", $"{packageName}-{version}.nupkg");
Stream packageStream;
await resource.CopyNupkgToStreamAsync( if (File.Exists(pathToPackage))
packageName, {
NuGetVersion.Parse(version), packageStream = File.OpenRead(pathToPackage);
packageStream, }
cache, else
logger, {
cancellationToken).ConfigureAwait(false); packageStream = new MemoryStream();
using PackageArchiveReader packageReader = new PackageArchiveReader(packageStream); await resource.CopyNupkgToStreamAsync(
NuspecReader nuspecReader = await packageReader.GetNuspecReaderAsync(cancellationToken).ConfigureAwait(false); packageName,
NuGetVersion.Parse(version),
var files = (await packageReader.GetFilesAsync(cancellationToken).ConfigureAwait(false)).ToArray(); packageStream,
files = files.Where(f => f.StartsWith(sourcePath, StringComparison.OrdinalIgnoreCase)).ToArray(); cache,
await packageReader.CopyFilesAsync(outputPath, files, logger,
(sourceFile, targetPath, fileStream) => { cancellationToken).ConfigureAwait(false);
fileStream.CopyToFile(targetPath);
return targetPath; packageStream.Position = 0;
}, }
logger, cancellationToken).ConfigureAwait(false); using (packageStream)
{
using PackageArchiveReader packageReader = new PackageArchiveReader(packageStream);
NuspecReader nuspecReader = await packageReader.GetNuspecReaderAsync(cancellationToken).ConfigureAwait(false);
var files = (await packageReader.GetFilesAsync(cancellationToken).ConfigureAwait(false)).ToArray();
files = files.Where(f => f.StartsWith(sourcePath, StringComparison.OrdinalIgnoreCase)).ToArray();
await packageReader.CopyFilesAsync(outputPath, files,
(sourceFile, targetPath, fileStream) => {
fileStream.CopyToFile(targetPath);
return targetPath;
},
logger, cancellationToken).ConfigureAwait(false);
}
} }
} }
@ -145,4 +164,44 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
public string GetVsWhere() => vswherePath; public string GetVsWhere() => vswherePath;
} }
class RefAssembliesToolset : AbstractToolset
{
readonly Dictionary<string, string> installedFrameworks = new Dictionary<string, string> {
{ "legacy", Path.Combine(Roundtrip.RoundtripAssembly.TestDir, "dotnet", "legacy") },
{ "2.2.0", Path.Combine(Roundtrip.RoundtripAssembly.TestDir, "dotnet", "netcore-2.2") },
};
public RefAssembliesToolset()
: base(Path.Combine(AppContext.BaseDirectory, "netfx"))
{
}
public async Task Fetch(string version, string packageName = "Microsoft.NETCore.App.Ref", string sourcePath = "ref/net5.0")
{
string path = Path.Combine(baseDir, version, sourcePath);
if (!Directory.Exists(path))
{
await FetchPackage(packageName, version, sourcePath, Path.Combine(baseDir, version)).ConfigureAwait(false);
}
installedFrameworks.Add(RoslynToolset.SanitizeVersion(version), path);
}
internal string GetPath(string targetFramework)
{
var (id, version) = UniversalAssemblyResolver.ParseTargetFramework(targetFramework);
string path;
if (id == TargetFrameworkIdentifier.NETFramework)
{
path = installedFrameworks["legacy"];
}
else
{
path = installedFrameworks[version.ToString(3)];
}
Debug.Assert(Path.Exists(path));
return path;
}
}
} }

24
ICSharpCode.Decompiler.Tests/Helpers/Tester.VB.cs

@ -16,12 +16,9 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.CodeDom.Compiler;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Text;
using System.Text.RegularExpressions; using System.Text.RegularExpressions;
using System.Threading.Tasks; using System.Threading.Tasks;
@ -49,27 +46,30 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
CompilerResults results = new CompilerResults(); CompilerResults results = new CompilerResults();
results.PathToAssembly = outputFileName; results.PathToAssembly = outputFileName;
var (roslynVersion, languageVersion) = (flags & CompilerOptions.UseRoslynMask) switch { bool targetNet40 = (flags & CompilerOptions.TargetNet40) != 0;
0 => ("legacy", "11"),
CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "14"), var (roslynVersion, languageVersion, targetFramework) = (flags & CompilerOptions.UseRoslynMask) switch {
CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest"), 0 => ("legacy", "11", null),
CompilerOptions.UseRoslyn3_11_0 => ("3.11.0", "latest"), CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "14", null),
_ => (roslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest", targetNet40 ? null : ".NETCoreApp,Version=v2.2"),
CompilerOptions.UseRoslyn3_11_0 => ("3.11.0", "latest", targetNet40 ? null : ".NETCoreApp,Version=v5.0"),
_ => (roslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest", targetNet40 ? null : ".NETCoreApp,Version=v10.0")
}; };
var vbcPath = roslynToolset.GetVBCompiler(roslynVersion); var vbcPath = roslynToolset.GetVBCompiler(roslynVersion);
IEnumerable<string> references; IEnumerable<string> references;
string libPath; string libPath;
if ((flags & CompilerOptions.UseRoslynMask) != 0 && (flags & CompilerOptions.TargetNet40) == 0) if ((flags & CompilerOptions.UseRoslynMask) != 0 && targetFramework != null)
{ {
var coreRefAsmPath = RefAssembliesToolset.GetPath(targetFramework);
references = coreDefaultReferences.Select(r => "-r:\"" + r + "\""); references = coreDefaultReferences.Select(r => "-r:\"" + r + "\"");
libPath = coreRefAsmPath; libPath = coreRefAsmPath;
} }
else else
{ {
references = defaultReferences.Select(r => "-r:\"" + r + "\""); references = defaultReferences.Select(r => "-r:\"" + r + "\"");
libPath = RefAsmPath; libPath = RefAssembliesToolset.GetPath("legacy");
} }
if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic))
{ {
@ -121,7 +121,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
var command = Cli.Wrap(vbcPath) var command = Cli.Wrap(vbcPath)
.WithArguments($"{otherOptions}-libpath:\"{libPath}\" {string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}") .WithArguments($"{otherOptions}-libpath:\"{libPath}\" {string.Join(" ", references)} -out:\"{Path.GetFullPath(results.PathToAssembly)}\" {string.Join(" ", sourceFileNames.Select(fn => '"' + Path.GetFullPath(fn) + '"'))}")
.WithValidation(CommandResultValidation.None); .WithValidation(CommandResultValidation.None);
Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}"); //Console.WriteLine($"\"{command.TargetFilePath}\" {command.Arguments}");
var result = await command.ExecuteBufferedAsync().ConfigureAwait(false); var result = await command.ExecuteBufferedAsync().ConfigureAwait(false);

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

@ -99,15 +99,16 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
static readonly string roslynLatestVersion; static readonly string roslynLatestVersion;
static readonly RoslynToolset roslynToolset; static readonly RoslynToolset roslynToolset;
static readonly VsWhereToolset vswhereToolset; static readonly VsWhereToolset vswhereToolset;
internal static readonly RefAssembliesToolset RefAssembliesToolset;
static Tester() static Tester()
{ {
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/net8.0"); testRunnerBasePath = Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/bin/Debug/net10.0");
#else #else
testRunnerBasePath = Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/bin/Release/net8.0"); testRunnerBasePath = Path.Combine(TesterPath, "../../../../../ICSharpCode.Decompiler.TestRunner/bin/Release/net10.0");
#endif #endif
// To parse: <Project><ItemGroup><PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0-3.final" /> // To parse: <Project><ItemGroup><PackageVersion Include="Microsoft.CodeAnalysis.CSharp" Version="4.8.0-3.final" />
packagesPropsFile = Path.Combine(TesterPath, "../../../../../Directory.Packages.props"); packagesPropsFile = Path.Combine(TesterPath, "../../../../../Directory.Packages.props");
@ -120,6 +121,7 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
roslynToolset = new RoslynToolset(); roslynToolset = new RoslynToolset();
vswhereToolset = new VsWhereToolset(); vswhereToolset = new VsWhereToolset();
RefAssembliesToolset = new RefAssembliesToolset();
} }
internal static async Task Initialize() internal static async Task Initialize()
@ -130,6 +132,9 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
await roslynToolset.Fetch(roslynLatestVersion).ConfigureAwait(false); await roslynToolset.Fetch(roslynLatestVersion).ConfigureAwait(false);
await vswhereToolset.Fetch().ConfigureAwait(false); await vswhereToolset.Fetch().ConfigureAwait(false);
await RefAssembliesToolset.Fetch("5.0.0", sourcePath: "ref/net5.0").ConfigureAwait(false);
await RefAssembliesToolset.Fetch("10.0.0-preview.4.25258.110", sourcePath: "ref/net10.0").ConfigureAwait(false);
#if DEBUG #if DEBUG
await BuildTestRunner("win-x86", "Debug").ConfigureAwait(false); await BuildTestRunner("win-x86", "Debug").ConfigureAwait(false);
@ -276,21 +281,15 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
return Regex.Replace(il, @"'<PrivateImplementationDetails>\{[0-9A-F-]+\}'", "'<PrivateImplementationDetails>'"); return Regex.Replace(il, @"'<PrivateImplementationDetails>\{[0-9A-F-]+\}'", "'<PrivateImplementationDetails>'");
} }
static readonly string coreRefAsmPath = new DotNetCorePathFinder(TargetFrameworkIdentifier.NET,
new Version(8, 0), "Microsoft.NETCore.App")
.GetReferenceAssemblyPath(".NETCoreApp,Version=v8.0");
public static readonly string RefAsmPath = Path.Combine(Environment.GetFolderPath(Environment.SpecialFolder.ProgramFilesX86),
@"Reference Assemblies\Microsoft\Framework\.NETFramework\v4.7.2");
static readonly string[] defaultReferences = new[] { static readonly string[] defaultReferences = new[] {
"System.dll", "System.dll",
"System.Core.dll", "System.Core.dll",
"System.Runtime.dll",
"System.Xml.dll", "System.Xml.dll",
"Microsoft.CSharp.dll" "Microsoft.CSharp.dll"
}; };
static readonly string[] coreDefaultReferences = new[] static readonly string[] core220DefaultReferences = new[]
{ {
"netstandard.dll", "netstandard.dll",
"mscorlib.dll", "mscorlib.dll",
@ -303,9 +302,12 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
"System.Linq.Queryable.dll", "System.Linq.Queryable.dll",
"System.IO.FileSystem.Watcher.dll", "System.IO.FileSystem.Watcher.dll",
"System.Memory.dll", "System.Memory.dll",
"System.Private.CoreLib.dll",
"System.Private.Xml.dll",
"System.Threading.dll", "System.Threading.dll",
"System.Threading.Thread.dll", "System.Threading.Thread.dll",
"System.Runtime.dll", "System.Runtime.dll",
"System.Runtime.Extensions.dll",
"System.Runtime.InteropServices.dll", "System.Runtime.InteropServices.dll",
"System.Xml.dll", "System.Xml.dll",
"System.Xml.ReaderWriter.dll", "System.Xml.ReaderWriter.dll",
@ -314,19 +316,45 @@ namespace ICSharpCode.Decompiler.Tests.Helpers
"Microsoft.VisualBasic.dll", "Microsoft.VisualBasic.dll",
}; };
const string targetFrameworkAttributeSnippet = @" static readonly string[] coreDefaultReferences = new[]
{
[assembly: System.Runtime.Versioning.TargetFramework("".NETCoreApp,Version=v8.0"", FrameworkDisplayName = """")] "netstandard.dll",
"mscorlib.dll",
"; "System.dll",
"System.Collections.dll",
"System.Console.dll",
"System.Core.dll",
"System.Linq.dll",
"System.Linq.Expressions.dll",
"System.Linq.Queryable.dll",
"System.IO.FileSystem.Watcher.dll",
"System.Memory.dll",
"System.Threading.dll",
"System.Threading.Thread.dll",
"System.Runtime.dll",
"System.Runtime.InteropServices.dll",
"System.Xml.dll",
"System.Xml.ReaderWriter.dll",
"System.ValueTuple.dll",
"Microsoft.CSharp.dll",
"Microsoft.VisualBasic.dll",
};
static readonly Lazy<string> targetFrameworkAttributeSnippetFile = new Lazy<string>(GetTargetFrameworkAttributeSnippetFile); static readonly Dictionary<string, Lazy<string>> targetFrameworkAttributeSnippetFiles = new() {
{ ".NETCoreApp,Version=v10.0", new Lazy<string>(() => GetTargetFrameworkAttributeSnippetFile(".NETCoreApp,Version=v10.0")) },
{ ".NETCoreApp,Version=v5.0", new Lazy<string>(() => GetTargetFrameworkAttributeSnippetFile(".NETCoreApp,Version=v5.0")) },
{ ".NETCoreApp,Version=v2.2", new Lazy<string>(() => GetTargetFrameworkAttributeSnippetFile(".NETCoreApp,Version=v2.2")) },
};
static string GetTargetFrameworkAttributeSnippetFile() static string GetTargetFrameworkAttributeSnippetFile(string targetFrameworkMoniker)
{ {
// Note: this leaks a temporary file, we're not attempting to delete it, because it is only one. // Note: this leaks a temporary file, we're not attempting to delete it, because it is only one.
var tempFile = Path.GetTempFileName(); var tempFile = Path.GetTempFileName();
File.WriteAllText(tempFile, targetFrameworkAttributeSnippet); File.WriteAllText(tempFile, $@"
[assembly: System.Runtime.Versioning.TargetFramework(""{targetFrameworkMoniker}"")]
");
return tempFile; return tempFile;
} }
@ -389,9 +417,6 @@ namespace System.Runtime.CompilerServices
if (!flags.HasFlag(CompilerOptions.TargetNet40)) if (!flags.HasFlag(CompilerOptions.TargetNet40))
{ {
preprocessorSymbols.Add("NETCORE"); preprocessorSymbols.Add("NETCORE");
preprocessorSymbols.Add("NET60");
preprocessorSymbols.Add("NET70");
preprocessorSymbols.Add("NET80");
} }
preprocessorSymbols.Add("ROSLYN"); preprocessorSymbols.Add("ROSLYN");
preprocessorSymbols.Add("CS60"); preprocessorSymbols.Add("CS60");
@ -411,6 +436,10 @@ namespace System.Runtime.CompilerServices
if (flags.HasFlag(CompilerOptions.UseRoslyn3_11_0) if (flags.HasFlag(CompilerOptions.UseRoslyn3_11_0)
|| flags.HasFlag(CompilerOptions.UseRoslynLatest)) || flags.HasFlag(CompilerOptions.UseRoslynLatest))
{ {
if (!flags.HasFlag(CompilerOptions.TargetNet40))
{
preprocessorSymbols.Add("NET50");
}
preprocessorSymbols.Add("ROSLYN3"); preprocessorSymbols.Add("ROSLYN3");
preprocessorSymbols.Add("CS80"); preprocessorSymbols.Add("CS80");
preprocessorSymbols.Add("CS90"); preprocessorSymbols.Add("CS90");
@ -418,10 +447,19 @@ namespace System.Runtime.CompilerServices
} }
if (flags.HasFlag(CompilerOptions.UseRoslynLatest)) if (flags.HasFlag(CompilerOptions.UseRoslynLatest))
{ {
if (!flags.HasFlag(CompilerOptions.TargetNet40))
{
preprocessorSymbols.Add("NET60");
preprocessorSymbols.Add("NET70");
preprocessorSymbols.Add("NET80");
preprocessorSymbols.Add("NET90");
preprocessorSymbols.Add("NET100");
}
preprocessorSymbols.Add("ROSLYN4"); preprocessorSymbols.Add("ROSLYN4");
preprocessorSymbols.Add("CS100"); preprocessorSymbols.Add("CS100");
preprocessorSymbols.Add("CS110"); preprocessorSymbols.Add("CS110");
preprocessorSymbols.Add("CS120"); preprocessorSymbols.Add("CS120");
preprocessorSymbols.Add("CS130");
} }
} }
else if ((flags & CompilerOptions.UseMcsMask) != 0) else if ((flags & CompilerOptions.UseMcsMask) != 0)
@ -453,10 +491,6 @@ namespace System.Runtime.CompilerServices
} }
bool targetNet40 = (flags & CompilerOptions.TargetNet40) != 0; bool targetNet40 = (flags & CompilerOptions.TargetNet40) != 0;
bool useRoslyn = (flags & CompilerOptions.UseRoslynMask) != 0; bool useRoslyn = (flags & CompilerOptions.UseRoslynMask) != 0;
if (useRoslyn && !targetNet40)
{
sourceFileNames.Add(targetFrameworkAttributeSnippetFile.Value);
}
if (targetNet40) if (targetNet40)
{ {
@ -470,36 +504,58 @@ namespace System.Runtime.CompilerServices
CompilerResults results = new CompilerResults(); CompilerResults results = new CompilerResults();
results.PathToAssembly = outputFileName; results.PathToAssembly = outputFileName;
var (roslynVersion, languageVersion) = (flags & CompilerOptions.UseRoslynMask) switch { var (roslynVersion, languageVersion, targetFramework) = (flags & CompilerOptions.UseRoslynMask) switch {
0 => ("legacy", "5"), 0 => ("legacy", "5", null),
CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "6"), CompilerOptions.UseRoslyn1_3_2 => ("1.3.2", "6", null),
CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest"), CompilerOptions.UseRoslyn2_10_0 => ("2.10.0", "latest", targetNet40 ? null : ".NETCoreApp,Version=v2.2"),
CompilerOptions.UseRoslyn3_11_0 => ("3.11.0", "latest"), CompilerOptions.UseRoslyn3_11_0 => ("3.11.0", "latest", targetNet40 ? null : ".NETCoreApp,Version=v5.0"),
_ => (roslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest") _ => (roslynLatestVersion, flags.HasFlag(CompilerOptions.Preview) ? "preview" : "latest", targetNet40 ? null : ".NETCoreApp,Version=v10.0")
}; };
var cscPath = roslynToolset.GetCSharpCompiler(roslynVersion); var cscPath = roslynToolset.GetCSharpCompiler(roslynVersion);
string libPath; string libPath, refAsmPath;
IEnumerable<string> references; IEnumerable<string> references;
if (useRoslyn && !targetNet40) if (useRoslyn && targetFramework != null)
{ {
libPath = "\"" + coreRefAsmPath + "\""; refAsmPath = RefAssembliesToolset.GetPath(targetFramework);
references = coreDefaultReferences.Select(r => "-r:\"" + Path.Combine(coreRefAsmPath, r) + "\""); if (targetFramework == ".NETCoreApp,Version=v2.2")
{
references = core220DefaultReferences;
if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic))
{
references = references.Append("Microsoft.VisualBasic.dll");
}
}
else
{
references = coreDefaultReferences;
if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic))
{
references = references.Append("Microsoft.VisualBasic.dll");
references = references.Append("Microsoft.VisualBasic.Core.dll");
}
}
libPath = "\"" + refAsmPath + "\"";
sourceFileNames.Add(targetFrameworkAttributeSnippetFiles[targetFramework].Value);
} }
else else
{ {
libPath = "\"" + RefAsmPath + "\",\"" + Path.Combine(RefAsmPath, "Facades") + "\""; refAsmPath = RefAssembliesToolset.GetPath("legacy");
references = defaultReferences.Select(r => "-r:\"" + Path.Combine(RefAsmPath, r) + "\""); libPath = "\"" + refAsmPath + "\"";
} references = defaultReferences;
if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic)) if (flags.HasFlag(CompilerOptions.ReferenceVisualBasic))
{ {
references = references.Concat(new[] { "-r:\"Microsoft.VisualBasic.dll\"" }); references = references.Append("Microsoft.VisualBasic.dll");
}
} }
if (useRoslyn && !targetNet40 && flags.HasFlag(CompilerOptions.ReferenceUnsafe)) if (useRoslyn && !targetNet40 && flags.HasFlag(CompilerOptions.ReferenceUnsafe))
{ {
references = references.Concat(new[] { "-r:\"System.Runtime.CompilerServices.Unsafe.dll\"" }); references = references.Append("System.Runtime.CompilerServices.Unsafe.dll");
} }
references = references.Select(r => "-r:\"" + Path.Combine(refAsmPath, r) + "\"");
string otherOptions = $"-nologo -noconfig " + string otherOptions = $"-nologo -noconfig " +
$"-langversion:{languageVersion} " + $"-langversion:{languageVersion} " +
$"-unsafe -o{(flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- ")}"; $"-unsafe -o{(flags.HasFlag(CompilerOptions.Optimize) ? "+ " : "- ")}";
@ -650,7 +706,7 @@ namespace System.Runtime.CompilerServices
CompilerOptions.UseRoslyn1_3_2 => CSharp.LanguageVersion.CSharp6, CompilerOptions.UseRoslyn1_3_2 => CSharp.LanguageVersion.CSharp6,
CompilerOptions.UseRoslyn2_10_0 => CSharp.LanguageVersion.CSharp7_3, CompilerOptions.UseRoslyn2_10_0 => CSharp.LanguageVersion.CSharp7_3,
CompilerOptions.UseRoslyn3_11_0 => CSharp.LanguageVersion.CSharp9_0, CompilerOptions.UseRoslyn3_11_0 => CSharp.LanguageVersion.CSharp9_0,
_ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp12_0, _ => cscOptions.HasFlag(CompilerOptions.Preview) ? CSharp.LanguageVersion.Latest : CSharp.LanguageVersion.CSharp13_0,
}; };
DecompilerSettings settings = new(langVersion) { DecompilerSettings settings = new(langVersion) {
// Never use file-scoped namespaces // Never use file-scoped namespaces
@ -685,7 +741,7 @@ namespace System.Runtime.CompilerServices
} }
var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(assemblyName), var compilation = CSharpCompilation.Create(Path.GetFileNameWithoutExtension(assemblyName),
syntaxTrees, coreDefaultReferences.Select(r => MetadataReference.CreateFromFile(Path.Combine(coreRefAsmPath, r))), syntaxTrees, coreDefaultReferences.Select(r => MetadataReference.CreateFromFile(Path.Combine(RefAssembliesToolset.GetPath(".NETCoreApp,Version=v10.0"), r))),
new CSharpCompilationOptions( new CSharpCompilationOptions(
OutputKind.DynamicallyLinkedLibrary, OutputKind.DynamicallyLinkedLibrary,
platform: Platform.AnyCpu, platform: Platform.AnyCpu,
@ -767,7 +823,7 @@ namespace System.Runtime.CompilerServices
string targetFramework = module.Metadata.DetectTargetFrameworkId(); string targetFramework = module.Metadata.DetectTargetFrameworkId();
var resolver = new UniversalAssemblyResolver(assemblyFileName, false, var resolver = new UniversalAssemblyResolver(assemblyFileName, false,
targetFramework, null, PEStreamOptions.PrefetchMetadata); targetFramework, null, PEStreamOptions.PrefetchMetadata);
resolver.AddSearchDirectory(targetFramework.Contains(".NETFramework") ? RefAsmPath : coreRefAsmPath); resolver.AddSearchDirectory(RefAssembliesToolset.GetPath(targetFramework));
var typeSystem = new DecompilerTypeSystem(module, resolver, settings); var typeSystem = new DecompilerTypeSystem(module, resolver, settings);
CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings); CSharpDecompiler decompiler = new CSharpDecompiler(typeSystem, settings);
decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAttributes()); decompiler.AstTransforms.Insert(0, new RemoveEmbeddedAttributes());

6
ICSharpCode.Decompiler.Tests/ICSharpCode.Decompiler.Tests.csproj

@ -7,7 +7,8 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<LangVersion>13</LangVersion>
<RuntimeIdentifier Condition="$(IsWindowsX64) == true">win-x64</RuntimeIdentifier> <RuntimeIdentifier Condition="$(IsWindowsX64) == true">win-x64</RuntimeIdentifier>
<RuntimeIdentifier Condition="$(IsWindowsARM64) == true">win-arm64</RuntimeIdentifier> <RuntimeIdentifier Condition="$(IsWindowsARM64) == true">win-arm64</RuntimeIdentifier>
@ -17,7 +18,7 @@
<AllowUnsafeBlocks>True</AllowUnsafeBlocks> <AllowUnsafeBlocks>True</AllowUnsafeBlocks>
<NoWarn>1701;1702;1705,67,169,1058,728,1720,649,168,251,660,661,675;1998;162;8632;626;8618;8714;8602;8981</NoWarn> <NoWarn>1701;1702;1705,67,169,1058,728,1720,649,168,251,660,661,675;1998;162;8632;626;8618;8714;8602;8981</NoWarn>
<DefineConstants>ROSLYN;ROSLYN2;ROSLYN3;ROSLYN4;NET60;CS60;CS70;CS71;CS72;CS73;CS80;CS90;CS100;CS110;CS120</DefineConstants> <DefineConstants>ROSLYN;ROSLYN2;ROSLYN3;ROSLYN4;NET60;CS60;CS70;CS71;CS72;CS73;CS80;CS90;CS100;CS110;CS120;CS130</DefineConstants>
<GenerateAssemblyVersionAttribute>False</GenerateAssemblyVersionAttribute> <GenerateAssemblyVersionAttribute>False</GenerateAssemblyVersionAttribute>
<GenerateAssemblyFileVersionAttribute>False</GenerateAssemblyFileVersionAttribute> <GenerateAssemblyFileVersionAttribute>False</GenerateAssemblyFileVersionAttribute>
@ -146,6 +147,7 @@
<Compile Include="TestCases\Pretty\Issue3442.cs" /> <Compile Include="TestCases\Pretty\Issue3442.cs" />
<Compile Include="TestCases\Pretty\Issue3483.cs" /> <Compile Include="TestCases\Pretty\Issue3483.cs" />
<Compile Include="TestCases\Pretty\PointerArithmetic.cs" /> <Compile Include="TestCases\Pretty\PointerArithmetic.cs" />
<Compile Include="TestCases\Pretty\ParamsCollections.cs" />
<None Include="TestCases\VBPretty\VBAutomaticEvents.vb" /> <None Include="TestCases\VBPretty\VBAutomaticEvents.vb" />
<Compile Include="TestCases\VBPretty\VBAutomaticEvents.cs" /> <Compile Include="TestCases\VBPretty\VBAutomaticEvents.cs" />
<Compile Include="TestCases\VBPretty\VBNonGenericForEach.cs" /> <Compile Include="TestCases\VBPretty\VBNonGenericForEach.cs" />

12
ICSharpCode.Decompiler.Tests/PrettyTestRunner.cs

@ -59,8 +59,6 @@ namespace ICSharpCode.Decompiler.Tests
static readonly CompilerOptions[] roslynOnlyWithNet40Options = static readonly CompilerOptions[] roslynOnlyWithNet40Options =
{ {
CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40, CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40, CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40, CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
@ -145,8 +143,6 @@ namespace ICSharpCode.Decompiler.Tests
{ {
CompilerOptions.None, CompilerOptions.None,
CompilerOptions.Optimize, CompilerOptions.Optimize,
CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40, CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40, CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40, CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
@ -167,8 +163,6 @@ namespace ICSharpCode.Decompiler.Tests
{ {
CompilerOptions.None, CompilerOptions.None,
CompilerOptions.Optimize, CompilerOptions.Optimize,
CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn1_3_2 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40, CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40, CompilerOptions.Optimize | CompilerOptions.UseRoslyn2_10_0 | CompilerOptions.TargetNet40,
CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40, CompilerOptions.UseRoslyn3_11_0 | CompilerOptions.TargetNet40,
@ -611,6 +605,12 @@ namespace ICSharpCode.Decompiler.Tests
await RunForLibrary(cscOptions: cscOptions); await RunForLibrary(cscOptions: cscOptions);
} }
[Test]
public async Task ParamsCollections([ValueSource(nameof(roslyn4OrNewerOptions))] CompilerOptions cscOptions)
{
await RunForLibrary(cscOptions: cscOptions);
}
[Test] [Test]
public async Task Issue1080([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions) public async Task Issue1080([ValueSource(nameof(roslynOnlyOptions))] CompilerOptions cscOptions)
{ {

4
ICSharpCode.Decompiler.Tests/TestCases/Correctness/Conversions.cs

@ -112,7 +112,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
Console.WriteLine(ReadZeroTerminatedString("Hello World!".Length)); Console.WriteLine(ReadZeroTerminatedString("Hello World!".Length));
C1.Test(); C1.Test();
#if ROSLYN2 && !NET40 #if CS120 && !NET40
C3.Run(); C3.Run();
#endif #endif
} }
@ -204,7 +204,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Correctness
} }
} }
#if ROSLYN2 && !NET40 #if CS120 && !NET40
class C3 class C3
{ {
[InlineArray(4)] struct MyArray { private int elem; } [InlineArray(4)] struct MyArray { private int elem; }

2
ICSharpCode.Decompiler.Tests/TestCases/ILPretty/Issue1325.il

@ -31,7 +31,7 @@
// .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 ) // .custom instance void [System.Runtime]System.Diagnostics.DebuggableAttribute::.ctor(valuetype [System.Runtime]System.Diagnostics.DebuggableAttribute/DebuggingModes) = ( 01 00 07 01 00 00 00 00 )
.custom instance void [System.Runtime]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 18 2E 4E 45 54 43 6F 72 65 41 70 70 2C 56 // ....NETCoreApp,V .custom instance void [System.Runtime]System.Runtime.Versioning.TargetFrameworkAttribute::.ctor(string) = ( 01 00 18 2E 4E 45 54 43 6F 72 65 41 70 70 2C 56 // ....NETCoreApp,V
65 72 73 69 6F 6E 3D 76 32 2E 31 01 00 54 0E 14 // ersion=v2.1..T.. 65 72 73 69 6F 6E 3D 76 32 2E 32 01 00 54 0E 14 // ersion=v2.2..T..
46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 79 // FrameworkDisplay 46 72 61 6D 65 77 6F 72 6B 44 69 73 70 6C 61 79 // FrameworkDisplay
4E 61 6D 65 00 ) // Name. 4E 61 6D 65 00 ) // Name.
.custom instance void [System.Runtime]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 05 44 65 62 75 67 00 00 ) // ...Debug.. .custom instance void [System.Runtime]System.Reflection.AssemblyConfigurationAttribute::.ctor(string) = ( 01 00 05 44 65 62 75 67 00 00 ) // ...Debug..

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/DelegateConstruction.cs

@ -631,21 +631,13 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty.DelegateConstruction
Action action = delegate { Action action = delegate {
list.Select((int x) => x * 2); list.Select((int x) => x * 2);
}; };
#if OPT && ROSLYN
Action obj = delegate {
#else
Action action2 = delegate { Action action2 = delegate {
#endif
list.Select((int x) => x * 2); list.Select((int x) => x * 2);
}; };
Console.WriteLine(); Console.WriteLine();
action(); action();
Console.WriteLine(); Console.WriteLine();
#if OPT && ROSLYN
obj();
#else
action2(); action2();
#endif
} }
catch (Exception) catch (Exception)
{ {

8
ICSharpCode.Decompiler.Tests/TestCases/Pretty/MetadataAttributes.cs

@ -9,7 +9,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{ {
[MethodImpl(MethodImplOptions.AggressiveInlining)] [MethodImpl(MethodImplOptions.AggressiveInlining)]
public extern void A(); public extern void A();
#if NETCORE #if !NET40 && ROSLYN3
[MethodImpl(MethodImplOptions.AggressiveOptimization)] [MethodImpl(MethodImplOptions.AggressiveOptimization)]
public extern void B(); public extern void B();
#endif #endif
@ -29,7 +29,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public extern void J(); public extern void J();
[MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.Native)] [MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.Native)]
public extern void A1(); public extern void A1();
#if NETCORE #if !NET40 && ROSLYN3
[MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.Native)] [MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.Native)]
public extern void B1(); public extern void B1();
#endif #endif
@ -49,7 +49,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public extern void J1(); public extern void J1();
[MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.OPTIL)] [MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.OPTIL)]
public extern void A2(); public extern void A2();
#if NETCORE #if !NET40 && ROSLYN3
[MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.OPTIL)] [MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.OPTIL)]
public extern void B2(); public extern void B2();
#endif #endif
@ -69,7 +69,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public extern void J2(); public extern void J2();
[MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.OPTIL)] [MethodImpl(MethodImplOptions.AggressiveInlining, MethodCodeType = MethodCodeType.OPTIL)]
public extern void A3(); public extern void A3();
#if NETCORE #if !NET40 && ROSLYN3
[MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.Runtime)] [MethodImpl(MethodImplOptions.AggressiveOptimization, MethodCodeType = MethodCodeType.Runtime)]
public extern void B3(); public extern void B3();
#endif #endif

21
ICSharpCode.Decompiler.Tests/TestCases/Pretty/ParamsCollections.cs

@ -0,0 +1,21 @@
using System;
using System.Collections.Generic;
namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
{
public static class ParamsCollections
{
public static void ParamsEnumerable(params IEnumerable<int> values)
{
}
public static void ParamsList(params List<int> values)
{
}
public static void ParamsReadOnlySpan(params ReadOnlySpan<int> values)
{
}
public static void ParamsSpan(params Span<int> values)
{
}
}
}

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

@ -1624,7 +1624,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static bool DoNotRemoveAssignmentBeforeSwitch(string x, out ConsoleKey key) public static bool DoNotRemoveAssignmentBeforeSwitch(string x, out ConsoleKey key)
{ {
#if NET40 || !ROSLYN #if NET40 || !ROSLYN4
key = (ConsoleKey)0; key = (ConsoleKey)0;
#else #else
key = ConsoleKey.None; key = ConsoleKey.None;
@ -1641,7 +1641,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
key = ConsoleKey.C; key = ConsoleKey.C;
break; break;
} }
#if NET40 || !ROSLYN #if NET40 || !ROSLYN4
return key != (ConsoleKey)0; return key != (ConsoleKey)0;
#else #else
return key != ConsoleKey.None; return key != ConsoleKey.None;

2
ICSharpCode.Decompiler.Tests/TestCases/Pretty/WellKnownConstants.cs

@ -83,7 +83,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public const float Float_Tenth = 0.1f; public const float Float_Tenth = 0.1f;
public const double Double_Tenth = 0.1; public const double Double_Tenth = 0.1;
#if ROSLYN && !NET40 #if ROSLYN2 && !NET40
public const float Float_PI = MathF.PI; public const float Float_PI = MathF.PI;
public const float Float_HalfOfPI = MathF.PI / 2f; public const float Float_HalfOfPI = MathF.PI / 2f;
public const float Float_QuarterOfPI = MathF.PI / 4f; public const float Float_QuarterOfPI = MathF.PI / 4f;

4
ICSharpCode.Decompiler.Tests/TypeSystem/TypeSystemLoaderTests.cs

@ -47,12 +47,12 @@ namespace ICSharpCode.Decompiler.Tests.TypeSystem
static readonly Lazy<PEFile> mscorlib = new Lazy<PEFile>( static readonly Lazy<PEFile> mscorlib = new Lazy<PEFile>(
delegate { delegate {
return LoadAssembly(Path.Combine(Helpers.Tester.RefAsmPath, "mscorlib.dll")); return LoadAssembly(Path.Combine(Helpers.Tester.RefAssembliesToolset.GetPath("legacy"), "mscorlib.dll"));
}); });
static readonly Lazy<PEFile> systemCore = new Lazy<PEFile>( static readonly Lazy<PEFile> systemCore = new Lazy<PEFile>(
delegate { delegate {
return LoadAssembly(Path.Combine(Helpers.Tester.RefAsmPath, "System.Core.dll")); return LoadAssembly(Path.Combine(Helpers.Tester.RefAssembliesToolset.GetPath("legacy"), "System.Core.dll"));
}); });
static readonly Lazy<PEFile> testAssembly = new Lazy<PEFile>( static readonly Lazy<PEFile> testAssembly = new Lazy<PEFile>(

2
ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs

@ -316,6 +316,8 @@ namespace ICSharpCode.Decompiler.CSharp
return true; return true;
if (settings.FixedBuffers && name.StartsWith("<", StringComparison.Ordinal) && name.Contains("__FixedBuffer")) if (settings.FixedBuffers && name.StartsWith("<", StringComparison.Ordinal) && name.Contains("__FixedBuffer"))
return true; return true;
if (settings.InlineArrays && name.StartsWith("<>y__InlineArray", StringComparison.Ordinal) && name.EndsWith("`1"))
return true;
} }
else if (type.IsCompilerGenerated(metadata)) else if (type.IsCompilerGenerated(metadata))
{ {

3
ICSharpCode.Decompiler/CSharp/CSharpLanguageVersion.cs

@ -35,7 +35,8 @@ namespace ICSharpCode.Decompiler.CSharp
CSharp10_0 = 1000, CSharp10_0 = 1000,
CSharp11_0 = 1100, CSharp11_0 = 1100,
CSharp12_0 = 1200, CSharp12_0 = 1200,
Preview = 1100, CSharp13_0 = 1300,
Preview = 1300,
Latest = 0x7FFFFFFF Latest = 0x7FFFFFFF
} }
} }

85
ICSharpCode.Decompiler/CSharp/CallBuilder.cs

@ -1026,25 +1026,14 @@ namespace ICSharpCode.Decompiler.CSharp
} }
private bool TransformParamsArgument(ExpectedTargetDetails expectedTargetDetails, ResolveResult targetResolveResult, private bool TransformParamsArgument(ExpectedTargetDetails expectedTargetDetails, ResolveResult targetResolveResult,
IMethod method, IParameter parameter, TranslatedExpression arg, ref List<IParameter> expectedParameters, IMethod method, IParameter parameter, TranslatedExpression paramsArgument, ref List<IParameter> expectedParameters,
ref List<TranslatedExpression> arguments) ref List<TranslatedExpression> arguments)
{ {
if (CheckArgument(out int length, out IType elementType)) var expressionBuilder = this.expressionBuilder;
if (ExtractArguments(out IType elementType, out var expandedParameters, out var expandedArguments))
{ {
var expandedParameters = new List<IParameter>(expectedParameters); expandedParameters.InsertRange(0, expectedParameters);
var expandedArguments = new List<TranslatedExpression>(arguments); expandedArguments.InsertRange(0, arguments);
if (length > 0)
{
var arrayElements = ((ArrayCreateExpression)arg.Expression).Initializer.Elements.ToArray();
for (int j = 0; j < length; j++)
{
expandedParameters.Add(new DefaultParameter(elementType, parameter.Name + j));
if (j < arrayElements.Length)
expandedArguments.Add(new TranslatedExpression(arrayElements[j]));
else
expandedArguments.Add(expressionBuilder.GetDefaultValueExpression(elementType).WithoutILInstruction());
}
}
if (IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, Empty<IType>.Array, if (IsUnambiguousCall(expectedTargetDetails, method, targetResolveResult, Empty<IType>.Array,
expandedArguments.SelectArray(a => a.ResolveResult), argumentNames: null, expandedArguments.SelectArray(a => a.ResolveResult), argumentNames: null,
firstOptionalArgumentIndex: -1, out _, firstOptionalArgumentIndex: -1, out _,
@ -1057,30 +1046,52 @@ namespace ICSharpCode.Decompiler.CSharp
} }
return false; return false;
bool CheckArgument(out int len, out IType t) bool ExtractArguments(out IType elementType, out List<IParameter> parameters, out List<TranslatedExpression> arguments)
{ {
len = 0; elementType = null;
t = null; parameters = null;
if (arg.ResolveResult is CSharpInvocationResolveResult csirr && arguments = null;
csirr.Arguments.Count == 0 && csirr.Member is IMethod emptyMethod && switch (paramsArgument.ResolveResult)
emptyMethod.IsStatic &&
"System.Array.Empty" == emptyMethod.FullName &&
emptyMethod.TypeArguments.Count == 1)
{ {
t = emptyMethod.TypeArguments[0]; case CSharpInvocationResolveResult { Member: IMethod method, Arguments: var args }:
return true; // match System.Array.Empty<T>()
} if (args is [] && method is { IsStatic: true, FullName: "System.Array.Empty", TypeArguments: [var type] })
{
if (arg.ResolveResult is ArrayCreateResolveResult acrr && elementType = type;
acrr.SizeArguments.Count == 1 && arguments = new();
acrr.SizeArguments[0].IsCompileTimeConstant && parameters = new();
acrr.SizeArguments[0].ConstantValue is int l) return true;
{ }
len = l; // match System.ReadOnlySpan<T>..ctor(ref readonly T)
t = ((ArrayType)acrr.Type).ElementType; if (paramsArgument.Expression is ObjectCreateExpression oce
return true; && method is {
IsConstructor: true,
Parameters: [{ ReferenceKind: ReferenceKind.RefReadOnly, Type: ByReferenceType { ElementType: var paramType } }],
DeclaringType: { TypeArguments: [var type2] } declaringType
}
&& declaringType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT)
&& paramType.Equals(type2))
{
elementType = type2;
arguments = new() { new TranslatedExpression(oce.Arguments.Single()) };
parameters = new() { new DefaultParameter(type2, string.Empty) };
return true;
}
return false;
case ArrayCreateResolveResult { Type: ArrayType { ElementType: var type3 }, SizeArguments: [{ ConstantValue: int arrayLength }] }:
elementType = type3;
arguments = new(((ArrayCreateExpression)paramsArgument.Expression).Initializer.Elements.Select(e => new TranslatedExpression(e)));
parameters = new List<IParameter>(arrayLength);
for (int i = 0; i < arrayLength; i++)
{
parameters.Add(new DefaultParameter(type3, string.Empty));
if (arguments.Count <= i)
arguments.Add(new TranslatedExpression(expressionBuilder.GetDefaultValueExpression(type3).WithoutILInstruction()));
}
return true;
default:
return false;
} }
return false;
} }
} }

2
ICSharpCode.Decompiler/CSharp/Resolver/CSharpConversions.cs

@ -779,7 +779,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
{ {
// C# 4.0 spec: §6.1.7 // C# 4.0 spec: §6.1.7
fromType = NullableType.GetUnderlyingType(fromType); fromType = NullableType.GetUnderlyingType(fromType);
if (fromType.IsReferenceType == false && toType.IsReferenceType == true) if (fromType.IsReferenceType == false && !fromType.IsByRefLike && toType.IsReferenceType == true)
return IsSubtypeOf(fromType, toType, 0); return IsSubtypeOf(fromType, toType, 0);
else else
return false; return false;

129
ICSharpCode.Decompiler/CSharp/Resolver/OverloadResolution.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
public readonly bool IsExpandedForm; public readonly bool IsExpandedForm;
/// <summary> /// <summary>
/// Gets the parameter types. In the first step, these are the types without any substition. /// Gets the parameter types. In the first step, these are the types without any substitution.
/// After type inference, substitutions will be performed. /// After type inference, substitutions will be performed.
/// </summary> /// </summary>
public readonly IType[] ParameterTypes; public readonly IType[] ParameterTypes;
@ -76,6 +76,24 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
/// </summary> /// </summary>
public Conversion[] ArgumentConversions; public Conversion[] ArgumentConversions;
/// <summary>
/// Gets the type of the collection that is used for the 'params' parameter (before any substitution!).
/// Otherwise returns SpecialType.UnknownType.
/// </summary>
public IType ParamsCollectionType {
get {
if (IsExpandedForm && Parameters.Count > 0)
{
IParameter lastParameter = Parameters[Parameters.Count - 1];
if (lastParameter.IsParams)
{
return lastParameter.Type;
}
}
return SpecialType.UnknownType;
}
}
public bool IsGenericMethod { public bool IsGenericMethod {
get { get {
IMethod method = Member as IMethod; IMethod method = Member as IMethod;
@ -83,7 +101,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
} }
} }
public int ArgumentsPassedToParamsArray { public int ArgumentsPassedToParams {
get { get {
int count = 0; int count = 0;
if (IsExpandedForm) if (IsExpandedForm)
@ -104,7 +122,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
this.Member = member; this.Member = member;
this.IsExpandedForm = isExpanded; this.IsExpandedForm = isExpanded;
IParameterizedMember memberDefinition = (IParameterizedMember)member.MemberDefinition; IParameterizedMember memberDefinition = (IParameterizedMember)member.MemberDefinition;
// For specificialized methods, go back to the original parameters: // For specialized methods, go back to the original parameters:
// (without any type parameter substitution, not even class type parameters) // (without any type parameter substitution, not even class type parameters)
// We'll re-substitute them as part of RunTypeInference(). // We'll re-substitute them as part of RunTypeInference().
this.Parameters = memberDefinition.Parameters; this.Parameters = memberDefinition.Parameters;
@ -286,9 +304,12 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
} }
if (candidate.IsExpandedForm && i == candidate.Parameters.Count - 1) if (candidate.IsExpandedForm && i == candidate.Parameters.Count - 1)
{ {
ArrayType arrayType = type as ArrayType; if (type is ArrayType arrayType && arrayType.Dimensions == 1)
if (arrayType != null && arrayType.Dimensions == 1)
type = arrayType.ElementType; type = arrayType.ElementType;
else if (type.IsKnownType(KnownTypeCode.ReadOnlySpanOfT) || type.IsKnownType(KnownTypeCode.SpanOfT))
type = type.TypeArguments[0];
else if (type.IsArrayInterfaceType())
type = type.TypeArguments[0];
else else
return false; // error: cannot unpack params-array. abort considering the expanded form for this candidate return false; // error: cannot unpack params-array. abort considering the expanded form for this candidate
} }
@ -772,8 +793,8 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
else if (c1.IsExpandedForm && !c2.IsExpandedForm) else if (c1.IsExpandedForm && !c2.IsExpandedForm)
return 2; return 2;
// prefer the member with less arguments mapped to the params-array // prefer the member with less arguments mapped to the params-collection
int r = c1.ArgumentsPassedToParamsArray.CompareTo(c2.ArgumentsPassedToParamsArray); int r = c1.ArgumentsPassedToParams.CompareTo(c2.ArgumentsPassedToParams);
if (r < 0) if (r < 0)
return 1; return 1;
else if (r > 0) else if (r > 0)
@ -797,13 +818,105 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return 1; return 1;
if (lift1 != null && lift2 == null) if (lift1 != null && lift2 == null)
return 2; return 2;
// prefer by-value parameters over in-parameters
r = BetterParameterPassingChoice(c1, c2);
if (r != 0)
return r;
if (c1.IsExpandedForm)
{
Debug.Assert(c2.IsExpandedForm);
r = BetterParamsCollectionType(c1.ParamsCollectionType, c2.ParamsCollectionType);
if (r != 0)
return r;
}
}
return 0;
}
int BetterParamsCollectionType(IType paramsCollectionType1, IType paramsCollectionType2)
{
// see https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-13.0/params-collections#better-function-member
bool isSpan1 = paramsCollectionType1.IsKnownType(KnownTypeCode.SpanOfT) || paramsCollectionType1.IsKnownType(KnownTypeCode.ReadOnlySpanOfT);
bool isSpan2 = paramsCollectionType2.IsKnownType(KnownTypeCode.SpanOfT) || paramsCollectionType2.IsKnownType(KnownTypeCode.ReadOnlySpanOfT);
if (!isSpan1 && !isSpan2)
{
bool implicitConversion1to2 = conversions.ImplicitConversion(paramsCollectionType1, paramsCollectionType2).IsValid;
bool implicitConversion2to1 = conversions.ImplicitConversion(paramsCollectionType2, paramsCollectionType1).IsValid;
if (implicitConversion1to2 && !implicitConversion2to1)
return 1;
if (!implicitConversion1to2 && implicitConversion2to1)
return 2;
}
else if (paramsCollectionType1.IsKnownType(KnownTypeCode.ReadOnlySpanOfT) && paramsCollectionType2.IsKnownType(KnownTypeCode.SpanOfT))
{
if (conversions.IdentityConversion(paramsCollectionType1.TypeArguments[0], paramsCollectionType2.TypeArguments[0]))
return 1; // ReadOnlySpan<T> is better than Span<T> if there exists an identity conversion between the element types
} }
else if (paramsCollectionType2.IsKnownType(KnownTypeCode.ReadOnlySpanOfT) && paramsCollectionType1.IsKnownType(KnownTypeCode.SpanOfT))
{
if (conversions.IdentityConversion(paramsCollectionType2.TypeArguments[0], paramsCollectionType1.TypeArguments[0]))
return 2; // ReadOnlySpan<T> is better than Span<T> if there exists an identity conversion between the element types
}
else if (isSpan1 && IsArrayOrArrayInterfaceType(paramsCollectionType2, out var elementType2))
{
if (conversions.IdentityConversion(paramsCollectionType1.TypeArguments[0], elementType2))
return 1; // Span<T> is better than an array type if there exists an identity conversion between the element types
}
else if (isSpan2 && IsArrayOrArrayInterfaceType(paramsCollectionType1, out var elementType1))
{
if (conversions.IdentityConversion(paramsCollectionType2.TypeArguments[0], elementType1))
return 2; // Span<T> is better than an array type if there exists an identity conversion between the element types
}
return 0;
}
bool IsArrayOrArrayInterfaceType(IType type, out IType elementType)
{
elementType = null;
if (type is ArrayType arrayType)
{
elementType = arrayType.ElementType;
return true;
}
if (type.IsArrayInterfaceType())
{
elementType = type.TypeArguments[0];
return true;
}
return false;
}
int BetterParameterPassingChoice(Candidate c1, Candidate c2)
{
Debug.Assert(c1.Parameters.Count == c2.Parameters.Count, "c1 and c2 must have the same number of parameters");
bool c1IsBetter = false;
bool c2IsBetter = false;
for (int i = 0; i < c1.Parameters.Count; i++)
{
ReferenceKind refKind1 = c1.Parameters[i].ReferenceKind;
ReferenceKind refKind2 = c2.Parameters[i].ReferenceKind;
if (refKind1 == ReferenceKind.None && refKind2 == ReferenceKind.In)
c1IsBetter = true; // by-value is better than in
if (refKind1 == ReferenceKind.In && refKind2 == ReferenceKind.None)
c2IsBetter = true;
}
if (c1IsBetter && !c2IsBetter)
return 1;
if (!c1IsBetter && c2IsBetter)
return 2;
return 0; return 0;
} }
int MoreSpecificFormalParameters(Candidate c1, Candidate c2) int MoreSpecificFormalParameters(Candidate c1, Candidate c2)
{ {
// prefer the member with more formal parmeters (in case both have different number of optional parameters) // prefer the member with more formal parameters (in case both have different number of optional parameters)
int r = c1.Parameters.Count.CompareTo(c2.Parameters.Count); int r = c1.Parameters.Count.CompareTo(c2.Parameters.Count);
if (r > 0) if (r > 0)
return 1; return 1;

21
ICSharpCode.Decompiler/CSharp/Resolver/TypeInference.cs

@ -759,7 +759,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
MakeLowerBoundInference(arrU.ElementType, arrV.ElementType); MakeLowerBoundInference(arrU.ElementType, arrV.ElementType);
return; return;
} }
else if (arrU != null && IsGenericInterfaceImplementedByArray(pV) && arrU.Dimensions == 1) else if (arrU != null && pV.IsArrayInterfaceType() && arrU.Dimensions == 1)
{ {
MakeLowerBoundInference(arrU.ElementType, pV.GetTypeArgument(0)); MakeLowerBoundInference(arrU.ElementType, pV.GetTypeArgument(0));
return; return;
@ -829,23 +829,6 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
return; return;
} }
} }
static bool IsGenericInterfaceImplementedByArray(ParameterizedType rt)
{
if (rt == null || rt.TypeParameterCount != 1)
return false;
switch (rt.GetDefinition()?.KnownTypeCode)
{
case KnownTypeCode.IEnumerableOfT:
case KnownTypeCode.ICollectionOfT:
case KnownTypeCode.IListOfT:
case KnownTypeCode.IReadOnlyCollectionOfT:
case KnownTypeCode.IReadOnlyListOfT:
return true;
default:
return false;
}
}
#endregion #endregion
#region MakeUpperBoundInference (§7.5.2.10) #region MakeUpperBoundInference (§7.5.2.10)
@ -880,7 +863,7 @@ namespace ICSharpCode.Decompiler.CSharp.Resolver
MakeUpperBoundInference(arrU.ElementType, arrV.ElementType); MakeUpperBoundInference(arrU.ElementType, arrV.ElementType);
return; return;
} }
else if (arrV != null && IsGenericInterfaceImplementedByArray(pU) && arrV.Dimensions == 1) else if (arrV != null && pU.IsArrayInterfaceType() && arrV.Dimensions == 1)
{ {
MakeUpperBoundInference(pU.GetTypeArgument(0), arrV.ElementType); MakeUpperBoundInference(pU.GetTypeArgument(0), arrV.ElementType);
return; return;

1
ICSharpCode.Decompiler/CSharp/Transforms/EscapeInvalidIdentifiers.cs

@ -166,6 +166,7 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
"System.Runtime.CompilerServices.NullableAttribute", "System.Runtime.CompilerServices.NullableAttribute",
"System.Runtime.CompilerServices.NullableContextAttribute", "System.Runtime.CompilerServices.NullableContextAttribute",
"System.Runtime.CompilerServices.NativeIntegerAttribute", "System.Runtime.CompilerServices.NativeIntegerAttribute",
"System.Runtime.CompilerServices.ParamCollectionAttribute",
"System.Runtime.CompilerServices.RefSafetyRulesAttribute", "System.Runtime.CompilerServices.RefSafetyRulesAttribute",
"System.Runtime.CompilerServices.ScopedRefAttribute", "System.Runtime.CompilerServices.ScopedRefAttribute",
"System.Runtime.CompilerServices.RequiresLocationAttribute", "System.Runtime.CompilerServices.RequiresLocationAttribute",

12
ICSharpCode.Decompiler/CSharp/Transforms/ReplaceMethodCallsWithOperators.cs

@ -57,8 +57,18 @@ namespace ICSharpCode.Decompiler.CSharp.Transforms
var arguments = invocationExpression.Arguments.ToArray(); var arguments = invocationExpression.Arguments.ToArray();
// Reduce "String.Concat(a, b)" to "a + b" // Reduce "String.Concat(a, b)" to "a + b"
if (IsStringConcat(method) && context.Settings.StringConcat && CheckArgumentsForStringConcat(arguments)) if (IsStringConcat(method) && context.Settings.StringConcat)
{ {
if (arguments is [ArrayCreateExpression ace] && method.Parameters is [{ Type: ArrayType }])
{
arguments = ace.Initializer.Elements.ToArray();
}
if (!CheckArgumentsForStringConcat(arguments))
{
return;
}
bool isInExpressionTree = invocationExpression.Ancestors.OfType<LambdaExpression>().Any( bool isInExpressionTree = invocationExpression.Ancestors.OfType<LambdaExpression>().Any(
lambda => lambda.Annotation<IL.ILFunction>()?.Kind == IL.ILFunctionKind.ExpressionTree); lambda => lambda.Annotation<IL.ILFunction>()?.Kind == IL.ILFunctionKind.ExpressionTree);
Expression arg0 = arguments[0].Detach(); Expression arg0 = arguments[0].Detach();

24
ICSharpCode.Decompiler/DecompilerSettings.cs

@ -166,10 +166,16 @@ namespace ICSharpCode.Decompiler
usePrimaryConstructorSyntaxForNonRecordTypes = false; usePrimaryConstructorSyntaxForNonRecordTypes = false;
inlineArrays = false; inlineArrays = false;
} }
if (languageVersion < CSharp.LanguageVersion.CSharp13_0)
{
paramsCollections = false;
}
} }
public CSharp.LanguageVersion GetMinimumRequiredVersion() public CSharp.LanguageVersion GetMinimumRequiredVersion()
{ {
if (paramsCollections)
return CSharp.LanguageVersion.CSharp13_0;
if (refReadOnlyParameters || usePrimaryConstructorSyntaxForNonRecordTypes || inlineArrays) if (refReadOnlyParameters || usePrimaryConstructorSyntaxForNonRecordTypes || inlineArrays)
return CSharp.LanguageVersion.CSharp12_0; return CSharp.LanguageVersion.CSharp12_0;
if (scopedRef || requiredMembers || numericIntPtr || utf8StringLiterals || unsignedRightShift || checkedOperators) if (scopedRef || requiredMembers || numericIntPtr || utf8StringLiterals || unsignedRightShift || checkedOperators)
@ -849,6 +855,24 @@ namespace ICSharpCode.Decompiler
} }
} }
bool paramsCollections = true;
/// <summary>
/// Support params collections.
/// </summary>
[Category("C# 13.0 / VS 2022.12")]
[Description("DecompilerSettings.DecompileParamsCollections")]
public bool ParamsCollections {
get { return paramsCollections; }
set {
if (paramsCollections != value)
{
paramsCollections = value;
OnPropertyChanged();
}
}
}
bool lockStatement = true; bool lockStatement = true;
/// <summary> /// <summary>

2
ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj

@ -51,7 +51,7 @@
<!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ --> <!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ -->
<PropertyGroup> <PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(GITHUB_ACTIONS)' == 'true'">true</RestoreLockedMode> <RestoreLockedMode>true</RestoreLockedMode>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)' == 'Debug'"> <PropertyGroup Condition="'$(Configuration)' == 'Debug'">

4
ICSharpCode.Decompiler/IL/ControlFlow/AwaitInFinallyTransform.cs

@ -16,12 +16,10 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.Decompiler.IL.Transforms; using ICSharpCode.Decompiler.IL.Transforms;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -109,7 +107,7 @@ namespace ICSharpCode.Decompiler.IL.ControlFlow
if (objectVariable.LoadCount != 1 || objectVariable.StoreCount > 2) if (objectVariable.LoadCount != 1 || objectVariable.StoreCount > 2)
continue; continue;
var beforeExceptionCaptureBlock = (Block)LocalFunctionDecompiler.GetStatement(objectVariable.LoadInstructions[0])?.Parent; var beforeExceptionCaptureBlock = Block.FindClosestBlock(objectVariable.LoadInstructions[0]);
if (beforeExceptionCaptureBlock == null) if (beforeExceptionCaptureBlock == null)
continue; continue;

2
ICSharpCode.Decompiler/IL/ILTypeExtensions.cs

@ -238,6 +238,8 @@ namespace ICSharpCode.Decompiler.IL
default: default:
return SpecialType.UnknownType; return SpecialType.UnknownType;
} }
case ILFunction func when func.DelegateType != null:
return func.DelegateType;
default: default:
return SpecialType.UnknownType; return SpecialType.UnknownType;
} }

16
ICSharpCode.Decompiler/IL/Instructions/Block.cs

@ -383,6 +383,22 @@ namespace ICSharpCode.Decompiler.IL
return null; return null;
} }
/// <summary>
/// Gets the closest ancestor that is child of a control-flow (top-level) Block.
/// Returns null, if the instruction is not a descendant of a Block.
/// </summary>
public static ILInstruction? GetContainingStatement(ILInstruction inst)
{
var curr = inst;
while (curr != null)
{
if (curr.Parent is Block { Kind: BlockKind.ControlFlow })
return curr;
curr = curr.Parent;
}
return null;
}
public bool MatchInlineAssignBlock([NotNullWhen(true)] out CallInstruction? call, [NotNullWhen(true)] out ILInstruction? value) public bool MatchInlineAssignBlock([NotNullWhen(true)] out CallInstruction? call, [NotNullWhen(true)] out ILInstruction? value)
{ {
call = null; call = null;

5
ICSharpCode.Decompiler/IL/Transforms/DetectCatchWhenConditionBlocks.cs

@ -16,9 +16,6 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic;
using System.Diagnostics;
using System.Linq; using System.Linq;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
@ -107,7 +104,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
// We are only interested in store "statements" copying the exception variable // We are only interested in store "statements" copying the exception variable
// without modifying it. // without modifying it.
var statement = LocalFunctionDecompiler.GetStatement(load); var statement = Block.GetContainingStatement(load);
if (!(statement is StLoc stloc)) if (!(statement is StLoc stloc))
{ {
i++; i++;

15
ICSharpCode.Decompiler/IL/Transforms/ExpressionTransforms.cs

@ -312,25 +312,14 @@ namespace ICSharpCode.Decompiler.IL.Transforms
protected internal override void VisitNewObj(NewObj inst) protected internal override void VisitNewObj(NewObj inst)
{ {
Block block;
if (TransformSpanTCtorContainingStackAlloc(inst, out ILInstruction locallocSpan)) if (TransformSpanTCtorContainingStackAlloc(inst, out ILInstruction locallocSpan))
{ {
context.Step("new Span<T>(stackalloc) -> stackalloc Span<T>", inst); context.Step("new Span<T>(stackalloc) -> stackalloc Span<T>", inst);
inst.ReplaceWith(locallocSpan); inst.ReplaceWith(locallocSpan);
block = null; ILInstruction stmt = Block.GetContainingStatement(locallocSpan);
ILInstruction stmt = locallocSpan;
while (stmt.Parent != null)
{
if (stmt.Parent is Block b)
{
block = b;
break;
}
stmt = stmt.Parent;
}
// Special case to eliminate extra store // Special case to eliminate extra store
if (stmt.GetNextSibling() is StLoc storeStmt && storeStmt.Value is LdLoc) if (stmt.GetNextSibling() is StLoc storeStmt && storeStmt.Value is LdLoc)
ILInlining.InlineIfPossible(block, stmt.ChildIndex, context); ILInlining.InlineIfPossible((Block)stmt.Parent, stmt.ChildIndex, context);
return; return;
} }
if (TransformArrayInitializers.TransformSpanTArrayInitialization(inst, context, out var replacement)) if (TransformArrayInitializers.TransformSpanTArrayInitialization(inst, context, out var replacement))

18
ICSharpCode.Decompiler/IL/Transforms/ILInlining.cs

@ -337,20 +337,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{ {
return true; return true;
} }
else if (IsPassedToReadOnlySpanOfCharCtor(loadInst)) else if (IsPassedToReadOnlySpanCtor(loadInst))
{ {
// Always inlining is possible here, because it's an 'in' or 'ref readonly' parameter // Always inlining is possible here, because it's an 'in' or 'ref readonly' parameter
// and the C# compiler allows calling it with an rvalue, even though that might produce // and the C# compiler allows calling it with an rvalue, even though that might produce
// a warning. Note that we don't need to check the expression classification, because // a warning. Note that we don't need to check the expression classification, because
// expressionBuilder.VisitAddressOf will handle creating the copy for us. // expressionBuilder.VisitAddressOf will handle creating the copy for us.
// This is necessary, because there are compiler-generated uses of this ctor when // This is necessary, because there are compiler-generated uses of this ctor when
// concatenating a string to a char and our following transforms assume the char is // passing a single-element array to a params ROS<T> parameter and our following transforms
// already inlined. // assume the value is already inlined.
return true; return true;
} }
if (IsPassedToInlineArrayAsSpan(loadInst)) else if (IsPassedToInlineArrayAsSpan(loadInst))
{ {
// Inlining is not allowed // Inlining is not allowed:
// <PrivateImplementationDetails>.InlineArrayAsReadOnlySpan(GetInlineArray()) is invalid C# code
return false; return false;
} }
else if (IsPassedToInParameter(loadInst)) else if (IsPassedToInParameter(loadInst))
@ -491,13 +492,16 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return call.GetParameter(ldloca.ChildIndex)?.ReferenceKind is ReferenceKind.In; return call.GetParameter(ldloca.ChildIndex)?.ReferenceKind is ReferenceKind.In;
} }
static bool IsPassedToReadOnlySpanOfCharCtor(LdLoca ldloca) static bool IsPassedToReadOnlySpanCtor(LdLoca ldloca)
{ {
if (ldloca.Parent is not NewObj call) if (ldloca.Parent is not NewObj call)
{ {
return false; return false;
} }
return IsReadOnlySpanCharCtor(call.Method); var method = call.Method;
return method.IsConstructor
&& method.Parameters.Count == 1
&& method.DeclaringType.IsKnownType(KnownTypeCode.ReadOnlySpanOfT);
} }
internal static bool IsReadOnlySpanCharCtor(IMethod method) internal static bool IsReadOnlySpanCharCtor(IMethod method)

13
ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

@ -575,17 +575,6 @@ namespace ICSharpCode.Decompiler.IL.Transforms
&& TransformDisplayClassUsage.IsPotentialClosure(context.CurrentTypeDefinition, type); && TransformDisplayClassUsage.IsPotentialClosure(context.CurrentTypeDefinition, type);
} }
internal static ILInstruction GetStatement(ILInstruction inst)
{
while (inst.Parent != null)
{
if (inst.Parent is Block b && b.Kind == BlockKind.ControlFlow)
return inst;
inst = inst.Parent;
}
return inst;
}
LocalFunctionMethod ReduceToLocalFunction(IMethod method, int typeParametersToRemove) LocalFunctionMethod ReduceToLocalFunction(IMethod method, int typeParametersToRemove)
{ {
int parametersToRemove = 0; int parametersToRemove = 0;
@ -747,7 +736,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (variable.Kind == VariableKind.Parameter) if (variable.Kind == VariableKind.Parameter)
return null; return null;
if (type.Kind == TypeKind.Struct) if (type.Kind == TypeKind.Struct)
return GetStatement(variable.AddressInstructions.OrderBy(i => i.StartILOffset).First()); return Block.GetContainingStatement(variable.AddressInstructions.OrderBy(i => i.StartILOffset).First());
else else
return (StLoc)variable.StoreInstructions[0]; return (StLoc)variable.StoreInstructions[0];
} }

2
ICSharpCode.Decompiler/IL/Transforms/TransformDisplayClassUsage.cs

@ -604,7 +604,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
if (context.Settings.LocalFunctions && closureType?.Kind == TypeKind.Struct if (context.Settings.LocalFunctions && closureType?.Kind == TypeKind.Struct
&& variable.UsesInitialValue && IsPotentialClosure(context, closureType)) && variable.UsesInitialValue && IsPotentialClosure(context, closureType))
{ {
initializer = LocalFunctionDecompiler.GetStatement(variable.AddressInstructions.OrderBy(i => i.StartILOffset).First()); initializer = Block.GetContainingStatement(variable.AddressInstructions.OrderBy(i => i.StartILOffset).First());
return true; return true;
} }
return false; return false;

6
ICSharpCode.Decompiler/Properties/DecompilerVersionInfo.template.cs

@ -1,10 +1,10 @@
public static class DecompilerVersionInfo public static class DecompilerVersionInfo
{ {
public const string Major = "9"; public const string Major = "10";
public const string Minor = "1"; public const string Minor = "0";
public const string Build = "0"; public const string Build = "0";
public const string Revision = "$INSERTREVISION$"; public const string Revision = "$INSERTREVISION$";
public const string VersionName = null; public const string VersionName = "preview1";
public const string FullVersion = Major + "." + Minor + "." + Build + ".$INSERTREVISION$$INSERTBRANCHPOSTFIX$$INSERTVERSIONNAMEPOSTFIX$"; public const string FullVersion = Major + "." + Minor + "." + Build + ".$INSERTREVISION$$INSERTBRANCHPOSTFIX$$INSERTVERSIONNAMEPOSTFIX$";
public const string FullVersionWithShortCommitHash = FullVersion + "+$INSERTSHORTCOMMITHASH$"; public const string FullVersionWithShortCommitHash = FullVersion + "+$INSERTSHORTCOMMITHASH$";

11
ICSharpCode.Decompiler/TypeSystem/DecompilerTypeSystem.cs

@ -138,12 +138,19 @@ namespace ICSharpCode.Decompiler.TypeSystem
/// </summary> /// </summary>
RefReadOnlyParameters = 0x10000, RefReadOnlyParameters = 0x10000,
/// <summary> /// <summary>
/// If this option is active, [ParamCollectionAttribute] on parameters is removed
/// and parameters are marked as params.
/// Otherwise, the attribute is preserved but the parameters are not marked
/// as if it was a normal parameter without any attributes.
/// </summary>
ParamsCollections = 0x20000,
/// <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 | ScopedRef | NativeIntegersWithoutAttribute | NativeIntegers | FunctionPointers | ScopedRef | NativeIntegersWithoutAttribute
| RefReadOnlyParameters | RefReadOnlyParameters | ParamsCollections
} }
/// <summary> /// <summary>
@ -185,6 +192,8 @@ namespace ICSharpCode.Decompiler.TypeSystem
typeSystemOptions |= TypeSystemOptions.NativeIntegersWithoutAttribute; typeSystemOptions |= TypeSystemOptions.NativeIntegersWithoutAttribute;
if (settings.RefReadOnlyParameters) if (settings.RefReadOnlyParameters)
typeSystemOptions |= TypeSystemOptions.RefReadOnlyParameters; typeSystemOptions |= TypeSystemOptions.RefReadOnlyParameters;
if (settings.ParamsCollections)
typeSystemOptions |= TypeSystemOptions.ParamsCollections;
return typeSystemOptions; return typeSystemOptions;
} }

3
ICSharpCode.Decompiler/TypeSystem/Implementation/AttributeListBuilder.cs

@ -258,6 +258,9 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
case "RequiresLocationAttribute": case "RequiresLocationAttribute":
return (options & TypeSystemOptions.RefReadOnlyParameters) != 0 return (options & TypeSystemOptions.RefReadOnlyParameters) != 0
&& (target == SymbolKind.Parameter); && (target == SymbolKind.Parameter);
case "ParamCollectionAttribute":
return (options & TypeSystemOptions.ParamsCollections) != 0
&& (target == SymbolKind.Parameter);
default: default:
return false; return false;
} }

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

@ -87,6 +87,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
// Parameter attributes: // Parameter attributes:
ParamArray, ParamArray,
ParamCollection,
In, In,
Out, Out,
Optional, Optional,
@ -169,6 +170,7 @@ namespace ICSharpCode.Decompiler.TypeSystem
new TopLevelTypeName("System.Runtime.CompilerServices", nameof(IndexerNameAttribute)), new TopLevelTypeName("System.Runtime.CompilerServices", nameof(IndexerNameAttribute)),
// Parameter attributes: // Parameter attributes:
new TopLevelTypeName("System", nameof(ParamArrayAttribute)), new TopLevelTypeName("System", nameof(ParamArrayAttribute)),
new TopLevelTypeName("System.Runtime.CompilerServices", "ParamCollectionAttribute"),
new TopLevelTypeName("System.Runtime.InteropServices", nameof(InAttribute)), new TopLevelTypeName("System.Runtime.InteropServices", nameof(InAttribute)),
new TopLevelTypeName("System.Runtime.InteropServices", nameof(OutAttribute)), new TopLevelTypeName("System.Runtime.InteropServices", nameof(OutAttribute)),
new TopLevelTypeName("System.Runtime.InteropServices", nameof(OptionalAttribute)), new TopLevelTypeName("System.Runtime.InteropServices", nameof(OptionalAttribute)),

18
ICSharpCode.Decompiler/TypeSystem/Implementation/MetadataParameter.cs

@ -125,6 +125,12 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
var metadata = module.metadata; var metadata = module.metadata;
var parameterDef = metadata.GetParameter(handle); var parameterDef = metadata.GetParameter(handle);
if ((module.TypeSystemOptions & TypeSystemOptions.ParamsCollections) != 0
&& parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ParamCollection))
{
// params collections are implicitly scoped
return default;
}
if (parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ScopedRef)) if (parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ScopedRef))
{ {
return new LifetimeAnnotation { ScopedRef = true }; return new LifetimeAnnotation { ScopedRef = true };
@ -135,11 +141,17 @@ namespace ICSharpCode.Decompiler.TypeSystem.Implementation
public bool IsParams { public bool IsParams {
get { get {
if (Type.Kind != TypeKind.Array)
return false;
var metadata = module.metadata; var metadata = module.metadata;
var parameterDef = metadata.GetParameter(handle); var parameterDef = metadata.GetParameter(handle);
return parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ParamArray); if (Type.Kind == TypeKind.Array)
{
return parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ParamArray);
}
if (module.TypeSystemOptions.HasFlag(TypeSystemOptions.ParamsCollections))
{
return parameterDef.GetCustomAttributes().HasKnownAttribute(metadata, KnownAttribute.ParamCollection);
}
return false;
} }
} }

17
ICSharpCode.Decompiler/TypeSystem/TypeSystemExtensions.cs

@ -306,6 +306,23 @@ namespace ICSharpCode.Decompiler.TypeSystem
} }
} }
public static bool IsArrayInterfaceType(this IType type)
{
if (type == null || type.TypeParameterCount != 1)
return false;
switch (type.GetDefinition()?.KnownTypeCode)
{
case KnownTypeCode.IEnumerableOfT:
case KnownTypeCode.ICollectionOfT:
case KnownTypeCode.IListOfT:
case KnownTypeCode.IReadOnlyCollectionOfT:
case KnownTypeCode.IReadOnlyListOfT:
return true;
default:
return false;
}
}
public static bool IsInlineArrayType(this IType type) public static bool IsInlineArrayType(this IType type)
{ {
if (type.Kind != TypeKind.Struct) if (type.Kind != TypeKind.Struct)

4
ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>Exe</OutputType> <OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<ServerGarbageCollection>true</ServerGarbageCollection> <ServerGarbageCollection>true</ServerGarbageCollection>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<IsPackable>true</IsPackable> <IsPackable>true</IsPackable>
@ -35,7 +35,7 @@
<!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ --> <!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ -->
<PropertyGroup> <PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(GITHUB_ACTIONS)' == 'true'">true</RestoreLockedMode> <RestoreLockedMode>true</RestoreLockedMode>
</PropertyGroup> </PropertyGroup>
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">

11
ICSharpCode.ILSpyCmd/packages.lock.json

@ -1,7 +1,7 @@
{ {
"version": 2, "version": 2,
"dependencies": { "dependencies": {
"net8.0": { "net10.0": {
"McMaster.Extensions.Hosting.CommandLine": { "McMaster.Extensions.Hosting.CommandLine": {
"type": "Direct", "type": "Direct",
"requested": "[4.1.1, )", "requested": "[4.1.1, )",
@ -425,8 +425,8 @@
"System.Collections.Immutable": { "System.Collections.Immutable": {
"type": "CentralTransitive", "type": "CentralTransitive",
"requested": "[9.0.4, )", "requested": "[9.0.4, )",
"resolved": "9.0.4", "resolved": "8.0.0",
"contentHash": "wfm2NgK22MmBe5qJjp52qzpkeDZKb4l9LbdubhZSehY1z4LS+lld6R+B+UQNb2AZRHu/QJlHxEUcRst5hIEejg==" "contentHash": "AurL6Y5BA1WotzlEvVaIDpqzpIPvYnnldxru8oXJU2yFxFUy3+pNXjXd1ymO+RA0rq0+590Q8gaz2l3Sr7fmqg=="
}, },
"System.Composition.AttributedModel": { "System.Composition.AttributedModel": {
"type": "CentralTransitive", "type": "CentralTransitive",
@ -438,10 +438,7 @@
"type": "CentralTransitive", "type": "CentralTransitive",
"requested": "[9.0.4, )", "requested": "[9.0.4, )",
"resolved": "9.0.4", "resolved": "9.0.4",
"contentHash": "qeJNsMmZPc/Lieg0Md+D4F6LoLcxV3b9QsUNmBRXc2ZVOkMbAcwuO9l2jbQFv3n+fLiHJilN8v6i5aJNivjrCQ==", "contentHash": "qeJNsMmZPc/Lieg0Md+D4F6LoLcxV3b9QsUNmBRXc2ZVOkMbAcwuO9l2jbQFv3n+fLiHJilN8v6i5aJNivjrCQ=="
"dependencies": {
"System.Collections.Immutable": "9.0.4"
}
}, },
"System.Runtime.CompilerServices.Unsafe": { "System.Runtime.CompilerServices.Unsafe": {
"type": "CentralTransitive", "type": "CentralTransitive",

4
ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj

@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0</TargetFramework> <TargetFramework>net10.0</TargetFramework>
<Nullable>enable</Nullable> <Nullable>enable</Nullable>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks> <AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<WarningsAsErrors>nullable</WarningsAsErrors> <WarningsAsErrors>nullable</WarningsAsErrors>
@ -51,7 +51,7 @@
<!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ --> <!-- https://devblogs.microsoft.com/nuget/enable-repeatable-package-restores-using-a-lock-file/ -->
<PropertyGroup> <PropertyGroup>
<RestorePackagesWithLockFile>true</RestorePackagesWithLockFile> <RestorePackagesWithLockFile>true</RestorePackagesWithLockFile>
<RestoreLockedMode Condition="'$(GITHUB_ACTIONS)' == 'true'">true</RestoreLockedMode> <RestoreLockedMode>true</RestoreLockedMode>
</PropertyGroup> </PropertyGroup>
<ItemGroup> <ItemGroup>

2
ICSharpCode.ILSpyX/MermaidDiagrammer/html/.vscode/tasks.json vendored

@ -9,7 +9,7 @@
"group": "build", "group": "build",
"type": "shell", "type": "shell",
"command": [ "command": [
"$folder = '../../../ICSharpCode.ILSpyCmd/bin/Debug/net8.0/';", // to avoid repetition "$folder = '../../../ICSharpCode.ILSpyCmd/bin/Debug/net10.0/';", // to avoid repetition
"$exePath = $folder + 'ilspycmd.exe';", "$exePath = $folder + 'ilspycmd.exe';",
"$assemblyPath = $folder + 'ICSharpCode.Decompiler.dll';", // comes with XML docs for testing the integration "$assemblyPath = $folder + 'ICSharpCode.Decompiler.dll';", // comes with XML docs for testing the integration
"if (Test-Path $exePath) {", "if (Test-Path $exePath) {",

14
ICSharpCode.ILSpyX/packages.lock.json

@ -1,7 +1,7 @@
{ {
"version": 2, "version": 2,
"dependencies": { "dependencies": {
"net8.0": { "net10.0": {
"K4os.Compression.LZ4": { "K4os.Compression.LZ4": {
"type": "Direct", "type": "Direct",
"requested": "[1.3.8, )", "requested": "[1.3.8, )",
@ -40,10 +40,7 @@
"type": "Direct", "type": "Direct",
"requested": "[9.0.4, )", "requested": "[9.0.4, )",
"resolved": "9.0.4", "resolved": "9.0.4",
"contentHash": "qeJNsMmZPc/Lieg0Md+D4F6LoLcxV3b9QsUNmBRXc2ZVOkMbAcwuO9l2jbQFv3n+fLiHJilN8v6i5aJNivjrCQ==", "contentHash": "qeJNsMmZPc/Lieg0Md+D4F6LoLcxV3b9QsUNmBRXc2ZVOkMbAcwuO9l2jbQFv3n+fLiHJilN8v6i5aJNivjrCQ=="
"dependencies": {
"System.Collections.Immutable": "9.0.4"
}
}, },
"System.Runtime.CompilerServices.Unsafe": { "System.Runtime.CompilerServices.Unsafe": {
"type": "Direct", "type": "Direct",
@ -77,8 +74,11 @@
"System.Collections.Immutable": { "System.Collections.Immutable": {
"type": "CentralTransitive", "type": "CentralTransitive",
"requested": "[9.0.4, )", "requested": "[9.0.4, )",
"resolved": "9.0.4", "resolved": "6.0.0",
"contentHash": "wfm2NgK22MmBe5qJjp52qzpkeDZKb4l9LbdubhZSehY1z4LS+lld6R+B+UQNb2AZRHu/QJlHxEUcRst5hIEejg==" "contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==",
"dependencies": {
"System.Runtime.CompilerServices.Unsafe": "6.0.0"
}
} }
} }
} }

2
ILSpy-tests

@ -1 +1 @@
Subproject commit 6f8860e420b54bdfd726ec3c58a4d178416f9156 Subproject commit 6cc4bb2942a1c6a134510ad4d916f77604d37b51

4
ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj

@ -75,8 +75,8 @@
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<ILSpyBuildPathX64>..\ILSpy\bin\$(Configuration)\net8.0-windows\win-x64\publish\fwdependent\</ILSpyBuildPathX64> <ILSpyBuildPathX64>..\ILSpy\bin\$(Configuration)\net10.0-windows\win-x64\publish\fwdependent\</ILSpyBuildPathX64>
<ILSpyBuildPathArm64>..\ILSpy\bin\$(Configuration)\net8.0-windows\win-arm64\publish\fwdependent\</ILSpyBuildPathArm64> <ILSpyBuildPathArm64>..\ILSpy\bin\$(Configuration)\net10.0-windows\win-arm64\publish\fwdependent\</ILSpyBuildPathArm64>
</PropertyGroup> </PropertyGroup>
<Target Name="IncludeILSpyDistributionInVSIXSubFolder" AfterTargets="ResolveProjectReferences"> <Target Name="IncludeILSpyDistributionInVSIXSubFolder" AfterTargets="ResolveProjectReferences">

2
ILSpy.AddIn/ILSpy.AddIn.csproj

@ -81,7 +81,7 @@
</ItemGroup> </ItemGroup>
<PropertyGroup> <PropertyGroup>
<ILSpyBuildPath>..\ILSpy\bin\$(Configuration)\net8.0-windows\win-x64\publish\fwdependent\</ILSpyBuildPath> <ILSpyBuildPath>..\ILSpy\bin\$(Configuration)\net10.0-windows\win-x64\publish\fwdependent\</ILSpyBuildPath>
</PropertyGroup> </PropertyGroup>
<Target Name="IncludeILSpyDistributionInVSIXSubFolder" AfterTargets="ResolveProjectReferences"> <Target Name="IncludeILSpyDistributionInVSIXSubFolder" AfterTargets="ResolveProjectReferences">

2
ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj

@ -7,7 +7,7 @@
</PropertyGroup> </PropertyGroup>
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<RuntimeIdentifier Condition="$(IsWindowsX64) == true">win-x64</RuntimeIdentifier> <RuntimeIdentifier Condition="$(IsWindowsX64) == true">win-x64</RuntimeIdentifier>
<RuntimeIdentifier Condition="$(IsWindowsARM64) == true">win-arm64</RuntimeIdentifier> <RuntimeIdentifier Condition="$(IsWindowsARM64) == true">win-arm64</RuntimeIdentifier>

2
ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj

@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<AssemblyName>ILSpy.BamlDecompiler.Plugin</AssemblyName> <AssemblyName>ILSpy.BamlDecompiler.Plugin</AssemblyName>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers> <RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo> <GenerateAssemblyInfo>False</GenerateAssemblyInfo>

2
ILSpy.Installer/setup.cs

@ -25,7 +25,7 @@ namespace ILSpy.Installer
#else #else
var buildPlatform = "x64"; var buildPlatform = "x64";
#endif #endif
var buildOutputDir = $@"ILSpy\bin\{buildConfiguration}\net8.0-windows\win-{buildPlatform}\publish\fwdependent"; var buildOutputDir = $@"ILSpy\bin\{buildConfiguration}\net10.0-windows\win-{buildPlatform}\publish\fwdependent";
var project = new Project("ILSpy", var project = new Project("ILSpy",
new InstallDir(@"%LocalAppData%\Programs\ILSpy", new InstallDir(@"%LocalAppData%\Programs\ILSpy",

2
ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj

@ -3,7 +3,7 @@
<PropertyGroup> <PropertyGroup>
<AssemblyName>ILSpy.ReadyToRun.Plugin</AssemblyName> <AssemblyName>ILSpy.ReadyToRun.Plugin</AssemblyName>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers> <RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo> <GenerateAssemblyInfo>False</GenerateAssemblyInfo>
<NeutralResourcesLanguage>en-US</NeutralResourcesLanguage> <NeutralResourcesLanguage>en-US</NeutralResourcesLanguage>

2
ILSpy.Tests/ILSpy.Tests.csproj

@ -2,7 +2,7 @@
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<IsPackable>false</IsPackable> <IsPackable>false</IsPackable>
<StartupObject>AutoGeneratedProgram</StartupObject> <StartupObject>AutoGeneratedProgram</StartupObject>

1
ILSpy.sln

@ -41,6 +41,7 @@ Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution
.editorconfig = .editorconfig .editorconfig = .editorconfig
Directory.Build.props = Directory.Build.props Directory.Build.props = Directory.Build.props
Directory.Packages.props = Directory.Packages.props Directory.Packages.props = Directory.Packages.props
global.json = global.json
EndProjectSection EndProjectSection
EndProject EndProject
Global Global

2
ILSpy/ILSpy.csproj

@ -2,7 +2,7 @@
<PropertyGroup> <PropertyGroup>
<OutputType>WinExe</OutputType> <OutputType>WinExe</OutputType>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<RollForward>major</RollForward> <RollForward>major</RollForward>
<RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers> <RuntimeIdentifiers>win-x64;win-arm64</RuntimeIdentifiers>
<GenerateAssemblyInfo>False</GenerateAssemblyInfo> <GenerateAssemblyInfo>False</GenerateAssemblyInfo>

1
ILSpy/Languages/CSharpLanguage.cs

@ -116,6 +116,7 @@ namespace ICSharpCode.ILSpy
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp10_0.ToString(), "C# 10.0 / VS 2022"), new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp10_0.ToString(), "C# 10.0 / VS 2022"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp11_0.ToString(), "C# 11.0 / VS 2022.4"), new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp11_0.ToString(), "C# 11.0 / VS 2022.4"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp12_0.ToString(), "C# 12.0 / VS 2022.8"), new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp12_0.ToString(), "C# 12.0 / VS 2022.8"),
new LanguageVersion(Decompiler.CSharp.LanguageVersion.CSharp13_0.ToString(), "C# 13.0 / VS 2022.12"),
}; };
} }
return versions; return versions;

9
ILSpy/Properties/Resources.Designer.cs generated

@ -918,6 +918,15 @@ namespace ICSharpCode.ILSpy.Properties {
} }
} }
/// <summary>
/// Looks up a localized string similar to Decompile params collections.
/// </summary>
public static string DecompilerSettings_DecompileParamsCollections {
get {
return ResourceManager.GetString("DecompilerSettings.DecompileParamsCollections", resourceCulture);
}
}
/// <summary> /// <summary>
/// Looks up a localized string similar to Decompile use of the &apos;dynamic&apos; type. /// Looks up a localized string similar to Decompile use of the &apos;dynamic&apos; type.
/// </summary> /// </summary>

3
ILSpy/Properties/Resources.resx

@ -327,6 +327,9 @@ Are you sure you want to continue?</value>
<data name="DecompilerSettings.DecompileForEachWithGetEnumeratorExtension" xml:space="preserve"> <data name="DecompilerSettings.DecompileForEachWithGetEnumeratorExtension" xml:space="preserve">
<value>Decompile foreach statements with GetEnumerator extension methods</value> <value>Decompile foreach statements with GetEnumerator extension methods</value>
</data> </data>
<data name="DecompilerSettings.DecompileParamsCollections" xml:space="preserve">
<value>Decompile params collections</value>
</data>
<data name="DecompilerSettings.DecompileUseOfTheDynamicType" xml:space="preserve"> <data name="DecompilerSettings.DecompileUseOfTheDynamicType" xml:space="preserve">
<value>Decompile use of the 'dynamic' type</value> <value>Decompile use of the 'dynamic' type</value>
</data> </data>

3
ILSpy/Properties/Resources.zh-Hans.resx

@ -315,6 +315,9 @@
<data name="DecompilerSettings.DecompileForEachWithGetEnumeratorExtension" xml:space="preserve"> <data name="DecompilerSettings.DecompileForEachWithGetEnumeratorExtension" xml:space="preserve">
<value>反编译使用 GetEnumerator 扩展方法的 foreach 语句</value> <value>反编译使用 GetEnumerator 扩展方法的 foreach 语句</value>
</data> </data>
<data name="DecompilerSettings.DecompileParamsCollections" xml:space="preserve">
<value />
</data>
<data name="DecompilerSettings.DecompileUseOfTheDynamicType" xml:space="preserve"> <data name="DecompilerSettings.DecompileUseOfTheDynamicType" xml:space="preserve">
<value>反编译 dynamic 类型</value> <value>反编译 dynamic 类型</value>
</data> </data>

2
TestPlugin/TestPlugin.csproj

@ -1,7 +1,7 @@
<?xml version="1.0" encoding="utf-8"?> <?xml version="1.0" encoding="utf-8"?>
<Project Sdk="Microsoft.NET.Sdk"> <Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup> <PropertyGroup>
<TargetFramework>net8.0-windows</TargetFramework> <TargetFramework>net10.0-windows</TargetFramework>
<AssemblyName>Test.Plugin</AssemblyName> <AssemblyName>Test.Plugin</AssemblyName>
<UseWpf>true</UseWpf> <UseWpf>true</UseWpf>
<EnableWindowsTargeting>true</EnableWindowsTargeting> <EnableWindowsTargeting>true</EnableWindowsTargeting>

2
global.json

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

6
publish.ps1

@ -1,6 +1,6 @@
$output_arm64 = "./ILSpy/bin/Release/net8.0-windows/win-arm64/publish/fwdependent" $output_arm64 = "./ILSpy/bin/Release/net10.0-windows/win-arm64/publish/fwdependent"
$output_x64 = "./ILSpy/bin/Release/net8.0-windows/win-x64/publish/fwdependent" $output_x64 = "./ILSpy/bin/Release/net10.0-windows/win-x64/publish/fwdependent"
$output_x64_selfcontained = "./ILSpy/bin/Release/net8.0-windows/win-x64/publish/selfcontained" $output_x64_selfcontained = "./ILSpy/bin/Release/net10.0-windows/win-x64/publish/selfcontained"
dotnet publish ./ILSpy/ILSpy.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64 dotnet publish ./ILSpy/ILSpy.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64
dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64 dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64

4
publishlocaldev.ps1

@ -1,12 +1,12 @@
# For local development of the VSIX package - build and publish (VS2022 also needs arm64) # For local development of the VSIX package - build and publish (VS2022 also needs arm64)
$output_x64 = "./ILSpy/bin/Release/net8.0-windows/win-x64/publish/fwdependent" $output_x64 = "./ILSpy/bin/Release/net10.0-windows/win-x64/publish/fwdependent"
dotnet publish ./ILSpy/ILSpy.csproj -c Release --no-restore --no-self-contained -r win-x64 -o $output_x64 dotnet publish ./ILSpy/ILSpy.csproj -c Release --no-restore --no-self-contained -r win-x64 -o $output_x64
dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Release --no-restore --no-self-contained -r win-x64 -o $output_x64 dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Release --no-restore --no-self-contained -r win-x64 -o $output_x64
dotnet publish ./ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj -c Release --no-restore --no-self-contained -r win-x64 -o $output_x64 dotnet publish ./ILSpy.BamlDecompiler/ILSpy.BamlDecompiler.csproj -c Release --no-restore --no-self-contained -r win-x64 -o $output_x64
$output_arm64 = "./ILSpy/bin/Release/net8.0-windows/win-arm64/publish/fwdependent" $output_arm64 = "./ILSpy/bin/Release/net10.0-windows/win-arm64/publish/fwdependent"
dotnet publish ./ILSpy/ILSpy.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64 dotnet publish ./ILSpy/ILSpy.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64
dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64 dotnet publish ./ILSpy.ReadyToRun/ILSpy.ReadyToRun.csproj -c Release --no-restore --no-self-contained -r win-arm64 -o $output_arm64

Loading…
Cancel
Save