Keep package entry selections decompilable

The stale-node guard compared selected nodes only against top-level assembly-list entries, so nodes owned by package entries looked removed even while their parent package was active. Walk the parent bundle chain before clearing the decompiler tab so restored or clicked package-entry selections still render.

Assisted-by: OpenCode:openai/gpt-5.5:OpenCode
This commit is contained in:
Siegfried Pammer
2026-10-04 15:51:26 +02:00
parent 77528d649d
commit 4d465bead3
2 changed files with 32 additions and 1 deletions
@@ -188,4 +188,24 @@ public class AssemblyTreeModelTests
sibling.Children.Should().BeEmpty(
"only the folders on the path down to the target get expanded.");
}
[AvaloniaTest]
public async Task Selecting_a_type_inside_a_package_entry_decompiles_it()
{
var (_, vm) = await TestHarness.BootAsync();
await vm.OpenAssemblyAsync(CreatePackage());
var nested = (await vm.AssemblyTreeModel.AssemblyList!.GetAllAssemblies())
.Single(a => a.FileName == "lib/net10.0/Nested.dll");
var type = nested.GetTypeSystemOrNull()!.MainModule.TypeDefinitions
.Single(t => t.Name == FixtureAssembly.TypeName);
var node = vm.AssemblyTreeModel.FindTreeNode(type);
((object?)node).Should().BeOfType<TypeTreeNode>();
vm.AssemblyTreeModel.SelectNode(node!);
var tab = await vm.DockWorkspace.WaitForDecompiledTextAsync();
tab.Text.Should().Contain(FixtureAssembly.TypeName,
"a live package-entry node must not be mistaken for a stale node from a removed assembly");
}
}
+12 -1
View File
@@ -803,7 +803,7 @@ namespace ICSharpCode.ILSpy.Docking
assemblyTreeModel.AssemblyList?.GetAssemblies() ?? []);
if (nodes.Any(n => n.AncestorsAndSelf()
.OfType<AssemblyTreeNode>()
.Any(a => !activeAssemblies.Contains(a.LoadedAssembly))))
.Any(a => !IsActiveAssemblyOrPackageEntry(a.LoadedAssembly, activeAssemblies))))
{
lastShownNodes = null;
ClearActiveDecompilerTab();
@@ -879,6 +879,17 @@ namespace ICSharpCode.ILSpy.Docking
ActivateMainTabIfNeeded(main);
}
static bool IsActiveAssemblyOrPackageEntry(ICSharpCode.ILSpyX.LoadedAssembly assembly,
HashSet<ICSharpCode.ILSpyX.LoadedAssembly> activeAssemblies)
{
for (var current = assembly; current != null; current = current.ParentBundle)
{
if (activeAssemblies.Contains(current))
return true;
}
return false;
}
// The "exactly one preview tab" rule: tree selections always route to the single preview
// ("the One"), tracked by factory.MainTab. Reuse it wherever it sits -- even if a frozen
// tab is currently active, ActivateMainTabIfNeeded brings it forward -- as long as it is