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
The Semantics and Association columns were read from offsets relative
to the metadata root instead of the current row: Semantics always
decoded the first two bytes of the metadata header and Association a
constant offset near it, so only the Method column ever carried real
row data. The Association coded-index width also used the plain-index
threshold (2^16) instead of the coded one (2^15 for one tag bit).
Rewrite the loop with a BlobReader positioned at the table start,
reading each column in sequence, and introduce SimpleIndexSize and
CodedIndexSize helpers encoding the ECMA-335 II.24.2.6 width rules.
The GUI's MethodSemantics metadata table view consumes this helper and
displayed the garbage values.
Assisted-by: Claude:claude-fable-5:Claude Code
On FIPS-mode systems the platform crypto provider refuses to create
SHA-1 instances (OpenSSL: error:03000098 invalid digest), so merely
displaying a strong-named assembly's identity failed. The public-key
token is a non-secret identity hash whose algorithm is fixed by
ECMA-335, so the two token sites now use dotnet/runtime's managed
Sha1ForNonSecretPurposes, vendored with its license header intact and
shielded from the repo formatter via generated_code in .editorconfig
so future upstream syncs diff cleanly. IncrementalHash was considered
and rejected: like SHA1.Create(), it resolves the digest through the
host crypto policy, and Roslyn's equivalent token code also relies on
the platform SHA-1, so it offers no precedent for FIPS safety.
Assisted-by: Claude:claude-fable-5:Claude Code
We now avoid the old `IModuleReference` interface which required allocating for every type being resolved.
Instead `MetadataModule.ResolveModule` now combines decoding+resolving assembly references into a single step.
This allows the type system to maintain a cache indexed by row number.
This also changes the behavior of resolving references within a compilation: We now prefer an exact match (name + version + publickeytoken) first; and fall back to a name-only match only if no exact match exists.
This somewhat improves the decompilation of assemblies created by using ilmerge to combine assemblies with different target frameworks.
While support for multi-module assemblies isn't fully working yet; it is clear at this point that we want
to treat each module in a multi-module assembly separately for the purposes of the type system.
This is a work-in-progress; ILSpy is not functional with this commit.
The old code path still exists but is broken because some classes were modified for the new system.
The new system is still highly incomplete (types only have fields, but no methods).