Browse Source

References folder under each assembly node

Assisted-by: Claude:claude-opus-4-7:Claude Code

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 2 months ago
parent
commit
7e17da5f61
  1. 19
      ILSpy.Tests/MainWindow/MainWindowTests.cs
  2. 90
      ILSpy/Assets/Icons/ReferenceFolder.svg
  3. 1
      ILSpy/Images.cs
  4. 48
      ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
  5. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  6. 52
      ILSpy/TreeNodes/ReferenceFolderTreeNode.cs

19
ILSpy.Tests/MainWindow/MainWindowTests.cs

@ -118,6 +118,25 @@ public class MainWindowTests @@ -118,6 +118,25 @@ public class MainWindowTests
firstMethod.Should().Be().CenteredInView();
}
[AvaloniaTest]
public async Task Assembly_Node_Has_References_Folder_Child()
{
var window = AppComposition.Current.GetExport<MainWindow>();
window.Show();
var vm = (MainWindowViewModel)window.DataContext!;
await vm.AssemblyTreeModel.WaitForAssembliesAsync(minimumCount: 3);
var assemblyNode = vm.AssemblyTreeModel.FindNode<AssemblyTreeNode>("System.Linq");
assemblyNode.EnsureLazyChildren();
var refFolder = assemblyNode.Children.OfType<ReferenceFolderTreeNode>().Single();
refFolder.Text.Should().Be(Resources.References);
refFolder.EnsureLazyChildren();
refFolder.Children.Should().NotBeEmpty();
refFolder.Children.Should().AllBeAssignableTo<AssemblyReferenceTreeNode>();
}
[AvaloniaTest]
public async Task Selecting_Type_Node_Decompiles_Type_Definition()
{

90
ILSpy/Assets/Icons/ReferenceFolder.svg

@ -0,0 +1,90 @@ @@ -0,0 +1,90 @@
<?xml version="1.0" encoding="UTF-8" standalone="no"?>
<svg
xmlns:dc="http://purl.org/dc/elements/1.1/"
xmlns:cc="http://creativecommons.org/ns#"
xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#"
xmlns:svg="http://www.w3.org/2000/svg"
xmlns="http://www.w3.org/2000/svg"
xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd"
xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape"
viewBox="0 0 16 16"
version="1.1"
id="svg12"
sodipodi:docname="ReferenceFolder.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)"
inkscape:export-filename="C:\Users\sie_p\Projects\ILSpy master\ILSpy\Images\ReferenceFolder.png"
inkscape:export-xdpi="96"
inkscape:export-ydpi="96">
<metadata
id="metadata18">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
<dc:title></dc:title>
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs16" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="1920"
inkscape:window-height="1017"
id="namedview14"
showgrid="false"
inkscape:zoom="29.5"
inkscape:cx="12.96698"
inkscape:cy="6.467825"
inkscape:window-x="-8"
inkscape:window-y="340"
inkscape:window-maximized="1"
inkscape:current-layer="svg12" />
<style
id="style2">.st0{opacity:0}.st0,.st1{fill:#f6f6f6}.st2{fill:#424242}</style>
<rect
id="rect3802"
width="16"
height="16"
x="-0.033898305"
y="0.033898298"
style="stroke:none;fill:#ffffff;fill-opacity:0" />
<g
id="g3796">
<path
style="display:inline;fill:#f6f6f6;stroke-width:0.66101694"
d="m 14.940678,2.7118644 c 0,1.9830508 0,3.9661017 0,5.9491526 -1.762712,0 -3.525424,0 -5.2881356,0 0,-0.661017 0,-1.3220339 0,-1.9830509 -0.440678,0 -0.8813559,0 -1.3220339,0 0,0.440678 0,0.8813557 0,1.3220339 -1.3220339,0 -2.6440678,0 -3.9661017,0 0,-1.5423729 0,-3.0847458 0,-4.6271186 1.3220339,0 2.6440678,0 3.9661017,0 0,0.4406779 0,0.8813559 0,1.3220338 0.440678,0 0.8813559,0 1.3220339,0 0,-0.6610169 0,-1.3220338 0,-1.9830508 1.7627116,0 3.5254236,0 5.2881356,0 z"
id="path6"
inkscape:connector-curvature="0" />
<path
class="st2"
d="M 5.0254237,4.0338983 H 7.6694915 V 7.3389831 H 5.0254237 Z M 10.313559,3.3728814 h 3.966102 V 8 H 10.313559 Z M 8.3305085,5.3559322 H 9.6525424 V 6.0169491 H 8.3305085 Z"
id="path9"
inkscape:connector-curvature="0"
style="fill:#424242;stroke-width:0.66101694" />
</g>
<g
id="g3800">
<path
class="st1"
d="m 11.635593,6.677966 v 5.949153 H 6.3474576 V 10.644068 H 5.0254237 v 1.322034 H 1.059322 V 7.338983 H 5.0254237 V 8.6610169 H 6.3474576 V 6.677966 Z"
id="path6-8"
inkscape:connector-curvature="0"
style="fill:#f6f6f6;stroke-width:0.66101694" />
<path
class="st2"
d="M 1.720339,7.9999999 H 4.3644068 V 11.305085 H 1.720339 Z M 7.0084746,7.338983 h 3.9661014 v 4.627119 H 7.0084746 Z M 5.0254237,9.3220339 H 6.3474576 V 9.9830508 H 5.0254237 Z"
id="path9-3"
inkscape:connector-curvature="0"
style="fill:#424242;stroke-width:0.66101694" />
</g>
</svg>

After

Width:  |  Height:  |  Size: 3.4 KiB

1
ILSpy/Images.cs

@ -75,6 +75,7 @@ namespace ILSpy.Images @@ -75,6 +75,7 @@ namespace ILSpy.Images
// Containers
public static readonly IImage Namespace = LoadSvg(nameof(Namespace));
public static readonly IImage ReferenceFolder = LoadSvg(nameof(ReferenceFolder));
// Types
public static readonly IImage Class = LoadSvg(nameof(Class));

48
ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs

@ -0,0 +1,48 @@ @@ -0,0 +1,48 @@
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using ICSharpCode.Decompiler.IL;
using ICSharpCode.Decompiler.Metadata;
namespace ILSpy.TreeNodes
{
/// <summary>
/// Single entry in the references folder. Minimal port: shows the reference name
/// using ILAmbience escaping plus a generic assembly icon. Children (the
/// per-reference type list and transitive references) are not yet implemented.
/// </summary>
sealed class AssemblyReferenceTreeNode : ILSpyTreeNode
{
readonly AssemblyReference reference;
readonly AssemblyTreeNode parentAssembly;
public AssemblyReferenceTreeNode(AssemblyReference reference, AssemblyTreeNode parentAssembly)
{
this.reference = reference ?? throw new ArgumentNullException(nameof(reference));
this.parentAssembly = parentAssembly ?? throw new ArgumentNullException(nameof(parentAssembly));
}
public AssemblyReference AssemblyReference => reference;
public override object Text => ILAmbience.EscapeName(reference.Name);
public override object Icon => Images.Images.Assembly;
}
}

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -173,6 +173,8 @@ namespace ILSpy.TreeNodes @@ -173,6 +173,8 @@ namespace ILSpy.TreeNodes
return;
}
Children.Add(new ReferenceFolderTreeNode(module, this));
var metadata = module.Metadata;
var namespaces = metadata.TypeDefinitions
.Where(t => metadata.GetTypeDefinition(t).GetDeclaringType().IsNil)

52
ILSpy/TreeNodes/ReferenceFolderTreeNode.cs

@ -0,0 +1,52 @@ @@ -0,0 +1,52 @@
// Copyright (c) 2026 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System.Linq;
using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.ILSpy.Properties;
namespace ILSpy.TreeNodes
{
/// <summary>
/// References folder under an assembly node. Children are one
/// <see cref="AssemblyReferenceTreeNode"/> per metadata <c>AssemblyRef</c>.
/// </summary>
sealed class ReferenceFolderTreeNode : ILSpyTreeNode
{
readonly MetadataFile module;
readonly AssemblyTreeNode parentAssembly;
public ReferenceFolderTreeNode(MetadataFile module, AssemblyTreeNode parentAssembly)
{
this.module = module;
this.parentAssembly = parentAssembly;
LazyLoading = true;
}
public override object Text => Resources.References;
public override object Icon => Images.Images.ReferenceFolder;
protected override void LoadChildren()
{
foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name))
Children.Add(new AssemblyReferenceTreeNode(r, parentAssembly));
}
}
}
Loading…
Cancel
Save