Browse Source

Port the missing icon variants and the Copy glyph from the WPF tree

The avalonia branch only carried the base set of tree-node icons.
FieldReadOnly, EnumValue, Indexer, VirtualMethod, ExtensionMethod and
PInvokeMethod were already SVGs in master:ILSpy/Images/ but never
copied over -- so e.g. readonly fields shared the same glyph as
mutable instance fields, and indexers were indistinguishable from
plain properties.

Bring across the seven SVGs (those six plus Copy for the Copy-
fully-qualified-name context-menu entry), register them on
Images.cs, and extend the icon dispatch in each tree node to mirror
WPF's logic:

  FieldTreeNode    EnumValue / Literal (const) / FieldReadOnly / Field
  PropertyTreeNode Indexer / Property, with the C# 14 Extension overlay
                   when the accessor is an extension member
  MethodTreeNode   Operator / extension Method / Constructor / PInvoke
                   (extern + DllImport, no body) / VirtualMethod /
                   Method

PInvoke detection uses the documented (!HasBody && DllImport) pair
so managed wrappers that re-apply the attribute via forwarding don't
inherit the native-call glyph.

Also wire the Copy icon onto the "Copy fully qualified name" entry
so the menu row matches its WPF counterpart.

Assisted-by: Claude:claude-opus-4-7:Claude Code
pull/3755/head
Siegfried Pammer 1 month ago
parent
commit
b1045f48e0
  1. 1
      ILSpy/Assets/Icons/Copy.svg
  2. 1
      ILSpy/Assets/Icons/EnumValue.svg
  3. 1
      ILSpy/Assets/Icons/ExtensionMethod.svg
  4. 69
      ILSpy/Assets/Icons/FieldReadOnly.svg
  5. 1
      ILSpy/Assets/Icons/Indexer.svg
  6. 79
      ILSpy/Assets/Icons/PInvokeMethod.svg
  7. 93
      ILSpy/Assets/Icons/VirtualMethod.svg
  8. 2
      ILSpy/Commands/CopyFullyQualifiedNameContextMenuEntry.cs
  9. 9
      ILSpy/Images.cs
  10. 15
      ILSpy/TreeNodes/FieldTreeNode.cs
  11. 41
      ILSpy/TreeNodes/MethodTreeNode.cs
  12. 17
      ILSpy/TreeNodes/PropertyTreeNode.cs

1
ILSpy/Assets/Icons/Copy.svg

@ -0,0 +1 @@ @@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}.icon-vs-fg{fill:#f0eff1}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M5 16v-3H1V0h6.618l2.987 3h1.017L16 7.379V16H5z" id="outline"/><path class="icon-vs-bg" d="M11.207 4H10.19L7.202 1H2v11h4v3h9V7.793L11.207 4zM11 5.207L13.793 8H11V5.207zM6 11H3V2h3.798L8.81 4H6v7zm8 3H7V5h3v4h4v5z" id="iconBg"/><path class="icon-vs-fg" d="M11 5.207L13.793 8H11V5.207zM6 11H3V2h3.798L8.81 4H6v7zm8 3H7V5h3v4h4v5z" id="iconFg"/></svg>

After

Width:  |  Height:  |  Size: 650 B

1
ILSpy/Assets/Icons/EnumValue.svg

@ -0,0 +1 @@ @@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-fg{fill:#f0eff1}.icon-vs-action-blue{fill:#00539c}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M0 15V6h6V2.586L7.585 1h6.829L16 2.586v5.829L14.414 10H10v5H0zm3-6z" id="outline"/><path class="icon-vs-fg" d="M8 3v3h5v1h-3v1h4V3H8zm5 2H9V4h4v1zM2 8v5h6V8H2zm5 3H3v-1h4v1z" id="iconFg"/><path class="icon-vs-action-blue" d="M10 6h3v1h-3V6zM9 4v1h4V4H9zm5-2H8L7 3v3h1V3h6v5h-4v1h4l1-1V3l-1-1zm-7 8H3v1h4v-1zm2-3v7H1V7h8zM8 8H2v5h6V8z" id="iconBg"/></svg>

After

Width:  |  Height:  |  Size: 664 B

1
ILSpy/Assets/Icons/ExtensionMethod.svg

@ -0,0 +1 @@ @@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16" enable-background="new 0 0 16 16"><style type="text/css">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;} .icon-vs-fg{fill:#F0EFF1;} .icon-vs-action-purple{fill:#652D90;}</style><path class="icon-canvas-transparent" d="M16 16h-16v-16h16v16z" id="canvas"/><path class="icon-vs-out" d="M.167 8.426v-5.57l4.884-2.47 4.704 2.481v5.513l-4.464 3.272-5.124-3.226zm14.303.63l-.47.469v-4.525h-4v4.525l-.47-.47-1.53 1.531v1.889l3.525 3.525h.949l3.526-3.525v-1.889l-1.53-1.53z" id="outline"/><path class="icon-vs-fg" d="M4.995 2.188l3.07 1.514-2.864 1.718-3.095-1.766 2.889-1.466zm0 7.356v-3.573l-3.209-1.793v3.319l3.167 2.064v.016l.008-.008.01.008v-.015l.024-.018zm3.195-5.118l-2.576 1.566v3.463l2.576-1.856v-3.173z" id="iconFg"/><g id="iconBg"><path class="icon-vs-action-purple" d="M8.755 7.874v-4.403l-3.714-1.959-3.874 1.959v4.403l4.081 2.57 3.507-2.57zm-3.76-5.686l3.07 1.514-2.864 1.718-3.095-1.766 2.889-1.466zm-.024 7.374v.016l-.01-.008-.008.007v-.015l-3.167-2.065v-3.319l3.209 1.793v3.573l-.024.018zm3.219-1.963l-2.576 1.856v-3.463l2.576-1.566v3.173z"/><path class="icon-vs-bg" d="M13 9h-2v-1h2v1zm0-3h-2v1h2v-1zm1.47 4.47l-1.47 1.469v-1.939h-2v1.939l-1.47-1.47-1.06 1.061 3.53 3.53 3.53-3.53-1.06-1.06z"/></g></svg>

After

Width:  |  Height:  |  Size: 1.3 KiB

69
ILSpy/Assets/Icons/FieldReadOnly.svg

@ -0,0 +1,69 @@ @@ -0,0 +1,69 @@
<?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"
enable-background="new 0 0 16 16"
version="1.1"
id="svg8"
sodipodi:docname="FieldReadOnly.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata14">
<rdf:RDF>
<cc:Work
rdf:about="">
<dc:format>image/svg+xml</dc:format>
<dc:type
rdf:resource="http://purl.org/dc/dcmitype/StillImage" />
</cc:Work>
</rdf:RDF>
</metadata>
<defs
id="defs12" />
<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="namedview10"
showgrid="false"
inkscape:zoom="14.75"
inkscape:cx="18.615736"
inkscape:cy="24.445591"
inkscape:window-x="-8"
inkscape:window-y="340"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<style
type="text/css"
id="style2">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-fg{fill:#F0EFF1;} .icon-vs-action-blue{fill:#00539C;}</style>
<path
class="icon-canvas-transparent"
d="M16 16h-16v-16h16v16z"
id="canvas" />
<path
class="icon-vs-out"
d="M0 10.736v-6.236l9-4.5 7 3.5v6.236l-9 4.5-7-3.5z"
id="outline" />
<path
class="icon-vs-action-blue"
d="M9 1l-8 4v5l6 3 8-4v-5l-6-3zm-2 5.882l-3.764-1.882 5.764-2.882 3.764 1.882-5.764 2.882z"
id="iconBg"
style="fill:#424242;fill-opacity:1" />
<path
class="icon-vs-fg"
d="M9 2.118l3.764 1.882-5.764 2.882-3.764-1.882 5.764-2.882z"
id="iconFg" />
</svg>

After

Width:  |  Height:  |  Size: 2.1 KiB

1
ILSpy/Assets/Icons/Indexer.svg

@ -0,0 +1 @@ @@ -0,0 +1 @@
<svg xmlns="http://www.w3.org/2000/svg" viewBox="0 0 16 16"><style>.icon-canvas-transparent{opacity:0;fill:#f6f6f6}.icon-vs-out{fill:#f6f6f6}.icon-vs-bg{fill:#424242}</style><path class="icon-canvas-transparent" d="M16 16H0V0h16v16z" id="canvas"/><path class="icon-vs-out" d="M11 15v-3h2V4h-2V1h5v14h-5zM0 15V1h5v3H3v8h2v3H0z" id="outline"/><g id="iconBg"><path class="icon-vs-bg" d="M4 14H1V2h3v1H2v10h2v1zM15 2h-3v1h2v10h-2v1h3V2z"/></g></svg>

After

Width:  |  Height:  |  Size: 445 B

79
ILSpy/Assets/Icons/PInvokeMethod.svg

@ -0,0 +1,79 @@ @@ -0,0 +1,79 @@
<?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"
enable-background="new 0 0 16 16"
version="1.1"
id="svg20"
sodipodi:docname="PInvokeMethod.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata26">
<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="defs24" />
<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="namedview22"
showgrid="false"
inkscape:zoom="53"
inkscape:cx="8.3584906"
inkscape:cy="10.264151"
inkscape:window-x="-8"
inkscape:window-y="340"
inkscape:window-maximized="1"
inkscape:current-layer="svg20" />
<style
type="text/css"
id="style10">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-bg{fill:#424242;} .icon-vs-fg{fill:#F0EFF1;} .icon-vs-action-purple{fill:#652D90;}</style>
<path
class="icon-canvas-transparent"
d="M16 16h-16v-16h16v16z"
id="canvas" />
<path
style="fill:#f6f6f6"
d="M 10.580078 0 L 9.0507812 1.5292969 L 9.5195312 2 L 4.9941406 2 L 4.9941406 4.7753906 L 4.8632812 4.7070312 L -0.021484375 7.1757812 L -0.021484375 12.746094 L 5.1015625 15.972656 L 9.5664062 12.701172 L 9.5664062 7.1875 L 7.3144531 6 L 9.5195312 6 L 9.0507812 6.4707031 L 10.580078 8 L 12.470703 8 L 15.994141 4.4746094 L 15.994141 3.5253906 L 12.470703 0 L 10.580078 0 z "
id="outline" />
<path
style="fill:#424242"
inkscape:connector-curvature="0"
id="path17"
d="m 8.965,3.03 v 2 h -1 v -2 z m -3,0 v 2 h 1 v -2 z m 4.47,-1.47 1.469,1.47 H 9.965 v 2 h 1.939 l -1.47,1.47 1.061,1.06 3.53,-3.53 -3.53,-3.53 z"
class="icon-vs-bg" />
<path
style="fill:#652d90"
inkscape:connector-curvature="0"
id="path15"
d="M 8.5663208,12.194755 V 7.7917547 l -3.714,-1.959 -3.87400005,1.959 v 4.4030003 l 4.08100005,2.57 z m -3.76,-5.6860003 3.07,1.514 -2.864,1.718 -3.095,-1.766 z m -0.024,7.3740003 v 0.016 l -0.01,-0.008 -0.008,0.007 v -0.015 l -3.167,-2.065 V 8.4987547 l 3.209,1.7930003 v 3.573 z m 3.219,-1.963 -2.576,1.856 v -3.463 l 2.576,-1.5660003 z"
class="icon-vs-action-purple" />
<path
class="icon-vs-fg"
d="m 4.8063208,6.5087547 3.07,1.514 -2.864,1.718 -3.095,-1.766 z m 0,7.3560003 v -3.573 l -3.209,-1.7930003 v 3.3190003 l 3.167,2.064 v 0.016 l 0.008,-0.008 0.01,0.008 v -0.015 z m 3.195,-5.1180003 -2.576,1.5660003 v 3.463 l 2.576,-1.856 z"
id="iconFg"
inkscape:connector-curvature="0"
style="fill:#f0eff1" />
</svg>

After

Width:  |  Height:  |  Size: 3.3 KiB

93
ILSpy/Assets/Icons/VirtualMethod.svg

@ -0,0 +1,93 @@ @@ -0,0 +1,93 @@
<?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"
enable-background="new 0 0 16 16"
version="1.1"
id="svg8"
sodipodi:docname="VirtualMethod.svg"
inkscape:version="0.92.4 (5da689c313, 2019-01-14)">
<metadata
id="metadata14">
<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="defs12" />
<sodipodi:namedview
pagecolor="#ffffff"
bordercolor="#666666"
borderopacity="1"
objecttolerance="10"
gridtolerance="10"
guidetolerance="10"
inkscape:pageopacity="0"
inkscape:pageshadow="2"
inkscape:window-width="2560"
inkscape:window-height="1377"
id="namedview10"
showgrid="false"
inkscape:zoom="41.7193"
inkscape:cx="3.3822659"
inkscape:cy="10.458595"
inkscape:window-x="1912"
inkscape:window-y="-8"
inkscape:window-maximized="1"
inkscape:current-layer="svg8" />
<style
type="text/css"
id="style2">.icon-canvas-transparent{opacity:0;fill:#F6F6F6;} .icon-vs-out{fill:#F6F6F6;} .icon-vs-fg{fill:#F0EFF1;} .icon-vs-action-purple{fill:#652D90;}</style>
<path
class="icon-canvas-transparent"
d="M16 16h-16v-16h16v16z"
id="canvas" />
<path
class="icon-vs-out"
d="M 14.712363,1.9097912 V 6.7016619 L 11.276564,9.1241143 H 10.760481 L 6.7287634,6.6047182 V 1.8972455 L 10.48961,0 h 0.637546 z"
id="outline"
inkscape:connector-curvature="0"
style="fill:#f6f6f6;stroke-width:0.57025713" />
<path
class="icon-vs-fg"
d="M 13.409326,2.5079909 10.998279,4.0032051 8.1914729,2.4361385 10.802111,1.1194148 Z M 7.8692777,2.909452 10.720563,4.5016099 v 3.253317 L 7.8692777,5.9728733 Z M 11.290821,7.7190006 V 4.4924858 l 2.281028,-1.4142377 v 3.0320572 z"
id="iconFg"
inkscape:connector-curvature="0"
style="fill:#f0eff1;stroke-width:0.57025713" />
<path
class="icon-vs-action-purple"
d="M 10.809523,0.47730523 7.2990205,2.2479537 V 6.2882255 L 11.015387,8.6108829 14.142106,6.4056984 V 2.2525157 Z M 13.409326,2.5079909 10.998279,4.0032051 8.1914729,2.4361385 10.802111,1.1194148 Z M 7.8692777,2.909452 10.720563,4.5016099 v 3.253317 L 7.8692777,5.9728733 Z M 11.290821,7.7190006 V 4.4924858 l 2.281028,-1.4142377 v 3.0320572 z"
id="iconBg"
inkscape:connector-curvature="0"
style="fill:#652d90;stroke-width:0.57025713" />
<path
class="icon-vs-out"
d="M 9.6816129,8.7585278 V 13.548601 L 6.2471024,15.970143 H 5.7312144 L 1.7010089,13.451692 V 8.7459868 L 5.4604432,6.8494533 h 0.6373085 z"
id="outline-4"
inkscape:connector-curvature="0"
style="fill:#f6f6f6;stroke-width:0.57004309" />
<path
class="icon-vs-fg"
d="M 8.3790645,9.3565032 5.9689214,10.851156 3.16317,9.2846777 5.7728268,7.9684481 Z M 2.8410948,9.7578136 5.6913109,11.349374 V 14.60147 L 2.8410948,12.820085 Z M 6.2613539,14.565557 V 11.340253 L 8.541527,9.9265461 v 3.0309199 z"
id="iconFg-4"
inkscape:connector-curvature="0"
style="fill:#f0eff1;stroke-width:0.57004309" />
<path
class="icon-vs-action-purple"
d="M 5.7802377,7.3265795 2.271052,9.0965632 v 4.0387558 l 3.7149707,2.321786 3.1255472,-2.204357 V 9.1011244 Z M 8.3790645,9.3565032 5.9689214,10.851156 3.16317,9.2846777 5.7728268,7.9684481 Z M 2.8410948,9.7578136 5.6913109,11.349374 V 14.60147 L 2.8410948,12.820085 Z M 6.2613539,14.565557 V 11.340253 L 8.541527,9.9265461 v 3.0309199 z"
id="iconBg-2"
inkscape:connector-curvature="0"
style="fill:#652d90;stroke-width:0.57004309" />
</svg>

After

Width:  |  Height:  |  Size: 4.0 KiB

2
ILSpy/Commands/CopyFullyQualifiedNameContextMenuEntry.cs

@ -34,7 +34,7 @@ namespace ILSpy.Commands @@ -34,7 +34,7 @@ namespace ILSpy.Commands
/// Copies the entity's <see cref="ICSharpCode.Decompiler.TypeSystem.IEntity.ReflectionName"/>
/// — the language-independent identifier used by FindNodeByPath etc. — to the clipboard.
/// </summary>
[ExportContextMenuEntry(Header = nameof(Resources.CopyName), Category = "Edit", Order = 600)]
[ExportContextMenuEntry(Header = nameof(Resources.CopyName), Category = "Edit", Icon = "Images/Copy", Order = 600)]
[Shared]
public sealed class CopyFullyQualifiedNameContextMenuEntry : IContextMenuEntry
{

9
ILSpy/Images.cs

@ -110,14 +110,23 @@ namespace ILSpy.Images @@ -110,14 +110,23 @@ namespace ILSpy.Images
public static readonly IImage Method = LoadSvg(nameof(Method));
public static readonly IImage Constructor = LoadSvg(nameof(Constructor));
public static readonly IImage Operator = LoadSvg(nameof(Operator));
public static readonly IImage VirtualMethod = LoadSvg(nameof(VirtualMethod));
public static readonly IImage ExtensionMethod = LoadSvg(nameof(ExtensionMethod));
public static readonly IImage PInvokeMethod = LoadSvg(nameof(PInvokeMethod));
// Fields / properties / events
public static readonly IImage Field = LoadSvg(nameof(Field));
public static readonly IImage FieldReadOnly = LoadSvg(nameof(FieldReadOnly));
public static readonly IImage EnumValue = LoadSvg(nameof(EnumValue));
public static readonly IImage Property = LoadSvg(nameof(Property));
public static readonly IImage Indexer = LoadSvg(nameof(Indexer));
public static readonly IImage Event = LoadSvg(nameof(Event));
public static readonly IImage Literal = LoadSvg(nameof(Literal));
public static readonly IImage ViewCode = LoadSvg(nameof(ViewCode));
// Editing / context-menu icons
public static readonly IImage Copy = LoadSvg(nameof(Copy));
// Reference overlays (small badge layered onto a base icon for TypeRef/MemberRef nodes).
internal static readonly IImage ReferenceOverlay = LoadSvg(nameof(ReferenceOverlay));
internal static readonly IImage ExportOverlay = LoadSvg(nameof(ExportOverlay));

15
ILSpy/TreeNodes/FieldTreeNode.cs

@ -45,22 +45,23 @@ namespace ILSpy.TreeNodes @@ -45,22 +45,23 @@ namespace ILSpy.TreeNodes
public override object Icon => GetIcon(FieldDefinition);
// Distinguish enum members and const fields from regular instance/static fields so the
// tree reads the way the C# source does. The IsReadOnly / FieldReadOnly variant from
// the WPF era isn't ported because we don't have a dedicated SVG for it yet -- such
// fields fall through to the base Field icon.
// Mirrors WPF's discriminator: enum value, const literal, readonly, plain field.
public static Avalonia.Media.IImage GetIcon(IField field)
{
// EnumValue: the field's declaring type is an enum and its return type is the enum
// itself -- this excludes the synthesised int32 'value__' backing field.
// EnumValue: declaring type is an enum and the return type is the enum itself --
// this excludes the synthesised int32 'value__' backing field.
if (field.DeclaringType.Kind == TypeKind.Enum && field.ReturnType.Kind == TypeKind.Enum)
return Images.Images.GetIcon(Images.Images.Enum,
return Images.Images.GetIcon(Images.Images.EnumValue,
Images.Images.GetOverlay(field.Accessibility));
if (field.IsConst)
return Images.Images.GetIcon(Images.Images.Literal,
Images.Images.GetOverlay(field.Accessibility));
if (field.IsReadOnly)
return Images.Images.GetIcon(Images.Images.FieldReadOnly,
Images.Images.GetOverlay(field.Accessibility), field.IsStatic);
return Images.Images.GetIcon(Images.Images.Field,
Images.Images.GetOverlay(field.Accessibility), field.IsStatic);
}

41
ILSpy/TreeNodes/MethodTreeNode.cs

@ -43,16 +43,37 @@ namespace ILSpy.TreeNodes @@ -43,16 +43,37 @@ namespace ILSpy.TreeNodes
public override object NavigationText => Language.EntityToString(MethodDefinition, ConversionFlags.ShowDeclaringType);
public override object Icon {
get {
var baseImage = MethodDefinition.IsConstructor ? Images.Images.Constructor :
MethodDefinition.IsOperator ? Images.Images.Operator :
Images.Images.Method;
return Images.Images.GetIcon(baseImage,
Images.Images.GetOverlay(MethodDefinition.Accessibility),
MethodDefinition.IsStatic,
MethodDefinition.IsExtensionMethod);
}
public override object Icon => GetIcon(MethodDefinition);
// Mirrors WPF's dispatch order: operator, extension method, constructor,
// P/Invoke (DllImport without a body), virtual, plain method. Tested against
// every kind in the analyzers fixtures.
public static Avalonia.Media.IImage GetIcon(IMethod method)
{
bool isExtensionMethod = method.IsExtensionMethod
|| (method.ResolveExtensionInfo()?.InfoOfExtensionMember((IMethod)method.MemberDefinition).HasValue == true);
if (method.IsOperator)
return Images.Images.GetIcon(Images.Images.Operator,
Images.Images.GetOverlay(method.Accessibility), false, isExtensionMethod);
if (isExtensionMethod)
return Images.Images.GetIcon(Images.Images.Method,
Images.Images.GetOverlay(method.Accessibility), false, true);
if (method.IsConstructor)
return Images.Images.GetIcon(Images.Images.Constructor,
Images.Images.GetOverlay(method.Accessibility), method.IsStatic);
// P/Invoke: extern method tagged with [DllImport]. !HasBody filters out the
// managed wrappers that also carry the attribute via attribute-forwarding.
if (!method.HasBody && method.HasAttribute(KnownAttribute.DllImport))
return Images.Images.GetIcon(Images.Images.PInvokeMethod,
Images.Images.GetOverlay(method.Accessibility), true);
return Images.Images.GetIcon(
method.IsVirtual ? Images.Images.VirtualMethod : Images.Images.Method,
Images.Images.GetOverlay(method.Accessibility), method.IsStatic);
}
public override bool ShowExpander => false;

17
ILSpy/TreeNodes/PropertyTreeNode.cs

@ -47,8 +47,21 @@ namespace ILSpy.TreeNodes @@ -47,8 +47,21 @@ namespace ILSpy.TreeNodes
public override object NavigationText => Language.EntityToString(PropertyDefinition, ConversionFlags.ShowDeclaringType);
public override object Icon => Images.Images.GetIcon(Images.Images.Property,
Images.Images.GetOverlay(PropertyDefinition.Accessibility), PropertyDefinition.IsStatic);
public override object Icon => GetIcon(PropertyDefinition);
// Mirrors WPF: indexers get a distinct base glyph; extension properties (C# 14
// extension blocks) layer the Extension overlay on top.
public static Avalonia.Media.IImage GetIcon(IProperty property)
{
IMethod? accessor = property.Getter ?? property.Setter;
bool isExtension = accessor is not null
&& property.ResolveExtensionInfo()?.InfoOfExtensionMember((IMethod)accessor.MemberDefinition) != null;
return Images.Images.GetIcon(
property.IsIndexer ? Images.Images.Indexer : Images.Images.Property,
Images.Images.GetOverlay(property.Accessibility),
property.IsStatic,
isExtension);
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
=> language.DecompileProperty(PropertyDefinition, output, options);

Loading…
Cancel
Save