diff --git a/ILSpy.Tests/AssemblyList/NestedNamespaceTreeTests.cs b/ILSpy.Tests/AssemblyList/NestedNamespaceTreeTests.cs index 2bf7c53a9..f41b9b03b 100644 --- a/ILSpy.Tests/AssemblyList/NestedNamespaceTreeTests.cs +++ b/ILSpy.Tests/AssemblyList/NestedNamespaceTreeTests.cs @@ -22,12 +22,14 @@ using System.Threading.Tasks; using Avalonia.Headless.NUnit; +using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.ILSpyX; using ICSharpCode.ILSpy; using ICSharpCode.ILSpy.AppEnv; using ICSharpCode.ILSpy.AssemblyTree; +using ICSharpCode.ILSpy.Languages; using ICSharpCode.ILSpy.TreeNodes; using NUnit.Framework; @@ -143,6 +145,36 @@ public class NestedNamespaceTreeTests } } + [AvaloniaTest] + public async Task Decompiling_A_Nested_Namespace_Uses_Its_Full_Path_Not_The_Display_Label() + { + // In nested mode a NamespaceTreeNode's display label is only its last segment ("Generic"), + // while the metadata it has to query -- and the name it titles the output with -- is the full + // path ("System.Collections.Generic"). Decompiling by the label queries the wrong namespace, + // usually an empty one, and titles the output after the wrong name. + + try + { + var (_, assemblyNode) = await BootNestedAsync(TreeNavigation.CoreLibName); + + var generic = assemblyNode.Children.OfType() + .SelectMany(DescendantNamespaces) + .Single(ns => ns.FullName == "System.Collections.Generic"); + + var language = AppComposition.Current.GetExport() + .Languages.OfType().First(); + var output = new PlainTextOutput(); + generic.Decompile(language, output, new DecompilationOptions(new DecompilerSettings())); + + Assert.That(output.ToString(), Does.Contain("System.Collections.Generic"), + "the namespace is decompiled and titled by its full path, not the 'Generic' display label"); + } + finally + { + ResetNestedMode(); + } + } + [AvaloniaTest] public async Task FindNamespaceNode_Resolves_A_Nested_Namespace() { diff --git a/ILSpy/Commands/SearchMsdnContextMenuEntry.cs b/ILSpy/Commands/SearchMsdnContextMenuEntry.cs index 8c025973b..062ccdf08 100644 --- a/ILSpy/Commands/SearchMsdnContextMenuEntry.cs +++ b/ILSpy/Commands/SearchMsdnContextMenuEntry.cs @@ -72,8 +72,8 @@ namespace ICSharpCode.ILSpy.Commands { switch (node) { - case NamespaceTreeNode ns when !string.IsNullOrEmpty(ns.Name): - return (MsdnPrefix + ns.Name).ToLowerInvariant(); + case NamespaceTreeNode ns when !string.IsNullOrEmpty(ns.FullName): + return (MsdnPrefix + ns.FullName).ToLowerInvariant(); case IMemberTreeNode m when m.Member is { } entity: // Reflection-name → docs path: backticks (generic arity) become hyphens, // `+` (nested type) becomes `.`, and ".ctor" gets a "-ctor" tail because @@ -96,7 +96,7 @@ namespace ICSharpCode.ILSpy.Commands switch (node) { case NamespaceTreeNode ns: - return !string.IsNullOrEmpty(ns.Name); + return !string.IsNullOrEmpty(ns.FullName); case IMemberTreeNode m when m.Member is { } entity: if (!IsExternallyVisible(entity.Accessibility)) return false; diff --git a/ILSpy/Search/ScopeSearchToNamespaceContextMenuEntry.cs b/ILSpy/Search/ScopeSearchToNamespaceContextMenuEntry.cs index a01ac7610..44e1653a8 100644 --- a/ILSpy/Search/ScopeSearchToNamespaceContextMenuEntry.cs +++ b/ILSpy/Search/ScopeSearchToNamespaceContextMenuEntry.cs @@ -60,7 +60,7 @@ namespace ICSharpCode.ILSpy.Search static string? Namespace(TextViewContext context) { if (context.SelectedTreeNodes is { Length: > 0 } nodes && nodes.All(n => n is NamespaceTreeNode)) - return nodes.OfType().FirstOrDefault()?.Name; + return nodes.OfType().FirstOrDefault()?.FullName; return (context.Reference?.Reference as IEntity)?.Namespace; } } diff --git a/ILSpy/TreeNodes/NamespaceTreeNode.cs b/ILSpy/TreeNodes/NamespaceTreeNode.cs index 2f1d6917d..7915edaff 100644 --- a/ILSpy/TreeNodes/NamespaceTreeNode.cs +++ b/ILSpy/TreeNodes/NamespaceTreeNode.cs @@ -96,8 +96,8 @@ namespace ICSharpCode.ILSpy.TreeNodes return; } var types = typeSystem.MainModule.TypeDefinitions - .Where(t => t.Namespace == name && t.DeclaringTypeDefinition == null); - language.DecompileNamespace(name, types, output, options); + .Where(t => t.Namespace == fullName && t.DeclaringTypeDefinition == null); + language.DecompileNamespace(fullName, types, output, options); } // A namespace counts as public-API iff at least one type it contains is public-API. The