Token navigation can select rows before the destination table has realized the target container, and DataGrid's own scroll pass can leave the row at an edge. Defer the final scroll until the row exists and center it using the row's actual scroll host.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
The decompiler text view should not opt into visible line numbers independently of DisplaySettings. Keep the XAML default aligned with the persisted setting so first render and loaded settings agree.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Fold the caret highlight implementation into the text view, remove click-to-highlight behavior, and make the symbol highlight option/theme colors clearer.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
While the caret rests on a symbol in the code view, every occurrence of it in the document is marked, so reading a method no longer needs a click per symbol. Off by default and independent of the click highlight's marks.
When a package only offers a newer netcoreapp asset than the available stable Microsoft.NETCore.App.Ref package, nugetfuzz cannot build a reference set for that asset. Prefer the net48 asset when one is available so the package can still be included in a corpus sweep.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
This commit also changes the ILAst representation of with-initializers to preserve the `<Clone>$()` call, so that BlockKind.WithInitializer only forces the block into a certain shape, without assigning its special semantics.
The tool is only useful if someone can run it from the docs alone, and the
README entry left out the parts that decide whether the attempt works: the
POSIX form of the environment variables, that the trace appears only when the
process exits, which speedscope tab to open, and that the numbers are samples
rather than a measurement.
The README keeps a pointer instead of a second copy, so the two cannot drift.
Assisted-by: Claude:claude-opus-5:Claude Code
Nothing showed where a decompiler run's bytes go. The runtime already writes
a trace on request - DOTNET_EnableEventPipe needs no tool and no code in
ilspycmd or the UI - and PerfView reads it, but only on Windows, and neither
knows that ICSharpCode.Decompiler.IL is a different concern from
ICSharpCode.Decompiler.TypeSystem.
So the tool is a converter, not a profiler: it turns GCAllocationTick events
into a byte-weighted speedscope profile, which is the part the stock
conversion does not do - dotnet-trace's speedscope output is weighted by
time - and groups the same bytes by area of the decompiler. An allocation is
placed by the namespace its type name mentions, and when the runtime reports
a nested or compiler-generated type without one, by the innermost decompiler
frame on its stack, which names the code that wanted the object rather than
the object.
Assisted-by: Claude:claude-opus-5:Claude Code
Non-UI decompilation runs do not consume debug steps, but debug builds still allocated steppers and step nodes unless each context opted out manually. Keep step contexts empty unless the caller enables RecordSteps, while preserving the shared stepper path for the UI debug-step view.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Debug assertions should not allocate formatted messages on successful checks. Route interpolated assertion messages through a DEBUG-only handler so the message is built only when the assertion fails.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
The MetadataMethod constructor cut the post-dot short name for every
static non-generic method whose name contains a dot, only to test it
for an op_ prefix that almost never matches. The prefix is now checked
on a span slice first, so the substring (still required by
OperatorDeclaration.GetOperatorType) is allocated only for actual
explicit-interface operator implementations.
Assisted-by: Claude:claude-fable-5:Claude Code
The "IL with C#" view cut up to four substrings (prefix, trimmed
prefix, highlighted range, suffix) out of every source line emitted
alongside an IL instruction. ISmartTextOutput now accepts a
ReadOnlySpan<char> - as a default interface method falling back to
Write(text.ToString()) so existing implementers keep working - and
AvaloniaEditTextOutput appends the span straight into its
StringBuilder. The overload lives on ISmartTextOutput rather than
ITextOutput because the latter is netstandard2.0 (no default interface
methods there), where a new member would break every external
implementer of the decompiler library; the highlighted-comment path is
typed against ISmartTextOutput already.
Assisted-by: Claude:claude-fable-5:Claude Code
CleanUpVariableName sits on the per-variable naming path of every
decompiled method and allocated up to three intermediates (backtick
cut, m_/_ prefix strip, lowercase-first concat) before producing its
result, and its callers added further throwaway substrings when
stripping get_/set_/Get/Set and interface-I prefixes. The cuts are now
slices over the original name: ContainsNonPrintableIdentifierChar and
IsValidName gained span overloads, and only the final lowered name is
materialized, in a single allocation via char[] (netstandard2.0 has no
string(span) constructor). IsKeyword keeps its string parameter - it
is called on that final string anyway, and the keyword HashSet has no
span lookup on netstandard2.0.
Assisted-by: Claude:claude-fable-5:Claude Code
EscapeIdentifier runs for every identifier token emitted, yet it built
a StringBuilder plus a fresh result string even for the overwhelmingly
common case of an identifier with no escapable characters. A pre-scan
now returns the original instance untouched in that case, and the
surrogate-pair copy appends the two chars directly instead of cutting
a two-char substring. New unit tests pin the escaping behavior and the
identity fast path.
Assisted-by: Claude:claude-fable-5:Claude Code
WriteOpCode allocated two strings per rendered ldarg.N/ldloc.N/stloc.N
instruction (the digit cut off the mnemonic plus the concatenated
local-reference key), even though the shortcut forms only ever produce
the indices 0-3. The digit text and the param_/loc_ reference keys now
come from static tables indexed by opcode arithmetic.
Assisted-by: Claude:claude-fable-5:Claude Code
SplitTypeParameterCountFromReflectionName allocated the digits after
the backtick only to feed int.TryParse and discard them, and the
TopLevelTypeName constructor cut the name part twice for generic
types (once at the dot, again at the backtick), dropping the first
cut. Both run for every generic reflection name parsed, e.g. for
typeof-valued attribute arguments and string-switch metadata. The
arity is now parsed in place with a digit loop (netstandard2.0 has
no span int.TryParse) and each final string is cut exactly once.
The digit loop only accepts plain ASCII digits, so suffixes like
`+1 that int.TryParse tolerated are now rejected; such names are not
legal reflection names. New unit tests pin the parse edge cases.
Assisted-by: Claude:claude-fable-5:Claude Code
AbstractSearchStrategy.IsMatch runs for every metadata row of every
loaded module on each keystroke, yet it re-stripped the operator prefix
per name and, for fuzzy terms, additionally lowercased both the name
and the term - the largest allocation source in interactive search.
The terms are invariant for the lifetime of a strategy (each keystroke
builds a new request and strategy), so the stripping and lowercasing
now happen once in the constructor, and the noncontiguous matcher
compares spans with per-char ToLowerInvariant. This switches fuzzy
matching from culture-sensitive to invariant lowercasing, which is the
appropriate semantic for matching metadata names.
The new IsMatchTests pin the +, -, =, ~ operator semantics (including
the pre-existing quirk that =Name compares against the backtick-
suffixed name of generic types) as observed before the change.
Assisted-by: Claude:claude-fable-5:Claude Code
The loop preceding the parse has already proven that the tail consists
solely of ASCII digits, so the Substring+int.TryParse pair only
re-validated them at the cost of a throwaway string allocation.
SplitName runs per variable and per reserved-name registration for
every decompiled method, making this one of the hottest Substring call
sites in the decompiler. Accumulating the digits inline keeps the
TryParse overflow semantics (fall back to number=1 and the unchanged
name) without allocating.
Assisted-by: Claude:claude-fable-5:Claude Code
Most methods use the decompiler settings read-only. Clone only for the WinForms InitializeComponent special case that temporarily overrides settings before running the method pipeline.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
The regression only needs the nested catch inside an enclosing handler from #2829. Removing the explicit try/finally keeps the fixture focused on the failing control-flow shape instead of compiler-generated cleanup details.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
When the branches of a conditional have different types, its type falls
back to the IL stack slot type, which is (U)IntPtr. IntroduceNativeIntTypeOnLocals
only retypes variables, so with native integers enabled the branches got
cast to IntPtr. Map (U)IntPtr to n(u)int the same way boxing does; pointer
types are unaffected.
Inlining may extend a named-argument block: CanExtendNamedArgument moves an
expression into the first named-argument store (or the second one for an
instance call) and checks reordering against the stored values. The reverse
move was refused: Block.CanInlineIntoSlot rejected every slot of a
CallWithNamedArgs block, and CanMoveInto checked reordering against the whole
store instruction, which counts as a write to a local. The foreach pattern
relies on CanUninline to pull the Current getter back out of the loop body's
first statement, so once the getter had been inlined into a named-argument
block the loop was emitted as using + while (MoveNext()). Both checks now
mirror what inlining allows, so an expression inlined into a named-argument
block can always be un-inlined again.
Assisted-by: Claude:claude-fable-5-1:Claude Code
ImageSharp 4.x / ImageSharp.Drawing 3.x add a build-time license check
that fails Release builds without a Six Labors license key, and the
older 3.x / 2.x line is the last one without it. Magick.NET is Apache
2.0, bundles the native ImageMagick library for win/linux/osx, and
covers every encoder the fixtures need (PNG/BMP/JPG/GIF), so the
generator moves to it instead of carrying a license key.
The checked-in binary fixtures are regenerated with the new encoders;
the rendered shape (square, circle, diagonal stripe, border) is the
same, only the encoded bytes differ.
Assisted-by: Claude:claude-fable-5-1:Claude Code
A catch inside an enclosing EH region can leave to a try body that immediately branches to the loop continuation. Treat that leave as a continue so decompilation does not expose the synthetic end label for the catch path.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Resource export sometimes needs framework-specific ResX type names. Exposing the WinForms and mscorlib assembly suffixes keeps the writer default-compatible while letting callers choose older resource type names when needed.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
ResX export should still produce a valid file when no resources were added and the writer is finalized through Close or Dispose. Calling Generate from Close preserves creation timing while matching the empty-file behavior.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
VB can lower event-handler closures through generated wrapper methods, closure copy constructors, and immediately invoked VB anonymous delegate helpers. Recognizing and unwrapping those shapes leaves the expected lambda form and lets captured locals be scalar-replaced instead of exposing generated closure artifacts.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Avoid reusing a temporary receiver's stored value for extension-method lookup when its inferred source type no longer matches the local type.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
AvaloniaEdit's line-number margin moves the caret and selects the line,
and a fold marker toggles its fold, on any pointer button; the WPF
margins only reacted to the left button. A middle click opens a
reference in a new tab over the text, so one that lands on the gutter
should do nothing instead of folding code or moving the caret. The text
area itself still sees every button.
#4042
Assisted-by: Claude:claude-fable-5-1:Claude Code