diff --git a/.github/workflows/build-ilspy.yml b/.github/workflows/build-ilspy.yml
index 8dbdf50a4..02a4f96ad 100644
--- a/.github/workflows/build-ilspy.yml
+++ b/.github/workflows/build-ilspy.yml
@@ -350,6 +350,13 @@ jobs:
--no-build --report-trx
--results-directory test-results
+ - name: Execute ilspycmd tests
+ run: >
+ dotnet test --project ICSharpCode.ILSpyCmd.Tests/ICSharpCode.ILSpyCmd.Tests.csproj
+ --configuration Release
+ --no-build --report-trx
+ --results-directory test-results
+
- name: Execute BAML decompiler tests
run: >
dotnet test --project ILSpy.BamlDecompiler.Tests/ILSpy.BamlDecompiler.Tests.csproj
diff --git a/ICSharpCode.ILSpyCmd.Tests/ICSharpCode.ILSpyCmd.Tests.csproj b/ICSharpCode.ILSpyCmd.Tests/ICSharpCode.ILSpyCmd.Tests.csproj
new file mode 100644
index 000000000..6f9f4528b
--- /dev/null
+++ b/ICSharpCode.ILSpyCmd.Tests/ICSharpCode.ILSpyCmd.Tests.csproj
@@ -0,0 +1,27 @@
+
+
+
+
+ net11.0
+ preview
+
+ false
+
+ true
+ ICSharpCode.ILSpyCmd.Tests.MicrosoftTestingPlatformEntryPoint
+ Exe
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/ICSharpCode.ILSpyCmd.Tests/MemberOptionTests.cs b/ICSharpCode.ILSpyCmd.Tests/MemberOptionTests.cs
new file mode 100644
index 000000000..db083b6ef
--- /dev/null
+++ b/ICSharpCode.ILSpyCmd.Tests/MemberOptionTests.cs
@@ -0,0 +1,156 @@
+// Copyright (c) 2026 Siegfried Pammer
+//
+// 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.IO;
+using System.Threading.Tasks;
+
+using NUnit.Framework;
+
+namespace ICSharpCode.ILSpyCmd.Tests
+{
+ [TestFixture]
+ public class ILSpyCmdMemberOptionTests
+ {
+ static readonly string testAssemblyPath = typeof(ILSpyCmdMemberOptionTests).Assembly.Location;
+
+ static async Task<(int ExitCode, string Output, string Error)> RunAsync(params string[] args)
+ {
+ var originalOut = Console.Out;
+ var originalError = Console.Error;
+ var stdout = new StringWriter();
+ var stderr = new StringWriter();
+ try
+ {
+ Console.SetOut(stdout);
+ Console.SetError(stderr);
+ int exitCode = await ILSpyCmdProgram.Main(args);
+ return (exitCode, stdout.ToString(), stderr.ToString());
+ }
+ finally
+ {
+ Console.SetOut(originalOut);
+ Console.SetError(originalError);
+ }
+ }
+
+ [Test]
+ public async Task MethodByDocumentationIdString()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck",
+ "-m", "M:ICSharpCode.ILSpyCmd.Tests.MemberOptionSample.Add(System.Int32,System.Int32)");
+
+ Assert.That(result.ExitCode, Is.EqualTo(0), result.Error);
+ Assert.That(result.Output, Does.Contain("int Add(int a, int b)"));
+ Assert.That(result.Output, Does.Not.Contain("Unrelated"));
+ }
+
+ [Test]
+ public async Task PropertyByDocumentationIdString()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck",
+ "-m", "P:ICSharpCode.ILSpyCmd.Tests.MemberOptionSample.Answer");
+
+ Assert.That(result.ExitCode, Is.EqualTo(0), result.Error);
+ Assert.That(result.Output, Does.Contain("Answer"));
+ Assert.That(result.Output, Does.Not.Contain("Add(int a, int b)"));
+ }
+
+ [Test]
+ public async Task MethodByMetadataToken()
+ {
+ int token = typeof(MemberOptionSample).GetMethod(nameof(MemberOptionSample.Add))!.MetadataToken;
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck", "-m", $"0x{token:x8}");
+
+ Assert.That(result.ExitCode, Is.EqualTo(0), result.Error);
+ Assert.That(result.Output, Does.Contain("int Add(int a, int b)"));
+ }
+
+ [Test]
+ public async Task UnknownMemberReportsError()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck",
+ "-m", "M:ICSharpCode.ILSpyCmd.Tests.MemberOptionSample.DoesNotExist");
+
+ Assert.That(result.ExitCode, Is.EqualTo(ProgramExitCodes.EX_DATAERR));
+ Assert.That(result.Error, Does.Contain("DoesNotExist"));
+ }
+
+ [Test]
+ public async Task MalformedTokenReportsTokenSpecificError()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck", "-m", "0xZZ000001");
+
+ Assert.That(result.ExitCode, Is.EqualTo(ProgramExitCodes.EX_DATAERR));
+ Assert.That(result.Error, Does.Contain("metadata token"));
+ Assert.That(result.Error, Does.Not.Contain("documentation id"));
+ }
+
+ [Test]
+ public async Task MemberOfAnotherModuleReportsDistinctError()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck", "-m", "M:System.Object.ToString");
+
+ Assert.That(result.ExitCode, Is.EqualTo(ProgramExitCodes.EX_DATAERR));
+ Assert.That(result.Error, Does.Contain("defined in"));
+ }
+
+ [Test]
+ public async Task SurroundingWhitespaceIsIgnored()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck",
+ "-m", " M:ICSharpCode.ILSpyCmd.Tests.MemberOptionSample.Add(System.Int32,System.Int32) ");
+
+ Assert.That(result.ExitCode, Is.EqualTo(0), result.Error);
+ Assert.That(result.Output, Does.Contain("int Add(int a, int b)"));
+ }
+
+ [Test]
+ public async Task OutOfRangeTokenReportsError()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck", "-m", "0x06ffffff");
+
+ Assert.That(result.ExitCode, Is.EqualTo(ProgramExitCodes.EX_DATAERR));
+ Assert.That(result.Error, Does.Contain("0x06ffffff"));
+ }
+
+ [Test]
+ public async Task TypeAndMemberOptionsAreMutuallyExclusive()
+ {
+ var result = await RunAsync(testAssemblyPath, "--disable-updatecheck",
+ "-t", "ICSharpCode.ILSpyCmd.Tests.MemberOptionSample",
+ "-m", "P:ICSharpCode.ILSpyCmd.Tests.MemberOptionSample.Answer");
+
+ Assert.That(result.ExitCode, Is.EqualTo(ProgramExitCodes.EX_USAGE));
+ }
+ }
+
+ public class MemberOptionSample
+ {
+ public int Add(int a, int b)
+ {
+ return a + b;
+ }
+
+ public string Answer => "42";
+
+ public void Unrelated()
+ {
+ }
+ }
+}
diff --git a/ICSharpCode.ILSpyCmd.Tests/packages.lock.json b/ICSharpCode.ILSpyCmd.Tests/packages.lock.json
new file mode 100644
index 000000000..9d2d754cd
--- /dev/null
+++ b/ICSharpCode.ILSpyCmd.Tests/packages.lock.json
@@ -0,0 +1,549 @@
+{
+ "version": 2,
+ "dependencies": {
+ "net11.0": {
+ "Microsoft.Testing.Extensions.TrxReport": {
+ "type": "Direct",
+ "requested": "[2.1.0, )",
+ "resolved": "2.1.0",
+ "contentHash": "cXmP225WcMLLOSrW8xekaNhfzdBwXX3cbXbE5qSzmLbK0KZe3z8rAObKj70FWiPPPzm2W22x0ZW93gsmAfK6Mg==",
+ "dependencies": {
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.1.0",
+ "Microsoft.Testing.Platform": "2.1.0"
+ }
+ },
+ "Microsoft.Testing.Extensions.VSTestBridge": {
+ "type": "Direct",
+ "requested": "[2.1.0, )",
+ "resolved": "2.1.0",
+ "contentHash": "bNRIEA2YoGr+Y+7LHdA7i1U80+7BAdf4K4Qh4Kx6eKkoBK/NV7QpoMg+GWPP0/eqAFzuUmUOIPVZ87Oo0Vyxmw==",
+ "dependencies": {
+ "Microsoft.TestPlatform.ObjectModel": "18.0.1",
+ "Microsoft.Testing.Extensions.Telemetry": "2.1.0",
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": "2.1.0",
+ "Microsoft.Testing.Platform": "2.1.0"
+ }
+ },
+ "NUnit": {
+ "type": "Direct",
+ "requested": "[4.6.1, )",
+ "resolved": "4.6.1",
+ "contentHash": "xS4+YaBFUv1r8bcAbjitSfYaRZGfMwUiMdiaRziBXZpKgVxKDSHhjUn0mV5mObHGZRZq6eNa+WFWr3g8grj66A=="
+ },
+ "NUnit3TestAdapter": {
+ "type": "Direct",
+ "requested": "[6.2.0, )",
+ "resolved": "6.2.0",
+ "contentHash": "8PMJB8za2u8S0ey/nEtvh9BHjLhv5yzUEMCmA0+VIPLKSeOAZ3TEHWDyAp0+iPQb3jnBH1o8k0PoU2FgzXLRnQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyModel": "8.0.2",
+ "Microsoft.Testing.Extensions.VSTestBridge": "2.1.0",
+ "Microsoft.Testing.Platform.MSBuild": "2.1.0"
+ }
+ },
+ "TomsToolbox.Composition.Analyzer": {
+ "type": "Direct",
+ "requested": "[2.24.0, )",
+ "resolved": "2.24.0",
+ "contentHash": "dKHqW1MeAMnDIbtx8qDTsGwy/7LUiQ3ccdzHX0PzCh1r98Lgl/1deIky9+ojZO0K5HjeA7uE+eW9/h+v7EOIBA=="
+ },
+ "Microsoft.ApplicationInsights": {
+ "type": "Transitive",
+ "resolved": "2.23.0",
+ "contentHash": "nWArUZTdU7iqZLycLKWe0TDms48KKGE6pONH2terYNa8REXiqixrMOkf1sk5DHGMaUTqONU2YkS4SAXBhLStgw==",
+ "dependencies": {
+ "System.Diagnostics.DiagnosticSource": "5.0.0"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "5Vnd2I75DmZCVEjSynIdJ/0EGafgnLQwgR3t2C2/fkjx/nRG+cLwxLLdInoHeCEpkD5K4Ov/g9ZCRYrl4TRsaA==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Binder": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "GqmN2o1CkJvk7uWp+p4CwBYW0w/zfoEbvsiFDbO2G8l1Uz+mrDAbAcZiXhU2lufKPby1cjAUdd5GTWpebYOkOA==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Configuration.CommandLine": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "33cBeR2HRbzHUTtmcmLdNOApneNGcymwwL4arHuotgVK9Frba8kcDTrvVTj7cSCmF1R9OiSbZH0KxNOwab3HUg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "KRfFSSCV58vEdU7mPED/YMzeovIWF5P0g8s9K8n9HEfy0/WzMq37SrPdXdFN5/dFT/rPMHpF7AvpoXHckbcBFg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Configuration.FileExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "ZOhZYwvbXGTgGVRwswIirofEMVHuWdxjdh0JeUZXwaF9cgcjXdz/t0ELtgaevw7ezTyv47yPNCgGreWtLkn3IQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Physical": "10.0.10",
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Configuration.UserSecrets": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "1s1sKFTk/Foam64JY6+m/diH8drL3Wx6V3gtSd5v1IEZtszZYyc1pW8uRnMblzpNiR0l0t8gGk7tXj3xHzFgdg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Configuration.Json": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Physical": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "ANyvsgkNBRvcJh2XLgn8veGmajf+8m0AbKK+HPWdRL1yraSNVVSmQhFntLtdz/C795jxqqup+k05cs/3jZQPOA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.DependencyModel": {
+ "type": "Transitive",
+ "resolved": "8.0.2",
+ "contentHash": "mUBDZZRgZrSyFOsJ2qJJ9fXfqd/kXJwf3AiDoqLD9m6TjY5OO/vLNOb9fb4juC0487eq4hcGN/M2Rh/CKS7QYw=="
+ },
+ "Microsoft.Extensions.Diagnostics": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "Kr/e7lUf4+N8tacbqJ2Ctwe/HarKdAc9ZkgKVVqvtJDBKbez+T/KnUwu82KSlnBp/SrpBcxc7u7xkE2oUZT/5Q==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Diagnostics.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "9uWiKpeOVac355STyChWR/pliFX/5CeLqChW9kKsaxyDH4EUTZxMkT4Jwp/J/peLm0GBFmSX5c0WCse3yCnq1Q==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "c5zqFCY9DiIpMovLd7/d/CTiEtrMOuQ639dhv3PABtKQIKNQikSHwQt8+N679uii9q+B55lgK28Uv64FOwEu8w==",
+ "dependencies": {
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.FileProviders.Physical": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "jhJAyo38kSrH3ARvWUk0h8itogVnQu2DCZuPo+s0Z+tXes0ugTxMPaHYzap85785eHQmPFqD9TYERqBbtGxn/w==",
+ "dependencies": {
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.10",
+ "Microsoft.Extensions.FileSystemGlobbing": "10.0.10",
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.FileSystemGlobbing": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "jSOCVxEwCd4Aq925kJVz1kSO1EpX2OHYKL04qVREXkDU7Ce3pVDdHPYm+fEy8y/th2kJf/DAstRHpJAqoNWP8w=="
+ },
+ "Microsoft.Extensions.Hosting.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "5LugpYGHk+mkn0a8IZgcyfBca8PCTAU9RQFoMrTdtOOidq88M2SI5f3px6ugnzgxC+eTkvYYJi8pzlUnG5xdAQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Diagnostics.Abstractions": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Logging": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "Tf6z5HsL0VDYRTfvsoNrTGHGheCwkTsZBA2FFh5ATJUbkAwug+FFNISJK2gjpUNemlAOoWllAK52HOWCjto3EQ==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Logging.Abstractions": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "zkFxGYUvdxAvIKTyXHrmW+Sux53D4SezD9dMyZ6hrwwzPQJNuwCRy1f5W7AvYTqacEGhWF2XderRQG1OvbV8og==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Logging.Configuration": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "cLrqxkuEfcilZ8SjK+9KAnpLk9lOoMPaOokF+wRUYie+iUEcdX4/p/+gJkt0BYgWLthjpBUCkVTBI6Kxg0nsOw==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.10",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10",
+ "Microsoft.Extensions.Options.ConfigurationExtensions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Logging.Console": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "VIlNzPwPS0GeQVSmCqqo36ugryX3LpE9ul6gEkks5VLET3weH/XMLeWmclwfoGn4Nxi2mwVibB+OZBVJ9tDqvg==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging.Configuration": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Logging.Debug": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "8+TZBnV5fgBXoVNJ5ROSErUwYogk4hOgV7c2HWK1u5cqKGmiUTUn7+KqZ35iQu8e/B7Ykccyz5OTjdXcidNZ9g==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Logging.EventLog": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "0RE4951AzQ+YD4gVrvbq0BhdsiBgSDo44yM7+QBZ2mrmMJeNjY+teCIYfUjqDPVYnKs0HR6SkkhgrX1YgXZq3Q==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10",
+ "System.Diagnostics.EventLog": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Logging.EventSource": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "85SAPwXhJtdBInzN2k7SChiFiBGh3KOWay5AfoY+GREF6P7oZA98+ST2p7Z9384iLKYjkZSKIZ/FqIO5aojtNw==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10",
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Options": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "srnhnk7nE8krBiIXp71LvBmKBtraBONWSRzdjJgRv1Ko9Mp8IVNqv4vIS9hGeVteBig8aQkva9ZG+sC+o5sVcA==",
+ "dependencies": {
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Options.ConfigurationExtensions": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "tnBmu/LwF25ZQK+HBNCu2xrwnkKoB/XEbJyooGGoYxHrhvxbSKi7eOFiJ4AXBy/QU4vtCvCJfoi8k9Ej72qzOQ==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.10",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10",
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Primitives": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "5wu/GrYVd8mG2DVUw3vFJzF+O336TyTGg/Kmcgw9bfwYhCoFiV5lR5QeEmKecJyrW4W54nMfD3p3589E8a7czQ=="
+ },
+ "Microsoft.Testing.Extensions.Telemetry": {
+ "type": "Transitive",
+ "resolved": "2.1.0",
+ "contentHash": "5TwgTx2u7k9Al/xbZ18QXq4Hdy2xewkVTI6K3sk+jY2ykqUkIKNuj7rFu3GOV5KnEUkevhw6eZcyZs77STHJIA==",
+ "dependencies": {
+ "Microsoft.ApplicationInsights": "2.23.0",
+ "Microsoft.Testing.Platform": "2.1.0"
+ }
+ },
+ "Microsoft.Testing.Extensions.TrxReport.Abstractions": {
+ "type": "Transitive",
+ "resolved": "2.1.0",
+ "contentHash": "D8xmIJYQFJ6D49Rx5/vPrkZZxb338Jkew+eSqZLBfBiWKw4QZKy3i1BOXiLfz0lOmaNErwDz/YWRojCdNl+B9Q==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "2.1.0"
+ }
+ },
+ "Microsoft.Testing.Platform": {
+ "type": "Transitive",
+ "resolved": "2.1.0",
+ "contentHash": "aHkjNTGIA+Zbdw6RJgSFrbDrCjO0CgqpElqYcvkRSeUhBv2bKarnvU3ep786U7UqrPlArT/B7VmImRibJD0Zrg=="
+ },
+ "Microsoft.Testing.Platform.MSBuild": {
+ "type": "Transitive",
+ "resolved": "2.1.0",
+ "contentHash": "UpfPebXQtHGrWz21+YLHmJSm+5zsuPE9U9pfdCtoB+67g75fDmWlNgpkH2ZmdVhSwkjNIed9Icg8Iu63z2ei5Q==",
+ "dependencies": {
+ "Microsoft.Testing.Platform": "2.1.0"
+ }
+ },
+ "Microsoft.TestPlatform.ObjectModel": {
+ "type": "Transitive",
+ "resolved": "18.0.1",
+ "contentHash": "qT/mwMcLF9BieRkzOBPL2qCopl8hQu6A1P7JWAoj/FMu5i9vds/7cjbJ/LLtaiwWevWLAeD5v5wjQJ/l6jvhWQ==",
+ "dependencies": {
+ "System.Reflection.Metadata": "8.0.0"
+ }
+ },
+ "Newtonsoft.Json": {
+ "type": "Transitive",
+ "resolved": "13.0.3",
+ "contentHash": "HrC5BXdl00IP9zeV+0Z848QWPAoCr9P3bDEZguI+gkLcBKAOxix/tLEAAHC+UvDNPv4a2d18lOReHMOagPa+zQ=="
+ },
+ "NuGet.Common": {
+ "type": "Transitive",
+ "resolved": "7.6.0",
+ "contentHash": "uyXLqkbbZmkMvdHOR23l1EHW2hRmULtzoG3Ocj84VpGptnNfkODVboHGJfDfcn9Gi9oUNDs8/VjL4FZcST6zVg==",
+ "dependencies": {
+ "NuGet.Frameworks": "7.6.0"
+ }
+ },
+ "NuGet.Configuration": {
+ "type": "Transitive",
+ "resolved": "7.6.0",
+ "contentHash": "+bNj+YneC5CNg1vR+WZjLAakscJlsi0KhADZUgIJPn4pwh8/jeCUMC5ik5cpET/i+QOplDy7aJVTGkpdfrlPww==",
+ "dependencies": {
+ "NuGet.Common": "7.6.0",
+ "System.Security.Cryptography.ProtectedData": "8.0.0"
+ }
+ },
+ "NuGet.Packaging": {
+ "type": "Transitive",
+ "resolved": "7.6.0",
+ "contentHash": "TDp+qHzRBy1zjwiJGCbfpdO0jMG5hH/bk7p1EABLKv9p5SIykDPGnbuYXm2iZO0QJ/H+hOI/vo5LfqM17Q+G0w==",
+ "dependencies": {
+ "Newtonsoft.Json": "13.0.3",
+ "NuGet.Configuration": "7.6.0",
+ "NuGet.Versioning": "7.6.0",
+ "System.Security.Cryptography.Pkcs": "8.0.1"
+ }
+ },
+ "NuGet.Versioning": {
+ "type": "Transitive",
+ "resolved": "7.6.0",
+ "contentHash": "TpZxfOoQBQk/0r/2uc1A1qNYIKHkJGgOrWP+ax3nsNAUN/1BOQMDrgmGADogSA4hOXH1ZJiyeYg4Ca+vUW0sEg=="
+ },
+ "System.Diagnostics.DiagnosticSource": {
+ "type": "Transitive",
+ "resolved": "5.0.0",
+ "contentHash": "tCQTzPsGZh/A9LhhA6zrqCRV4hOHsK90/G7q3Khxmn6tnB1PuNU0cRaKANP2AWcF9bn0zsuOoZOSrHuJk6oNBA=="
+ },
+ "System.Diagnostics.EventLog": {
+ "type": "Transitive",
+ "resolved": "10.0.10",
+ "contentHash": "OvGz3PrzuAI/Sj7LTcXcCe3FClRI1IyRMZjNONcZtFh+Ww7nAtSh4kh08r8KVe/xxkXJPjR0Y1jF7H+N42d4xQ=="
+ },
+ "System.Security.Cryptography.ProtectedData": {
+ "type": "Transitive",
+ "resolved": "8.0.0",
+ "contentHash": "+TUFINV2q2ifyXauQXRwy4CiBhqvDEDZeVJU7qfxya4aRYOKzVBpN+4acx25VcPB9ywUN6C0n8drWl110PhZEg=="
+ },
+ "icsharpcode.bamldecompiler": {
+ "type": "Project",
+ "dependencies": {
+ "ICSharpCode.Decompiler": "[8.0.0-noversion, )"
+ }
+ },
+ "icsharpcode.decompiler": {
+ "type": "Project",
+ "dependencies": {
+ "System.Collections.Immutable": "[9.0.0, )",
+ "System.Reflection.Metadata": "[9.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": "[10.0.10, )",
+ "System.Reflection.Metadata": "[10.0.10, )",
+ "System.Runtime.CompilerServices.Unsafe": "[6.1.2, )"
+ }
+ },
+ "ilspycmd": {
+ "type": "Project",
+ "dependencies": {
+ "ICSharpCode.BamlDecompiler": "[10.0.0-noversion, )",
+ "ICSharpCode.Decompiler": "[8.0.0-noversion, )",
+ "ICSharpCode.ILSpyX": "[8.0.0-noversion, )",
+ "McMaster.Extensions.Hosting.CommandLine": "[5.1.0, )",
+ "Microsoft.Extensions.Hosting": "[10.0.10, )",
+ "NuGet.Protocol": "[7.6.0, )",
+ "System.Security.Cryptography.Pkcs": "[10.0.10, )"
+ }
+ },
+ "K4os.Compression.LZ4": {
+ "type": "CentralTransitive",
+ "requested": "[1.3.8, )",
+ "resolved": "1.3.8",
+ "contentHash": "LhwlPa7c1zs1OV2XadMtAWdImjLIsqFJPoRcIWAadSRn0Ri1DepK65UbWLPmt4riLqx2d40xjXRk0ogpqNtK7g=="
+ },
+ "McMaster.Extensions.CommandLineUtils": {
+ "type": "CentralTransitive",
+ "requested": "[5.1.0, )",
+ "resolved": "5.1.0",
+ "contentHash": "YceiKmxdsBrlkAJpmJ2N8XkLyAH01xLsm4VLfjNp5MvtAom2wflZtEBz3CLMQret6Z7jSh3oBO1ULF1Is0tNxA=="
+ },
+ "McMaster.Extensions.Hosting.CommandLine": {
+ "type": "CentralTransitive",
+ "requested": "[5.1.0, )",
+ "resolved": "5.1.0",
+ "contentHash": "XN6s/86/bP0PSsP5p2eX49ZKmWrURSNg7nvrG5vws3abm7Py1A4bv3x3Pdvg7FqR8mLgEE0gNTI1qDtlYQIQnw==",
+ "dependencies": {
+ "McMaster.Extensions.CommandLineUtils": "5.1.0",
+ "Microsoft.Extensions.Hosting.Abstractions": "10.0.5",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.5"
+ }
+ },
+ "Microsoft.Extensions.Configuration": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "plJWK2zpWuuyxI8F8s2scx6Je7N1Ajjs6HvYUGKwRnDMWIVIz9FHwAkiT7ASgrvAOd10T0FPVlh9BzAJJME+jg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Primitives": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.Configuration.Json": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "uvJ6sHwjgrkMEJOgiC76G0mcZGXerwyyWkwX34EOjCbxKG6TCtfAoqDKAMsCvEBf9HxjlGQEgqsSMOGCmGBf+A==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Configuration.FileExtensions": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.10"
+ }
+ },
+ "Microsoft.Extensions.DependencyInjection.Abstractions": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "z/2xXlFw2aLGjHyEm6E0tQ+In6VfzQzTrtArbQ2c0TQE16ZbyDCMGPvaUT9I0s8rgy9sRWlU2P9waW37qV04qA=="
+ },
+ "Microsoft.Extensions.Hosting": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "tL9FkfV64GPUDSPvwrgyw42LVzsnVAnyrqJEuZVJbODgrQ3eL63zmzEcVWoCHzfgqUhWggzbgAyUCnz/zfI3Pg==",
+ "dependencies": {
+ "Microsoft.Extensions.Configuration": "10.0.10",
+ "Microsoft.Extensions.Configuration.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Configuration.Binder": "10.0.10",
+ "Microsoft.Extensions.Configuration.CommandLine": "10.0.10",
+ "Microsoft.Extensions.Configuration.EnvironmentVariables": "10.0.10",
+ "Microsoft.Extensions.Configuration.FileExtensions": "10.0.10",
+ "Microsoft.Extensions.Configuration.Json": "10.0.10",
+ "Microsoft.Extensions.Configuration.UserSecrets": "10.0.10",
+ "Microsoft.Extensions.DependencyInjection": "10.0.10",
+ "Microsoft.Extensions.DependencyInjection.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Diagnostics": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Abstractions": "10.0.10",
+ "Microsoft.Extensions.FileProviders.Physical": "10.0.10",
+ "Microsoft.Extensions.Hosting.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging": "10.0.10",
+ "Microsoft.Extensions.Logging.Abstractions": "10.0.10",
+ "Microsoft.Extensions.Logging.Configuration": "10.0.10",
+ "Microsoft.Extensions.Logging.Console": "10.0.10",
+ "Microsoft.Extensions.Logging.Debug": "10.0.10",
+ "Microsoft.Extensions.Logging.EventLog": "10.0.10",
+ "Microsoft.Extensions.Logging.EventSource": "10.0.10",
+ "Microsoft.Extensions.Options": "10.0.10"
+ }
+ },
+ "Mono.Cecil": {
+ "type": "CentralTransitive",
+ "requested": "[0.11.6, )",
+ "resolved": "0.11.6",
+ "contentHash": "f33RkDtZO8VlGXCtmQIviOtxgnUdym9xx/b1p9h91CRGOsJFxCFOFK1FDbVt1OCf1aWwYejUFa2MOQyFWTFjbA=="
+ },
+ "NuGet.Frameworks": {
+ "type": "CentralTransitive",
+ "requested": "[7.6.0, )",
+ "resolved": "7.6.0",
+ "contentHash": "rJ7QtKN45XzLXCrMATve6eFLiUyUGEkA1rFSb6U6Fw6laM4hEAcKOrcdbgWlcFUlCK2158qP1LF00hg/ivF3nw=="
+ },
+ "NuGet.Protocol": {
+ "type": "CentralTransitive",
+ "requested": "[7.6.0, )",
+ "resolved": "7.6.0",
+ "contentHash": "Ccb9dJG9hW0FdHFjXoHmhJBBJRYSCeSJArLdZjyZj6/FEAIKezLn75KFQNrTPE5UiAp4HVrjBizufZ/0IXhfKQ==",
+ "dependencies": {
+ "NuGet.Packaging": "7.6.0"
+ }
+ },
+ "System.Collections.Immutable": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "Ih5zrydoDc1H5I0eNP6f4Lzw3cjsPMN4Nikd86kbyi66y0flkM9GfjVo62aUbcxeTbypzBCFAFQ+/6RF2jRORg=="
+ },
+ "System.Composition.AttributedModel": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "alK+Ew7XBsxHgwmSmiZzg7x4sLpNIaQ3QVJUkJ/issHZY0L+RHceqO27pDp0J0sDnSf8g6yJNpDnWSKL5sAa/g=="
+ },
+ "System.Reflection.Metadata": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "NZIS6/IUBh70nJfVvE577oDc81y5GfYRgjWssC8AGpSlVzSu5YfbHXEtHXyLeEY7gqqbAaASwJEP0Oy3Q54Jfw=="
+ },
+ "System.Runtime.CompilerServices.Unsafe": {
+ "type": "CentralTransitive",
+ "requested": "[6.1.2, )",
+ "resolved": "6.1.2",
+ "contentHash": "2hBr6zdbIBTDE3EhK7NSVNdX58uTK6iHW/P/Axmm9sl1xoGSLqDvMtpecn226TNwHByFokYwJmt/aQQNlO5CRw=="
+ },
+ "System.Security.Cryptography.Pkcs": {
+ "type": "CentralTransitive",
+ "requested": "[10.0.10, )",
+ "resolved": "10.0.10",
+ "contentHash": "KG8t5RHczdgB3IWvRndpI0nE1DSo7ikDYSDbITxfgRFyIvnYiKzuPjaZOsPnwFQ1aOGUl9sEulJul9wlHLEUoA=="
+ }
+ }
+ }
+}
\ No newline at end of file
diff --git a/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj b/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj
index 405d9e687..8a70111f4 100644
--- a/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj
+++ b/ICSharpCode.ILSpyCmd/ICSharpCode.ILSpyCmd.csproj
@@ -71,4 +71,8 @@
+
+
+
+
diff --git a/ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs b/ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs
index 1d4489fc5..5968c22d4 100644
--- a/ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs
+++ b/ICSharpCode.ILSpyCmd/IlspyCmdProgram.cs
@@ -23,7 +23,9 @@ using System.IO;
using System.IO.Compression;
using System.IO.MemoryMappedFiles;
using System.Linq;
+using System.Globalization;
using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
using System.Reflection.PortableExecutable;
using System.Threading;
using System.Threading.Tasks;
@@ -33,6 +35,7 @@ using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.CSharp;
using ICSharpCode.Decompiler.CSharp.ProjectDecompiler;
using ICSharpCode.Decompiler.DebugInfo;
+using ICSharpCode.Decompiler.Documentation;
using ICSharpCode.Decompiler.Disassembler;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Solution;
@@ -105,6 +108,9 @@ Examples:
[Option("-t|--type ", "The fully qualified name of the type to decompile.", CommandOptionType.SingleValue)]
public string TypeName { get; }
+ [Option("-m|--member ", "The single member to decompile: an XML documentation id string (e.g. \"M:System.String.Concat(System.String,System.String)\", as also accepted by the UI's --navigateto option) or a metadata token (e.g. 0x06000005).", CommandOptionType.SingleValue)]
+ public string MemberIdString { get; }
+
[Option("-il|--ilcode", "Show IL code.", CommandOptionType.NoValue)]
public bool ShowILCodeFlag { get; }
@@ -359,6 +365,12 @@ Examples:
}
else
{
+ if (MemberIdString != null && TypeName != null)
+ {
+ app.Error.WriteLine("The --type and --member options are mutually exclusive.");
+ return ProgramExitCodes.EX_USAGE;
+ }
+
if (outputDirectory != null)
{
string outputName = Path.GetFileNameWithoutExtension(fileName);
@@ -366,6 +378,11 @@ Examples:
(string.IsNullOrEmpty(TypeName) ? outputName : TypeName) + ".decompiled.cs"));
}
+ if (MemberIdString != null)
+ {
+ return DecompileMember(fileName, output, MemberIdString);
+ }
+
return Decompile(fileName, output, TypeName);
}
}
@@ -619,6 +636,84 @@ Examples:
return 0;
}
+ int DecompileMember(string assemblyFileName, TextWriter output, string idOrToken)
+ {
+ CSharpDecompiler decompiler = GetDecompiler(assemblyFileName);
+
+ if (!TryResolveMember(decompiler.TypeSystem, idOrToken, out EntityHandle handle, out string error))
+ {
+ Console.Error.WriteLine(error);
+ return ProgramExitCodes.EX_DATAERR;
+ }
+
+ output.Write(decompiler.DecompileAsString(handle));
+ return 0;
+ }
+
+ ///
+ /// Resolves a member reference supplied on the command line: either an XML
+ /// documentation id string ("M:...", "P:...", "F:...", "E:..." or "T:...") or a
+ /// metadata token in hexadecimal "0x06000005" form. Documentation id strings use
+ /// the same syntax as the compiler-generated documentation files and the UI's
+ /// --navigateto option.
+ ///
+ static bool TryResolveMember(IDecompilerTypeSystem typeSystem, string idOrToken, out EntityHandle handle, out string error)
+ {
+ handle = default;
+ error = null;
+ string trimmed = idOrToken.Trim();
+
+ if (trimmed.StartsWith("0x", StringComparison.OrdinalIgnoreCase))
+ {
+ if (!int.TryParse(trimmed.AsSpan(2), NumberStyles.HexNumber, CultureInfo.InvariantCulture, out int tokenValue))
+ {
+ error = $"'{trimmed}' is not a valid metadata token; expected a hexadecimal value like 0x06000005.";
+ return false;
+ }
+ var metadata = typeSystem.MainModule.MetadataFile.Metadata;
+ var candidate = MetadataTokens.EntityHandle(tokenValue);
+ int rowNumber = tokenValue & 0x00ffffff;
+ int rowCount = candidate.Kind switch {
+ HandleKind.TypeDefinition => metadata.TypeDefinitions.Count,
+ HandleKind.FieldDefinition => metadata.FieldDefinitions.Count,
+ HandleKind.MethodDefinition => metadata.MethodDefinitions.Count,
+ HandleKind.PropertyDefinition => metadata.PropertyDefinitions.Count,
+ HandleKind.EventDefinition => metadata.EventDefinitions.Count,
+ _ => 0,
+ };
+ if (rowNumber < 1 || rowNumber > rowCount)
+ {
+ error = $"Metadata token {trimmed} does not reference a type or member of this module.";
+ return false;
+ }
+ handle = candidate;
+ return true;
+ }
+
+ IEntity entity;
+ try
+ {
+ entity = IdStringProvider.FindEntity(trimmed, new SimpleTypeResolveContext(typeSystem.MainModule));
+ }
+ catch (ReflectionNameParseException ex)
+ {
+ error = $"'{trimmed}' is not a valid documentation id string: {ex.Message}";
+ return false;
+ }
+ if (entity == null || entity.MetadataToken.IsNil)
+ {
+ error = $"Member '{trimmed}' was not found in this module. Expected an XML documentation id string (e.g. \"M:System.String.Concat(System.String,System.String)\") or a metadata token (e.g. 0x06000005).";
+ return false;
+ }
+ if (entity.ParentModule != typeSystem.MainModule)
+ {
+ error = $"Member '{trimmed}' is defined in '{entity.ParentModule?.AssemblyName}', not in this module.";
+ return false;
+ }
+ handle = entity.MetadataToken;
+ return true;
+ }
+
///
/// Resolves a type name supplied on the command line to a single type definition.
///
diff --git a/ILSpy.Desktop.slnf b/ILSpy.Desktop.slnf
index 1317367df..906305e90 100644
--- a/ILSpy.Desktop.slnf
+++ b/ILSpy.Desktop.slnf
@@ -5,6 +5,7 @@
"ICSharpCode.BamlDecompiler\\ICSharpCode.BamlDecompiler.csproj",
"ICSharpCode.Decompiler.TestRunner\\ICSharpCode.Decompiler.TestRunner.csproj",
"ICSharpCode.Decompiler.Tests\\ICSharpCode.Decompiler.Tests.csproj",
+ "ICSharpCode.ILSpyCmd.Tests\\ICSharpCode.ILSpyCmd.Tests.csproj",
"ICSharpCode.Decompiler\\ICSharpCode.Decompiler.csproj",
"ICSharpCode.ILSpyX\\ICSharpCode.ILSpyX.csproj",
"ILSpy.BamlDecompiler.Tests\\ILSpy.BamlDecompiler.Tests.csproj",
diff --git a/ILSpy.XPlat.slnf b/ILSpy.XPlat.slnf
index ca432d29c..42d3936e9 100644
--- a/ILSpy.XPlat.slnf
+++ b/ILSpy.XPlat.slnf
@@ -3,6 +3,7 @@
"path": "ILSpy.sln",
"projects": [
"ICSharpCode.ILSpyCmd\\ICSharpCode.ILSpyCmd.csproj",
+ "ICSharpCode.ILSpyCmd.Tests\\ICSharpCode.ILSpyCmd.Tests.csproj",
"ICSharpCode.Decompiler.PowerShell\\ICSharpCode.Decompiler.PowerShell.csproj",
"ICSharpCode.Decompiler.TestRunner\\ICSharpCode.Decompiler.TestRunner.csproj",
"ICSharpCode.Decompiler.Tests\\ICSharpCode.Decompiler.Tests.csproj",
diff --git a/ILSpy.sln b/ILSpy.sln
index 2de1bce33..b75eea7a1 100644
--- a/ILSpy.sln
+++ b/ILSpy.sln
@@ -49,6 +49,8 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.BamlDecompiler.Tests"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ILSpy.BamlDecompiler.Tests.Windows", "ILSpy.BamlDecompiler.Tests.Windows\ILSpy.BamlDecompiler.Tests.Windows.csproj", "{7A5C3CEF-0744-4643-BA1E-7AE6610FF269}"
EndProject
+Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ICSharpCode.ILSpyCmd.Tests", "ICSharpCode.ILSpyCmd.Tests\ICSharpCode.ILSpyCmd.Tests.csproj", "{042FE5F2-3C0A-4B99-A268-D1917CC67B47}"
+EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@@ -239,6 +241,18 @@ Global
{7A5C3CEF-0744-4643-BA1E-7AE6610FF269}.Release|x64.Build.0 = Release|Any CPU
{7A5C3CEF-0744-4643-BA1E-7AE6610FF269}.Release|x86.ActiveCfg = Release|Any CPU
{7A5C3CEF-0744-4643-BA1E-7AE6610FF269}.Release|x86.Build.0 = Release|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Debug|Any CPU.Build.0 = Debug|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Debug|x64.ActiveCfg = Debug|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Debug|x64.Build.0 = Debug|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Debug|x86.ActiveCfg = Debug|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Debug|x86.Build.0 = Debug|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Release|Any CPU.ActiveCfg = Release|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Release|Any CPU.Build.0 = Release|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Release|x64.ActiveCfg = Release|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Release|x64.Build.0 = Release|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Release|x86.ActiveCfg = Release|Any CPU
+ {042FE5F2-3C0A-4B99-A268-D1917CC67B47}.Release|x86.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE