mirror of https://github.com/icsharpcode/ILSpy.git
Tree:
d9ff200d62
christophwille/closedhierarchies
christophwille/membench
compound-assignment-operators
fix/1982-params-attribute-args
fix/2040-invalid-xml-characters
fix/2093-navigateto-reference-assembly
fix/2362-xalz-references
fix/2372-address-taken-by
fix/3282-indexer-optional-arguments
fix/3568-record-member-order
fix/4059-deconstruct-out-slots
fix/lambda-parameter-syntax
fix/scroll-children-on-expand
gh-pages
ldmembertoken
master
natural-type-lambdas-methods
null-coalescing-assignment
release/10.1
release/6.2
release/7.1
release/7.2
release/8.1
substring-optimizations
tests/829-async-method-builder-override
tests/829-collection-expressions
tests/829-compound-assignment-operators
tests/829-coverage-audit
tests/829-expression-tree-named-optional-args
tests/829-expression-variables-in-initializers
tests/829-extended-property-patterns
tests/829-extension-members
tests/829-extension-operators
tests/829-file-local-types
tests/829-improved-definite-assignment
tests/829-improved-overload-candidates
tests/829-inline-arrays
tests/829-interpolated-string-improvements
tests/829-lambda-param-modifiers
tests/829-list-patterns
tests/829-lock-object
tests/829-mixed-deconstruction
tests/829-null-coalescing-assignment
tests/829-null-conditional-assignment
tests/829-object-initializer-indexer
tests/829-overload-resolution-priority
tests/829-params-collections
tests/829-pattern-matching-improvements
tests/829-primary-constructors
tests/829-ref-unsafe-in-iterators-async
tests/829-sealed-record-tostring
tests/829-target-typed-conditional
tests/829-tuple-comparison
win-a11y-textsize
1.0-Beta
1.0-M1
1.0-M2
1.0-M3
1.0.0
2.0.0
2.1
2.2
2.3
2.3.1
3.0-Preview1
3.0-Preview2
3.0.2
v10.0
v10.0-preview1
v10.0-preview2
v10.0-preview3
v10.0.1
v10.1
v10.1.1
v11.0
v11.0-preview1
v11.0-rc
v2.3.2
v2.4
v3.0
v3.0-beta1
v3.0-beta2
v3.0-beta2a
v3.0-beta3
v3.0-beta4
v3.0.1
v3.1-beta1
v3.1-final
v3.1-rc
v3.2-beta
v3.2-rc
v3.2.0
v4.0
v4.0-alpha1
v4.0-beta1
v4.0-beta2
v4.0-beta3
v4.0-rc1
v4.0-rc2
v4.0.1
v5.0
v5.0-preview1
v5.0-preview2
v5.0-preview3
v5.0-preview4
v5.0-rc1
v5.0.1
v5.0.2
v6.0
v6.0-preview1
v6.0-preview2
v6.0-preview3
v6.0-preview4
v6.0-rc1
v6.1
v6.2
v6.2-preview1
v6.2-preview2
v6.2.1
v7.0
v7.0-preview1
v7.0-preview2
v7.0-preview3
v7.0-rc1
v7.0-rc2
v7.1
v7.2
v7.2-preview1
v7.2-preview2
v7.2-preview3
v7.2-preview4
v7.2-rc
v7.2.1
v8.0
v8.0-preview1
v8.0-preview2
v8.0-preview3
v8.0-preview4
v8.0-rc1
v8.1
v8.1.1
v8.2
v9.0
v9.0-preview1
v9.0-preview2
v9.0-preview3
v9.0-rc
v9.1
${ noResults }
11 Commits (d9ff200d62356244df2ff927e232da966df6e408)
| Author | SHA1 | Message | Date |
|---|---|---|---|
|
|
1f448dbb29 |
Scroll a node's new children into view when it is expanded
The WPF tree did this, and the Avalonia port kept the routine but never wired it up: the row template's expander binds IsExpanded straight to the node, so no expansion reached the control and HandleExpanding sat with no callers. Expanding a row near the bottom of the pane left its children off screen. The rule copies the native Windows tree control: scroll far enough to show the new children, but stop at the expanded node so it never leaves the viewport, and do not move at all when the children already fit. The reveal now hangs off user gestures only -- the expander's Click and the keyboard cases -- because the paths that expand nodes programmatically position the viewport themselves afterwards, which is what the removed doNotScrollOnExpanding flag used to arrange. Assisted-by: Claude:claude-opus-5:Claude Code |
2 days ago |
|
|
fa464968e1 |
Reorder the tree rows when the assembly list is sorted
Sorting reorders the assembly list in place and reports it as a Move, which nothing downstream could act on: the tree node's handler had cases for Add, Remove and Reset only, and neither the child collection nor the flattener had a move at all. The rows therefore kept their pre-sort order until something else forced a rebuild. Moving the node rather than removing and re-inserting it keeps its identity, so an expanded subtree stays expanded and its row is not rebuilt. A run longer than one row has to be reported the way the consumer reads it: Avalonia's VirtualizingStackPanel applies a ranged move by removing OldItems.Count rows and re-inserting them at NewStartingIndex - (Count - 1), so a run reported by its final start index lands short by its own length. For a single row - a collapsed node, and every move a sort makes - the two readings coincide. Assisted-by: Claude:claude-opus-5[1m]:Claude Code |
2 days ago |
|
|
228041085b |
Fix #3290: marshal EnsureLazyChildren onto the tree's owning thread
The crash is a NullReferenceException in GetNodeByVisibleIndex, reached when a background decompile realizes a node's children while the UI thread is indexing the flattener. Eight ILSpyTreeNode.Decompile overrides call EnsureLazyChildren from that task; two wrapped it in Dispatcher.UIThread.Invoke, six did not, and one of the two lost its wrapper in the Avalonia port with no test noticing for a release cycle. A rule every call site has to remember is a rule that gets broken again, so EnsureLazyChildren marshals itself instead: SetOwner already named the owning thread, and now also carries the host's way onto it. A call already on the owner runs inline, so a blocking invoke cannot deadlock on itself and a nested load costs no further hop; an unowned tree is left unmarshalled, which keeps building a subtree on a worker and publishing it on the UI thread legal. The affinity check stays as the regression detector, but its fail-fast throw was worthless on its own: tree mutation happens inside callers that catch Exception, so the throw ended up rendered into the decompiled output and the run passed. The violation is now recorded before the throw, and an assembly-level NUnit test action fails the test that produced one - an assembly-level teardown failure is reported but leaves the exit code at zero. Assisted-by: Claude:claude-opus-5:Claude Code |
2 weeks ago |
|
|
ca3e528ce2 |
Add a Debug-only thread-affinity check to the shared tree model
Issue #3290 is a NullReferenceException in GetNodeByVisibleIndex that is provably unreachable single-threaded: TreeFlattener.Count and GetNodeByVisibleIndex read the same totalListLength fields back to back, so a stale index yields ArgumentOutOfRangeException, never an NRE. A stress harness with reader threads racing an IsExpanded/Children mutator reproduces exactly that NRE, so the crash requires a mutation from a foreign thread. The rule that a displayed tree is only mutated from the UI thread was pure convention: ICSharpCode.ILSpyX/TreeView contained no VerifyAccess, lock or dispatcher of any kind, and two tree nodes already carry a Dispatcher.UIThread.Invoke workaround for the same hazard, which means it has been hit before and fixed one site at a time. ICSharpCode.ILSpyX is host-agnostic and must not name a dispatcher, so ownership is stated by the host instead of inferred: SetOwner(Thread) marks the thread allowed to mutate a node and its subtree. Unowned means unchecked, which is what makes the analyzer pattern legal - build a subtree on a worker, publish it on the UI thread - without an exception carved into the rule. The owner is resolved by walking up the model-parent chain to the nearest explicit owner rather than stamped onto every node. That buys the propagation rules for free: one call on the root covers the whole displayed tree, children attached later inherit it with no bookkeeping, and a subtree built off-thread is unchecked while it is being built yet inherits the owner the moment it is attached - an attachment which is itself a checked mutation of the owned tree. A subtree that already carries a different owner would otherwise leave one displayed tree demanding two threads, so that case is reported once and the incoming owner dropped, rather than reported on every later mutation. Re-owning is allowed because handing a tree over is the point, but the handoff must come from the current owner: a background thread taking a live tree away from the UI is the race being hunted. The check sits in SharpTreeNodeCollection.OnCollectionChanged, which every Children mutator funnels through, and in the IsExpanded and IsHidden setters - the three entry points that invalidate totalListLength. Checking in OnCollectionChanged also means a violation is reported before OnChildrenChanged rewrites the flat-list tree, so the AVL structure is left intact. Violations are collected rather than fatal by default, with per-call-site deduplication and a count, and the first hit of each site written straight through to a log file so a long exploratory session can be read while it runs. FailFast makes them throw so tests can observe one deterministically. Everything is behind #if DEBUG plus [Conditional("DEBUG")], so the release build has no field on SharpTreeNode and no call at any site; verified by decompiling the release assembly. Assisted-by: Claude:claude-opus-5:Claude Code |
2 weeks ago |
|
|
065c9098fb |
Cover tree mutation under a scrolled, virtualized SharpTreeView
Issue #3290 reports a NullReferenceException inside SharpTreeNode.GetNodeByVisibleIndex, reached from a WPF virtualizing panel's measure pass. The frame is still live: the Avalonia SharpTreeView binds the TreeFlattener straight to ItemsSource, so Avalonia's virtualization indexes the same flat-list walk on every measure. Driving the model directly shows the indexer cannot walk off the end on one thread: TreeFlattener.Count and GetNodeByVisibleIndex read the same totalListLength fields with nothing in between, so a stale index becomes an ArgumentOutOfRangeException and never a null dereference. Randomized sweeps over insert/remove/expand/collapse/hide/reparent found no state where the two disagree. Only a mutation concurrent with the descent reproduces the reported frame, and every tree mutation in the app is marshalled to the UI thread. These tests pin the interleaving that the port changed: the flattened list shrinking underneath a realized index range, and a lazy subtree loading and reloading while scrolled. The first asserts the panel is actually virtualizing, so it cannot quietly degrade into a non-virtualized run that proves nothing. Assisted-by: Claude:claude-opus-5:Claude Code |
2 weeks ago |
|
|
1b78c76215 |
Synchronize headless UI tests on idle and hit-tested clicks
The headless UI tests synchronized with the application by pumping a fixed number of frames (39 loops of RunJobs/Delay across 19 files) and by pressing at a point computed once from a control's bounds. Both encode how fast the machine that wrote the test was: on the loaded Windows Debug CI agent the frame count comes up short and the point goes stale, which is the recurring timeout in the tree context-menu tests and the reason each such failure was repaired one test at a time. Waiters.WaitForIdleAsync replaces the frame loops. It observes the actual precondition - no dispatcher job queued at Background priority or above, no assembly still loading in the background sweep, a frame rendered - and requires it on two consecutive polls so a thread-pool continuation about to post back is caught as well. Window.ClickAsync replaces element-targeted MouseDown/MouseUp pairs. It re-resolves the target on every poll and presses only once the window's hit test at the click point answers with that target, reporting the point and what was hit instead on timeout. That diagnostic exposed one vacuous test: User_Click_On_Visible_Row_Does_Not_Recentre_Viewport clicked the centre of a row wider than the tree viewport, which lies under the decompiler text view, so its assertion held without the row ever being clicked. It now clamps the point to the viewport like the other tree-row clicks. Clicks at text positions and press-only gutter clicks stay raw; they do not target an element. Assisted-by: Claude:claude-fable-5:Claude Code |
2 weeks ago |
|
|
c84a330ee1 |
Add omnibar breadcrumb and search bar above the decompiled code
ILSpy showed the current location only implicitly in the tree selection and kept search in a separate docked pane. The omnibar, modelled on the Files community app and jiripolasek's EditorBar, puts an address-bar atop each decompiler document: a breadcrumb of the node (Assembly > Namespace > Type > Member) whose segments navigate and whose chevrons list child nodes, turning into a search box on typing that reuses the existing search engine. It coexists with the docked search pane and ships off by default behind the Options / Display 'Tab options' EnableOmnibar toggle, which applies live. Assisted-by: Claude:claude-opus-4-8:Claude Code |
3 months ago |
|
|
51aafa0fd9 |
Move ILSpy UI code back to the ICSharpCode.ILSpy root namespace
The Avalonia port had placed the UI app in an ILSpy.* namespace tree, while the csproj RootNamespace and every prior release (through 10.1) use ICSharpCode.ILSpy.*. Restoring the historical namespace reduces the public API diff against release/10.1 for plugin authors and removes the shadowing that forced global:: qualifiers in the test project. The Images class and AccessOverlayIcon enum move back into the root namespace (as in 10.1), since an ICSharpCode.ILSpy.Images namespace would shadow the Images class for all code inside ICSharpCode.ILSpy. Assisted-by: Claude:claude-fable-5:Claude Code |
3 months ago |
|
|
61bd014c2d |
Land external file drops anywhere on the assembly tree
Two failure modes that both showed the user the "no" cursor with no other feedback: 1. ResolveDropTarget returned null when e.Source had no SharpTreeViewItem ancestor, so Explorer drops landing in the gap beneath the last row (or onto an empty list) never reached SharpTreeNode.InternalDrop. 2. The middle 50% of a row produces a DropPlace.Inside target on the row's own node. Most concrete SharpTreeNodes inherit the base CanDrop (returns false), so a literal "drop a .dll onto an assembly row" refused even though AssemblyListTreeNode happily accepts that payload. For (1), fall back to (Root, Children.Count, DropPlace.Inside) when no row is hit. For (2), introduce PickAcceptingTarget which retries with the empty-space (root) target when the initial CanDrop is false. Both OnDragOver and OnDrop go through the same picker so the cursor and the actual drop agree on the outcome. The retry skips when the initial target already IS the root, so a real refusal still surfaces as "no". The marker adorner stays hidden for empty-space drops because the place is always Inside (Item is null for that case); the existing DropPlace.Inside early return covers it. DropTarget, DropPlace, and the two new helpers are internal-visible to the ILSpy.Tests project for the unit tests that assert the fallback chain. Assisted-by: Claude:claude-opus-4-7[1m]:Claude Code |
3 months ago |
|
|
3e8e08644b |
Add type-ahead search; prove native shift-range extend/shrink
OnTextInput drives incremental prefix search over the visible (flattened) nodes with a 1s idle reset -- a fresh keystroke advances past the current row, a growing prefix refines forward. A regression test confirms the payoff of the ListBox base: SelectionMode.Multiple extends AND shrinks a shift-range from the anchor (Shift+Down x2 then Shift+Up -> A,B), so the migrated control needs none of the ProDataGrid reflection workaround. |
3 months ago |
|
|
85cf2bb61f |
Scaffold a ListBox-based SharpTreeView control (Phase 1)
First increment of the from-scratch Avalonia tree control that will replace the ProDataGrid hierarchical usage. SharpTreeView : ListBox binds the cross-platform TreeFlattener (an IList + INotifyCollectionChanged of visible SharpTreeNodes) straight as ItemsSource, so the ListBox virtualizes it and provides anchor-based extend/shrink selection natively -- no HierarchicalNode wrapper, no model<->grid sync layer. Includes Root/ShowRoot/ShowLines props, Reload/flattener wiring, deselect-on-hide, selection->node.IsSelected, FocusNode/ScrollIntoNodeView/HandleExpanding, container overrides, and the tree keyboard gestures (Left/Right, numpad +/-/*, Enter/Space activate). SharpTreeViewItem : ListBoxItem (double-click expand), an IPlatformRoutedEventArgs adapter, an indent converter, and a ControlTheme (chevron expander + indent + icon + text) wired into App.axaml. The control is additive and not yet wired to any pane. Smoke tests prove the core: flatten, virtualize, expand/collapse row-count updates, and selection sync. |
3 months ago |