diff --git a/.github/workflows/build-frontends.yml b/.github/workflows/build-frontends.yml
index 2ebe5fd40..d9abeabe5 100644
--- a/.github/workflows/build-frontends.yml
+++ b/.github/workflows/build-frontends.yml
@@ -6,6 +6,9 @@ on:
pull_request:
branches: [ master, release/** ]
+permissions:
+ contents: read
+
jobs:
build:
runs-on: ubuntu-latest
diff --git a/.github/workflows/build-ilspy.yml b/.github/workflows/build-ilspy.yml
index 10e5d8e9d..d596d8fcb 100644
--- a/.github/workflows/build-ilspy.yml
+++ b/.github/workflows/build-ilspy.yml
@@ -6,8 +6,13 @@ on:
pull_request:
branches: [ master, release/** ]
+permissions:
+ contents: read
+
jobs:
Build:
+ permissions:
+ packages: write # for dotnet nuget push
runs-on: windows-2022
strategy:
fail-fast: false
@@ -30,12 +35,15 @@ jobs:
with:
dotnet-version: '8.0.x'
dotnet-quality: 'ga'
-
+ env:
+ DOTNET_INSTALL_DIR: ${{ runner.temp }}/.dotnet
+ DOTNET_ROOT: ${{ runner.temp }}/.dotnet
+
- name: Add msbuild to PATH
uses: microsoft/setup-msbuild@v2
- name: Install dotnet-format
- run: dotnet tool install -g dotnet-format --version "8.0.453106" --add-source https://pkgs.dev.azure.com/dnceng/public/_packaging/dotnet8/nuget/v3/index.json
+ 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
- name: Get Version
id: version
@@ -150,7 +158,20 @@ jobs:
if: github.ref == 'refs/heads/master' && matrix.configuration == 'release'
run: |
dotnet nuget push "ICSharpCode.ILSpyX\bin\Release\ICSharpCode.ILSpyX*.nupkg" --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}
-
+
+ - name: Upload BamlDecompiler NuGet release build artifacts
+ if: matrix.configuration == 'release'
+ uses: actions/upload-artifact@v4
+ with:
+ name: ICSharpCode.BamlDecompiler NuGet Package (${{ matrix.configuration }})
+ path: ICSharpCode.BamlDecompiler\bin\Release\ICSharpCode.BamlDecompiler*.nupkg
+ if-no-files-found: error
+
+ - name: Publish DecomBamlDecompilerpiler NuGet
+ if: github.ref == 'refs/heads/master' && matrix.configuration == 'release'
+ run: |
+ dotnet nuget push "ICSharpCode.BamlDecompiler\bin\Release\ICSharpCode.BamlDecompiler*.nupkg" --api-key ${{ secrets.GITHUB_TOKEN }} --source https://nuget.pkg.github.com/${{ github.repository_owner }}
+
- name: Upload zip binaries build artifacts
uses: actions/upload-artifact@v4
with:
diff --git a/.github/workflows/codeql-analysis.yml b/.github/workflows/codeql-analysis.yml
index 1886a05af..f7cd2250c 100644
--- a/.github/workflows/codeql-analysis.yml
+++ b/.github/workflows/codeql-analysis.yml
@@ -6,8 +6,15 @@ on:
pull_request:
branches: [ master, release/** ]
+permissions:
+ contents: read
+
jobs:
analyze:
+ permissions:
+ actions: read # for github/codeql-action/init to get workflow details
+ security-events: write # for github/codeql-action/analyze to upload SARIF results
+
name: Analyze
runs-on: ubuntu-latest
diff --git a/.github/workflows/generate-bom.yml b/.github/workflows/generate-bom.yml
index 5cfafea63..44cf80453 100644
--- a/.github/workflows/generate-bom.yml
+++ b/.github/workflows/generate-bom.yml
@@ -3,6 +3,9 @@ name: Generate BOM
on:
workflow_dispatch:
+permissions:
+ contents: read
+
jobs:
build:
diff --git a/.github/workflows/lock.yml b/.github/workflows/lock.yml
index 3bc404b70..4ef571260 100644
--- a/.github/workflows/lock.yml
+++ b/.github/workflows/lock.yml
@@ -4,8 +4,13 @@ on:
schedule:
- cron: '0 0 * * *'
+permissions:
+ contents: read
+
jobs:
lock:
+ permissions:
+ issues: write # for dessant/lock-threads to lock issues
runs-on: ubuntu-latest
steps:
- uses: dessant/lock-threads@v5.0.1
diff --git a/.github/workflows/scorecard.yml b/.github/workflows/scorecard.yml
new file mode 100644
index 000000000..1ba02149a
--- /dev/null
+++ b/.github/workflows/scorecard.yml
@@ -0,0 +1,47 @@
+name: Scorecard supply-chain security
+on:
+ # For Branch-Protection check. Only the default branch is supported. See
+ # https://github.com/ossf/scorecard/blob/main/docs/checks.md#branch-protection (disabled)
+ # branch_protection_rule:
+ workflow_dispatch:
+
+ # schedule ("Maintained") and push are disabled atm
+ # schedule:
+ # - cron: '25 1 * * 2'
+ # push:
+ # branches: [ "master" ]
+
+permissions: read-all
+
+jobs:
+ analysis:
+ name: Scorecard analysis
+ runs-on: ubuntu-latest
+ permissions:
+ security-events: write # Needed to upload the results to code-scanning dashboard.
+ id-token: write # Needed to publish results and get a badge (see publish_results below).
+
+ steps:
+ - name: "Checkout code"
+ uses: actions/checkout@b4ffde65f46336ab88eb53be808477a3936bae11 # v4.1.1
+ with:
+ persist-credentials: false
+
+ - name: "Run analysis"
+ uses: ossf/scorecard-action@0864cf19026789058feabb7e87baa5f140aac736 # v2.3.1
+ with:
+ results_file: results.sarif
+ results_format: sarif
+ publish_results: true
+
+ - name: "Upload artifact"
+ uses: actions/upload-artifact@97a0fba1372883ab732affbe8f94b823f91727db # v3.pre.node20
+ with:
+ name: SARIF file
+ path: results.sarif
+ retention-days: 5
+
+ - name: "Upload to code-scanning"
+ uses: github/codeql-action/upload-sarif@v3
+ with:
+ sarif_file: results.sarif
diff --git a/BuildTools/pre-commit b/BuildTools/pre-commit
index eee675c87..1067d5581 100644
--- a/BuildTools/pre-commit
+++ b/BuildTools/pre-commit
@@ -5,7 +5,7 @@
set -eu
-DOTNET_FORMAT_VERSION=8.0.453106
+DOTNET_FORMAT_VERSION=8.3.546805
DOTNET_PATH="$LOCALAPPDATA/ICSharpCode/ILSpy/dotnet-format-$DOTNET_FORMAT_VERSION"
if [ ! -d "$DOTNET_PATH" ]; then
echo "Downloading dotnet-format $DOTNET_FORMAT_VERSION..."
diff --git a/Directory.Packages.props b/Directory.Packages.props
index 054032035..5c5711fea 100644
--- a/Directory.Packages.props
+++ b/Directory.Packages.props
@@ -5,19 +5,19 @@
-
+
-
-
+
+
-
+
-
-
+
+
@@ -25,32 +25,35 @@
-
-
-
+
+
+
-
+
-
+
-
+
-
-
-
-
-
-
-
+
+
+
+
+
+
+
-
-
-
+
+
+
+
+
+
-
+
\ No newline at end of file
diff --git a/ICSharpCode.BamlDecompiler/ICSharpCode.BamlDecompiler.csproj b/ICSharpCode.BamlDecompiler/ICSharpCode.BamlDecompiler.csproj
index cd022af4b..d054a6512 100644
--- a/ICSharpCode.BamlDecompiler/ICSharpCode.BamlDecompiler.csproj
+++ b/ICSharpCode.BamlDecompiler/ICSharpCode.BamlDecompiler.csproj
@@ -41,6 +41,12 @@
+
+
+ true
+ true
+
+
diff --git a/ICSharpCode.BamlDecompiler/packages.lock.json b/ICSharpCode.BamlDecompiler/packages.lock.json
new file mode 100644
index 000000000..2fe6f64a0
--- /dev/null
+++ b/ICSharpCode.BamlDecompiler/packages.lock.json
@@ -0,0 +1,44 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net8.0": {
+ "TomsToolbox.Composition.Analyzer": {
+ "type": "Direct",
+ "requested": "[2.21.0, )",
+ "resolved": "2.21.0",
+ "contentHash": "vJx9hxAzjni34slGz78ewqYP9Ylk8dJszfEUK1TF5cflVKMBO3ORSFd0FtICTwJtE8munvZrMrcLWwXt5bIcEA=="
+ },
+ "icsharpcode.decompiler": {
+ "type": "Project",
+ "dependencies": {
+ "System.Collections.Immutable": "[6.0.0, )",
+ "System.Reflection.Metadata": "[6.0.0, )"
+ }
+ },
+ "System.Collections.Immutable": {
+ "type": "CentralTransitive",
+ "requested": "[9.0.0, )",
+ "resolved": "6.0.0",
+ "contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==",
+ "dependencies": {
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "System.Reflection.Metadata": {
+ "type": "CentralTransitive",
+ "requested": "[9.0.0, )",
+ "resolved": "6.0.0",
+ "contentHash": "sffDOcex1C3HO5kDolOYcWXTwRpZY/LvJujM6SMjn63fWMJWchYAAmkoAJXlbpZ5yf4d+KMgxd+LeETa4gD9sQ==",
+ "dependencies": {
+ "System.Collections.Immutable": "6.0.0"
+ }
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "CentralTransitive",
+ "requested": "[6.1.0, )",
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
index 2b877d110..a0901f255 100644
--- a/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/CorrectnessTestRunner.cs
@@ -409,7 +409,7 @@ namespace ICSharpCode.Decompiler.Tests
options |= CompilerOptions.UseTestRunner;
string testFileName = testName + ".cs";
string testOutputFileName = TestsAssemblyOutput.GetFilePath(TestCasePath, testName, Tester.GetSuffix(options) + ".exe");
- CompilerResults outputFile = null, decompiledOutputFile = null;
+ Helpers.CompilerResults outputFile = null, decompiledOutputFile = null;
try
{
@@ -453,7 +453,7 @@ namespace ICSharpCode.Decompiler.Tests
options |= CompilerOptions.UseTestRunner;
string testFileName = testName + ".vb";
string testOutputFileName = TestsAssemblyOutput.GetFilePath(TestCasePath, testName, Tester.GetSuffix(options) + ".exe");
- CompilerResults outputFile = null, decompiledOutputFile = null;
+ Helpers.CompilerResults outputFile = null, decompiledOutputFile = null;
try
{
@@ -477,7 +477,7 @@ namespace ICSharpCode.Decompiler.Tests
async Task RunIL(string testFileName, CompilerOptions options = CompilerOptions.UseDebug, AssemblerOptions asmOptions = AssemblerOptions.None)
{
string outputFile = null;
- CompilerResults decompiledOutputFile = null;
+ Helpers.CompilerResults decompiledOutputFile = null;
bool optionsForce32Bit = options.HasFlag(CompilerOptions.Force32Bit);
bool asmOptionsForce32Bit = asmOptions.HasFlag(AssemblerOptions.Force32Bit);
diff --git a/ICSharpCode.Decompiler.Tests/ProjectDecompiler/TargetFrameworkTests.cs b/ICSharpCode.Decompiler.Tests/ProjectDecompiler/TargetFrameworkTests.cs
index df78e9bc1..1a9557c77 100644
--- a/ICSharpCode.Decompiler.Tests/ProjectDecompiler/TargetFrameworkTests.cs
+++ b/ICSharpCode.Decompiler.Tests/ProjectDecompiler/TargetFrameworkTests.cs
@@ -19,6 +19,7 @@
using System;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
+using ICSharpCode.Decompiler.Metadata;
using NUnit.Framework;
@@ -119,5 +120,14 @@ namespace ICSharpCode.Decompiler.Tests
// Assert
Assert.That(targetFramework.Moniker, Is.EqualTo(expectedMoniker));
}
+
+ [TestCase(".NETCoreApp, Version=v5.0", TargetFrameworkIdentifier.NET, "5.0.0")]
+ [TestCase(".NETCoreApp, Version=v10.0", TargetFrameworkIdentifier.NET, "10.0.0")]
+ public void VerifyUniversalAssemblyResolverParseTargetFramework(string targetFramework, TargetFrameworkIdentifier identifier, string version)
+ {
+ var (id, v) = UniversalAssemblyResolver.ParseTargetFramework(targetFramework);
+ Assert.That(id, Is.EqualTo(identifier));
+ Assert.That(v.ToString(3), Is.EqualTo(version));
+ }
}
}
diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
index 856c02028..f5647187f 100644
--- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
+++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs
@@ -67,6 +67,76 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
+ public class ImplicitInt
+ {
+ private readonly int s;
+
+ public ImplicitInt(int s)
+ {
+ this.s = s;
+ }
+
+ public static implicit operator int(ImplicitInt v)
+ {
+ return v.s;
+ }
+ }
+
+ public class ImplicitConversionConflictWithLong
+ {
+ private readonly int s;
+
+ public ImplicitConversionConflictWithLong(int s)
+ {
+ this.s = s;
+ }
+
+ public static implicit operator int(ImplicitConversionConflictWithLong v)
+ {
+ return v.s;
+ }
+
+ public static implicit operator long(ImplicitConversionConflictWithLong v)
+ {
+ return v.s;
+ }
+ }
+
+ public class ImplicitConversionConflictWithString
+ {
+ private readonly int s;
+
+ public ImplicitConversionConflictWithString(int s)
+ {
+ this.s = s;
+ }
+
+ public static implicit operator int(ImplicitConversionConflictWithString v)
+ {
+ return v.s;
+ }
+
+ public static implicit operator string(ImplicitConversionConflictWithString v)
+ {
+ return string.Empty;
+ }
+ }
+
+ public class ExplicitInt
+ {
+ private readonly int s;
+
+ public ExplicitInt(int s)
+ {
+ this.s = s;
+ }
+
+ public static explicit operator int(ExplicitInt v)
+ {
+ return v.s;
+ }
+ }
+
public enum State
{
False,
@@ -310,6 +380,118 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
}
}
+ public static void SwitchOverExplicitInt(ExplicitInt i)
+ {
+ switch ((int)i)
+ {
+ case 0:
+ Console.WriteLine("zero");
+ break;
+ case 5:
+ Console.WriteLine("five");
+ break;
+ case 10:
+ Console.WriteLine("ten");
+ break;
+ case 15:
+ Console.WriteLine("fifteen");
+ break;
+ case 20:
+ Console.WriteLine("twenty");
+ break;
+ case 25:
+ Console.WriteLine("twenty-five");
+ break;
+ case 30:
+ Console.WriteLine("thirty");
+ break;
+ }
+ }
+
+ public static void SwitchOverImplicitInt(ImplicitInt i)
+ {
+ switch (i)
+ {
+ case 0:
+ Console.WriteLine("zero");
+ break;
+ case 5:
+ Console.WriteLine("five");
+ break;
+ case 10:
+ Console.WriteLine("ten");
+ break;
+ case 15:
+ Console.WriteLine("fifteen");
+ break;
+ case 20:
+ Console.WriteLine("twenty");
+ break;
+ case 25:
+ Console.WriteLine("twenty-five");
+ break;
+ case 30:
+ Console.WriteLine("thirty");
+ break;
+ }
+ }
+
+ public static void SwitchOverImplicitIntConflictLong(ImplicitConversionConflictWithLong i)
+ {
+ switch ((int)i)
+ {
+ case 0:
+ Console.WriteLine("zero");
+ break;
+ case 5:
+ Console.WriteLine("five");
+ break;
+ case 10:
+ Console.WriteLine("ten");
+ break;
+ case 15:
+ Console.WriteLine("fifteen");
+ break;
+ case 20:
+ Console.WriteLine("twenty");
+ break;
+ case 25:
+ Console.WriteLine("twenty-five");
+ break;
+ case 30:
+ Console.WriteLine("thirty");
+ break;
+ }
+ }
+
+ public static void SwitchOverImplicitIntConflictString(ImplicitConversionConflictWithString i)
+ {
+ switch ((string)i)
+ {
+ case "0":
+ Console.WriteLine("zero");
+ break;
+ case "5":
+ Console.WriteLine("five");
+ break;
+ case "10":
+ Console.WriteLine("ten");
+ break;
+ case "15":
+ Console.WriteLine("fifteen");
+ break;
+ case "20":
+ Console.WriteLine("twenty");
+ break;
+ case "25":
+ Console.WriteLine("twenty-five");
+ break;
+ case "30":
+ Console.WriteLine("thirty");
+ break;
+ }
+ }
+
// SwitchDetection.UseCSharpSwitch requires more complex heuristic to identify this when compiled with Roslyn
public static void CompactSwitchOverInt(int i)
{
@@ -421,9 +603,7 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty
public static string SwitchOverImplicitString(ImplicitString s)
{
- // we emit an explicit cast, because the rules used by the C# compiler are counter-intuitive:
- // The C# compiler does *not* take the type of the switch labels into account at all.
- switch ((string)s)
+ switch (s)
{
case "First case":
return "Text1";
diff --git a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs
index 620424ca8..bc60f38c9 100644
--- a/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs
+++ b/ICSharpCode.Decompiler.Tests/UglyTestRunner.cs
@@ -146,7 +146,7 @@ namespace ICSharpCode.Decompiler.Tests
if (!File.Exists(ilFile))
{
// re-create .il file if necessary
- CompilerResults output = null;
+ Helpers.CompilerResults output = null;
try
{
output = await Tester.CompileCSharp(csFile, cscOptions).ConfigureAwait(false);
diff --git a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
index 520619787..7147785de 100644
--- a/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
+++ b/ICSharpCode.Decompiler/CSharp/CSharpDecompiler.cs
@@ -521,7 +521,7 @@ namespace ICSharpCode.Decompiler.CSharp
file.DetectTargetFrameworkId(), file.DetectRuntimePack(),
settings.LoadInMemory ? PEStreamOptions.PrefetchMetadata : PEStreamOptions.Default,
settings.ApplyWindowsRuntimeProjections ? MetadataReaderOptions.ApplyWindowsRuntimeProjections : MetadataReaderOptions.None);
- return new DecompilerTypeSystem(file, resolver);
+ return new DecompilerTypeSystem(file, resolver, settings);
}
static TypeSystemAstBuilder CreateAstBuilder(DecompilerSettings settings)
diff --git a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
index 635d32871..2b32f842b 100644
--- a/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs
@@ -3900,31 +3900,94 @@ namespace ICSharpCode.Decompiler.CSharp
}
}
- protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context)
+ internal (TranslatedExpression, IType, StringToInt) TranslateSwitchValue(SwitchInstruction inst, bool isExpressionContext)
{
TranslatedExpression value;
IType type;
+ // prepare expression and expected type
if (inst.Value is StringToInt strToInt)
{
- value = Translate(strToInt.Argument)
- .ConvertTo(
- strToInt.ExpectedType,
- this,
- allowImplicitConversion: false // switch-expression does not support implicit conversions
- );
- type = compilation.FindType(KnownTypeCode.String);
+ value = Translate(strToInt.Argument);
+ type = strToInt.ExpectedType ?? compilation.FindType(KnownTypeCode.String);
}
else
{
strToInt = null;
value = Translate(inst.Value);
- if (inst.Type != null)
+ type = inst.Type ?? value.Type;
+ }
+
+ // find and unwrap the input type
+ IType inputType = value.Type;
+ if (value.Expression is CastExpression && value.ResolveResult is ConversionResolveResult crr)
+ {
+ inputType = crr.Input.Type;
+ }
+ inputType = NullableType.GetUnderlyingType(inputType).GetEnumUnderlyingType();
+
+ // check input/underlying type for compatibility
+ bool allowImplicitConversion;
+ if (IsCompatibleWithSwitch(inputType) || (strToInt != null && inputType.Equals(type)))
+ {
+ allowImplicitConversion = !isExpressionContext;
+ }
+ else
+ {
+ var applicableImplicitConversionOperators = inputType.GetMethods(IsCompatibleImplicitConversionOperator).ToArray();
+ switch (applicableImplicitConversionOperators.Length)
{
- value = value.ConvertTo(inst.Type, this, allowImplicitConversion: true);
+ case 0:
+ allowImplicitConversion = !isExpressionContext;
+ break;
+ case 1:
+ allowImplicitConversion = !isExpressionContext;
+ // TODO validate
+ break;
+ default:
+ allowImplicitConversion = false;
+ break;
}
- type = value.Type;
}
+ value = value.ConvertTo(type, this, allowImplicitConversion: allowImplicitConversion);
+
+ var caseType = strToInt != null
+ ? compilation.FindType(KnownTypeCode.String)
+ : type;
+
+ return (value, caseType, strToInt);
+
+ static bool IsCompatibleWithSwitch(IType type)
+ {
+ return type.IsKnownType(KnownTypeCode.SByte)
+ || type.IsKnownType(KnownTypeCode.Byte)
+ || type.IsKnownType(KnownTypeCode.Int16)
+ || type.IsKnownType(KnownTypeCode.UInt16)
+ || type.IsKnownType(KnownTypeCode.Int32)
+ || type.IsKnownType(KnownTypeCode.UInt32)
+ || type.IsKnownType(KnownTypeCode.Int64)
+ || type.IsKnownType(KnownTypeCode.UInt64)
+ || type.IsKnownType(KnownTypeCode.Char)
+ || type.IsKnownType(KnownTypeCode.String);
+ }
+
+ bool IsCompatibleImplicitConversionOperator(IMethod operatorMethod)
+ {
+ if (!operatorMethod.IsOperator)
+ return false;
+ if (operatorMethod.Name != "op_Implicit")
+ return false;
+ if (operatorMethod.Parameters.Count != 1)
+ return false;
+ return IsCompatibleWithSwitch(operatorMethod.ReturnType);
+ }
+ }
+
+ protected internal override TranslatedExpression VisitSwitchInstruction(SwitchInstruction inst, TranslationContext context)
+ {
+ // switch-expression does not support implicit conversions
+ var (value, type, strToInt) = TranslateSwitchValue(inst, true);
+
IL.SwitchSection defaultSection = inst.GetDefaultSection();
SwitchExpression switchExpr = new SwitchExpression();
switchExpr.Expression = value;
diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
index 4dfc5f658..094a51355 100644
--- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
+++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs
@@ -210,30 +210,7 @@ namespace ICSharpCode.Decompiler.CSharp
var oldCaseLabelMapping = caseLabelMapping;
caseLabelMapping = new Dictionary();
- TranslatedExpression value;
- IType type;
- if (inst.Value is StringToInt strToInt)
- {
- value = exprBuilder.Translate(strToInt.Argument)
- .ConvertTo(
- strToInt.ExpectedType,
- exprBuilder,
- // switch statement does support implicit conversions in general, however, the rules are
- // not very intuitive and in order to prevent bugs, we emit an explicit cast.
- allowImplicitConversion: false
- );
- type = exprBuilder.compilation.FindType(KnownTypeCode.String);
- }
- else
- {
- strToInt = null;
- value = exprBuilder.Translate(inst.Value);
- if (inst.Type != null)
- {
- value = value.ConvertTo(inst.Type, exprBuilder, allowImplicitConversion: true);
- }
- type = value.Type;
- }
+ var (value, type, strToInt) = exprBuilder.TranslateSwitchValue(inst, false);
IL.SwitchSection defaultSection = inst.GetDefaultSection();
diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 1abe4653e..d45e054ca 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -48,6 +48,12 @@
+
+
+
+ true
+ true
+
True
diff --git a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
index e254d243b..8302038b8 100644
--- a/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
+++ b/ICSharpCode.Decompiler/IL/Transforms/SwitchOnStringTransform.cs
@@ -1070,10 +1070,12 @@ namespace ICSharpCode.Decompiler.IL.Transforms
stringValues.Add((null, nullValueCaseBlock));
}
// In newer Roslyn versions (>=3.7) the null check appears in the default case, not prior to the switch.
- if (!stringValues.Any(pair => pair.Value == null) && IsNullCheckInDefaultBlock(ref exitOrDefaultBlock, switchValueLoad.Variable, out nullValueCaseBlock))
+ ILInstruction exitOrDefault = exitOrDefaultBlock;
+ if (!stringValues.Any(pair => pair.Value == null) && IsNullCheckInDefaultBlock(ref exitOrDefault, switchValueLoad.Variable, out nullValueCaseBlock))
{
stringValues.Add((null, nullValueCaseBlock));
}
+ exitOrDefaultBlock = (Block)exitOrDefault;
context.Step(nameof(MatchRoslynSwitchOnString), switchValueLoad);
if (exitOrDefaultBlock != null)
@@ -1176,7 +1178,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
if (!instructions[i + 1].MatchBranch(out var nextBlock))
return false;
- if (!exitBlockJump.MatchBranch(out nullCase))
+ if (!exitBlockJump.MatchBranch(out nullCase) && !exitBlockJump.MatchLeave(out _))
return false;
// if (comp(ldloc switchValueVar == ldnull)) br ...
// br switchOnLengthBlock
@@ -1202,7 +1204,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
switchValueVar = null; // will be extracted in MatchSwitchOnLengthBlock
switchOnLengthBlockStartOffset = i;
}
- Block defaultCase = null;
+ ILInstruction defaultCase = null;
if (!MatchSwitchOnLengthBlock(ref switchValueVar, switchOnLengthBlock, switchOnLengthBlockStartOffset, out var blocksByLength))
return false;
List<(string, ILInstruction)> stringValues = new();
@@ -1216,41 +1218,51 @@ namespace ICSharpCode.Decompiler.IL.Transforms
else
{
int length = (int)b.Length.Intervals[0].Start;
- if (MatchSwitchOnCharBlock(b.TargetBlock, length, switchValueVar, out var mapping))
+ switch (b.TargetBlock)
{
- foreach (var item in mapping)
- {
- if (!stringValues.Any(x => x.Item1 == item.StringValue))
+ case Leave leave:
+ break;
+ case Block targetBlock:
+ if (MatchSwitchOnCharBlock(targetBlock, length, switchValueVar, out var mapping))
+ {
+ foreach (var item in mapping)
+ {
+ if (!stringValues.Any(x => x.Item1 == item.StringValue))
+ {
+ stringValues.Add(item);
+ }
+ else
+ {
+ return false;
+ }
+ }
+ }
+ else if (MatchRoslynCaseBlockHead(targetBlock, switchValueVar, out var bodyOrLeave, out var exit, out string stringValue, out _))
+ {
+ if (exit != defaultCase)
+ return false;
+ if (!stringValues.Any(x => x.Item1 == stringValue))
+ {
+ stringValues.Add((stringValue, bodyOrLeave));
+ }
+ else
+ {
+ return false;
+ }
+ }
+ else if (length == 0)
{
- stringValues.Add(item);
+ stringValues.Add(("", b.TargetBlock));
}
else
{
return false;
}
- }
- }
- else if (MatchRoslynCaseBlockHead(b.TargetBlock, switchValueVar, out var bodyOrLeave, out var exit, out string stringValue, out _))
- {
- if (exit != defaultCase)
+ break;
+ default:
return false;
- if (!stringValues.Any(x => x.Item1 == stringValue))
- {
- stringValues.Add((stringValue, bodyOrLeave));
- }
- else
- {
- return false;
- }
- }
- else if (length == 0)
- {
- stringValues.Add(("", b.TargetBlock));
- }
- else
- {
- return false;
}
+
}
}
@@ -1278,7 +1290,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
var newSwitch = new SwitchInstruction(new StringToInt(new LdLoc(switchValueVar), values, switchValueVar.Type));
newSwitch.Sections.AddRange(sections);
- newSwitch.Sections.Add(new SwitchSection { Labels = defaultLabel, Body = new Branch(defaultCase) });
+ newSwitch.Sections.Add(new SwitchSection { Labels = defaultLabel, Body = defaultCase is Block b2 ? new Branch(b2) : defaultCase });
newSwitch.AddILRange(instructions[i]);
if (nullCase != null)
{
@@ -1399,7 +1411,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return results?.Count > 0;
}
- bool MatchSwitchOnLengthBlock(ref ILVariable switchValueVar, Block switchOnLengthBlock, int startOffset, out List<(LongSet Length, Block TargetBlock)> blocks)
+ bool MatchSwitchOnLengthBlock(ref ILVariable switchValueVar, Block switchOnLengthBlock, int startOffset, out List<(LongSet Length, ILInstruction TargetBlock)> blocks)
{
blocks = null;
SwitchInstruction @switch;
@@ -1482,17 +1494,18 @@ namespace ICSharpCode.Decompiler.IL.Transforms
{
if (section.HasNullLabel)
return false;
- if (!section.Body.MatchBranch(out var target))
+ if (!section.Body.MatchBranch(out var target) && !section.Body.MatchLeave(out _))
return false;
+ ILInstruction targetInst = target ?? section.Body;
if (section.Labels.Count() != 1)
{
- defaultCase ??= target;
- if (defaultCase != target)
+ defaultCase ??= targetInst;
+ if (defaultCase != targetInst)
return false;
}
else
{
- blocks.Add((section.Labels, target));
+ blocks.Add((section.Labels, targetInst));
}
}
return true;
@@ -1506,10 +1519,10 @@ namespace ICSharpCode.Decompiler.IL.Transforms
/// br newDefaultBlock
/// }
///
- private bool IsNullCheckInDefaultBlock(ref Block exitOrDefaultBlock, ILVariable switchVar, out Block nullValueCaseBlock)
+ private bool IsNullCheckInDefaultBlock(ref ILInstruction exitOrDefault, ILVariable switchVar, out Block nullValueCaseBlock)
{
nullValueCaseBlock = null;
- if (exitOrDefaultBlock == null)
+ if (exitOrDefault is not Block exitOrDefaultBlock)
return false;
if (!exitOrDefaultBlock.Instructions[0].MatchIfInstruction(out var condition, out var thenBranch))
return false;
@@ -1523,7 +1536,7 @@ namespace ICSharpCode.Decompiler.IL.Transforms
return false;
if (elseBlock.Parent != exitOrDefaultBlock.Parent)
return false;
- exitOrDefaultBlock = elseBlock;
+ exitOrDefault = elseBlock;
return true;
}
diff --git a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
index 90ba8724a..ffd6d700d 100644
--- a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
+++ b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
@@ -189,15 +189,16 @@ namespace ICSharpCode.Decompiler.Metadata
switch (pair[0].Trim().ToUpperInvariant())
{
case "VERSION":
- var versionString = pair[1].TrimStart('v', ' ', '\t');
- if (identifier == TargetFrameworkIdentifier.NETCoreApp ||
- identifier == TargetFrameworkIdentifier.NETStandard)
- {
- if (versionString.Length == 3)
- versionString += ".0";
- }
+ var versionString = pair[1].TrimStart('v', 'V', ' ', '\t');
+
if (!Version.TryParse(versionString, out version))
+ {
version = null;
+ }
+ else
+ {
+ version = new Version(version.Major, version.Minor, version.Build < 0 ? 0 : version.Build);
+ }
// .NET 5 or greater still use ".NETCOREAPP" as TargetFrameworkAttribute value...
if (version?.Major >= 5 && identifier == TargetFrameworkIdentifier.NETCoreApp)
identifier = TargetFrameworkIdentifier.NET;
diff --git a/ICSharpCode.Decompiler/Properties/DecompilerVersionInfo.template.cs b/ICSharpCode.Decompiler/Properties/DecompilerVersionInfo.template.cs
index 947188ef1..8810b7e16 100644
--- a/ICSharpCode.Decompiler/Properties/DecompilerVersionInfo.template.cs
+++ b/ICSharpCode.Decompiler/Properties/DecompilerVersionInfo.template.cs
@@ -4,7 +4,7 @@
public const string Minor = "0";
public const string Build = "0";
public const string Revision = "$INSERTREVISION$";
- public const string VersionName = "preview3";
+ public const string VersionName = "RC";
public const string FullVersion = Major + "." + Minor + "." + Build + ".$INSERTREVISION$$INSERTBRANCHPOSTFIX$$INSERTVERSIONNAMEPOSTFIX$";
public const string FullVersionWithShortCommitHash = FullVersion + "+$INSERTSHORTCOMMITHASH$";
diff --git a/ICSharpCode.Decompiler/packages.lock.json b/ICSharpCode.Decompiler/packages.lock.json
new file mode 100644
index 000000000..c6e34ae99
--- /dev/null
+++ b/ICSharpCode.Decompiler/packages.lock.json
@@ -0,0 +1,91 @@
+{
+ "version": 1,
+ "dependencies": {
+ ".NETStandard,Version=v2.0": {
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "NETStandard.Library": {
+ "type": "Direct",
+ "requested": "[2.0.3, )",
+ "resolved": "2.0.3",
+ "contentHash": "st47PosZSHrjECdjeIzZQbzivYBJFv6P2nv4cj2ypdI204DO+vZ7l5raGMiX4eXMJ53RfOIg+/s4DHVZ54Nu2A==",
+ "dependencies": {
+ "Microsoft.NETCore.Platforms": "1.1.0"
+ }
+ },
+ "System.Collections.Immutable": {
+ "type": "Direct",
+ "requested": "[6.0.0, )",
+ "resolved": "6.0.0",
+ "contentHash": "l4zZJ1WU2hqpQQHXz1rvC3etVZN+2DLmQMO79FhOTZHMn8tDRr+WU287sbomD0BETlmKDn0ygUgVy9k5xkkJdA==",
+ "dependencies": {
+ "System.Memory": "4.5.4",
+ "System.Runtime.CompilerServices.Unsafe": "6.0.0"
+ }
+ },
+ "System.Reflection.Metadata": {
+ "type": "Direct",
+ "requested": "[6.0.0, )",
+ "resolved": "6.0.0",
+ "contentHash": "sffDOcex1C3HO5kDolOYcWXTwRpZY/LvJujM6SMjn63fWMJWchYAAmkoAJXlbpZ5yf4d+KMgxd+LeETa4gD9sQ==",
+ "dependencies": {
+ "System.Collections.Immutable": "6.0.0"
+ }
+ },
+ "TunnelVisionLabs.ReferenceAssemblyAnnotator": {
+ "type": "Direct",
+ "requested": "[1.0.0-alpha.160, )",
+ "resolved": "1.0.0-alpha.160",
+ "contentHash": "ktxB8PGoPpIaYKjLk/+P94Fi2Qw2E1Dw7atBQRrKnHA57sk8WwmkI4RJmg6s5ph4k1RIaaAZMus05ah/AikEkA=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.NETCore.Platforms": {
+ "type": "Transitive",
+ "resolved": "1.1.0",
+ "contentHash": "kz0PEW2lhqygehI/d6XsPCQzD7ff7gUJaVGPVETX611eadGsA3A877GdSlU0LRVMCTH/+P3o2iDTak+S08V2+A=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ },
+ "System.Buffers": {
+ "type": "Transitive",
+ "resolved": "4.5.1",
+ "contentHash": "Rw7ijyl1qqRS0YQD/WycNst8hUUMgrMH4FCn1nNm27M4VxchZ1js3fVjQaANHO5f3sN4isvP4a+Met9Y4YomAg=="
+ },
+ "System.Memory": {
+ "type": "Transitive",
+ "resolved": "4.5.4",
+ "contentHash": "1MbJTHS1lZ4bS4FmsJjnuGJOu88ZzTT2rLvrhW7Ygic+pC0NWA+3hgAen0HRdsocuQXCkUTdFn9yHJJhsijDXw==",
+ "dependencies": {
+ "System.Buffers": "4.5.1",
+ "System.Numerics.Vectors": "4.4.0",
+ "System.Runtime.CompilerServices.Unsafe": "4.5.3"
+ }
+ },
+ "System.Numerics.Vectors": {
+ "type": "Transitive",
+ "resolved": "4.4.0",
+ "contentHash": "UiLzLW+Lw6HLed1Hcg+8jSRttrbuXv7DANVj0DkL9g6EnnzbL75EB7EWsw5uRbhxd/4YdG8li5XizGWepmG3PQ=="
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Transitive",
+ "resolved": "6.0.0",
+ "contentHash": "/iUeP3tq1S0XdNNoMz5C9twLSrM/TH+qElHkXWaPvuNOt+99G75NrV0OS2EqHx5wMN7popYjpc8oTjC1y16DLg=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj b/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj
index ca25d2eef..aba229ad0 100644
--- a/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj
+++ b/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj
@@ -31,6 +31,12 @@
+
+
+
+ true
+ true
+
false
diff --git a/ICSharpCode.ILSpyCmd/packages.lock.json b/ICSharpCode.ILSpyCmd/packages.lock.json
new file mode 100644
index 000000000..0ffdf6bd2
--- /dev/null
+++ b/ICSharpCode.ILSpyCmd/packages.lock.json
@@ -0,0 +1,453 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net8.0": {
+ "McMaster.Extensions.Hosting.CommandLine": {
+ "type": "Direct",
+ "requested": "[4.1.1, )",
+ "resolved": "4.1.1",
+ "contentHash": "+a37L3hHZC2KG1sbwdzTGlUWIJWYQv/9I4dLnrC0OVusR/665hkewjlz1jiAKa8jYbve4GTSZsRCoVXcSFFrdA==",
+ "dependencies": {
+ "McMaster.Extensions.CommandLineUtils": "4.1.1",
+ "Microsoft.Extensions.Hosting.Abstractions": "6.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "6.0.0"
+ }
+ },
+ "Microsoft.Extensions.Hosting": {
+ "type": "Direct",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "bP9EEkHBEfjgYiG8nUaXqMk/ujwJrffOkNPP7onpRMO8R+OUSESSP4xHkCAXgYZ1COP2Q9lXlU5gkMFh20gRuw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.Binder": "8.0.2",
+ "Microsoft.Extensions.Configuration.CommandLine": "8.0.0",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "8.0.0",
+ "Microsoft.Extensions.Configuration.FileExtensions": "8.0.1",
+ "Microsoft.Extensions.Configuration.Json": "8.0.1",
+ "Microsoft.Extensions.Configuration.UserSecrets": "8.0.1",
+ "Microsoft.Extensions.DependencyInjection": "8.0.1",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics": "8.0.1",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Physical": "8.0.0",
+ "Microsoft.Extensions.Hosting.Abstractions": "8.0.1",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging.Configuration": "8.0.1",
+ "Microsoft.Extensions.Logging.Console": "8.0.1",
+ "Microsoft.Extensions.Logging.Debug": "8.0.1",
+ "Microsoft.Extensions.Logging.EventLog": "8.0.1",
+ "Microsoft.Extensions.Logging.EventSource": "8.0.1",
+ "Microsoft.Extensions.Options": "8.0.2"
+ }
+ },
+ "NuGet.Protocol": {
+ "type": "Direct",
+ "requested": "[6.12.1, )",
+ "resolved": "6.12.1",
+ "contentHash": "VBN7OtG/Y9Rnj1WT3G8X88ZHu5Pq+yzca5Z6OI/FWXcENVAQkUl0ml6Cv8ghOqYyiuvnObGDV9oWLD/bIuVtDw==",
+ "dependencies": {
+ "NuGet.Packaging": "6.12.1"
+ }
+ },
+ "TomsToolbox.Composition.Analyzer": {
+ "type": "Direct",
+ "requested": "[2.21.0, )",
+ "resolved": "2.21.0",
+ "contentHash": "vJx9hxAzjni34slGz78ewqYP9Ylk8dJszfEUK1TF5cflVKMBO3ORSFd0FtICTwJtE8munvZrMrcLWwXt5bIcEA=="
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "3lE/iLSutpgX1CC0NOW70FJoGARRHbyKmG7dc0klnUZ9Dd9hS6N/POPWhKhMLCEuNN5nXEY5agmlFtH562vqhQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "8.0.2",
+ "contentHash": "7IQhGK+wjyGrNsPBjJcZwWAr+Wf6D4+TwOptUt77bWtgNkiV8tDEbhFS+dDamtQFZ2X7kWG9m71iZQRj2x3zgQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.CommandLine": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "NZuZMz3Q8Z780nKX3ifV1fE7lS+6pynDHK71OfU4OZ1ItgvDOhyOC7E6z+JMZrAj63zRpwbdldYFk499t3+1dQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "plvZ0ZIpq+97gdPNNvhwvrEZ92kNml9hd1pe3idMA7svR0PztdzVLkoWLcRFgySYXUJc3kSM3Xw3mNFMo/bxRA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "EJzSNO9oaAXnTdtdNO6npPRsIIeZCBSNmdQ091VDO7fBiOtJAAeEq6dtrVXIi3ZyjC5XRSAtVvF8SzcneRHqKQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Physical": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.UserSecrets": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "7tYqdPPpAK+3jO9d5LTuCK2VxrEdf85Ol4trUr6ds4jclBecadWZ/RyPCbNjfbN5iGTfUnD/h65TOQuqQv2c+A==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.Json": "8.0.1",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileProviders.Physical": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "BmANAnR5Xd4Oqw7yQ75xOAYODybZQRzdeNucg7kS5wWKd2PNnMdYtJ2Vciy0QLylRmv42DGl5+AFL9izA6F1Rw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
+ }
+ },
+ "Microsoft.Extensions.Diagnostics": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "doVPCUUCY7c6LhBsEfiy3W1bvS7Mi6LkfQMS8nlC22jZWNxBv8VO8bdfeyvpYFst6Kxqk7HBC6lytmEoBssvSQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Diagnostics.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "elH2vmwNmsXuKmUeMQ4YW9ldXiF+gSGDgg1vORksob5POnpaI6caj1Hu8zaYbEuibhqCoWg0YRWDazBY3zjBfg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "ZbaMlhJlpisjuWbvXr4LdAst/1XxH3vZ6A0BsgTphZ2L4PGuxRLz7Jr/S7mkAAnOn78Vu0fKhEgNF5JO3zfjqQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "UboiXxpPUpwulHvIAVE36Knq0VSHaAmfrFkegLyBZeaADuKezJ/AIXYAW8F5GBlGk/VaibN2k/Zn1ca8YAfVdA==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.FileSystemGlobbing": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "OK+670i7esqlQrPjdIKRbsyMCe9g5kSLpRRQGSr4Q58AOYEe/hCnfLZprh7viNisSUUQZmMrbbuDaIrP+V1ebQ=="
+ },
+ "Microsoft.Extensions.Hosting.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "nHwq9aPBdBPYXPti6wYEEfgXddfBrYC+CQLn+qISiwQq5tpfaqDZSKOJNxoe9rfQxGf1c+2wC/qWFe1QYJPYqw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "8.0.1",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
+ }
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "4x+pzsQEbqxhNf1QYRr5TDkLP9UsLT3A6MdRKDDEgrW7h1ljiEPgTNhKYUhNCCAaVpQECVQ+onA91PTPnIp6Lw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "8.0.2",
+ "contentHash": "nroMDjS7hNBPtkZqVBbSiQaQjWRDxITI8Y7XnDs97rqG3EbzVTNLZQf7bIeUJcaHOV8bca47s1Uxq94+2oGdxA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2"
+ }
+ },
+ "Microsoft.Extensions.Logging.Configuration": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "QWwTrsgOnJMmn+XUslm8D2H1n3PkP/u/v52FODtyBc/k4W9r3i2vcXXeeX/upnzllJYRRbrzVzT0OclfNJtBJA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.Binder": "8.0.2",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Logging.Console": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "uzcg/5U2eLyn5LIKlERkdSxw6VPC1yydnOSQiRRWGBGN3kphq3iL4emORzrojScDmxRhv49gp5BI8U3Dz7y4iA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging.Configuration": "8.0.1",
+ "Microsoft.Extensions.Options": "8.0.2"
+ }
+ },
+ "Microsoft.Extensions.Logging.Debug": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "B8hqNuYudC2RB+L/DI33uO4rf5by41fZVdcVL2oZj0UyoAZqnwTwYHp1KafoH4nkl1/23piNeybFFASaV2HkFg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2"
+ }
+ },
+ "Microsoft.Extensions.Logging.EventLog": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "ZD1m4GXoxcZeDJIq8qePKj+QAWeQNO/OG8skvrOG8RQfxLp9MAKRoliTc27xanoNUzeqvX5HhS/I7c0BvwAYUg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2",
+ "System.Diagnostics.EventLog": "8.0.1"
+ }
+ },
+ "Microsoft.Extensions.Logging.EventSource": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "YMXMAla6B6sEf/SnfZYTty633Ool3AH7KOw2LOaaEqwSo2piK4f7HMtzyc3CNiipDnq1fsUSuG5Oc7ZzpVy8WQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Logging": "8.0.1",
+ "Microsoft.Extensions.Logging.Abstractions": "8.0.2",
+ "Microsoft.Extensions.Options": "8.0.2",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "8.0.2",
+ "contentHash": "dWGKvhFybsaZpGmzkGCbNNwBD1rVlWzrZKANLW/CcbFJpCEceMCGzT7zZwHOGBCbwM0SzBuceMj5HN1LKV1QqA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "0f4DMRqEd50zQh+UyJc+/HiBsZ3vhAQALgdkcQEalSH1L2isdC7Yj54M3cyo5e+BeO5fcBQ7Dxly8XiBBcvRgw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.Binder": "8.0.0",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Options": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bXJEZrW9ny8vjMF1JV253WeLhpEVzFo1lyaZu1vQ4ZxWUlVvknZ/+ftFgVheLubb4eZPSwwxBeqS1JkCOjxd8g=="
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "NuGet.Common": {
+ "type": "Transitive",
+ "resolved": "6.12.1",
+ "contentHash": "nk8nTdhQl4x2VaAQUvefI7DDYAuBDlE+OZZRffm50Qx5dUAEq8wkc5JIqrN2lTEohObHPI/SXyG2UFdMQkrdyg==",
+ "dependencies": {
+ "NuGet.Frameworks": "6.12.1"
+ }
+ },
+ "NuGet.Configuration": {
+ "type": "Transitive",
+ "resolved": "6.12.1",
+ "contentHash": "IRwlY1379ZgJ0oEJvjD+lDuOhJ5S1fsU5n/bEC5/i0+N9bo2WIMDAdaQ/qIdyK/gMJ/YWS+++GSX6rN7luqEvg==",
+ "dependencies": {
+ "NuGet.Common": "6.12.1",
+ "System.Security.Cryptography.ProtectedData": "4.4.0"
+ }
+ },
+ "NuGet.Frameworks": {
+ "type": "Transitive",
+ "resolved": "6.12.1",
+ "contentHash": "kPaRD5RJC0ByUg+yGX6bDz5XHMI7OYmQwP8kbtef+vZ+csj/VDb5Bwas4ChxwhoAbI8lEvwP5/3aViQPpgNBow=="
+ },
+ "NuGet.Packaging": {
+ "type": "Transitive",
+ "resolved": "6.12.1",
+ "contentHash": "6s5NO3VNX6fIx6GwuWZtIsal9W1xkelYd3Vg2KUAg1zGqnKC3wB5IZlombvVGVGcwyl/A+iDvpUwSvgeDoB3wA==",
+ "dependencies": {
+ "Newtonsoft.Json": "13.0.3",
+ "NuGet.Configuration": "6.12.1",
+ "NuGet.Versioning": "6.12.1",
+ "System.Formats.Asn1": "8.0.1",
+ "System.Security.Cryptography.Pkcs": "6.0.4"
+ }
+ },
+ "NuGet.Versioning": {
+ "type": "Transitive",
+ "resolved": "6.12.1",
+ "contentHash": "fJ6rFYANDnohFsdpaY79FvrJxI6murmoOxXz6nZlf819F48+IBKMnAIg3oIBRtZq5y498ObMtKnro5IitvizUg=="
+ },
+ "System.ComponentModel.Annotations": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "dMkqfy2el8A8/I76n2Hi1oBFEbG1SfxD2l5nhwXV3XjlnOmwxJlQbYpJH4W51odnU9sARCSAgv7S3CyAFMkpYg=="
+ },
+ "System.Diagnostics.EventLog": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "n1ZP7NM2Gkn/MgD8+eOT5MulMj6wfeQMNS2Pizvq5GHCZfjlFMXV2irQlQmJhwA2VABC57M0auudO89Iu2uRLg=="
+ },
+ "System.Formats.Asn1": {
+ "type": "Transitive",
+ "resolved": "8.0.1",
+ "contentHash": "XqKba7Mm/koKSjKMfW82olQdmfbI5yqeoLV/tidRp7fbh5rmHAQ5raDI/7SU0swTzv+jgqtUGkzmFxuUg0it1A=="
+ },
+ "System.Security.Cryptography.Pkcs": {
+ "type": "Transitive",
+ "resolved": "6.0.4",
+ "contentHash": "LGbXi1oUJ9QgCNGXRO9ndzBL/GZgANcsURpMhNR8uO+rca47SZmciS3RSQUvlQRwK3QHZSHNOXzoMUASKA+Anw==",
+ "dependencies": {
+ "System.Formats.Asn1": "6.0.0"
+ }
+ },
+ "System.Security.Cryptography.ProtectedData": {
+ "type": "Transitive",
+ "resolved": "4.4.0",
+ "contentHash": "cJV7ScGW7EhatRsjehfvvYVBvtiSMKgN8bOVI0bQhnF5bU7vnHVIsH49Kva7i7GWaWYvmEzkYVk1TC+gZYBEog=="
+ },
+ "icsharpcode.decompiler": {
+ "type": "Project",
+ "dependencies": {
+ "System.Collections.Immutable": "[6.0.0, )",
+ "System.Reflection.Metadata": "[6.0.0, )"
+ }
+ },
+ "icsharpcode.ilspyx": {
+ "type": "Project",
+ "dependencies": {
+ "ICSharpCode.Decompiler": "[8.0.0-noversion, )",
+ "K4os.Compression.LZ4": "[1.3.8, )",
+ "Mono.Cecil": "[0.11.6, )",
+ "System.Composition.AttributedModel": "[9.0.0, )",
+ "System.Reflection.Metadata": "[9.0.0, )",
+ "System.Runtime.CompilerServices.Unsafe": "[6.1.0, )"
+ }
+ },
+ "K4os.Compression.LZ4": {
+ "type": "CentralTransitive",
+ "requested": "[1.3.8, )",
+ "resolved": "1.3.8",
+ "contentHash": "LhwlPa7c1zs1OV2XadMtAWdImjLIsqFJPoRcIWAadSRn0Ri1DepK65UbWLPmt4riLqx2d40xjXRk0ogpqNtK7g=="
+ },
+ "McMaster.Extensions.CommandLineUtils": {
+ "type": "CentralTransitive",
+ "requested": "[4.1.1, )",
+ "resolved": "4.1.1",
+ "contentHash": "zxgDY+G5yVq2q8sVB3Z275Qkxed1jC95nwAfnlSyoG4l5Nicvd4+ke1jXusEZEfyuErlAgXCKS937c13FmZWBg==",
+ "dependencies": {
+ "System.ComponentModel.Annotations": "5.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "CentralTransitive",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "0J/9YNXTMWSZP2p2+nvl8p71zpSwokZXZuJW+VjdErkegAnFdO1XlqtA62SJtgVYHdKu3uPxJHcMR/r35HwFBA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Primitives": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "CentralTransitive",
+ "requested": "[8.0.1, )",
+ "resolved": "8.0.1",
+ "contentHash": "L89DLNuimOghjV3tLx0ArFDwVEJD6+uGB3BMCMX01kaLzXkaXHb2021xOMl2QOxUxbdePKUZsUY7n2UUkycjRg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "8.0.0",
+ "Microsoft.Extensions.Configuration.Abstractions": "8.0.0",
+ "Microsoft.Extensions.Configuration.FileExtensions": "8.0.1",
+ "Microsoft.Extensions.FileProviders.Abstractions": "8.0.0"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "CentralTransitive",
+ "requested": "[8.0.2, )",
+ "resolved": "8.0.2",
+ "contentHash": "3iE7UF7MQkCv1cxzCahz+Y/guQbTqieyxyaWKhrRO91itI9cOKO76OHeQDahqG4MmW5umr3CcCvGmK92lWNlbg=="
+ },
+ "Mono.Cecil": {
+ "type": "CentralTransitive",
+ "requested": "[0.11.6, )",
+ "resolved": "0.11.6",
+ "contentHash": "f33RkDtZO8VlGXCtmQIviOtxgnUdym9xx/b1p9h91CRGOsJFxCFOFK1FDbVt1OCf1aWwYejUFa2MOQyFWTFjbA=="
+ },
+ "System.Collections.Immutable": {
+ "type": "CentralTransitive",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "QhkXUl2gNrQtvPmtBTQHb0YsUrDiDQ2QS09YbtTTiSjGcf7NBqtYbrG/BE06zcBPCKEwQGzIv13IVdXNOSub2w=="
+ },
+ "System.Composition.AttributedModel": {
+ "type": "CentralTransitive",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "iri00l/zIX9g4lHMY+Nz0qV1n40+jFYAmgsaiNn16xvt2RDwlqByNG4wgblagnDYxm3YSQQ0jLlC/7Xlk9CzyA=="
+ },
+ "System.Reflection.Metadata": {
+ "type": "CentralTransitive",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "ANiqLu3DxW9kol/hMmTWbt3414t9ftdIuiIU7j80okq2YzAueo120M442xk1kDJWtmZTqWQn7wHDvMRipVOEOQ==",
+ "dependencies": {
+ "System.Collections.Immutable": "9.0.0"
+ }
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "CentralTransitive",
+ "requested": "[6.1.0, )",
+ "resolved": "6.1.0",
+ "contentHash": "5o/HZxx6RVqYlhKSq8/zronDkALJZUT2Vz0hx43f0gwe8mwlM0y2nYlqdBwLMzr262Bwvpikeb/yEwkAa5PADg=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj b/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj
index 76a7b3504..4272c40aa 100644
--- a/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj
+++ b/ICSharpCode.ILSpyX/ICSharpCode.ILSpyX.csproj
@@ -48,6 +48,12 @@
+
+
+ true
+ true
+
+
diff --git a/ICSharpCode.ILSpyX/packages.lock.json b/ICSharpCode.ILSpyX/packages.lock.json
new file mode 100644
index 000000000..37a460ef0
--- /dev/null
+++ b/ICSharpCode.ILSpyX/packages.lock.json
@@ -0,0 +1,79 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net8.0": {
+ "K4os.Compression.LZ4": {
+ "type": "Direct",
+ "requested": "[1.3.8, )",
+ "resolved": "1.3.8",
+ "contentHash": "LhwlPa7c1zs1OV2XadMtAWdImjLIsqFJPoRcIWAadSRn0Ri1DepK65UbWLPmt4riLqx2d40xjXRk0ogpqNtK7g=="
+ },
+ "Microsoft.SourceLink.GitHub": {
+ "type": "Direct",
+ "requested": "[8.0.0, )",
+ "resolved": "8.0.0",
+ "contentHash": "G5q7OqtwIyGTkeIOAc3u2ZuV/kicQaec5EaRnc0pIeSnh9LUjj+PYQrJYBURvDt7twGl2PKA7nSN0kz1Zw5bnQ==",
+ "dependencies": {
+ "Microsoft.Build.Tasks.Git": "8.0.0",
+ "Microsoft.SourceLink.Common": "8.0.0"
+ }
+ },
+ "Mono.Cecil": {
+ "type": "Direct",
+ "requested": "[0.11.6, )",
+ "resolved": "0.11.6",
+ "contentHash": "f33RkDtZO8VlGXCtmQIviOtxgnUdym9xx/b1p9h91CRGOsJFxCFOFK1FDbVt1OCf1aWwYejUFa2MOQyFWTFjbA=="
+ },
+ "System.Composition.AttributedModel": {
+ "type": "Direct",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "iri00l/zIX9g4lHMY+Nz0qV1n40+jFYAmgsaiNn16xvt2RDwlqByNG4wgblagnDYxm3YSQQ0jLlC/7Xlk9CzyA=="
+ },
+ "System.Reflection.Metadata": {
+ "type": "Direct",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "ANiqLu3DxW9kol/hMmTWbt3414t9ftdIuiIU7j80okq2YzAueo120M442xk1kDJWtmZTqWQn7wHDvMRipVOEOQ==",
+ "dependencies": {
+ "System.Collections.Immutable": "9.0.0"
+ }
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "Direct",
+ "requested": "[6.1.0, )",
+ "resolved": "6.1.0",
+ "contentHash": "5o/HZxx6RVqYlhKSq8/zronDkALJZUT2Vz0hx43f0gwe8mwlM0y2nYlqdBwLMzr262Bwvpikeb/yEwkAa5PADg=="
+ },
+ "TomsToolbox.Composition.Analyzer": {
+ "type": "Direct",
+ "requested": "[2.21.0, )",
+ "resolved": "2.21.0",
+ "contentHash": "vJx9hxAzjni34slGz78ewqYP9Ylk8dJszfEUK1TF5cflVKMBO3ORSFd0FtICTwJtE8munvZrMrcLWwXt5bIcEA=="
+ },
+ "Microsoft.Build.Tasks.Git": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "bZKfSIKJRXLTuSzLudMFte/8CempWjVamNUR5eHJizsy+iuOuO/k2gnh7W0dHJmYY0tBf+gUErfluCv5mySAOQ=="
+ },
+ "Microsoft.SourceLink.Common": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "dk9JPxTCIevS75HyEQ0E4OVAFhB2N+V9ShCXf8Q6FkUQZDkgLI12y679Nym1YqsiSysuQskT7Z+6nUf3yab6Vw=="
+ },
+ "icsharpcode.decompiler": {
+ "type": "Project",
+ "dependencies": {
+ "System.Collections.Immutable": "[6.0.0, )",
+ "System.Reflection.Metadata": "[6.0.0, )"
+ }
+ },
+ "System.Collections.Immutable": {
+ "type": "CentralTransitive",
+ "requested": "[9.0.0, )",
+ "resolved": "9.0.0",
+ "contentHash": "QhkXUl2gNrQtvPmtBTQHb0YsUrDiDQ2QS09YbtTTiSjGcf7NBqtYbrG/BE06zcBPCKEwQGzIv13IVdXNOSub2w=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj b/ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj
index 83404ae2f..c5d27caea 100644
--- a/ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj
+++ b/ILSpy.AddIn.VS2022/ILSpy.AddIn.VS2022.csproj
@@ -149,7 +149,7 @@
-
+
Always
true
diff --git a/ILSpy.AddIn.VS2022/source.extension.vsixmanifest.template b/ILSpy.AddIn.VS2022/source.extension.vsixmanifest.template
index be1488335..55e6649e6 100644
--- a/ILSpy.AddIn.VS2022/source.extension.vsixmanifest.template
+++ b/ILSpy.AddIn.VS2022/source.extension.vsixmanifest.template
@@ -5,7 +5,7 @@
ILSpy 2022
Integrates the ILSpy decompiler into Visual Studio.
https://ilspy.net
- license.txt
+ LICENSE
ILSpy-Large.ico
ILSpy;IL;decompile;decompiler;decompilation;C#;CSharp;.NET;Productivity;Open Source;Free
diff --git a/ILSpy.AddIn/ILSpy.AddIn.csproj b/ILSpy.AddIn/ILSpy.AddIn.csproj
index 9b41766fd..bdcf4d021 100644
--- a/ILSpy.AddIn/ILSpy.AddIn.csproj
+++ b/ILSpy.AddIn/ILSpy.AddIn.csproj
@@ -148,7 +148,7 @@
-
+
Always
true
diff --git a/ILSpy.AddIn/source.extension.vsixmanifest.template b/ILSpy.AddIn/source.extension.vsixmanifest.template
index b87e1d1dc..c3d0d0d60 100644
--- a/ILSpy.AddIn/source.extension.vsixmanifest.template
+++ b/ILSpy.AddIn/source.extension.vsixmanifest.template
@@ -5,7 +5,7 @@
ILSpy
Integrates the ILSpy decompiler into Visual Studio.
https://ilspy.net
- license.txt
+ LICENSE
ILSpy-Large.ico
diff --git a/ILSpy.Installer/ILSpy.Installer.csproj b/ILSpy.Installer/ILSpy.Installer.csproj
index 6edfaab49..266020a76 100644
--- a/ILSpy.Installer/ILSpy.Installer.csproj
+++ b/ILSpy.Installer/ILSpy.Installer.csproj
@@ -15,7 +15,7 @@
-
+
diff --git a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs
index 26a3dc0df..de2620bd7 100644
--- a/ILSpy.ReadyToRun/ReadyToRunLanguage.cs
+++ b/ILSpy.ReadyToRun/ReadyToRunLanguage.cs
@@ -30,6 +30,7 @@ using System.Runtime.CompilerServices;
using ICSharpCode.AvalonEdit.Highlighting;
using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution;
using ICSharpCode.Decompiler.TypeSystem;
@@ -96,6 +97,10 @@ namespace ICSharpCode.ILSpy.ReadyToRun
public void WriteReference(IMember member, string text, bool isDefinition = false)
{
}
+
+ public void WriteReference(MetadataFile metadata, Handle handle, string text, string protocol = "decompile", bool isDefinition = false)
+ {
+ }
}
#endif
diff --git a/ILSpy/Commands/CreateDiagramContextMenuEntry.cs b/ILSpy/Commands/CreateDiagramContextMenuEntry.cs
new file mode 100644
index 000000000..edbbe14a3
--- /dev/null
+++ b/ILSpy/Commands/CreateDiagramContextMenuEntry.cs
@@ -0,0 +1,124 @@
+// Copyright (c) 2024 Christoph Wille for the SharpDevelop Team
+//
+// Permission is hereby granted, free of charge, to any person obtaining a copy of this
+// software and associated documentation files (the "Software"), to deal in the Software
+// without restriction, including without limitation the rights to use, copy, modify, merge,
+// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
+// to whom the Software is furnished to do so, subject to the following conditions:
+//
+// The above copyright notice and this permission notice shall be included in all copies or
+// substantial portions of the Software.
+//
+// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
+// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
+// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
+// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
+// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
+// DEALINGS IN THE SOFTWARE.
+
+using System;
+using System.Composition;
+using System.Diagnostics;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows;
+
+using ICSharpCode.Decompiler;
+using ICSharpCode.ILSpy.Docking;
+using ICSharpCode.ILSpy.Properties;
+using ICSharpCode.ILSpy.TreeNodes;
+using ICSharpCode.ILSpyX.MermaidDiagrammer;
+
+using Microsoft.Win32;
+
+namespace ICSharpCode.ILSpy.TextView
+{
+ [ExportContextMenuEntry(Header = nameof(Resources._CreateDiagram), Category = nameof(Resources.Save), Icon = "Images/Save")]
+ [Shared]
+ sealed class CreateDiagramContextMenuEntry(DockWorkspace dockWorkspace) : IContextMenuEntry
+ {
+ public void Execute(TextViewContext context)
+ {
+ var assembly = (context.SelectedTreeNodes?.FirstOrDefault() as AssemblyTreeNode)?.LoadedAssembly;
+ if (assembly == null)
+ return;
+
+ var selectedPath = SelectDestinationFolder();
+ if (string.IsNullOrEmpty(selectedPath))
+ return;
+
+ dockWorkspace.RunWithCancellation(ct => Task.Factory.StartNew(() => {
+ AvalonEditTextOutput output = new() {
+ EnableHyperlinks = true
+ };
+ Stopwatch stopwatch = Stopwatch.StartNew();
+ try
+ {
+ var command = new GenerateHtmlDiagrammer {
+ Assembly = assembly.FileName,
+ OutputFolder = selectedPath
+ };
+
+ command.Run();
+ }
+ catch (OperationCanceledException)
+ {
+ output.WriteLine();
+ output.WriteLine(Resources.GenerationWasCancelled);
+ throw;
+ }
+ stopwatch.Stop();
+ output.WriteLine(Resources.GenerationCompleteInSeconds, stopwatch.Elapsed.TotalSeconds.ToString("F1"));
+ output.WriteLine();
+ output.WriteLine("Learn more: " + "https://github.com/icsharpcode/ILSpy/wiki/Diagramming#tips-for-using-the-html-diagrammer");
+ output.WriteLine();
+
+ var diagramHtml = Path.Combine(selectedPath, "index.html");
+ output.AddButton(null, Resources.OpenExplorer, delegate { Process.Start("explorer", "/select,\"" + diagramHtml + "\""); });
+ output.WriteLine();
+ return output;
+ }, ct), Properties.Resources.CreatingDiagram).Then(dockWorkspace.ShowText).HandleExceptions();
+
+ return;
+ }
+
+ public bool IsEnabled(TextViewContext context) => true;
+
+ public bool IsVisible(TextViewContext context)
+ {
+ return context.SelectedTreeNodes?.Length == 1
+ && context.SelectedTreeNodes?.FirstOrDefault() is AssemblyTreeNode tn
+ && tn.LoadedAssembly.IsLoadedAsValidAssembly;
+ }
+
+ static string SelectDestinationFolder()
+ {
+ OpenFolderDialog dialog = new();
+ dialog.Multiselect = false;
+ dialog.Title = "Select target folder";
+
+ if (dialog.ShowDialog() != true)
+ {
+ return null;
+ }
+
+ string selectedPath = Path.GetDirectoryName(dialog.FolderName);
+ bool directoryNotEmpty;
+ try
+ {
+ directoryNotEmpty = Directory.EnumerateFileSystemEntries(selectedPath).Any();
+ }
+ catch (Exception e) when (e is IOException || e is UnauthorizedAccessException || e is System.Security.SecurityException)
+ {
+ MessageBox.Show(
+ "The directory cannot be accessed. Please ensure it exists and you have sufficient rights to access it.",
+ "Target directory not accessible",
+ MessageBoxButton.OK, MessageBoxImage.Error);
+ return null;
+ }
+
+ return dialog.FolderName;
+ }
+ }
+}
diff --git a/ILSpy/Controls/CustomDialog.cs b/ILSpy/Controls/CustomDialog.cs
index 994bedffc..63ca6bef9 100644
--- a/ILSpy/Controls/CustomDialog.cs
+++ b/ILSpy/Controls/CustomDialog.cs
@@ -51,9 +51,8 @@ namespace ICSharpCode.ILSpy.Controls
using (Graphics g = this.CreateGraphics())
{
- Rectangle screen = Screen.PrimaryScreen.WorkingArea;
- SizeF size = g.MeasureString(message, label.Font, screen.Width - 20);
- Size clientSize = size.ToSize();
+ SizeF size = TextRenderer.MeasureText(message, label.Font, default, TextFormatFlags.NoPrefix);
+ Size clientSize = new Size((int)Math.Ceiling(size.Width * 96 / g.DpiX) + DockPadding.Left + DockPadding.Right, (int)Math.Ceiling(size.Height * 96 / g.DpiY) + DockPadding.Top + DockPadding.Bottom);
Button[] buttons = new Button[buttonLabels.Length];
int[] positions = new int[buttonLabels.Length];
int pos = 0;
@@ -65,8 +64,8 @@ namespace ICSharpCode.ILSpy.Controls
string buttonLabel = buttonLabels[i];
newButton.Text = buttonLabel;
newButton.Click += new EventHandler(ButtonClick);
- SizeF buttonSize = g.MeasureString(buttonLabel, newButton.Font);
- newButton.Width = Math.Max(newButton.Width, ((int)Math.Ceiling(buttonSize.Width / 8.0) + 1) * 8);
+ SizeF buttonSize = TextRenderer.MeasureText(buttonLabel, newButton.Font);
+ newButton.Width = Math.Max(newButton.Width, ((int)Math.Ceiling(buttonSize.Width * 96 / g.DpiX / 8.0) + 1) * 8);
positions[i] = pos;
buttons[i] = newButton;
pos += newButton.Width + 4;
@@ -87,7 +86,7 @@ namespace ICSharpCode.ILSpy.Controls
{
clientSize.Width = pos;
}
- clientSize.Height += panel.Height + 6;
+ clientSize.Height += panel.Height;
this.ClientSize = clientSize;
int start = (clientSize.Width - pos) / 2;
for (int i = 0; i < buttons.Length; i++)
diff --git a/ILSpy/Docking/DockWorkspace.cs b/ILSpy/Docking/DockWorkspace.cs
index d92b92847..2fe0d0fc2 100644
--- a/ILSpy/Docking/DockWorkspace.cs
+++ b/ILSpy/Docking/DockWorkspace.cs
@@ -25,6 +25,7 @@ using System.Linq;
using System.Reflection;
using System.Threading;
using System.Threading.Tasks;
+using System.Windows.Data;
using System.Windows.Threading;
using AvalonDock;
@@ -50,6 +51,7 @@ namespace ICSharpCode.ILSpy.Docking
private readonly IExportProvider exportProvider;
private readonly ObservableCollection tabPages = [];
+ private ReadOnlyCollection toolPanes;
readonly SessionSettings sessionSettings;
@@ -123,7 +125,7 @@ namespace ICSharpCode.ILSpy.Docking
public ReadOnlyObservableCollection TabPages { get; }
- public ReadOnlyCollection ToolPanes => exportProvider
+ public ReadOnlyCollection ToolPanes => toolPanes ??= exportProvider
.GetExportedValues("ToolPane")
.OrderBy(item => item.Title)
.ToArray()
@@ -194,6 +196,9 @@ namespace ICSharpCode.ILSpy.Docking
{
serializer.LayoutSerializationCallback -= LayoutSerializationCallback;
}
+
+ DockingManager.SetBinding(DockingManager.AnchorablesSourceProperty, new Binding(nameof(ToolPanes)));
+ DockingManager.SetBinding(DockingManager.DocumentsSourceProperty, new Binding(nameof(TabPages)));
}
void LayoutSerializationCallback(object sender, LayoutSerializationCallbackEventArgs e)
@@ -226,6 +231,11 @@ namespace ICSharpCode.ILSpy.Docking
return ActiveTabPage.ShowTextViewAsync(textView => textView.RunWithCancellation(taskCreation));
}
+ public Task RunWithCancellation(Func> taskCreation, string progressTitle)
+ {
+ return ActiveTabPage.ShowTextViewAsync(textView => textView.RunWithCancellation(taskCreation, progressTitle));
+ }
+
internal void ShowNodes(AvalonEditTextOutput output, TreeNodes.ILSpyTreeNode[] nodes, IHighlightingDefinition highlighting)
{
ActiveTabPage.ShowTextView(textView => textView.ShowNodes(output, nodes, highlighting));
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index 6bd46530f..ba2e33f5b 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -58,7 +58,7 @@
-
+
license.txt
@@ -93,6 +93,11 @@
+
+
+
+
+
diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml
index 99c5ee08f..a60f6c990 100644
--- a/ILSpy/MainWindow.xaml
+++ b/ILSpy/MainWindow.xaml
@@ -67,8 +67,6 @@
diff --git a/ILSpy/Properties/Resources.Designer.cs b/ILSpy/Properties/Resources.Designer.cs
index ca8b55151..01628056b 100644
--- a/ILSpy/Properties/Resources.Designer.cs
+++ b/ILSpy/Properties/Resources.Designer.cs
@@ -114,6 +114,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to Create _Diagram....
+ ///
+ public static string _CreateDiagram {
+ get {
+ return ResourceManager.GetString("_CreateDiagram", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to _File.
///
@@ -567,6 +576,15 @@ namespace ICSharpCode.ILSpy.Properties {
}
}
+ ///
+ /// Looks up a localized string similar to Creating diagram....
+ ///
+ public static string CreatingDiagram {
+ get {
+ return ResourceManager.GetString("CreatingDiagram", resourceCulture);
+ }
+ }
+
///
/// Looks up a localized string similar to Culture.
///
diff --git a/ILSpy/Properties/Resources.resx b/ILSpy/Properties/Resources.resx
index b853b0641..bcb79fae7 100644
--- a/ILSpy/Properties/Resources.resx
+++ b/ILSpy/Properties/Resources.resx
@@ -210,6 +210,9 @@ Are you sure you want to continue?
Create
+
+ Creating diagram...
+
Culture
@@ -1036,6 +1039,9 @@ Do you want to continue?
_Collapse all tree nodes
+
+ Create _Diagram...
+
_File
diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs
index 2e65074d1..4e748fd2a 100644
--- a/ILSpy/TextView/DecompilerTextView.cs
+++ b/ILSpy/TextView/DecompilerTextView.cs
@@ -595,14 +595,14 @@ namespace ICSharpCode.ILSpy.TextView
/// the task.
/// If another task is started before the previous task finishes running, the previous task is cancelled.
///
- public Task RunWithCancellation(Func> taskCreation)
+ public Task RunWithCancellation(Func> taskCreation, string? progressTitle = null)
{
if (waitAdorner.Visibility != Visibility.Visible)
{
waitAdorner.Visibility = Visibility.Visible;
// Work around a WPF bug by setting IsIndeterminate only while the progress bar is visible.
// https://github.com/icsharpcode/ILSpy/issues/593
- progressTitle.Text = Properties.Resources.Decompiling;
+ this.progressTitle.Text = progressTitle == null ? Properties.Resources.Decompiling : progressTitle;
progressBar.IsIndeterminate = true;
progressText.Text = null;
progressText.Visibility = Visibility.Collapsed;
diff --git a/doc/license.txt b/LICENSE
similarity index 92%
rename from doc/license.txt
rename to LICENSE
index 52c20debd..22e1b4257 100644
--- a/doc/license.txt
+++ b/LICENSE
@@ -1,6 +1,6 @@
MIT license
-Copyright (c) 2011-2023 AlphaSierraPapa for the ILSpy team
+Copyright (c) 2011-2025 AlphaSierraPapa for the ILSpy team
Permission is hereby granted, free of charge, to any person obtaining a copy of this
software and associated documentation files (the "Software"), to deal in the Software
diff --git a/NuGet.config b/NuGet.config
index 5209a02bf..ccdac39a4 100644
--- a/NuGet.config
+++ b/NuGet.config
@@ -4,7 +4,7 @@
-
+
@@ -12,7 +12,7 @@
-
+
diff --git a/SECURITY.md b/SECURITY.md
new file mode 100644
index 000000000..1ba498f29
--- /dev/null
+++ b/SECURITY.md
@@ -0,0 +1,15 @@
+# Security Policy
+
+## Supported Versions
+
+Supported are the latest released version as well as the latest preview/rc version.
+
+## Reporting a Vulnerability
+
+Security issues and bugs should be reported privately to christoph.wille AT gmail.com. Please note that
+we cannot guarantee a response time (*) although we will strive to get back to you within one business day. If you
+do not hear back from Chris within a week, alternatively try to contact siegfriedpammer AT gmail.com.
+
+Please do not open issues for anything you think might have a security implication.
+
+(*) We are an OSS project entirely run by volunteers and sometimes lifetm will mean longer response times.
diff --git a/doc/ILSpyAboutPage.txt b/doc/ILSpyAboutPage.txt
index 0b5610aea..cf181a904 100644
--- a/doc/ILSpyAboutPage.txt
+++ b/doc/ILSpyAboutPage.txt
@@ -3,7 +3,7 @@ ILSpy is the open-source .NET assembly browser and decompiler.
Website: https://ilspy.net/
Found a bug? https://github.com/icsharpcode/ILSpy/issues/new/choose
-Copyright 2011-2023 AlphaSierraPapa for the ILSpy team
+Copyright 2011-2025 AlphaSierraPapa for the ILSpy team
Current and past contributors: https://github.com/icsharpcode/ILSpy/graphs/contributors
ILSpy is distributed under the MIT License.
diff --git a/doc/ILSpyAboutPage_zh_Hans.txt b/doc/ILSpyAboutPage_zh_Hans.txt
index ebaf5676d..3723702f8 100644
--- a/doc/ILSpyAboutPage_zh_Hans.txt
+++ b/doc/ILSpyAboutPage_zh_Hans.txt
@@ -4,7 +4,7 @@ ILSpy 是开源的 .NET 程序集浏览器和反编译器。
反馈BUG: https://github.com/icsharpcode/ILSpy/issues/new/choose
中文翻译反馈:https://github.com/maikebing/ILSpy/issues
-Copyright 2011-2023 AlphaSierraPapa for the ILSpy team
+Copyright 2011-2025 AlphaSierraPapa for the ILSpy team
当前和过去的贡献者: https://github.com/icsharpcode/ILSpy/graphs/contributors
ILSpy 基于 MIT 许可证发行。
diff --git a/doc/copyright.txt b/doc/copyright.txt
index de4935037..979e262b9 100644
--- a/doc/copyright.txt
+++ b/doc/copyright.txt
@@ -1,4 +1,4 @@
-Copyright 2011-2023 for the ILSpy team
+Copyright 2011-2025 for the ILSpy team
by
AlphaSierraPapa, Christoph Wille