diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
index 87ee648aa8..36513a7547 100644
--- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
+++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj
@@ -98,6 +98,7 @@
+
@@ -362,6 +363,9 @@
+
+
+
diff --git a/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs b/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs
index d1b642a308..983eaf0f58 100644
--- a/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs
+++ b/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs
@@ -19,6 +19,7 @@
#nullable enable
using System;
+using System.Collections.Immutable;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
@@ -275,6 +276,42 @@ public string FullName {
return bytes;
}
+ ImmutableArray typeReferences;
+ public ImmutableArray TypeReferences {
+ get {
+ var value = typeReferences;
+ if (value.IsDefault)
+ {
+ value = Metadata.TypeReferences
+ .Select(r => new TypeReferenceMetadata(Metadata, r))
+ .Where(r => r.ResolutionScope == Handle)
+ .OrderBy(r => r.Namespace)
+ .ThenBy(r => r.Name)
+ .ToImmutableArray();
+ typeReferences = value;
+ }
+ return value;
+ }
+ }
+
+ ImmutableArray exportedTypes;
+ public ImmutableArray ExportedTypes {
+ get {
+ var value = exportedTypes;
+ if (value.IsDefault)
+ {
+ value = Metadata.ExportedTypes
+ .Select(r => new ExportedTypeMetadata(Metadata, r))
+ .Where(r => r.Implementation == Handle)
+ .OrderBy(r => r.Namespace)
+ .ThenBy(r => r.Name)
+ .ToImmutableArray();
+ exportedTypes = value;
+ }
+ return value;
+ }
+ }
+
public AssemblyReference(MetadataReader metadata, AssemblyReferenceHandle handle)
{
if (metadata == null)
diff --git a/ICSharpCode.Decompiler/Metadata/ExportedTypeMetadata.cs b/ICSharpCode.Decompiler/Metadata/ExportedTypeMetadata.cs
new file mode 100644
index 0000000000..3bada57eed
--- /dev/null
+++ b/ICSharpCode.Decompiler/Metadata/ExportedTypeMetadata.cs
@@ -0,0 +1,103 @@
+// Copyright (c) 2023 James May
+//
+// 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.
+
+#nullable enable
+
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Metadata;
+
+namespace ICSharpCode.Decompiler.Metadata
+{
+#if !VSADDIN
+ ///
+ /// Convenience wrapper for and .
+ ///
+ public sealed class ExportedTypeMetadata
+ {
+ readonly ExportedType entry;
+
+ public MetadataReader Metadata { get; }
+ public ExportedTypeHandle Handle { get; }
+
+ string? name;
+ public string Name {
+ get {
+ try
+ {
+ return name ??= Metadata.GetString(entry.Name);
+ }
+ catch (BadImageFormatException)
+ {
+ return name = $"ET:{Handle}";
+ }
+ }
+ }
+
+ string? @namespace;
+ public string Namespace {
+ get {
+ try
+ {
+ return @namespace ??= Metadata.GetString(entry.Namespace);
+ }
+ catch (BadImageFormatException)
+ {
+ return @namespace = $"namespace(ET:{Handle})";
+ }
+ }
+ }
+
+ public EntityHandle Implementation => entry.Implementation;
+ public TypeAttributes Attributes => entry.Attributes;
+ public bool IsForwarder => entry.IsForwarder;
+ public NamespaceDefinition NamespaceDefinition => Metadata.GetNamespaceDefinition(entry.NamespaceDefinition);
+
+ ImmutableArray exportedTypes;
+ public ImmutableArray ExportedTypes {
+ get {
+ var value = exportedTypes;
+ if (value.IsDefault)
+ {
+ value = Metadata.ExportedTypes
+ .Select(r => new ExportedTypeMetadata(Metadata, r))
+ .Where(r => r.Implementation == Handle)
+ .OrderBy(r => r.Namespace)
+ .ThenBy(r => r.Name)
+ .ToImmutableArray();
+ exportedTypes = value;
+ }
+ return value;
+ }
+ }
+
+ public ExportedTypeMetadata(MetadataReader metadata, ExportedTypeHandle handle)
+ {
+ Metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
+ if (handle.IsNil)
+ throw new ArgumentNullException(nameof(handle));
+ Handle = handle;
+ entry = metadata.GetExportedType(handle);
+ }
+
+ public override string ToString() => $"{Namespace}::{Name}";
+ }
+#endif
+}
diff --git a/ICSharpCode.Decompiler/Metadata/MemberReferenceMetadata.cs b/ICSharpCode.Decompiler/Metadata/MemberReferenceMetadata.cs
new file mode 100644
index 0000000000..001f58776f
--- /dev/null
+++ b/ICSharpCode.Decompiler/Metadata/MemberReferenceMetadata.cs
@@ -0,0 +1,69 @@
+// Copyright (c) 2023 James May
+//
+// 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.
+
+#nullable enable
+
+using System;
+using System.Reflection.Metadata;
+
+namespace ICSharpCode.Decompiler.Metadata
+{
+#if !VSADDIN
+ ///
+ /// Convenience wrapper for and .
+ ///
+ public sealed class MemberReferenceMetadata
+ {
+ readonly MemberReference entry;
+
+ public MetadataReader Metadata { get; }
+ public MemberReferenceHandle Handle { get; }
+
+ string? name;
+
+ public string Name {
+ get {
+ try
+ {
+ return name ??= Metadata.GetString(entry.Name);
+ }
+ catch (BadImageFormatException)
+ {
+ return name = $"MR:{Handle}";
+ }
+ }
+ }
+
+ public EntityHandle Parent => entry.Parent;
+
+ public MemberReferenceKind MemberReferenceKind => entry.GetKind();
+
+ public MemberReferenceMetadata(MetadataReader metadata, MemberReferenceHandle handle)
+ {
+ Metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
+ if (handle.IsNil)
+ throw new ArgumentNullException(nameof(handle));
+ Handle = handle;
+ entry = metadata.GetMemberReference(handle);
+ }
+
+ public override string ToString()
+ => Name;
+ }
+#endif
+}
diff --git a/ICSharpCode.Decompiler/Metadata/ModuleReferenceMetadata.cs b/ICSharpCode.Decompiler/Metadata/ModuleReferenceMetadata.cs
new file mode 100644
index 0000000000..eee2078f88
--- /dev/null
+++ b/ICSharpCode.Decompiler/Metadata/ModuleReferenceMetadata.cs
@@ -0,0 +1,132 @@
+// Copyright (c) 2023 James May
+//
+// 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.
+
+#nullable enable
+
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection;
+using System.Reflection.Metadata;
+
+namespace ICSharpCode.Decompiler.Metadata
+{
+#if !VSADDIN
+ public class ModuleReferenceMetadata /* : IModuleReference*/
+ {
+ readonly ModuleReference entry;
+
+ public MetadataReader Metadata { get; }
+ public ModuleReferenceHandle Handle { get; }
+
+ string? name;
+ public string Name {
+ get {
+ if (name == null)
+ {
+ try
+ {
+ name = Metadata.GetString(entry.Name);
+ }
+ catch (BadImageFormatException)
+ {
+ name = $"AR:{Handle}";
+ }
+ }
+ return name;
+ }
+ }
+
+ ImmutableArray attributes;
+ public ImmutableArray Attributes {
+ get {
+ var value = attributes;
+ if (value.IsDefault)
+ {
+ value = entry.GetCustomAttributes().Select(Metadata.GetCustomAttribute).ToImmutableArray();
+ attributes = value;
+ }
+ return value;
+ }
+ }
+
+ ImmutableArray typeReferences;
+ public ImmutableArray TypeReferences {
+ get {
+ var value = typeReferences;
+ if (value.IsDefault)
+ {
+ value = Metadata.TypeReferences
+ .Select(r => new TypeReferenceMetadata(Metadata, r))
+ .Where(r => r.ResolutionScope == Handle)
+ .OrderBy(r => r.Namespace)
+ .ThenBy(r => r.Name)
+ .ToImmutableArray();
+ typeReferences = value;
+ }
+ return value;
+ }
+ }
+
+ ImmutableArray exportedTypes;
+ public ImmutableArray ExportedTypes {
+ get {
+ var value = exportedTypes;
+ if (value.IsDefault)
+ {
+ value = Metadata.ExportedTypes
+ .Select(r => new ExportedTypeMetadata(Metadata, r))
+ .Where(r => r.Implementation == Handle)
+ .OrderBy(r => r.Namespace)
+ .ThenBy(r => r.Name)
+ .ToImmutableArray();
+ exportedTypes = value;
+ }
+ return value;
+ }
+ }
+
+ public ModuleReferenceMetadata(MetadataReader metadata, ModuleReferenceHandle handle)
+ {
+ if (metadata == null)
+ throw new ArgumentNullException(nameof(metadata));
+ if (handle.IsNil)
+ throw new ArgumentNullException(nameof(handle));
+ Metadata = metadata;
+ Handle = handle;
+ entry = metadata.GetModuleReference(handle);
+ }
+
+ public ModuleReferenceMetadata(PEFile module, ModuleReferenceHandle handle)
+ {
+ if (module == null)
+ throw new ArgumentNullException(nameof(module));
+ if (handle.IsNil)
+ throw new ArgumentNullException(nameof(handle));
+ Metadata = module.Metadata;
+ Handle = handle;
+ entry = Metadata.GetModuleReference(handle);
+ }
+
+ public override string ToString()
+ {
+ return Name;
+ }
+ }
+#endif
+}
diff --git a/ICSharpCode.Decompiler/Metadata/PEFile.cs b/ICSharpCode.Decompiler/Metadata/PEFile.cs
index 8279407671..c180de1792 100644
--- a/ICSharpCode.Decompiler/Metadata/PEFile.cs
+++ b/ICSharpCode.Decompiler/Metadata/PEFile.cs
@@ -177,6 +177,22 @@ public ImmutableArray AssemblyReferences {
}
}
+ ImmutableArray moduleReferences;
+ public ImmutableArray ModuleReferences {
+ get {
+ var value = moduleReferences;
+ if (value.IsDefault)
+ {
+ value = Metadata.GetModuleReferences()
+ .Select(m => new ModuleReferenceMetadata(this, m))
+ .ToImmutableArray();
+
+ moduleReferences = value;
+ }
+ return value;
+ }
+ }
+
public ImmutableArray Resources => GetResources().ToImmutableArray();
IEnumerable GetResources()
diff --git a/ICSharpCode.Decompiler/Metadata/TypeReferenceMetadata.cs b/ICSharpCode.Decompiler/Metadata/TypeReferenceMetadata.cs
new file mode 100644
index 0000000000..fb2c826048
--- /dev/null
+++ b/ICSharpCode.Decompiler/Metadata/TypeReferenceMetadata.cs
@@ -0,0 +1,112 @@
+// Copyright (c) 2023 James May
+//
+// 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.
+
+#nullable enable
+
+using System;
+using System.Collections.Immutable;
+using System.Linq;
+using System.Reflection.Metadata;
+
+namespace ICSharpCode.Decompiler.Metadata
+{
+#if !VSADDIN
+ public sealed class TypeReferenceMetadata
+ {
+ readonly TypeReference entry;
+
+ public MetadataReader Metadata { get; }
+ public TypeReferenceHandle Handle { get; }
+
+ string? name;
+ public string Name {
+ get {
+ try
+ {
+ return name ??= Metadata.GetString(entry.Name);
+ }
+ catch (BadImageFormatException)
+ {
+ return name = $"TR:{Handle}";
+ }
+ }
+ }
+
+ string? @namespace;
+ public string Namespace {
+ get {
+ try
+ {
+ return @namespace ??= Metadata.GetString(entry.Namespace);
+ }
+ catch (BadImageFormatException)
+ {
+ return @namespace = $"namespace(TR:{Handle})";
+ }
+ }
+ }
+
+ public EntityHandle ResolutionScope => entry.ResolutionScope;
+
+ ImmutableArray memberReferences;
+ public ImmutableArray MemberReferences {
+ get {
+ var value = memberReferences;
+ if (value.IsDefault)
+ {
+ value = Metadata.MemberReferences
+ .Select(r => new MemberReferenceMetadata(Metadata, r))
+ .Where(r => r.Parent == Handle)
+ .OrderBy(r => r.Name)
+ .ToImmutableArray();
+ memberReferences = value;
+ }
+ return value;
+ }
+ }
+
+ ImmutableArray typeReferences;
+ public ImmutableArray TypeReferences {
+ get {
+ var value = typeReferences;
+ if (value.IsDefault)
+ {
+ value = Metadata.TypeReferences
+ .Select(r => new TypeReferenceMetadata(Metadata, r))
+ .Where(r => r.ResolutionScope == Handle)
+ .OrderBy(r => r.Name)
+ .ToImmutableArray();
+ typeReferences = value;
+ }
+ return value;
+ }
+ }
+
+ public TypeReferenceMetadata(MetadataReader metadata, TypeReferenceHandle handle)
+ {
+ Metadata = metadata ?? throw new ArgumentNullException(nameof(metadata));
+ if (handle.IsNil)
+ throw new ArgumentNullException(nameof(handle));
+ Handle = handle;
+ entry = metadata.GetTypeReference(handle);
+ }
+
+ public override string ToString() => $"{Namespace}::{Name}";
+ }
+#endif
+}
diff --git a/ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs b/ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs
index 9df4bf8a41..36712ee645 100644
--- a/ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/FullTypeName.cs
@@ -165,6 +165,22 @@ public string ReflectionName {
}
}
+ public string FullName {
+ get {
+ if (nestedTypes == null)
+ return topLevelType.Namespace + "." + topLevelType.Name;
+ StringBuilder b = new StringBuilder(topLevelType.Namespace);
+ b.Append('.');
+ b.Append(topLevelType.Name);
+ foreach (NestedTypeName nt in nestedTypes)
+ {
+ b.Append('.');
+ b.Append(nt.Name);
+ }
+ return b.ToString();
+ }
+ }
+
///
/// Gets the total type parameter count.
///
diff --git a/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs
index 28a0f33b7e..9489194bf4 100644
--- a/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs
+++ b/ICSharpCode.Decompiler/TypeSystem/Implementation/UnknownType.cs
@@ -95,6 +95,10 @@ public override string ReflectionName {
get { return namespaceKnown ? fullTypeName.ReflectionName : "?"; }
}
+ public override string FullName {
+ get { return namespaceKnown ? fullTypeName.FullName : "?"; }
+ }
+
public FullTypeName FullTypeName => fullTypeName;
public override int TypeParameterCount => fullTypeName.TypeParameterCount;
diff --git a/ILSpy/Images/ExportOverlay.svg b/ILSpy/Images/ExportOverlay.svg
new file mode 100644
index 0000000000..d396359683
--- /dev/null
+++ b/ILSpy/Images/ExportOverlay.svg
@@ -0,0 +1,86 @@
+
+
+
+
diff --git a/ILSpy/Images/ExportOverlay.xaml b/ILSpy/Images/ExportOverlay.xaml
new file mode 100644
index 0000000000..387c04fb4e
--- /dev/null
+++ b/ILSpy/Images/ExportOverlay.xaml
@@ -0,0 +1,18 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy/Images/Images.cs b/ILSpy/Images/Images.cs
index ab1012278f..5b48f10bc8 100644
--- a/ILSpy/Images/Images.cs
+++ b/ILSpy/Images/Images.cs
@@ -27,6 +27,8 @@ namespace ICSharpCode.ILSpy
{
static class Images
{
+ private static readonly Rect iconRect = new Rect(0, 0, 16, 16);
+
static ImageSource Load(string icon)
{
var image = new DrawingImage(LoadDrawingGroup(null, "Images/" + icon));
@@ -85,6 +87,7 @@ static ImageSource Load(string icon)
public static readonly ImageSource Interface = Load("Interface");
public static readonly ImageSource Delegate = Load("Delegate");
public static readonly ImageSource Enum = Load("Enum");
+ public static readonly ImageSource Type = Load("ShowPublicOnly");
public static readonly ImageSource Field = Load("Field");
public static readonly ImageSource FieldReadOnly = Load("FieldReadOnly");
@@ -109,9 +112,15 @@ static ImageSource Load(string icon)
private static readonly ImageSource OverlayPrivate = Load("OverlayPrivate");
private static readonly ImageSource OverlayPrivateProtected = Load("OverlayPrivateProtected");
private static readonly ImageSource OverlayCompilerControlled = Load("OverlayCompilerControlled");
+ private static readonly ImageSource OverlayReference = Load("ReferenceOverlay");
private static readonly ImageSource OverlayStatic = Load("OverlayStatic");
+ public static readonly ImageSource TypeReference = GetIcon("ShowPublicOnly", "ReferenceOverlay");
+ public static readonly ImageSource MethodReference = GetIcon("Method", "ReferenceOverlay");
+ public static readonly ImageSource FieldReference = GetIcon("Field", "ReferenceOverlay");
+ public static readonly ImageSource ExportedType = GetIcon("ShowPublicOnly", "ExportOverlay");
+
public static ImageSource Load(object part, string icon)
{
if (icon.EndsWith(".png", StringComparison.OrdinalIgnoreCase))
@@ -202,6 +211,45 @@ public static ImageSource GetIcon(MemberIcon icon, AccessOverlayIcon overlay, bo
return memberIconCache.GetIcon(icon, overlay, isStatic);
}
+ private static ImageSource GetIcon(string baseImage, string overlay = null, bool isStatic = false)
+ {
+ ImageSource baseImageSource = Load(baseImage);
+ ImageSource overlayImageSource = overlay != null ? Load(overlay) : null;
+
+ return CreateOverlayImage(baseImageSource, overlayImageSource, isStatic);
+ }
+
+ private static ImageSource CreateOverlayImage(ImageSource baseImage, ImageSource overlay, bool isStatic)
+ {
+ var group = new DrawingGroup();
+
+ Drawing baseDrawing = new ImageDrawing(baseImage, iconRect);
+
+ if (overlay != null)
+ {
+ var nestedGroup = new DrawingGroup { Transform = new ScaleTransform(0.8, 0.8) };
+ nestedGroup.Children.Add(baseDrawing);
+ group.Children.Add(nestedGroup);
+ group.Children.Add(new ImageDrawing(overlay, iconRect));
+ }
+ else
+ {
+ group.Children.Add(baseDrawing);
+ }
+
+ if (isStatic)
+ {
+ group.Children.Add(new ImageDrawing(Images.OverlayStatic, iconRect));
+ }
+
+ var image = new DrawingImage(group);
+ if (image.CanFreeze)
+ {
+ image.Freeze();
+ }
+ return image;
+ }
+
#region icon caches & overlay management
private class TypeIconCache : IconCache
@@ -380,39 +428,6 @@ private static ImageSource GetOverlayImage(AccessOverlayIcon overlay)
}
return overlayImage;
}
-
- private static readonly Rect iconRect = new Rect(0, 0, 16, 16);
-
- private static ImageSource CreateOverlayImage(ImageSource baseImage, ImageSource overlay, bool isStatic)
- {
- var group = new DrawingGroup();
-
- Drawing baseDrawing = new ImageDrawing(baseImage, iconRect);
-
- if (overlay != null)
- {
- var nestedGroup = new DrawingGroup { Transform = new ScaleTransform(0.8, 0.8) };
- nestedGroup.Children.Add(baseDrawing);
- group.Children.Add(nestedGroup);
- group.Children.Add(new ImageDrawing(overlay, iconRect));
- }
- else
- {
- group.Children.Add(baseDrawing);
- }
-
- if (isStatic)
- {
- group.Children.Add(new ImageDrawing(Images.OverlayStatic, iconRect));
- }
-
- var image = new DrawingImage(group);
- if (image.CanFreeze)
- {
- image.Freeze();
- }
- return image;
- }
}
#endregion
diff --git a/ILSpy/Images/README.md b/ILSpy/Images/README.md
index 82decd3387..05dcc6f092 100644
--- a/ILSpy/Images/README.md
+++ b/ILSpy/Images/README.md
@@ -18,6 +18,7 @@ Icons used in ILSpy:
| Enum | x | x | VS 2017 Icon Pack (Enumerator) | |
| EnumValue | x | x | VS 2017 Icon Pack (EnumItem) | |
| Event | x | x | VS 2017 Icon Pack (Event) | |
+| ExportOverlay | x | x | slightly modified VS 2017 Icon Pack (Export) | |
| ExtensionMethod | x | x | VS 2017 Icon Pack (ExtensionMethod) | |
| Field | x | x | VS 2017 Icon Pack (Field) | |
| FieldReadOnly | x | x | VS 2017 Icon Pack (Field) with different color | |
@@ -53,12 +54,13 @@ Icons used in ILSpy:
| ProgramDebugDatabase | x | x | VS 2017 Icon Pack (ProgramDebugDatabase) | |
| Property | x | x | VS 2017 Icon Pack (Property) | |
| ReferenceFolder | x | x | combined VS 2017 Icon Pack (Reference) two times | |
+| ReferenceOverlay | x | x | extracted arrow from VS 2017 Icon Pack (TypeShortcut) | |
| Refresh | x | x | VS 2017 Icon Pack (Refresh) | |
| Resource | x | x | VS 2017 Icon Pack (Document) | |
| ResourceImage | x | x | VS 2017 Icon Pack (Image) | |
| ResourceResourcesFile | x | x | VS 2017 Icon Pack (LocalResources) | |
| ResourceXml | x | x | VS 2017 Icon Pack (XMLFile) | |
-| ResourceXsd | x | x | combined VS 2017 Icon Pack (XMLSchema) with the "file symbol in ResourceXslt | |
+| ResourceXsd | x | x | combined VS 2017 Icon Pack (XMLSchema) with the file symbol in ResourceXslt | |
| ResourceXsl | x | x | VS 2017 Icon Pack (XMLTransformation) | |
| ResourceXslt | x | x | VS 2017 Icon Pack (XSLTTemplate) | |
| Save | x | x | VS 2017 Icon Pack (Save) | |
diff --git a/ILSpy/Images/ReferenceOverlay.svg b/ILSpy/Images/ReferenceOverlay.svg
new file mode 100644
index 0000000000..8d6a8ef7af
--- /dev/null
+++ b/ILSpy/Images/ReferenceOverlay.svg
@@ -0,0 +1,55 @@
+
+
diff --git a/ILSpy/Images/ReferenceOverlay.xaml b/ILSpy/Images/ReferenceOverlay.xaml
new file mode 100644
index 0000000000..a07e0cb790
--- /dev/null
+++ b/ILSpy/Images/ReferenceOverlay.xaml
@@ -0,0 +1,12 @@
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/ILSpy/TreeNodes/AssemblyReferenceReferencedTypesTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceReferencedTypesTreeNode.cs
new file mode 100644
index 0000000000..642cb80eef
--- /dev/null
+++ b/ILSpy/TreeNodes/AssemblyReferenceReferencedTypesTreeNode.cs
@@ -0,0 +1,64 @@
+// Copyright (c) 2023 James May
+//
+// 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;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.ILSpy.TreeNodes
+{
+ ///
+ /// Referenced Types node in assembly reference list
+ ///
+ public sealed class AssemblyReferenceReferencedTypesTreeNode : ILSpyTreeNode
+ {
+ readonly MetadataModule module;
+ readonly AssemblyReference r;
+
+ public AssemblyReferenceReferencedTypesTreeNode(MetadataModule module, AssemblyReference r)
+ {
+ this.module = module ?? throw new ArgumentNullException(nameof(module));
+ this.r = r ?? throw new ArgumentNullException(nameof(r));
+
+ this.LazyLoading = true;
+ }
+
+ public override object Text => $"Referenced Types ({r.TypeReferences.Length + r.ExportedTypes.Length})";
+ public override object Icon => Images.MetadataTable;
+
+ protected override void LoadChildren()
+ {
+ foreach (var typeRef in r.TypeReferences)
+ this.Children.Add(new TypeReferenceTreeNode(module, typeRef));
+
+ foreach (var exportedType in r.ExportedTypes)
+ this.Children.Add(new ExportedTypeTreeNode(module, exportedType));
+ }
+
+ public override bool ShowExpander => !r.TypeReferences.IsEmpty || !r.ExportedTypes.IsEmpty;
+
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ {
+ EnsureLazyChildren();
+ foreach (ILSpyTreeNode child in Children)
+ child.Decompile(language, output, options);
+ }
+ }
+}
diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
index ad003ffcc8..3db5f974ee 100644
--- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
@@ -21,6 +21,7 @@
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
namespace ICSharpCode.ILSpy.TreeNodes
{
@@ -29,17 +30,19 @@ namespace ICSharpCode.ILSpy.TreeNodes
///
public sealed class AssemblyReferenceTreeNode : ILSpyTreeNode
{
+ readonly MetadataModule module;
readonly AssemblyReference r;
readonly AssemblyTreeNode parentAssembly;
- public AssemblyReferenceTreeNode(AssemblyReference r, AssemblyTreeNode parentAssembly)
+ public AssemblyReferenceTreeNode(MetadataModule module, AssemblyReference r, AssemblyTreeNode parentAssembly)
{
+ this.module = module ?? throw new ArgumentNullException(nameof(module));
this.r = r ?? throw new ArgumentNullException(nameof(r));
this.parentAssembly = parentAssembly ?? throw new ArgumentNullException(nameof(parentAssembly));
this.LazyLoading = true;
}
- public IAssemblyReference AssemblyNameReference => r;
+ public AssemblyReference AssemblyReference => r;
public override object Text {
get { return Language.EscapeName(r.Name) + GetSuffixString(r.Handle); }
@@ -75,12 +78,15 @@ public override void ActivateItem(System.Windows.RoutedEventArgs e)
protected override void LoadChildren()
{
+ this.Children.Add(new AssemblyReferenceReferencedTypesTreeNode(module, r));
+
var resolver = parentAssembly.LoadedAssembly.GetAssemblyResolver(MainWindow.Instance.CurrentDecompilerSettings.AutoLoadAssemblyReferences);
- var module = resolver.Resolve(r);
- if (module != null)
+ var referencedModule = resolver.Resolve(r);
+ if (referencedModule != null)
{
- foreach (var childRef in module.AssemblyReferences)
- this.Children.Add(new AssemblyReferenceTreeNode(childRef, parentAssembly));
+ var module = (MetadataModule)referencedModule.GetTypeSystemWithCurrentOptionsOrNull().MainModule;
+ foreach (var childRef in referencedModule.AssemblyReferences)
+ this.Children.Add(new AssemblyReferenceTreeNode(module, childRef, parentAssembly));
}
}
diff --git a/ILSpy/TreeNodes/ExportedTypeTreeNode.cs b/ILSpy/TreeNodes/ExportedTypeTreeNode.cs
new file mode 100644
index 0000000000..262d4c7a99
--- /dev/null
+++ b/ILSpy/TreeNodes/ExportedTypeTreeNode.cs
@@ -0,0 +1,63 @@
+// Copyright (c) 2023 James May
+//
+// 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;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.ILSpy.TreeNodes
+{
+ ///
+ /// exported type within assembly reference list.
+ ///
+ public sealed class ExportedTypeTreeNode : ILSpyTreeNode
+ {
+ readonly MetadataModule module;
+ readonly ExportedTypeMetadata r;
+ readonly IType resolvedType;
+
+ public ExportedTypeTreeNode(MetadataModule module, ExportedTypeMetadata r)
+ {
+ this.module = module ?? throw new ArgumentNullException(nameof(module));
+ this.r = r ?? throw new ArgumentNullException(nameof(r));
+ this.resolvedType = module.ResolveType(r.Handle, default);
+
+ this.LazyLoading = true;
+ }
+
+ public override object Text
+ => Language.TypeToString(resolvedType, includeNamespace: true) + GetSuffixString(r.Handle);
+
+ public override object Icon => Images.ExportedType;
+
+ protected override void LoadChildren()
+ {
+ foreach (var exportedType in r.ExportedTypes)
+ this.Children.Add(new ExportedTypeTreeNode(module, exportedType));
+ }
+
+ public override bool ShowExpander => !r.ExportedTypes.IsEmpty;
+
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ {
+ language.WriteCommentLine(output, $"{Language.TypeToString(resolvedType, includeNamespace: true)} (Exported, IsForwarder: {r.IsForwarder}, Attributes: {(int)r.Attributes:X8})");
+ }
+ }
+}
diff --git a/ILSpy/TreeNodes/MemberReferenceTreeNode.cs b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs
new file mode 100644
index 0000000000..33ae47cffc
--- /dev/null
+++ b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs
@@ -0,0 +1,67 @@
+// Copyright (c) 2023 James May
+//
+// 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.
+
+#nullable enable
+
+using System;
+using System.Reflection.Metadata;
+
+using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.ILSpy.TreeNodes
+{
+ ///
+ /// Reference to member from assembly reference list.
+ ///
+ public sealed class MemberReferenceTreeNode : ILSpyTreeNode
+ {
+ readonly MetadataModule module;
+ readonly MemberReferenceMetadata r;
+ readonly IMember resolvedMember;
+
+ public MemberReferenceTreeNode(MetadataModule module, MemberReferenceMetadata r)
+ {
+ this.module = module ?? throw new ArgumentNullException(nameof(module));
+ this.r = r;
+ this.resolvedMember = r.MemberReferenceKind switch {
+ MemberReferenceKind.Method => module.ResolveMethod(r.Handle, default),
+ MemberReferenceKind.Field => (IMember)module.ResolveEntity(r.Handle),
+ _ => throw new NotSupportedException(),
+ };
+ }
+
+ public override object Text => Signature + GetSuffixString(r.Handle);
+
+ public override object Icon => r.MemberReferenceKind switch {
+ MemberReferenceKind.Method => Images.MethodReference,
+ MemberReferenceKind.Field => Images.FieldReference,
+ _ => throw new NotSupportedException(),
+ };
+
+ public string Signature => resolvedMember is IMethod m ? Language.MethodToString(m, false, false, false) : Language.FieldToString((IField)resolvedMember, false, false, false);
+
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ {
+ language.WriteCommentLine(output, Signature);
+ }
+
+ public override object ToolTip => Language.GetRichTextTooltip(resolvedMember);
+ }
+}
diff --git a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
index b800e55911..c0c37654a6 100644
--- a/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs
@@ -17,9 +17,13 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Linq;
using System.Reflection.Metadata;
+using System.Reflection.Metadata.Ecma335;
using ICSharpCode.Decompiler;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.ILSpy.Metadata;
namespace ICSharpCode.ILSpy.TreeNodes
{
@@ -28,6 +32,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
///
sealed class ModuleReferenceTreeNode : ILSpyTreeNode
{
+ readonly PEFile module;
readonly AssemblyTreeNode parentAssembly;
readonly MetadataReader metadata;
readonly ModuleReferenceHandle handle;
@@ -37,20 +42,21 @@ sealed class ModuleReferenceTreeNode : ILSpyTreeNode
readonly string moduleName;
readonly bool containsMetadata;
- public ModuleReferenceTreeNode(AssemblyTreeNode parentAssembly, ModuleReferenceHandle r, MetadataReader module)
+ public ModuleReferenceTreeNode(AssemblyTreeNode parentAssembly, ModuleReferenceHandle r, PEFile module)
{
this.parentAssembly = parentAssembly ?? throw new ArgumentNullException(nameof(parentAssembly));
if (r.IsNil)
throw new ArgumentNullException(nameof(r));
- this.metadata = module;
this.handle = r;
- this.reference = module.GetModuleReference(r);
+ this.module = module ?? throw new ArgumentNullException(nameof(module));
+ this.metadata = module.Metadata;
+ this.reference = module.Metadata.GetModuleReference(r);
this.moduleName = Language.EscapeName(metadata.GetString(reference.Name));
- foreach (var h in module.AssemblyFiles)
+ foreach (var h in metadata.AssemblyFiles)
{
- var file = module.GetAssemblyFile(h);
- if (module.StringComparer.Equals(file.Name, moduleName))
+ var file = metadata.GetAssemblyFile(h);
+ if (metadata.StringComparer.Equals(file.Name, moduleName))
{
this.file = file;
this.fileHandle = h;
diff --git a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
index 347e07d670..e978a7e8a5 100644
--- a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
+++ b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs
@@ -22,6 +22,7 @@
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.ILSpy.Properties;
namespace ICSharpCode.ILSpy.TreeNodes
@@ -48,10 +49,11 @@ public ReferenceFolderTreeNode(PEFile module, AssemblyTreeNode parentAssembly)
protected override void LoadChildren()
{
var metadata = module.Metadata;
+ var metadataModule = (MetadataModule)module.GetTypeSystemWithCurrentOptionsOrNull().MainModule;
foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name))
- this.Children.Add(new AssemblyReferenceTreeNode(r, parentAssembly));
+ this.Children.Add(new AssemblyReferenceTreeNode(metadataModule, r, parentAssembly));
foreach (var r in metadata.GetModuleReferences().OrderBy(r => metadata.GetString(metadata.GetModuleReference(r).Name)))
- this.Children.Add(new ModuleReferenceTreeNode(parentAssembly, r, metadata));
+ this.Children.Add(new ModuleReferenceTreeNode(parentAssembly, r, module));
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
diff --git a/ILSpy/TreeNodes/TypeReferenceTreeNode.cs b/ILSpy/TreeNodes/TypeReferenceTreeNode.cs
new file mode 100644
index 0000000000..d8039181cf
--- /dev/null
+++ b/ILSpy/TreeNodes/TypeReferenceTreeNode.cs
@@ -0,0 +1,73 @@
+// Copyright (c) 2023 James May
+//
+// 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;
+using ICSharpCode.Decompiler.Metadata;
+using ICSharpCode.Decompiler.TypeSystem;
+
+namespace ICSharpCode.ILSpy.TreeNodes
+{
+ ///
+ /// referenced type within assembly reference list.
+ ///
+ public sealed class TypeReferenceTreeNode : ILSpyTreeNode
+ {
+ readonly MetadataModule module;
+ readonly TypeReferenceMetadata r;
+ readonly IType resolvedType;
+
+ public TypeReferenceTreeNode(MetadataModule module, TypeReferenceMetadata r)
+ {
+ this.module = module ?? throw new ArgumentNullException(nameof(module));
+ this.r = r ?? throw new ArgumentNullException(nameof(r));
+ this.resolvedType = module.ResolveType(r.Handle, default);
+
+ this.LazyLoading = true;
+ }
+
+ public override object Text
+ => Language.TypeToString(resolvedType, includeNamespace: false) + GetSuffixString(r.Handle);
+
+ public override object Icon => Images.TypeReference;
+
+ protected override void LoadChildren()
+ {
+ foreach (var typeRef in r.TypeReferences)
+ this.Children.Add(new TypeReferenceTreeNode(module, typeRef));
+
+ foreach (var memberRef in r.MemberReferences)
+ this.Children.Add(new MemberReferenceTreeNode(module, memberRef));
+ }
+
+ public override bool ShowExpander => !r.TypeReferences.IsEmpty || !r.MemberReferences.IsEmpty;
+
+ public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
+ {
+ language.WriteCommentLine(output, Language.TypeToString(resolvedType, includeNamespace: true));
+ EnsureLazyChildren();
+ foreach (ILSpyTreeNode child in Children)
+ {
+ output.Indent();
+ child.Decompile(language, output, options);
+ output.Unindent();
+ }
+ }
+ }
+}