From 0de6238d650b554d92880e51d49ef6a5a94ac120 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Sun, 1 Nov 2020 15:56:16 +0100 Subject: [PATCH] Support resolving assembly references within a bundle. --- .../RoundtripAssembly.cs | 7 +- .../ProjectDecompiler/IProjectInfoProvider.cs | 4 +- .../ProjectFileWriterDefault.cs | 2 +- .../ProjectFileWriterSdkStyle.cs | 4 +- .../WholeProjectDecompiler.cs | 9 ++- .../Metadata/AssemblyReferences.cs | 24 +++++- .../Metadata/UniversalAssemblyResolver.cs | 9 +-- ILSpy/AssemblyList.cs | 4 +- ILSpy/Languages/CSharpLanguage.cs | 2 +- ILSpy/LoadedAssembly.cs | 44 +++++++---- ILSpy/LoadedPackage.cs | 74 +++++++++++++++++-- ILSpy/Properties/AssemblyInfo.template.cs | 4 +- ILSpy/TreeNodes/AssemblyListTreeNode.cs | 29 +++++--- ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs | 23 ++---- ILSpy/TreeNodes/AssemblyTreeNode.cs | 5 +- ILSpy/TreeNodes/PackageFolderTreeNode.cs | 21 ++++-- 16 files changed, 184 insertions(+), 81 deletions(-) diff --git a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs index fade0cf68..a11fab56d 100644 --- a/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs +++ b/ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs @@ -30,7 +30,6 @@ using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Tests.Helpers; using Microsoft.Build.Locator; -using Microsoft.Win32; using NUnit.Framework; @@ -199,7 +198,7 @@ namespace ICSharpCode.Decompiler.Tests settings.UseSdkStyleProjectFormat = false; } - var decompiler = new TestProjectDecompiler(projectGuid, resolver, settings); + var decompiler = new TestProjectDecompiler(projectGuid, resolver, resolver, settings); if (snkFilePath != null) { @@ -318,8 +317,8 @@ namespace ICSharpCode.Decompiler.Tests class TestProjectDecompiler : WholeProjectDecompiler { - public TestProjectDecompiler(Guid projecGuid, IAssemblyResolver resolver, DecompilerSettings settings) - : base(settings, projecGuid, resolver, debugInfoProvider: null) + public TestProjectDecompiler(Guid projecGuid, IAssemblyResolver resolver, AssemblyReferenceClassifier assemblyReferenceClassifier, DecompilerSettings settings) + : base(settings, projecGuid, resolver, assemblyReferenceClassifier, debugInfoProvider: null) { } } diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs index 307ca5060..306afd456 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs @@ -32,6 +32,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler /// IAssemblyResolver AssemblyResolver { get; } + AssemblyReferenceClassifier AssemblyReferenceClassifier { get; } + /// /// Gets the C# language version of the project. /// @@ -52,4 +54,4 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler /// string StrongNameKeyFile { get; } } -} \ No newline at end of file +} diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs index fe131f06a..af98d6045 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs @@ -153,7 +153,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler w.WriteStartElement("Reference"); w.WriteAttributeString("Include", r.Name); var asm = project.AssemblyResolver.Resolve(r); - if (asm != null && !project.AssemblyResolver.IsGacAssembly(r)) + if (asm != null && !project.AssemblyReferenceClassifier.IsGacAssembly(r)) { w.WriteElementString("HintPath", asm.FileName); } diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs index 75d862173..f6045514c 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs @@ -256,7 +256,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler foreach (var reference in module.AssemblyReferences.Where(r => !ImplicitReferences.Contains(r.Name))) { - if (isNetCoreApp && project.AssemblyResolver.IsSharedAssembly(reference, out string runtimePack) && targetPacks.Contains(runtimePack)) + if (isNetCoreApp && project.AssemblyReferenceClassifier.IsSharedAssembly(reference, out string runtimePack) && targetPacks.Contains(runtimePack)) { continue; } @@ -265,7 +265,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler xml.WriteAttributeString("Include", reference.Name); var asembly = project.AssemblyResolver.Resolve(reference); - if (asembly != null && !project.AssemblyResolver.IsGacAssembly(reference)) + if (asembly != null && !project.AssemblyReferenceClassifier.IsGacAssembly(reference)) { xml.WriteElementString("HintPath", FileUtility.GetRelativePath(project.TargetDirectory, asembly.FileName)); } diff --git a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs index 18deba3e8..9cb28d5de 100644 --- a/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs +++ b/ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs @@ -66,6 +66,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler public IAssemblyResolver AssemblyResolver { get; } + public AssemblyReferenceClassifier AssemblyReferenceClassifier { get; } + public IDebugInfoProvider DebugInfoProvider { get; } /// @@ -94,15 +96,16 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler #endregion public WholeProjectDecompiler(IAssemblyResolver assemblyResolver) - : this(new DecompilerSettings(), assemblyResolver, debugInfoProvider: null) + : this(new DecompilerSettings(), assemblyResolver, assemblyReferenceClassifier: null, debugInfoProvider: null) { } public WholeProjectDecompiler( DecompilerSettings settings, IAssemblyResolver assemblyResolver, + AssemblyReferenceClassifier assemblyReferenceClassifier, IDebugInfoProvider debugInfoProvider) - : this(settings, Guid.NewGuid(), assemblyResolver, debugInfoProvider) + : this(settings, Guid.NewGuid(), assemblyResolver, assemblyReferenceClassifier, debugInfoProvider) { } @@ -110,11 +113,13 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler DecompilerSettings settings, Guid projectGuid, IAssemblyResolver assemblyResolver, + AssemblyReferenceClassifier assemblyReferenceClassifier, IDebugInfoProvider debugInfoProvider) { Settings = settings ?? throw new ArgumentNullException(nameof(settings)); ProjectGuid = projectGuid; AssemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver)); + AssemblyReferenceClassifier = assemblyReferenceClassifier ?? new AssemblyReferenceClassifier(); DebugInfoProvider = debugInfoProvider; projectWriter = Settings.UseSdkStyleProjectFormat ? ProjectFileWriterSdkStyle.Create() : ProjectFileWriterDefault.Create(); } diff --git a/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs b/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs index aca5bd21e..f5353731c 100644 --- a/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs +++ b/ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs @@ -48,8 +48,28 @@ namespace ICSharpCode.Decompiler.Metadata PEFile Resolve(IAssemblyReference reference); PEFile ResolveModule(PEFile mainModule, string moduleName); #endif - bool IsGacAssembly(IAssemblyReference reference); - bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack); + } + + public class AssemblyReferenceClassifier + { + /// + /// For GAC assembly references, the WholeProjectDecompiler will omit the HintPath in the + /// generated .csproj file. + /// + public virtual bool IsGacAssembly(IAssemblyReference reference) + { + return UniversalAssemblyResolver.GetAssemblyInGac(reference) != null; + } + + /// + /// For .NET Core framework references, the WholeProjectDecompiler will omit the + /// assembly reference if the runtimePack is already included as an SDK. + /// + public virtual bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack) + { + runtimePack = null; + return false; + } } public interface IAssemblyReference diff --git a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs index d8e829604..3697c671a 100644 --- a/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs +++ b/ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs @@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.Metadata } // This is inspired by Mono.Cecil's BaseAssemblyResolver/DefaultAssemblyResolver. - public class UniversalAssemblyResolver : IAssemblyResolver + public class UniversalAssemblyResolver : AssemblyReferenceClassifier, IAssemblyResolver { static UniversalAssemblyResolver() { @@ -184,12 +184,7 @@ namespace ICSharpCode.Decompiler.Metadata } #endif - public virtual bool IsGacAssembly(IAssemblyReference reference) - { - return GetAssemblyInGac(reference) != null; - } - - public virtual bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack) + public override bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack) { return dotNetCorePathFinder.TryResolveDotNetCoreShared(reference, out runtimePack) != null; } diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs index 4c10546e1..f1e9cd9e2 100644 --- a/ILSpy/AssemblyList.cs +++ b/ILSpy/AssemblyList.cs @@ -204,7 +204,7 @@ namespace ICSharpCode.ILSpy return asm; } - var newAsm = new LoadedAssembly(this, file, Task.FromResult(stream)); + var newAsm = new LoadedAssembly(this, file, stream: Task.FromResult(stream)); newAsm.IsAutoLoaded = isAutoLoaded; lock (assemblies) { @@ -227,7 +227,7 @@ namespace ICSharpCode.ILSpy return null; var index = this.assemblies.IndexOf(target); - var newAsm = new LoadedAssembly(this, file, Task.FromResult(stream)); + var newAsm = new LoadedAssembly(this, file, stream: Task.FromResult(stream)); newAsm.IsAutoLoaded = target.IsAutoLoaded; lock (assemblies) { diff --git a/ILSpy/Languages/CSharpLanguage.cs b/ILSpy/Languages/CSharpLanguage.cs index ad460679a..4d257d0d6 100644 --- a/ILSpy/Languages/CSharpLanguage.cs +++ b/ILSpy/Languages/CSharpLanguage.cs @@ -489,7 +489,7 @@ namespace ICSharpCode.ILSpy readonly DecompilationOptions options; public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, DecompilationOptions options) - : base(options.DecompilerSettings, assembly.GetAssemblyResolver(), assembly.GetDebugInfoOrNull()) + : base(options.DecompilerSettings, assembly.GetAssemblyResolver(), assembly.GetAssemblyReferenceClassifier(), assembly.GetDebugInfoOrNull()) { this.assembly = assembly; this.options = options; diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index 727d7628f..604972df5 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -41,7 +41,9 @@ namespace ICSharpCode.ILSpy /// /// Represents a file loaded into ILSpy. /// - /// Note: the file is not necessarily an assembly. + /// Note: this class is misnamed. + /// The file is not necessarily an assembly, nor is it necessarily loaded. + /// /// A LoadedAssembly can refer to: /// * a .NET module (single-file) loaded into ILSpy /// * a non-existant file @@ -79,17 +81,27 @@ namespace ICSharpCode.ILSpy readonly AssemblyList assemblyList; readonly string fileName; readonly string shortName; + readonly IAssemblyResolver providedAssemblyResolver; + + public LoadedAssembly ParentBundle { get; } - public LoadedAssembly(AssemblyList assemblyList, string fileName, Task stream = null) + public LoadedAssembly(AssemblyList assemblyList, string fileName, Task stream = null, IAssemblyResolver assemblyResolver = null) { this.assemblyList = assemblyList ?? throw new ArgumentNullException(nameof(assemblyList)); this.fileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); + this.providedAssemblyResolver = assemblyResolver; this.loadingTask = Task.Run(() => LoadAsync(stream)); // requires that this.fileName is set this.shortName = Path.GetFileNameWithoutExtension(fileName); this.resolver = new MyAssemblyResolver(this); } + public LoadedAssembly(LoadedAssembly bundle, string fileName, Task stream, IAssemblyResolver assemblyResolver = null) + : this(bundle.assemblyList, fileName, stream, assemblyResolver) + { + this.ParentBundle = bundle; + } + /// /// Returns a target framework identifier in the form '<framework>Version=v<version>'. /// Returns an empty string if no TargetFrameworkAttribute was found or the file doesn't contain an assembly header, i.e., is only a module. @@ -265,12 +277,14 @@ namespace ICSharpCode.ILSpy var bundle = LoadedPackage.FromBundle(fileName); if (bundle != null) { + bundle.LoadedAssembly = this; return new LoadResult(loadAssemblyException, bundle); } // If it's not a .NET module, maybe it's a zip archive (e.g. .nupkg) try { var zip = LoadedPackage.FromZipFile(fileName); + zip.LoadedAssembly = this; return new LoadResult(loadAssemblyException, zip); } catch (InvalidDataException) @@ -364,24 +378,19 @@ namespace ICSharpCode.ILSpy this.parent = parent; } - public bool IsGacAssembly(IAssemblyReference reference) - { - return parent.universalResolver?.IsGacAssembly(reference) == true; - } - - public bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack) - { - runtimePack = null; - return parent.universalResolver?.IsSharedAssembly(reference, out runtimePack) == true; - } - - public PEFile Resolve(Decompiler.Metadata.IAssemblyReference reference) + public PEFile Resolve(IAssemblyReference reference) { + var module = parent.providedAssemblyResolver?.Resolve(reference); + if (module != null) + return module; return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull(); } public PEFile ResolveModule(PEFile mainModule, string moduleName) { + var module = parent.providedAssemblyResolver?.ResolveModule(mainModule, moduleName); + if (module != null) + return module; return parent.LookupReferencedModule(mainModule, moduleName)?.GetPEFileOrNull(); } } @@ -393,6 +402,11 @@ namespace ICSharpCode.ILSpy return resolver; } + public AssemblyReferenceClassifier GetAssemblyReferenceClassifier() + { + return universalResolver; + } + /// /// Returns the debug info for this assembly. Returns null in case of load errors or no debug info is available. /// @@ -439,6 +453,8 @@ namespace ICSharpCode.ILSpy MyUniversalResolver universalResolver; /// + /// 0) if we're inside a package, look for filename.dll in parent directories + /// (this step already happens in MyAssemblyResolver; not in LookupReferencedAssembly) /// 1) try to find exact match by tfm + full asm name in loaded assemblies /// 2) try to find match in search paths /// 3) if a.deps.json is found: search %USERPROFILE%/.nuget/packages/* as well diff --git a/ILSpy/LoadedPackage.cs b/ILSpy/LoadedPackage.cs index 91611b5c4..d6ed2be4b 100644 --- a/ILSpy/LoadedPackage.cs +++ b/ILSpy/LoadedPackage.cs @@ -16,6 +16,7 @@ // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // DEALINGS IN THE SOFTWARE. +using System; using System.Collections.Generic; using System.Diagnostics; using System.IO; @@ -23,6 +24,7 @@ using System.IO.Compression; using System.IO.MemoryMappedFiles; using System.Linq; using System.Reflection; +using System.Threading.Tasks; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; @@ -40,6 +42,11 @@ namespace ICSharpCode.ILSpy Bundle, } + /// + /// Gets the LoadedAssembly instance representing this bundle. + /// + internal LoadedAssembly LoadedAssembly { get; set; } + public PackageKind Kind { get; } /// @@ -47,8 +54,7 @@ namespace ICSharpCode.ILSpy /// public IReadOnlyList Entries { get; } - internal IReadOnlyList TopLevelEntries { get; } - internal IReadOnlyList TopLevelFolders { get; } + internal PackageFolder RootFolder { get; } public LoadedPackage(PackageKind kind, IEnumerable entries) { @@ -56,15 +62,14 @@ namespace ICSharpCode.ILSpy this.Entries = entries.ToArray(); var topLevelEntries = new List(); var folders = new Dictionary(); - var rootFolder = new PackageFolder(""); + var rootFolder = new PackageFolder(this, null, ""); folders.Add("", rootFolder); foreach (var entry in this.Entries) { var (dirname, filename) = SplitName(entry.Name); GetFolder(dirname).Entries.Add(new FolderEntry(filename, entry)); } - this.TopLevelEntries = rootFolder.Entries; - this.TopLevelFolders = rootFolder.Folders; + this.RootFolder = rootFolder; static (string, string) SplitName(string filename) { @@ -81,7 +86,7 @@ namespace ICSharpCode.ILSpy return result; var (dirname, basename) = SplitName(name); PackageFolder parent = GetFolder(dirname); - result = new PackageFolder(basename); + result = new PackageFolder(this, parent, basename); parent.Folders.Add(result); folders.Add(name, result); return result; @@ -205,19 +210,72 @@ namespace ICSharpCode.ILSpy public abstract string FullName { get; } } - class PackageFolder + class PackageFolder : IAssemblyResolver { /// /// Gets the short name of the folder. /// public string Name { get; } - public PackageFolder(string name) + readonly LoadedPackage package; + readonly PackageFolder parent; + + internal PackageFolder(LoadedPackage package, PackageFolder parent, string name) { + this.package = package; + this.parent = parent; this.Name = name; } public List Folders { get; } = new List(); public List Entries { get; } = new List(); + + public PEFile Resolve(IAssemblyReference reference) + { + var asm = ResolveFileName(reference.Name + ".dll"); + if (asm != null) + { + return asm.GetPEFileOrNull(); + } + return parent?.Resolve(reference); + } + + public PEFile ResolveModule(PEFile mainModule, string moduleName) + { + var asm = ResolveFileName(moduleName + ".dll"); + if (asm != null) + { + return asm.GetPEFileOrNull(); + } + return parent?.ResolveModule(mainModule, moduleName); + } + + readonly Dictionary assemblies = new Dictionary(StringComparer.OrdinalIgnoreCase); + + internal LoadedAssembly ResolveFileName(string name) + { + if (package.LoadedAssembly == null) + return null; + lock (assemblies) + { + if (assemblies.TryGetValue(name, out var asm)) + return asm; + var entry = Entries.FirstOrDefault(e => string.Equals(name, e.Name, StringComparison.OrdinalIgnoreCase)); + if (entry != null) + { + asm = new LoadedAssembly( + package.LoadedAssembly, entry.Name, + assemblyResolver: this, + stream: Task.Run(entry.TryOpenStream) + ); + } + else + { + asm = null; + } + assemblies.Add(name, asm); + return asm; + } + } } } diff --git a/ILSpy/Properties/AssemblyInfo.template.cs b/ILSpy/Properties/AssemblyInfo.template.cs index e8a9aa640..36973401d 100644 --- a/ILSpy/Properties/AssemblyInfo.template.cs +++ b/ILSpy/Properties/AssemblyInfo.template.cs @@ -36,8 +36,8 @@ using System.Runtime.InteropServices; internal static class RevisionClass { - public const string Major = "6"; - public const string Minor = "3"; + public const string Major = "7"; + public const string Minor = "0"; public const string Build = "0"; public const string Revision = "$INSERTREVISION$"; public const string VersionName = "preview1"; diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs index ff819c9be..4fdc24fa0 100644 --- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs @@ -25,6 +25,7 @@ using System.Windows; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.TypeSystem; +using ICSharpCode.Decompiler.Util; using ICSharpCode.TreeView; namespace ICSharpCode.ILSpy.TreeNodes @@ -182,13 +183,7 @@ namespace ICSharpCode.ILSpy.TreeNodes { if (module == null) return null; - App.Current.Dispatcher.VerifyAccess(); - foreach (AssemblyTreeNode node in this.Children) - { - if (node.LoadedAssembly.IsLoaded && node.LoadedAssembly.GetPEFileOrNull()?.FileName == module.FileName) - return node; - } - return null; + return FindAssemblyNode(module.GetLoadedAssembly()); } public AssemblyTreeNode FindAssemblyNode(LoadedAssembly asm) @@ -196,10 +191,24 @@ namespace ICSharpCode.ILSpy.TreeNodes if (asm == null) return null; App.Current.Dispatcher.VerifyAccess(); - foreach (AssemblyTreeNode node in this.Children) + if (asm.ParentBundle != null) + { + var bundle = FindAssemblyNode(asm.ParentBundle); + if (bundle == null) + return null; + foreach (var node in TreeTraversal.PreOrder(bundle.Children, r => (r as PackageFolderTreeNode)?.Children).OfType()) + { + if (node.LoadedAssembly == asm) + return node; + } + } + else { - if (node.LoadedAssembly == asm) - return node; + foreach (AssemblyTreeNode node in this.Children) + { + if (node.LoadedAssembly == asm) + return node; + } } return null; } diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs index eecf00c1f..1bdee39a0 100644 --- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs @@ -56,29 +56,22 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void ActivateItem(System.Windows.RoutedEventArgs e) { - var assemblyListNode = parentAssembly.Parent as AssemblyListTreeNode; - if (assemblyListNode != null) + if (parentAssembly.Parent is AssemblyListTreeNode assemblyListNode) { - assemblyListNode.Select(assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedAssembly(r))); + var resolver = parentAssembly.LoadedAssembly.GetAssemblyResolver(); + assemblyListNode.Select(assemblyListNode.FindAssemblyNode(resolver.Resolve(r))); e.Handled = true; } } protected override void LoadChildren() { - var assemblyListNode = parentAssembly.Parent as AssemblyListTreeNode; - if (assemblyListNode != null) + var resolver = parentAssembly.LoadedAssembly.GetAssemblyResolver(); + var module = resolver.Resolve(r); + if (module != null) { - var refNode = assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedAssembly(r)); - if (refNode != null) - { - var module = refNode.LoadedAssembly.GetPEFileOrNull(); - if (module != null) - { - foreach (var childRef in module.AssemblyReferences) - this.Children.Add(new AssemblyReferenceTreeNode(childRef, refNode)); - } - } + foreach (var childRef in module.AssemblyReferences) + this.Children.Add(new AssemblyReferenceTreeNode(childRef, parentAssembly)); } } diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs index cb9393cfd..7b88aec7e 100644 --- a/ILSpy/TreeNodes/AssemblyTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs @@ -182,7 +182,7 @@ namespace ICSharpCode.ILSpy.TreeNodes else if (loadResult.Package != null) { var package = loadResult.Package; - this.Children.AddRange(PackageFolderTreeNode.LoadChildrenForFolder(package.TopLevelFolders, package.TopLevelEntries)); + this.Children.AddRange(PackageFolderTreeNode.LoadChildrenForFolder(package.RootFolder)); } } @@ -460,13 +460,14 @@ namespace ICSharpCode.ILSpy.TreeNodes foreach (var node in context.SelectedTreeNodes) { var la = ((AssemblyTreeNode)node).LoadedAssembly; + var resolver = la.GetAssemblyResolver(); var module = la.GetPEFileOrNull(); if (module != null) { var metadata = module.Metadata; foreach (var assyRef in metadata.AssemblyReferences) { - la.LookupReferencedAssembly(new AssemblyReference(module, assyRef)); + resolver.Resolve(new AssemblyReference(module, assyRef)); } } } diff --git a/ILSpy/TreeNodes/PackageFolderTreeNode.cs b/ILSpy/TreeNodes/PackageFolderTreeNode.cs index d2df7e78e..f9e3c94dd 100644 --- a/ILSpy/TreeNodes/PackageFolderTreeNode.cs +++ b/ILSpy/TreeNodes/PackageFolderTreeNode.cs @@ -19,7 +19,6 @@ using System; using System.Collections.Generic; using System.Linq; -using System.Threading.Tasks; using ICSharpCode.Decompiler; using ICSharpCode.TreeView; @@ -48,12 +47,12 @@ namespace ICSharpCode.ILSpy.TreeNodes protected override void LoadChildren() { - this.Children.AddRange(LoadChildrenForFolder(folder.Folders, folder.Entries)); + this.Children.AddRange(LoadChildrenForFolder(folder)); } - internal static IEnumerable LoadChildrenForFolder(IReadOnlyList folders, IReadOnlyList entries) + internal static IEnumerable LoadChildrenForFolder(PackageFolder root) { - foreach (var folder in folders.OrderBy(f => f.Name)) + foreach (var folder in root.Folders.OrderBy(f => f.Name)) { string newName = folder.Name; var subfolder = folder; @@ -65,13 +64,19 @@ namespace ICSharpCode.ILSpy.TreeNodes } yield return new PackageFolderTreeNode(subfolder, newName); } - foreach (var entry in entries.OrderBy(e => e.Name)) + foreach (var entry in root.Entries.OrderBy(e => e.Name)) { if (entry.Name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase)) { - var asmList = MainWindow.Instance.CurrentAssemblyList; - var asm = new LoadedAssembly(asmList, entry.Name, Task.Run(entry.TryOpenStream)); - yield return new AssemblyTreeNode(asm); + var asm = root.ResolveFileName(entry.Name); + if (asm != null) + { + yield return new AssemblyTreeNode(asm); + } + else + { + yield return ResourceTreeNode.Create(entry); + } } else {