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(); + } + } + } +}