Commit Graph
9556 Commits
Author SHA1 Message Date
Christoph Wille 24ec3327e7 Merge pull request #4045 from icsharpcode/dependabot/github_actions/github/codeql-action-4.37.8
Bump github/codeql-action from 4.37.7 to 4.37.8
2026-08-25 07:42:23 +02:00
dependabot[bot] 678699877b Bump github/codeql-action from 4.37.7 to 4.37.8
Bumps [github/codeql-action](https://github.com/github/codeql-action) from 4.37.7 to 4.37.8.
- [Release notes](https://github.com/github/codeql-action/releases)
- [Changelog](https://github.com/github/codeql-action/blob/main/CHANGELOG.md)
- [Commits](https://github.com/github/codeql-action/compare/v4.37.7...v4.37.8)

---
updated-dependencies:
- dependency-name: github/codeql-action
  dependency-version: 4.37.8
  dependency-type: direct:production
  update-type: version-update:semver-patch
...

Signed-off-by: dependabot[bot] <[email protected]>
2026-08-24 22:43:43 +00:00
Christoph Wille 542d3b0407 Merge pull request #4044 from icsharpcode/fix/4040-search-result-icon-overlays
Fix #4040: Compose accessibility and static overlays onto search result icons
2026-08-24 18:36:24 +02:00
Christoph Wille 6e298af439 Cover the method, property, event and namespace-fallback search icon arms
The search icon tests only exercised the type and field delegations; the
method, property and event arms and the namespace LocationImage fallback
for top-level types were untested.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-24 12:54:20 +02:00
Christoph Wille c80a2ec36a Route remaining flat icon sites through the tree nodes' GetIcon helpers
The derived-types entries, the compare pane, and the analyzer tree nodes
still built their icons from bare base images (or private duplicates of
the helper logic), losing the accessibility/static overlays and the
kind-specific glyphs (enum value, literal, readonly field, indexer,
P/Invoke, virtual and extension methods). The WPF frontend routes all of
these through the tree nodes' static GetIcon helpers; do the same so
every pane composes icons identically by construction.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-24 12:51:09 +02:00
Christoph Wille 300c075ffe Map protected-internal types to the plain protected overlay
The WPF frontend uses a type-only overlay mapper that shows protected
internal types with the plain protected badge, while members get the
combined protected-internal badge; the Avalonia frontend ran both through
the shared Images.GetOverlay and so badged types differently. Restore the
type-only mapping in TypeTreeNode.GetIcon, which now also covers search
results and every other caller of the helper.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-24 12:38:56 +02:00
Christoph Wille c11eded3ea Fix #4040: Compose accessibility and static overlays onto search result icons
The search result factory built icons from the bare base images, bypassing
Images.GetIcon, so search results lost the private/internal/protected and
static mini-overlays (and flattened interfaces, structs, enums and delegates
to the class icon; constructors, operators and indexers to the plain member
icons). Delegate to the tree nodes' GetIcon helpers instead, as the WPF
frontend's SearchResultFactory did, so search icons match the assembly tree
by construction. TypeTreeNode and EventTreeNode get the same static GetIcon
extraction the other member tree nodes already had.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-24 10:27:03 +02:00
Christoph Wille 88dd08a947 Merge pull request #4039 from icsharpcode/fix/ui-regressions-4027-4028-4030
Fix five Avalonia UI regressions: mouse navigation, derived types, Enter, Delete, Analyze in the Analyzer pane
2026-08-24 07:16:09 +02:00
Christoph Wille 38f113f1ef Analyzer pane no longer duplicates entries analysed from different panes (#4030)
The pane deduped new entries by comparing IModule instances, but analyzer
results live in the type system each analyzer run builds, so the same
member analysed from a result row and from the assembly tree (or from a
re-run analysis after its rows were collapsed away) never matched and got
a second top-level row. The loaded MetadataFile is the identity that
survives across type systems.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-23 17:19:09 +02:00
Siegfried Pammer 52f9748728 Merge pull request #4014 from icsharpcode/default-literals-convertto
Emit C# 7.1 default literals where the context supplies the type
2026-08-23 13:50:19 +02:00
Christoph Wille 7bf102f3b4 Keep the default literal's type when a conversion is unwrapped
Making a conversion implicit by unwrapping it hands the operand to a
different target type, and a default literal takes its value from that
type: "S? x = new S?(default)" holds a value, while "S? x = default" is
null. Unwrapping the nullable constructor around a shortened literal
therefore turned "S? x = default(S)" into a null nullable. The literal is
spelled out again whenever unwrapping moves it to a type other than the one
it was shortened from.

Converting a using resource to the declared variable type is unconditional
now (except when the declaration says "var", which supplies no type): the
declaration always spells the type out, so any conversion to it may stay
implicit, which is also what shortens default(T) there.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-22 21:35:22 +02:00
Christoph Wille 9238c3b63c Shorten default(T) in place, and say why operators keep the type
Mutating the DefaultValueExpression is enough here; ConvertTo already hands
out mutated input nodes elsewhere (UnwrapChild), so building a replacement
node and copying the annotations over bought nothing.

The operator special case is easy to mistake for a cosmetic preference,
because the null literal is accepted in the same position: it converts only
to reference and nullable types, so it still narrows operator overload
resolution, whereas the default literal converts to everything and C#
rejects it outright for every binary operator except == and !=.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-22 21:35:22 +02:00
Christoph Wille fe9f6db3ee Emit C# 7.1 default literals where the context supplies the type
Shortening default(T) is the same problem as removing the redundant cast
around a lambda whose delegate type the context already fixes, so it uses
the same mechanism: ConvertTo makes the explicit type implicit when the
conversion is an identity conversion and the caller allows an implicit
one. The literal keeps the type it was shortened from, so any later
conversion to a different type - or any context that requires an explicit
type, such as an overload resolution recheck falling back to CastArguments
- can spell default(T) out again. That keeps the value intact where the
bare literal would change it, e.g. "object o = default(SomeStruct)", which
boxes a non-null struct while "default" would be null.

Because the shortened literal resolves to DefaultLiteralResolveResult,
CallBuilder's existing overload resolution recheck sees a real default
literal and rejects ambiguous calls on its own; no separate bookkeeping
about which arguments may stay untyped is needed. Only the contexts that
supply no target type at all restore the explicit form: an awaited
expression, and arguments of operator methods, which later become operator
or cast syntax rather than calls.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-22 21:35:22 +02:00
Siegfried Pammer f3f80cd463 Ignore blank, comment and directive lines when aligning code diffs
The pretty-print comparison already treats blank lines, comment-only lines
and preprocessor directives as ignorable, but only when scoring a single
diff entry: they still sat in the line collections handed to the aligner. A
run of #if/#else/#endif around a statement could then push the aligner into
matching an adjacent brace as inserted-and-deleted, failing a test whose
decompiled output was in fact correct. Drop those lines before diffing so
they cannot skew the alignment.

Assisted-by: Claude:claude-opus-4-8:Claude Code
2026-08-22 21:35:09 +02:00
Christoph Wille 9dd0879b91 Analyze is offered again for Analyzer pane rows (#4030)
The port dropped IMemberTreeNode from AnalyzerEntityTreeNode, so the
member-based context-menu entries (Analyze, Copy name, ...) no longer
recognised analyzer rows and a result row could not be promoted to a
top-level entry. Top-level rows keep the entry hidden: re-analysing
them is a no-op, and Remove is the entry for those rows.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-22 10:37:35 +02:00
Christoph Wille 9132a0960b Delete key removes the selected tree rows again (#4030)
The WPF SharpTreeView bound ApplicationCommands.Delete at class level, so
Delete deleted the top-level selection of any tree whose nodes opt in via
CanDelete/Delete -- which is how a top-level analyzer entry was removed
from the Analyzer pane. The Avalonia tree never received that binding;
only the assembly list pane carried a hand-rolled Delete handler for
assemblies, so the analyzer pane lost the key entirely even though its
nodes still implement the deletion overrides.

Moving the gesture back into SharpTreeView restores it for every tree
and lets the pane-specific handler (with its own reselect logic) go.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-22 10:20:03 +02:00
Christoph Wille dfca502681 Fix #4027: mouse back/forward buttons navigate the history again
WPF translated XButton1/XButton2 into BrowseBack/BrowseForward
commands by itself, so the WPF frontend got the behaviour for free
and the buttons never reached the control under the pointer as a
click. Avalonia has no such translation and KeyBinding cannot express
pointer buttons, so only Alt+Left / Alt+Right survived the migration.
MainWindow now swallows the X-button press while it tunnels (Dock
would otherwise activate the pane under the pointer, AvaloniaEdit
would focus the editor or toggle a folding marker) and routes the
release to the existing DockWorkspace navigation commands.

Navigating also no longer moves the active pane to the editor: the
history target is usually the already-active tab, and Dock's
ActiveDockable setter re-runs InitActiveDockable -> SetFocusedDockable
even for an unchanged value, so re-activating it only moved the
focus. WPF's ActiveTabPage setter was a no-op for the same value.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-22 10:19:52 +02:00
Christoph Wille a04d40b895 Fix #4030: Enter did not activate the selected tree row
Avalonia 12 treats plain Enter/Space on a ListBoxItem as selection
input: the container marks the KeyDown handled before it bubbles, so
SharpTreeView.OnKeyDown never saw the keys and its activation handling
(navigate to the member from an analyzer row, toggle a checkable row)
was dead. Override ShouldTriggerSelection -- the extension point added
for this in Avalonia 12 -- to suppress the selection trigger exactly
for the case OnKeyDown activates instead: a single selected row that
is the row the key landed on. Multi-row selections keep the default
collapse-to-focused-row behaviour.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-20 10:15:58 +02:00
Christoph Wille 28a5cbb219 Fix #4028: derived-type entries were hidden by the filter cascade
DerivedTypesEntryNode.Filter reported Recurse, but the cascade's
Recurse handling force-loads the entry's lazy children and hides the
entry when all of them are hidden. A leaf derived type has no children,
so every entry under "Derived Types" ended up hidden, and the hiding
propagated up the whole derived chain. The WPF tree showed these
entries as matches; Match restores that and also keeps the entries'
children lazy instead of eagerly scanning the assembly list for each
level of the chain.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-20 10:11:53 +02:00
Daniel Grunwald f4ac761a10 Merge pull request #4021 from icsharpcode/tests/async-await-patterns
Add an async/await pattern test suite and fix the await operand conversions it found
2026-08-19 15:42:01 +02:00
Christoph Wille a546eae3ad Tie the .NET Framework fixture host to the test host's lifetime
The PowerShell host used to sleep for a fixed 300 s, so any run in which
the process walks got slow (as happened on a starved CI runner) lost the
host mid-fixture and failed the remaining tests for the wrong reason.
Waiting on the test host's PID makes the fixture independent of wall
clock and also guarantees the host disappears with the test host even
if the teardown never runs.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-19 15:03:51 +02:00
Christoph Wille c2fd475d25 Merge pull request #4033 from icsharpcode/decompiler-tests-server-gc
Use server GC for the decompiler test suite (workstation GC on the shared Windows CI runner)
2026-08-19 15:03:25 +02:00
Christoph Wille 1ddd5986ae Run the Windows CI test step under workstation GC
The Windows job runs every test host of the solution concurrently on a
4-core runner. With ICSharpCode.Decompiler.Tests on server GC that host
sits at 98-100% CPU for the whole test step, and the neighbours starve:
the process-module walk in ILSpy.Tests.Windows exceeded its 60 s budget
(OperationCanceledException in NetFrameworkProcessesTests, Release job),
a background sampler measured its own walk over the ~170 runner processes
at 40-170 s instead of a few seconds, and ILSpy.Tests took 685 s instead
of 375 s (Release). Memory was not the constraint: never below 9 GB free,
disk idle. The decompiler suite itself moved little on that box (Debug
1393 s -> 1226 s, Release 664 s -> 751 s). Server GC stays on for machines
the suite has to itself; the Linux job runs the projects one at a time.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-19 14:33:45 +02:00
Christoph Wille 7f8d641501 Use server GC for the decompiler test suite
The suite keeps one NUnit worker per logical CPU busy with allocation-heavy
decompiles (223 GB allocated per run), so under workstation GC every
gen0/gen1 collection any worker triggers suspends the whole process.
Measured on a 24-thread Windows box (Debug, ILSpy-tests checked out):
27,229 gen0 / 6,919 gen1 collections and 305 s of total GC pause in a
553 s run, at 45% average CPU. With server GC the same run takes 310 s,
1,251 gen0 / 492 gen1, 14 s of pause, 80% CPU, for the same ~46 min of
processor time; the in-suite roundtrip decompiles drop 2-3x
(Random_TestCase_1 353 s -> 133 s, ExplicitConversions 319 s -> 136 s,
NRefactory_CSharp 337 s -> 156 s). Standalone ilspycmd timings are
unaffected, which is what pointed at contention inside the test process
rather than decompiler cost.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-19 14:33:45 +02:00
Christoph Wille 5689dabaa9 Render a frame while the headless UI tests wait
Hit testing for synthesized input is answered from the rendered scene, not from
the visual tree, and Dispatcher.UIThread.RunJobs() does not render one. The
context-menu gesture helpers pumped dispatcher jobs alone, so after Escape closed
a menu the next right-click could still be routed to the light-dismiss overlay of
the frame that was on screen: no ContextRequested was raised, no row became the
context target, and the assertion two lines later reported an unhighlighted row.
The macOS CI runner lost that race roughly once in forty gestures; a probe build
repeating the gesture caught a right-click that produced neither a pointer-over
nor a menu, and the fix survived 120 gestures on the same runner.

Avalonia's own headless input helpers pump the dispatcher and the render timer
together for this reason.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-19 14:31:42 +02:00
Daniel Grunwald c1ac674b0e Avoid unused ref-locals if not allowed by the option.
This is needed to pass the AsyncAwaitPatterns correctness test with legacy csc.
2026-08-18 21:53:39 +02:00
Daniel Grunwald 59d8ae904b Fix tests on Windows with legacy csc.
There's an additional local variable when decompiling the non-optimized code; and explicitly putting that variable
into the test case just makes it fail due to yet another additional variable.
2026-08-18 21:36:46 +02:00
Christoph Wille 471d58550c Merge the load-bearing-cast await shapes into the main fixture
They were split out only because they were failing; there is no reason to keep
a second fixture now that they pass. Folding them in also widens their coverage
from roslyn4OrNewer to every defaultOptions config -- legacy csc, Roslyn 1.3.2
onwards and the net40 targets -- with the 'in'-receiver extension gated on CS72
because that one needs C# 7.2. IAwaitable and ClassAwaitable were declared
identically in both files and collapse into one declaration.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-18 21:36:46 +02:00
Christoph Wille d0c9cc9bae Track the await shapes that still fail as issues, not as a red test
The fixture was written as a spec of nine await shapes that decompiled to code
that does not compile. Six no longer do. Of the rest, default(Task) was never a
defect -- it compiles to the same ldnull as (Task)null, so the two are
indistinguishable in IL and the cast is a correct decompilation. The three real
ones are unrelated to the await conversion and have no correct output to pin
yet, so they move to #4017, #4018 and #4019; what stays behind is a regression
test for the shapes where the cast in front of the operand is load-bearing.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-18 21:36:46 +02:00
Christoph Wille f2b80df148 Look through the box when checking an await's GetAwaiter
An operand boxed for the GetAwaiter call is typed 'object', so the member
lookup that decides whether the await needs a cast finds nothing and a
redundant cast to the receiver type reaches the output. C# inserts that boxing
conversion implicitly, so the box may be dropped -- but only after the lookup
confirms the unboxed operand still binds the same GetAwaiter, and only via the
resolve result: UnwrapChild detaches the operand from the AST, so running it
speculatively leaves a cast with no child behind and decompilation of the whole
method falls back to the raw state machine.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-18 21:36:46 +02:00
Daniel Grunwald e530b1c1b6 Avoid allowImplicitConversion: true for await expressions -- there's no target type that the C# compiler could convert to.
Instead, use `IsAppropriateCallTarget` to detect whether an explicit cast is necessary for calling the correct `GetAwaiter` method.
2026-08-18 21:36:45 +02:00
Siegfried Pammer d8aca3f113 Add an async/await pattern test suite for ExpressionBuilder.VisitAwait
The await surface had almost no fixture coverage beyond Task/ValueTask: every
GetAwaiter in the corpus was an instance method on the awaited type itself, so
the conversion VisitAwait applies to the operand was never exercised for an
inherited, interface-typed or extension-method awaiter. Probing that surface
turned up eight defects, all of which produce C# that does not compile.

AsyncAwaitPatterns pins the shapes that do round-trip, along the three axes the
translation actually depends on: the GetAwaiter receiver, the operand
expression, and the context the await sits in. Its Correctness twin pins what
Pretty cannot see - copy semantics of struct awaitables and the evaluation
order around the suspension point.

AsyncAwaitPatternsBugs is the spec for the defects, written as the C# that
ought to come out, with the current wrong output named per member. It fails
today; that is the point, and fixing a defect is meant to delete a comment
rather than edit an expectation.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-18 21:36:45 +02:00
Siegfried Pammer 1b050476b6 Merge pull request #4012 from icsharpcode/fix/ilspy-tests-window-leak
Stop ILSpy.Tests from retaining every test's app graph (15 GB -> 0.7 GB)
2026-08-18 21:31:16 +02:00
Christoph Wille ba084e82f7 Describe how AnalyzerTreeNode resolves the analyzer registry
The registry's summary still described the static accessor as resolving
it once, which stopped being true when the accessors began going through
the current composition host on every access.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-18 20:37:09 +02:00
Christoph Wille d4212b1965 Withdraw only the Help items the closing window itself promoted
The app-level NativeMenu is process-wide, so the withdrawal a window does
on Closed has to name the items that window put there. Withdrawing
"whatever is promoted right now" is correct only while one window exists
at a time: with two, closing the older one takes the newer one's About /
Check for Updates out of the macOS app menu, and nothing ever puts them
back. Not reachable today - MainWindow is [Shared] and Attach runs from
its ctor - but the failure mode is silent and permanent, and carrying the
list costs nothing. Removing an item that is already gone is a no-op, so
a superseded window's Closed stays harmless.

The promotion tests also have to leave the app menu as they found it:
it is declared on Application and outlives the test, it is not gated on
macOS, and on Windows and Linux nothing re-promotes over the leftovers.

Assisted-by: Claude:claude-opus-5:Claude Code
2026-08-18 20:37:09 +02:00
Christoph Wille d5636e318f Assert the search pane's DataContext before checking the progress binding
ProgressBar.IsIndeterminate defaults to false, so the "nothing is running
yet" assertion would also pass against a pane whose DataContext is not
the resolved SearchPaneModel, and the failure would only surface one
line later, blamed on the binding direction rather than on the missing
DataContext.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-18 20:37:09 +02:00
Christoph Wille 84a7839a29 Withdraw a window's Help items from the macOS app menu, and add a retention canary
The app-level NativeMenu declared in App.axaml lives as long as the
process, while every MainWindow builds its own Help items over its own
command instances (AboutCommand reaches the DockWorkspace and, through
it, the whole app graph). PromoteHelpToMacAppMenu inserted each window's
items without taking the previous window's out and nothing removed them
on close, so on macOS the headless suite kept every test's app graph
alive - the same 13 MB per test as the anchors fixed earlier on this
branch, and the reason the memory win did not reproduce on macOS
(retained gen2 still climbing to ~4 GB there while a Windows run peaks
at 0.7 GB). Forcing the macOS path on Windows reproduces the growth
(14.3 GB peak private bytes over the suite); withdrawn, it is 0.7 GB.

Three smaller anchors of the same kind, found while making the canary
below hold in the full suite: RichNodeText and AnalyzerTreeNode cached
the first container's exports in statics, which subscribed later
windows to a stale settings object, handed later analyzers the first
test's assembly list, and kept the first app graph reachable for the
run; and a search still in flight when its container went away kept its
drain timer and IsSearching - hence the pane's indeterminate progress
animation on the render clock - alive, retaining every window a search
test closed mid-run (about 30 of them, ~400 MB).

The canary test closes a MainWindow the way the per-test teardown does
and waits for it to become collectable. It fails on any single anchor
being restored (checked by leaving DetachFlyouts out), which is the
regression guard the individual anchor fixes lacked; the teardown body
is exposed as TearDownTestState so the test performs exactly what
AfterTest does.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-18 20:37:09 +02:00
Christoph Wille 1c9c3d9c2a Run the indeterminate progress animations only while something is in progress
The search pane's progress bar was permanently indeterminate and merely
hidden when idle, and the decompiler view's bar defaults to
indeterminate mode whether or not a decompilation is running. The
indeterminate indicator is an infinite keyframe animation that keeps
running - and keeps the control's whole visual tree alive through the
render clock - for as long as the pseudo-class is set, hidden or not.
Both bars now go indeterminate only for the duration of the work.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-18 20:36:18 +02:00
Christoph Wille 27f5e2bc69 Unsubscribe DebugStepsPaneModel from the static writing options on dispose
WritingOptions is process-wide static state, and the pane subscribes to
its PropertyChanged in the constructor. Every composition container
that is built and disposed (the headless UI test suite does that per
test) left its pane behind on that event, and through the pane's
LanguageService the rest of the container's object graph with it.
System.Composition disposes IDisposable shared parts with the
container, which is the moment to let go.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-18 20:36:18 +02:00
Christoph Wille 3b37eff5d3 Close every window a headless UI test showed, and let go of shared flyouts
The headless test host runs the app without an application lifetime,
so the window-closing step in ResetAppState never had a list to work
from and every MainWindow the suite showed stayed open - and reachable
from the compositor, together with its view-models, assembly tree and
loaded assemblies. Measured at about 13 MB per test, 15 GB over the
suite, enough to page out the CI runner and stall the tests that scan
process module lists.

Closing is not sufficient on its own: Avalonia's Button subscribes to
its flyout's Opened/Closed and only unsubscribes when the Flyout
property changes, and Dock's ToolChromeControl theme hands every tool
pane's chrome button one shared MenuFlyout resource, which therefore
pinned every closed window's visual tree. The flyouts are detached
before the window closes.

Assisted-by: Claude:claude-fable-5:Claude Code
2026-08-18 20:36:18 +02:00
Siegfried Pammer 0b9a8abc1f Merge pull request #4022 from SychicBoy/fix-1459-floating-point-constants
Improve floating-point fraction and negative constant reconstruction
2026-08-18 09:48:20 +02:00
dependabot[bot] e2b236b994 Bump github/codeql-action from 4.37.6 to 4.37.7 (#4026) 2026-08-18 08:25:55 +02:00
Siegfried Pammer 2311b64409 Cover the fractions that were not written as fractions
The preferred-scale lookup reaches well past the byte-normalization cases it was
added for: any value that is exactly n/2^k for a k the old denominator limit
could not reach now prints as a fraction, so constants that used to be short
exact decimals changed shape. That is the widest-reaching part of the change and
nothing pinned it.

The added constants are those values, including the unreduced 126 / 1024 that a
lowest-terms rewrite would turn into 63 / 512, plus two that must keep their
decimal form so the length gate stays covered from both sides.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-18 05:27:46 +02:00
Siegfried Pammer fef7a5babe Merge pull request #4013 from icsharpcode/feature/ilspycmd-ilast
Add ILAst output to ilspycmd debug builds
2026-08-18 05:22:23 +02:00
Siegfried Pammer f7306d05da Merge pull request #4024 from icsharpcode/fix-3352
Avoid using query expressions if there's indications that lambda parameter types cannot be omitted.
2026-08-18 05:21:21 +02:00
Siegfried Pammer 83c007614f Merge pull request #4025 from icsharpcode/fix/package-search-followups
Fix package search and navigation follow-ups from #4023
2026-08-18 05:13:52 +02:00
Siegfried Pammer 482c0bd81b Reach package-nested nodes from every lookup, and only along one path
Resolving a metadata file to its assembly node learned to descend into packages,
but three sibling lookups kept their own scan of the root's direct children, so
a token reference, a metadata:// link and a LoadedAssembly reference still
resolved to nothing inside a package. One of them sat behind a guard whose
result was never used, which returned early for exactly the case it was meant to
serve. Routing all of them through the one lookup fixes them together.

Namespaces were matched by comparing a full name against a node label, which is
only ever equal in flat mode: with nested namespace nodes the label is the last
segment, and the empty-name test matched the first child rather than the global
namespace node. The assembly node already indexes its namespaces by full name.

The descent itself no longer sweeps the package depth-first. Expanding a folder
resolves and extracts every .dll it holds, so the path is taken from the
package's folder graph, which costs no tree node and reads no entry.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-17 22:40:47 +02:00
Siegfried Pammer 3dfb59ac87 Resolve package entries by identity and end walks nobody reads
Searching a package resolves its entries by file name against a case-insensitive
cache, which is right for an assembly reference but wrong for an archive entry:
two entries differing only in case are two files, and they collapsed onto one
LoadedAssembly, so one was searched twice and the other never. Keying the cache
by the entry itself separates them, and the entry's package-relative path
becomes the assembly's file name, which is what tells the copies of one assembly
in a multi-target package apart wherever a search result shows a location.

Cancellation was only checked between top-level list entries, so a walk the user
had already replaced by typing another character kept extracting package entries
alongside the run they were waiting for. The omnibar had no way to end its run at
all: its view model is per document tab and nothing cancelled it when the tab
went away.

Assisted-by: Claude:claude-opus-5[1m]:Claude Code
2026-08-17 22:39:27 +02:00
Daniel Grunwald 85399bfc00 Add missing space in new (string,int)[] 2026-08-17 22:31:13 +02:00
Siegfried Pammer c5a30e2869 Merge pull request #4023 from icsharpcode/fix/package-search-and-nav
Search inside packages without stalling, and navigate to what it finds
2026-08-17 22:18:06 +02:00