UnscopedRef only appeared on a params parameter anywhere in the
suite; a ref-returning method and property on a ref struct pin the
attribute round-trip.
Assisted-by: Claude:claude-fable-5:Claude Code
Static abstract interface members had no checked operator or
unsigned-right-shift coverage, and static abstract property getters
were never read as rvalues through the constraint.
Assisted-by: Claude:claude-fable-5:Claude Code
Compound assignments selecting between op_Addition and
op_CheckedAddition across a checked block boundary were not
covered.
Assisted-by: Claude:claude-fable-5:Claude Code
Generic attributes were only closed over simple types; constructed
generic, array, and enum type arguments exercise separate paths in
the custom-attribute blob decoder.
Assisted-by: Claude:claude-fable-5:Claude Code
SetsRequiredMembers had no coverage anywhere; required members
across a base/derived pair and in a generic abstract host were also
untested.
Assisted-by: Claude:claude-fable-5:Claude Code
readonly record struct had no coverage, and no record overrode a
synthesized member; user-declared ToString and PrintMembers pin the
synthesized-vs-user member detection.
Assisted-by: Claude:claude-fable-5:Claude Code
Only two plain ASCII u8 literals were covered; the empty literal and
a literal made of escape sequences pin the recovery heuristic
boundaries.
Assisted-by: Claude:claude-fable-5:Claude Code
The C# 6 index-initializer syntax was only covered through custom
indexers; a real Dictionary<,> initialized with [key] = value pins
the choice between the index form and the Add form.
Assisted-by: Claude:claude-fable-5:Claude Code
ConfigureAwait(false) inside an async iterator and await foreach
over ConfiguredCancelableAsyncEnumerable were not covered.
Assisted-by: Claude:claude-fable-5:Claude Code
Only interface-based disposal was covered; a using declaration over
a ref struct with a pattern-based Dispose exercises the recognition
heuristic without IDisposable.
Assisted-by: Claude:claude-fable-5:Claude Code
protected and protected internal default interface members, static
properties and field-like events in interfaces, and a generic
interface with a constrained generic default method were not
covered.
Assisted-by: Claude:claude-fable-5:Claude Code
The fixture had an iterator local function but no async local
function; the async state-machine-in-local-function shape, static
and capturing, was not covered.
Assisted-by: Claude:claude-fable-5:Claude Code
await inside a null-coalescing expression, as a do-while condition,
on a ValueTask, and inside an interpolated-string hole (the
DefaultInterpolatedStringHandler lowering) were not covered.
Assisted-by: Claude:claude-fable-5:Claude Code
dynamic used as a while-loop condition and the null-conditional
invocation operator on a dynamic receiver were not covered.
Assisted-by: Claude:claude-fable-5:Claude Code
AddChecked/MultiplyChecked/ConvertChecked nodes were not covered;
they are pretty-printed as a checked block around the tree-building
calls.
Assisted-by: Claude:claude-fable-5:Claude Code
Only group-by continuations were covered; a continuation introduced
by select-into exercises a different transparent-identifier reset.
Assisted-by: Claude:claude-fable-5:Claude Code
Virtual/override/sealed-override auto-properties, implicit and
explicit interface implementations, asymmetric accessor
accessibility, and auto-properties in structs were not covered.
Assisted-by: Claude:claude-fable-5:Claude Code
Anonymous types nested as members of other anonymous types (and read
back through the projection), ToString on an anonymous instance, and
explicit member projections were not covered.
Assisted-by: Claude:claude-fable-5:Claude Code
The lifted-operator matrix only used pure expressions; compound
assignment on nullable locals and boxing/unboxing conversions of
Nullable<T> were not covered.
Assisted-by: Claude:claude-fable-5:Claude Code
All iterator producers in the fixture used concrete element types;
a generic method pins the reconstruction of the generic state
machine type.
Assisted-by: Claude:claude-fable-5:Claude Code
Generic co-/contravariance had no test coverage at all: no out/in
variance modifier on any interface or delegate declaration and no
variant reference conversion appeared anywhere in the test suite.
The new fixture pins declarations (including a constrained covariant
interface and an explicit implementation of a variant interface) and
conversion shapes that must not produce explicit casts.
Assisted-by: Claude:claude-fable-5:Claude Code
All existing filter tests only read state; a filter that mutates a
ref local observed by the handler pins the ordering between the
filter expression and the handler body.
Assisted-by: Claude:claude-fable-5:Claude Code
Pins the reconstruction of a continue statement in a catch block
inside a foreach loop, which used to decompile to a goto targeting
a label at the end of the loop body. #2829 reported the goto form
and can be closed.
Assisted-by: Claude:claude-fable-5:Claude Code
The UnsafeCode fixture had no double-indirection coverage at all:
no pointer-to-pointer loads, stores, or indexing, and no fixed
statement over an element of a pointer array.
Assisted-by: Claude:claude-fable-5:Claude Code
The Documentation namespace (XmlDocumentationProvider, IdStringProvider,
XmlDocLoader) had no test coverage at all, even though XmlDoc is listed
as an implemented C# 1 feature on the wiki Language-Feature-Roadmap.
These tests pin ID-string generation and FindEntity round-trips for the
intricate encodings (nested generic types, `0/``0 type-parameter
references, ref/out @ suffixes, pointer and jagged/multi-dimensional
array forms incl. [0:,0:], conversion operators with the ~ReturnType
suffix, indexers, #ctor) plus XmlDocumentationProvider lookup by ID
string and by entity against a generated doc file. All green.
Assisted-by: Claude:claude-fable-5:Claude Code
Doc-comment folds were created with defaultCollapsed hardcoded to true,
so /// blocks always started collapsed. The new Display option is
bridged into DecompilerSettings like the other expand flags and drives
the fold's default state.
Detecting the last line of a doc-comment block requires sibling
navigation between trivia nodes, so trivia now carry parent, sibling
list, and index state. That state lives on the Trivia subclass to keep
AstNode's size unchanged, and the tree API treats trivia as a separate
navigation space: Next/PrevSibling and Remove work within the owning
list, Slot is null, ReplaceWith throws instead of aliasing the trivia
index into the parent's child slots, GetNextNode/GetPrevNode stop at
the list boundary, Clone and CopyAnnotationsFrom deep-copy and reparent
trivia, and CheckInvariant validates the trivia lists.
Assisted-by: Claude:claude-fable-5:Claude Code
AvaloniaEdit 12's TextView.InvalidateLayer only invalidates the TextView's
measure and never re-renders the per-layer child visuals, so the caret layer
repaints only on caret blinks (focused editor) or scroll changes. During
debug-step navigation focus stays in the Debug Steps panel, so the one scroll
repaint painted an early animation frame and nothing ever erased it: the frame
stayed composited as a caret-sized black line fixed in the viewport. The
adorner now invalidates the layer visuals itself on start, every animation
frame, and dismissal, and keeps its rectangles in document coordinates so the
deferred centering scroll cannot strand the highlight at a stale viewport
position.
Assisted-by: Claude:claude-fable-5:Claude Code
Local OpenSSL defaults can reject legacy SHA-1 signatures during dotnet operations. Set the required compatibility flag inside the repository scripts so restore, build, publish, clean, and formatting paths do not depend on each caller's shell environment.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Browsing an embedded .baml resource runs it through BamlReader.ReadDocument,
whose post-parse defer pass walks the record list with NavigateTree. That walk
recursed on every nested StaticResourceStart/KeyElementStart record with no
depth cap and indexed the record list with no bound. A crafted resource could
therefore drive recursion into a StackOverflowException -- which is uncatchable
and kills the process despite the resource node's try/catch -- or walk the index
off the end of the list. Both are reachable from ordinary resource browsing, no
project export required.
Consolidate the duplicated defer walk into one bounded, depth-capped helper that
fails with a catchable InvalidDataException, so the existing UI catch turns a
malformed resource into a "BAML decompilation failed" message instead of a crash.
Reject an oversized signature length before it drives a multi-gigabyte allocation
(it is read before the MSBAML check), and resolve defer offsets with TryGetValue
so a bogus offset reports malformed data rather than escaping as a bare
KeyNotFoundException.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Avalonia apps pack every resource (compiled XAML, image/SVG assets, ...)
behind a single !AvaloniaResources manifest blob, which until now fell
through to the generic resource node and could not be browsed. Parse the
blob's index and expose each packed file as its own entry, mirroring how
.resources files are unpacked, so individual files can be viewed and
saved. The reader is bounds-checked against crafted offsets/sizes in the
same defensive spirit as the recent .rsrc parsing guards.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Reduce nested generation routines by moving constructor, child-dispatch, slot, and slot-kind emission into focused helpers. This keeps generator behavior intact while making the source-generator control flow easier to review and maintain.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
The step recorder is shared by C# AST and ILAst replay, so keep the public infrastructure out of IL.Transforms and pass language-specific node navigation through neutral node metadata.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
The IL (Stepper) and C# (TransformContext) paths each recorded the changed
node, its seam neighbours, and its ancestor chain with duplicated logic that
could drift. Move the ordering/dedup/seam strategy onto
Stepper.Node.RecordModifiedNode; each language keeps only its own node
navigation.
Assisted-by: Claude:claude-opus-4-8:Claude Code
Keep the IsUnsafe visitor path context-free while avoiding repeated null guards around debug-step recording in the unsafe modifier transform.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
TreeViewItem handles Enter for expand and collapse before bubble-phase handlers run, so install the replay shortcut in the tunnel phase to keep group-row commands reachable.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Normal decompiles do not consume node ranges, so keep AvaloniaEdit node tracking opt-in and enable it only for step-limited replay output.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Avoid stale dispatcher callbacks scrolling the editor after a later decompile has cleared or replaced the debug-step highlight.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
Keep existing modified-node candidates when a transform cannot provide a produced node, matching the IL transform helper and preserving highlight fallback quality.
Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
OnSelectionChanged deferred its Steps = null via Dispatcher.Post. The selection
message is raised synchronously on the UI thread right as the new selection's
decompile is kicked off (AssemblyTreeModel.RaiseSelectionChanged), so a deferred
clear can land on a later dispatcher cycle than the decompile's StepperUpdated
populate post and wipe the freshly recorded steps -- leaving the pane empty
until the next decompile (the intermittent CI timeout in the debug-step UI
tests, where both C# and ILAst share this handler). Clear synchronously so the
blank is pinned to the selection moment, strictly before that selection's
decompile can finish and post its steps.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The replay tests only checked DebugStepHighlight was non-null, which the
ancestor fallback satisfies unconditionally -- a regression widening every
highlight to the enclosing method would have passed. Assert instead that the
range lies in bounds, does not span the whole document, and (unless it is a
zero-length removal caret) covers non-whitespace rendered code.
Assisted-by: Claude:claude-opus-4-8:Claude Code
When the step limit falls on a C# transform step, Stepper.Step records the node
as LimitReachedStep but throws before TransformContext can attach the node's
highlight candidates, so the 'show state before' view had only the bare modified
node to resolve against -- and nothing if that node renders no text of its own.
The IL path already records its candidates before the throw; mirror that on the
C# side by attaching the candidates to the limit-reached node in the catch, then
re-throwing so the pipeline still halts.
Assisted-by: Claude:claude-opus-4-8:Claude Code
NodeLookup.AddNode indexed every annotation of every rendered node by reference
identity, but the debug-step highlighter only ever looks up the DebugStepMarker;
the rest were dead keys, and a shared annotation (ResolveResult and friends,
copied across nodes) would resolve to whichever node rendered last. Make
DebugStepMarker public and bridge only it -- behaviour-preserving for resolution
while dropping the per-annotation dictionary churn on every rendered node.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The debug-step node bracket (MarkNodeStart/try/finally/MarkNodeEnd) was copied
into every hand-written WriteTo override and re-emitted by the T4 generator, so
a newly added instruction could silently omit it and lose step highlighting with
no compile error or test failure. Seal WriteTo on ILInstruction to apply the
bracket once and delegate to a new abstract WriteToCore; move every override
(hand-written and generated) to WriteToCore without the wrapper. Rendered output
is unchanged -- the marks are no-ops unless the output tracks nodes.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The step tree can run to hundreds of entries per decompile, so finding a
specific mutation means scrolling. Add a filter box in the pane's top-right
corner: a row survives when its description -- or any descendant's -- contains
the text (case-insensitive), keeping the path to every match, and the tree
auto-expands while filtering so matches nested under transform groups stay
visible. Implemented as an item-visibility converter over the existing TreeView
rather than switching to SharpTreeView, which would change the Steps contract
and rewrite the pane's tests for no functional gain here.
Assisted-by: Claude:claude-opus-4-8:Claude Code
A step that removes a node has nothing left to highlight in the resulting text,
so range resolution fell back to the enclosing block and flooded it. Record the
changed node's surviving neighbours as seam anchors (captured before the
mutation) and split a step's candidates into precise / seam / ancestor tiers:
when neither the node nor its marker resolves, place a zero-length caret at the
gap -- the successor's start, else the predecessor's end -- and only fall back
to the enclosing block when no neighbour survives. A zero-length highlight is
rendered as a caret (positioned, pulsed, centered) with no background mark.
Assisted-by: Claude:claude-opus-4-8:Claude Code
NodeLookup population runs per AST node (and per annotation) on every on-screen
C# decompile, but the debug-step highlighter only consumes it when a step limit
is set. Gate the node-tracking token writer on StepLimit so the common Release
path skips the bookkeeping; AvaloniaEditTextOutput is an ISmartTextOutput, so it
still gets full syntax highlighting via the existing branch.
Assisted-by: Claude:claude-opus-4-8:Claude Code
The debug-step highlight centred with a logical (line-number * line-height)
calculation posted at default dispatcher priority. That ignores collapsed
foldings above the target, races the layout of a just-applied document
(silently no-oping when the viewport is not yet measured), and does not recheck
the document, so a newer decompile could scroll the wrong content. The symptom
was unreliable centring, most visible in the ILAst view whose nested block
output is fold-dense and larger.
Route the highlight through the existing CenterLineInView helper that bookmark
navigation already uses: it centres via GetVisualTopByDocumentLine (fold-aware),
runs at Background priority so the document finishes measuring first, and
rechecks the document identity.
Assisted-by: Claude:claude-opus-4-8:Claude Code
MarkNodeStart and BeginSpan captured builder.Length to anchor a node range
or highlight span, but indentation is written lazily on the first token of a
line. A node or span opened at the start of an indented line therefore
recorded its start before the leading tabs, so the debug-step highlight (and
any span) extended back across the indentation to column 0.
Flush the pending indent in both before capturing the offset, matching the
WPF AvalonEditTextOutput.BeginSpan the Avalonia port derived from. The emitted
text is unchanged -- the indent is written either way, in the same place; only
the recorded start moves to the first real character.
Assisted-by: Claude:claude-opus-4-8:Claude Code