Commit Graph
40 Commits
Author SHA1 Message Date
Siegfried Pammer e61128fe30 Fix PDB dump review findings
Use the PDB table row width for StateMachineMethod external MethodDef references, and include method-level custom debug information in decoded PDB output. Also report a missing Portable PDB explicitly when a debug metadata table is requested from an assembly without one.

Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
2026-10-04 19:11:01 +02:00
Siegfried Pammer eec881e113 Honor bundle entries when dumping PDBs
The PDB dumper opened the outer package path directly, so --bundle-entry was ignored while dumping debug information. Load package inputs through the shared entry resolver and pass Cecil the selected assembly image while keeping ordinary files on the path-based code path for adjacent PDB discovery.

Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
2026-10-04 09:07:45 +02:00
Siegfried Pammer 30dbce447e Add --dump-pdb, a cross-platform replacement for Pdb2Xml
The Pdb2Xml command that just left the app was the only way to see a PDB's
contents, and it was Windows-only. Mono.Cecil's symbol readers cover the
Portable and the Windows (native MSF) format in managed code and pick the
right one themselves, so a single dump path serves both on every OS.

Cecil's object model, rather than raw metadata, is what makes this work for
Windows PDBs at all: they have no metadata tables for --dump-table to read.
That also settles the split between the two options - --dump-table stays the
raw row view of a Portable PDB, --dump-pdb is the decoded one.

Neither symbol reader exposes the document list, so the documents are
collected from the sequence points that reference them.

Assisted-by: Claude:claude-opus-5:Claude Code
2026-10-02 07:44:55 +02:00
Siegfried Pammer 58be31306e Dump the Portable PDB debug tables with --dump-table
The metadata-table dumper only knew the Cor tables, so the debug metadata a
Portable PDB carries had no command-line view at all; the GUI has shown those
eight tables for years. Moving the dumper into ILSpyX puts it next to the PDB
providers it now needs and makes it available to any host, not just ilspycmd.

Two things a user would otherwise trip over: a standalone .pdb is accepted as
an input file, and asking an assembly for a debug table resolves the embedded
or adjacent PDB instead of reporting an empty table. Reading a debug table
without either would silently print nothing at all.

The GUI's StateMachineMethod reader moves to a shared extension. Its own copy
read the MethodDef column with ReadInt16 and switched to the wide form at
ushort.MaxValue rather than 1 << 16, so a large enough method table would have
produced negative RIDs.

Assisted-by: Claude:claude-opus-5:Claude Code
2026-10-02 07:44:55 +02:00
Siegfried Pammer 16737cc582 Convert BAML to XAML when exporting a project from the command line
A WPF assembly keeps its windows and pages as BAML, so a project exported
without converting them back is missing the parts that make it a WPF
application - and the reader has no XAML to look at either. The CLI could
do the conversion since --decompile-baml was added, but only if asked,
which meant that everything the project exporter learned about WPF (Page
and ApplicationDefinition items, resources, generated members removed
from the code-behind) was invisible to anyone following issue #2253 from
the command line.

The flag is kept and ignored: it is documented and scripted against, and
asking for what is now the default has to keep working.

The test fixture is a real .g.resources container rather than a directly
embedded .baml stream, because only entries inside a container reach
WriteResourceToFile - a standalone .baml is copied out untouched, which
is worth its own look.

Assisted-by: Claude:claude-opus-5:Claude Code
2026-09-04 11:10:53 +02:00
Siegfried Pammer 71ac2b9ca9 Fix #3154: accept single-file bundles as ilspycmd input
Every mode loaded the input file with its own `new PEFile(fileName)` call, so a
bundle - which the UI opens fine, because LoadedAssembly goes through the file
loader registry - failed identically in all of them. The five call sites now
share one load helper that runs the same registry, which also makes archives
work and keeps one detection point for both front ends.

Which assembly inside a bundle is meant is not something to guess, so a package
without --bundle-entry lists its managed entries and exits non-zero. The entry
point is only annotated in that listing: the manifest has no marker for it, so
it is derived the way the host does it, from the runtime-config entry's name,
and stays unannotated where that does not resolve.

Assisted-by: Claude:claude-opus-5:Claude Code
2026-09-02 00:12:30 +02:00
Siegfried Pammer 9971c7e6df Find the member a hand-written documentation id was aiming at
Typing "M:System.Linq.Enumerable.Where" at a command line is a reasonable thing
to do, and it found nothing: resolution compares the whole id string, so a form
without the parameter list only ever matched a member that genuinely takes none.
Spelling the signature out is no answer, because it means knowing the overload
count before asking. The same goes for a generic arity - and the exact spelling,
Dictionary`2, does not even survive an unquoted bash prompt, where a backtick
starts command substitution.

None of that makes the short form legal. Measured against Roslyn: its own
DocumentationCommentId resolver accepts no abbreviation at all, and the compiler
never emits one - a cref is a different grammar, which the compiler binds and
rewrites into a full id, warning CS0419 and picking one member when the cref is
ambiguous. A prefixed cref is copied through unvalidated, so an id in a
documentation file can be anything a human typed.

So the id grammar stays exact and IdStringProvider stays with it, which is what
lets cref-following trust its answer. The tolerance belongs to the callers that
serve people typing, and lives in DocumentationIdSearch as a ladder that loosens
one thing at a time: the exact id, then the id without its parameter list, then
without generic arities. Stating a detail wrongly still finds nothing; only
leaving one out asks for any. A rung may match several members and all of them
are returned, because which to present is the caller's decision and hiding the
rest would hide that the id was ambiguous.

ilspycmd shows every member of the group, headed by a comment naming the
ambiguity, and accepts the shapes people actually type: no prefix, a shortened
namespace, and arity written the cref or C# way.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-29 11:31:24 +02:00
Siegfried Pammer 3a8340ef60 Stop pointing the ILAst docs at a language that is not there
The ilspycmd dump and the contributor notes described themselves by reference to
the UI's ILAst language; the pane is what walks that pipeline now.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-27 09:46:46 +02:00
Siegfried Pammer 0566a81510 Make the ILAst dump faithful to what the decompiler runs
The dump is only useful if it shows the same thing the real pipeline is fed and
covers everything a transform bug can hide in, so: accessor bodies are reached
through the metadata handles (ITypeDefinition.Methods hides every method that
has method semantics), the PDB reaches the ILReader (UseDebugSymbols alone is
inert without DebugInfo), and the writing options carry the same sugar as the
UI's ILAst pane.

A method whose body cannot be read, transformed or written no longer aborts the
run, and the failure now travels through the decompilation-error path, so a
crashing transform is visible in stderr and in the exit code instead of being
buried in the output a script just collected.

BlockILTransform entries name the transforms they contain: two of them ran as
identical rows before, and asking for a nested transform by name reported it as
unknown while the listing did in fact run it.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-16 12:14:05 +02:00
Siegfried Pammer 259c843483 Add ILAst output to ilspycmd debug builds
The decompiler's intermediate representation was reachable only through the
GUI's ILAst language, so anyone debugging a transform or a matcher had to do it
by hand in the UI. --ilast writes the same representation to stdout, and
--after-transform truncates the pipeline at a chosen point, which makes the
effect of a single transform diffable and scriptable.

Debug-only, like the UI language it mirrors: ILAst serves ILSpy's own
development, not the users of the released tool, so it stays out of the shipped
NuGet package and out of the README's option list.

Nested per-block transforms stay unaddressable: they run inside a
BlockILTransform entry, and reaching them needs the Stepper, which is compiled
out of release builds anyway.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-16 12:03:37 +02:00
Siegfried Pammer 3cb27b0dcc Fix #3510: keep exporting a project when a member cannot be decompiled
One member the decompiler could not handle aborted the whole export, so a
single unsupported method in a large assembly left the user with nothing: no
sources, no .csproj, no way around it. Recovering silently would trade that
for a worse outcome - broken output nobody knows is broken - so every failure
is recorded, written where the content would have gone, and pointed at the
issue tracker.

The recovery has to hold for anything the export touches, not just method
bodies: a file that cannot be created, a resource that cannot be decoded, an
output visitor that throws mid-type. Each of those costs its own unit and
nothing else, and the units behind a failure are still produced - dropping
them would make the export look complete when it is not.

Consumers that relied on the exception keep their failure signal: ilspycmd
exits non-zero and lists the failures, the PowerShell cmdlets raise an error
record per failure, and the round-trip suite asserts the export reported none
- otherwise a crash on a method its own tests never call would ship green.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-10 21:00:47 +02:00
Siegfried Pammer 199b7bf151 Add --dump-table metadata dump mode to ilspycmd
The GUI has the metadata-tables view; the CLI had nothing, so checking
e.g. which MethodSemantics rows reference a Property row required a
hand-written System.Reflection.Metadata script. --dump-table <name>
prints every row of a table (RID, token, resolved names, heap offsets,
coded indexes) as an aligned text table, or as JSON with --json, for
the same 39 Cor tables the GUI shows.

Row enumeration for tables without public SRM row access lives in
MetadataExtensions next to the existing GetMethodSemantics helper, so
the GUI's raw-reading table nodes can be folded onto the shared
readers later. Every table's columns are spelled out explicitly in
ECMA-335 declaration order: reflecting over the SRM row structs would
tie the output (and its column order) to runtime internals, and
deterministic output is the point of the feature. JSON uses
System.Text.Json from the shared framework, so no new package
reference is needed.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-02 11:13:52 +02:00
Siegfried Pammer 74bc61b70f ilspycmd: add --member for single-member decompilation
Decompiling one method or property previously required decompiling its
whole type and searching the output, which is wasteful for scripted and
agent-driven use against large assemblies. The new -m|--member option
accepts an XML documentation id string (the syntax of compiler-generated
documentation files and of the UI's --navigateto option) or a metadata
token in 0x06000005 form, resolves it against the main module (with a
bounds check for tokens and distinct error messages for malformed ids,
unknown members, and members of other modules), and prints just that
member through the engine's single-member decompilation path.

The tests seed a new ICSharpCode.ILSpyCmd.Tests project (part of the
XPlat and Desktop solution filters and of the per-project CI test
steps), driving the real Main in-process via InternalsVisibleTo, so
future ilspycmd features have a dedicated home for CLI tests.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-07-28 14:25:04 +02:00
Siegfried Pammer 07d5a01d2b Add license headers to source files that lacked them
Backfills the standard MIT X11 header on hand-written files that never
got one, attributing each to its first-commit author and year from git
history. Code vendored from dotnet/runtime and Humanizr/Humanizer gets
its origin's license lines and a provenance note instead. Generated
files (Resources.Designer.cs, the version-info template), tool-managed
suppression files, and BAML test-case fixtures intentionally stay
header-less.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-07-05 21:09:46 +02:00
Siegfried Pammer 53498c5691 Fix #3797: resolve ilspycmd -t type names with fuzzy matching
--list-* printed generic types without their `n arity suffix, yet -t only
accepted the exact reflection name, so a name copied straight from the listing
threw "Could not find type definition". The listing now prints the reflection
name, and -t resolves through a ladder of progressively looser, uniqueness-
checked rules: the engine's exact lookup, an arity- and nesting-separator-
insensitive FullName match, a case-insensitive match, a namespace-less simple
name, and a trailing segment path ("Dictionary.KeyCollection"). The input is
parsed with System.Reflection.Metadata.TypeName and reduced to its underlying
definition first, so assembly qualification, generic arguments, and
array/pointer/byref decorations cannot corrupt the comparison key. An ambiguous
name reports its candidates instead of guessing, and a miss prints name
suggestions and returns EX_DATAERR rather than dumping a stack trace.

Assisted-by: Claude:claude-opus-4-8:Claude Code
2026-06-22 19:42:14 +02:00
Siegfried Pammer d89bf8589b Make PortablePdbWriter an instance type with an embed-source option
The portable-PDB writer carried its knobs (no-logo, pdb id, progress,
progress title) as a growing list of optional WritePdb parameters.
Turn the type into a configured instance whose options are properties,
and add EmbedSourceFiles (default true): when a PDB is generated next
to a project export whose .cs are already on disk, embedding the source
again is redundant, so the caller can turn it off. The per-document
checksum/hash is computed either way, so documents still resolve.

Assisted-by: Claude:claude-opus-4-8:Claude Code
2026-06-08 18:34:56 +02:00
Siegfried Pammer e02097dccf Replace ISettingsFilePathProvider with Func<string> and move IResourceFileHandler to ILSpyX. 2026-06-08 07:34:42 +02:00
Christoph Wille 1a9807079d Fix typos in cmd line options help (ILSpyCmd) 2026-05-18 07:03:44 +02:00
Siegfried Pammer d5e2e61a90 ilspycmd: route update-check messages to stderr
stdout is the data channel: --resource may be writing a binary payload to
it. Update-check notices on stdout would tail-append to the binary stream
and corrupt extracted files. Move them to stderr (npm/cargo/pip
convention) so meta-output stays out of the data path.
2026-05-07 22:31:10 +02:00
Siegfried Pammer 28fffb7e2c ilspycmd: add --list-resources, --resource, and --decompile-baml
--list-resources prints every leaf in the assembly's embedded
resources (including individual entries inside .resources containers).

--resource <name> extracts a single leaf. Names ending in .baml are
decompiled to XAML; everything else is emitted as raw bytes. Without
-o, BAML goes to stdout as text and binary leaves go to the binary
stdout stream. Unknown names exit with EX_DATAERR and print the
available leaves to stderr.

--decompile-baml is a modifier for -p that swaps in the new
BamlAwareWholeProjectDecompiler so .baml entries become .xaml Page
items in the generated project. Default -p behaviour is unchanged.
2026-05-07 22:31:10 +02:00
sonyps5201314 193a463766 Support batch PDB generation. (#3619)
* Support batch PDB generation.

* Use `FileMode.Create` for output PDB files to ensure existing files are fully overwritten/truncated.

* Localize the string `Generating portable PDB...`.

* Refine `GeneratePdbForAssemblies` implementation.

* Replace direct calls to `explorer.exe` with the Shell API to prevent spawning an `explorer.exe` process that doesn't exit automatically on every call.

* Batch calls to `ShellHelper.OpenFolderAndSelectItems` instead of looping `OpenFolderAndSelectItem`.

* Localize the string `Open Explorer`.

* Fix `OpenCmdHere` malfunction when ILSpy is running from a different drive than the OS.

* Refine `GeneratePdbForAssemblies` implementation.

* Replace WinForms `FolderBrowserDialog` with WPF `OpenFolderDialog`.

* Add license header

* Exclude duplicate entries entered by the user within `OpenFolderAndSelectItems`.

* Explicitly declare that `ShellHelper.cs` is a module that allows Pinvoke.

* Use `FileMode.Create` for output PDB files to ensure existing files are fully overwritten/truncated.

* Show original filenames when generating PDBs to improve UX during batch processing.
2025-11-25 23:00:21 +01:00
Peter Crabtree e7a64f3114 dev: Correct typo in ReportExcludedTypes (ilspycmd) 2025-08-26 06:51:20 +02:00
Siegfried Pammer bf5249be2b Add --ilspy-settingsfile and -ds|--decompiler-setting name=value options 2025-07-06 17:57:15 +02:00
Holger Schmidt 09ed31d391 Generate Mermaid HTML diagrammer from input assembly via ilspycmd (#3324)
* added mermaid class diagrammer

contributed from https://github.com/h0lg/netAmermaid - find earlier git history there

* reading from embedded resource instead of file

* swapped out icon to brand diagrammers as an ILSpy product

reusing linked ..\ILSpy\Images\ILSpy.ico from UI project

* added required ilspycmd options and routed call

* adjusted VS Code task to generate model.json required by the JS/CSS/HTML dev loop

* added debug launchSettings

* updated help command output

* using ILSpyX build info in generated diagrammers
removing unused code

* using explicit type where it's not obvious

* outputting in to a folder next to and named after the input assembly + " diagrammer" by default

* renamed diagrammer output to index.html

to support default web server configs in the wild

* improved instructions for creating an off-line diagrammer

* added developer-facing doco for how to edit the HTML/JS/CSS parts

* renamed to remove netAmermaid branding

* updated repo URL and doco link to new Wiki page

* copied over doco

* removed obsolete parts

* moved CLI doco into ILSpyCmd README

* removed end-user facing chapters that go into the Wiki from dev-facing doco

* updated to ilspycmd API and rebranded to ILSpy

* removed doco that's now in https://github.com/icsharpcode/ILSpy/wiki/Diagramming

* added tasks
2024-11-15 07:56:50 +01:00
Siegfried Pammer 963ff7cb3d Fix #3151: Make IProjectFileWriter API public 2024-03-31 18:46:46 +02:00
Christoph Wille 6e3b9ecc57 Make update check explicit, see #3101 2023-10-14 18:27:23 +02:00
Christoph Wille ca60ee84e4 Add option to disable the update check (might not be desired in automation scenarios) 2023-07-13 08:06:19 +02:00
Christoph Wille 35a3d97066 Activate update check in finally of OnExecuteAsync 2023-07-12 15:29:19 +02:00
Christoph Wille bf91f463f9 Latest version check added (disabled). (Temp) Fixed DirectoryExists for ReferencePaths (see https://github.com/natemcmaster/CommandLineUtils/issues/536) 2023-07-12 14:56:44 +02:00
Christoph Wille 8e3c1af974 Start using HostBuilder with CommandLineUtils 2023-07-12 14:14:29 +02:00
Christoph Wille 5156a9db00 Update CommandLineUtils, switch to OnExecuteAsync (although async is not yet used) 2023-07-12 14:08:40 +02:00
Daniel Grunwald 448fe3065e Also reject absolute paths in bundle decompression 2022-12-18 16:48:32 +01:00
Siegfried Pammer c797d53a76 Remove superfluous dollar signs from bundle/package error messages. 2022-12-05 23:00:18 +01:00
Siegfried Pammer 2a47bef99a Skip bundle entries that do not contain a plain relative path. 2022-12-05 23:00:18 +01:00
Siegfried Pammer 6855f589fc Fix #2858: Make sure that target directory of DumpPackageAssemblies exists. 2022-12-05 23:00:18 +01:00
Siegfried Pammer a6721df590 Fix #2707: Resolve full path to OutputDirectory before using it. 2022-06-16 18:02:59 +02:00
superstrom 29bfe82d11 Fix allowed Language Versions 2022-06-03 14:32:11 -04:00
Christoph Wille d5be62eb80 Fix #2675 2022-04-22 15:31:54 +02:00
Siegfried Pammer 05eb2cdf04 Fix #2363: CLI support for generating a solution from multiple projects (based on code provided by @marwie in #2364) 2022-04-15 19:43:31 +02:00
Christoph Wille afff9c325d Rename ics.d.Console to ics.ILSpyCmd 2022-04-07 15:49:47 +02:00