diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 5c4539d5a..36513a754 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -98,6 +98,7 @@ + diff --git a/ICSharpCode.Decompiler/Metadata/ModuleReferenceMetadata.cs b/ICSharpCode.Decompiler/Metadata/ModuleReferenceMetadata.cs new file mode 100644 index 000000000..eee2078f8 --- /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 827940767..c180de179 100644 --- a/ICSharpCode.Decompiler/Metadata/PEFile.cs +++ b/ICSharpCode.Decompiler/Metadata/PEFile.cs @@ -177,6 +177,22 @@ namespace ICSharpCode.Decompiler.Metadata } } + 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/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs b/ILSpy/TreeNodes/ModuleReferenceTreeNode.cs index b800e5591..c0c37654a 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 @@ namespace ICSharpCode.ILSpy.TreeNodes 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 adb72732c..9d8452d4a 100644 --- a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs +++ b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs @@ -51,7 +51,7 @@ namespace ICSharpCode.ILSpy.TreeNodes foreach (var r in module.AssemblyReferences.OrderBy(r => r.Name)) this.Children.Add(new AssemblyReferenceTreeNode(module, 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)