diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index bb3b5aab2..7378034a7 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -362,6 +362,7 @@ + diff --git a/ICSharpCode.Decompiler/Metadata/MemberReferenceMetadata.cs b/ICSharpCode.Decompiler/Metadata/MemberReferenceMetadata.cs new file mode 100644 index 000000000..001f58776 --- /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/TypeReferenceMetadata.cs b/ICSharpCode.Decompiler/Metadata/TypeReferenceMetadata.cs index 0c2c4b5db..fb2c82604 100644 --- a/ICSharpCode.Decompiler/Metadata/TypeReferenceMetadata.cs +++ b/ICSharpCode.Decompiler/Metadata/TypeReferenceMetadata.cs @@ -63,6 +63,23 @@ namespace ICSharpCode.Decompiler.Metadata 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 { diff --git a/ILSpy/TreeNodes/MemberReferenceTreeNode.cs b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs new file mode 100644 index 000000000..c69443029 --- /dev/null +++ b/ILSpy/TreeNodes/MemberReferenceTreeNode.cs @@ -0,0 +1,60 @@ +// 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; + +namespace ICSharpCode.ILSpy.TreeNodes +{ + /// + /// Reference to member from assembly reference list. + /// + public sealed class MemberReferenceTreeNode : ILSpyTreeNode + { + readonly PEFile module; + private readonly MemberReferenceMetadata r; + + public MemberReferenceTreeNode(PEFile module, MemberReferenceMetadata r) + { + this.module = module ?? throw new ArgumentNullException(nameof(module)); + this.r = r; + } + + public override object Text => r.Name + GetSuffixString(r.Handle); + + public override object Icon => r.MemberReferenceKind switch { + MemberReferenceKind.Method => Images.Method, + MemberReferenceKind.Field => Images.Field, + _ => Images.Class, + }; + + public string Signature => Language.GetEntityName(module, r.Handle, fullName: true, omitGenerics: false); + + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) + { + language.WriteCommentLine(output, Signature); + } + + public override object ToolTip => Signature; + } +} diff --git a/ILSpy/TreeNodes/TypeReferenceTreeNode.cs b/ILSpy/TreeNodes/TypeReferenceTreeNode.cs index aeb4519bb..a0f76fa0c 100644 --- a/ILSpy/TreeNodes/TypeReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/TypeReferenceTreeNode.cs @@ -44,6 +44,14 @@ namespace ICSharpCode.ILSpy.TreeNodes public override object Icon => Images.Class; + protected override void LoadChildren() + { + foreach (var memberRef in r.MemberReferences) + this.Children.Add(new MemberReferenceTreeNode(module, memberRef)); + } + + public override bool ShowExpander => !r.MemberReferences.IsEmpty; + public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { language.WriteCommentLine(output, $"{Language.GetEntityName(module, r.Handle, fullName: true, omitGenerics: false)}");