Browse Source

Support resolving assembly references within a bundle.

pull/2191/head
Daniel Grunwald 5 years ago
parent
commit
0de6238d65
  1. 7
      ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs
  2. 4
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs
  3. 2
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs
  4. 4
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterSdkStyle.cs
  5. 9
      ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs
  6. 24
      ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs
  7. 9
      ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs
  8. 4
      ILSpy/AssemblyList.cs
  9. 2
      ILSpy/Languages/CSharpLanguage.cs
  10. 44
      ILSpy/LoadedAssembly.cs
  11. 74
      ILSpy/LoadedPackage.cs
  12. 4
      ILSpy/Properties/AssemblyInfo.template.cs
  13. 29
      ILSpy/TreeNodes/AssemblyListTreeNode.cs
  14. 23
      ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
  15. 5
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  16. 21
      ILSpy/TreeNodes/PackageFolderTreeNode.cs

7
ICSharpCode.Decompiler.Tests/RoundtripAssembly.cs

@ -30,7 +30,6 @@ using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.Tests.Helpers; using ICSharpCode.Decompiler.Tests.Helpers;
using Microsoft.Build.Locator; using Microsoft.Build.Locator;
using Microsoft.Win32;
using NUnit.Framework; using NUnit.Framework;
@ -199,7 +198,7 @@ namespace ICSharpCode.Decompiler.Tests
settings.UseSdkStyleProjectFormat = false; settings.UseSdkStyleProjectFormat = false;
} }
var decompiler = new TestProjectDecompiler(projectGuid, resolver, settings); var decompiler = new TestProjectDecompiler(projectGuid, resolver, resolver, settings);
if (snkFilePath != null) if (snkFilePath != null)
{ {
@ -318,8 +317,8 @@ namespace ICSharpCode.Decompiler.Tests
class TestProjectDecompiler : WholeProjectDecompiler class TestProjectDecompiler : WholeProjectDecompiler
{ {
public TestProjectDecompiler(Guid projecGuid, IAssemblyResolver resolver, DecompilerSettings settings) public TestProjectDecompiler(Guid projecGuid, IAssemblyResolver resolver, AssemblyReferenceClassifier assemblyReferenceClassifier, DecompilerSettings settings)
: base(settings, projecGuid, resolver, debugInfoProvider: null) : base(settings, projecGuid, resolver, assemblyReferenceClassifier, debugInfoProvider: null)
{ {
} }
} }

4
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/IProjectInfoProvider.cs

@ -32,6 +32,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
/// </summary> /// </summary>
IAssemblyResolver AssemblyResolver { get; } IAssemblyResolver AssemblyResolver { get; }
AssemblyReferenceClassifier AssemblyReferenceClassifier { get; }
/// <summary> /// <summary>
/// Gets the C# language version of the project. /// Gets the C# language version of the project.
/// </summary> /// </summary>
@ -52,4 +54,4 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
/// </summary> /// </summary>
string StrongNameKeyFile { get; } string StrongNameKeyFile { get; }
} }
} }

2
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/ProjectFileWriterDefault.cs

@ -153,7 +153,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
w.WriteStartElement("Reference"); w.WriteStartElement("Reference");
w.WriteAttributeString("Include", r.Name); w.WriteAttributeString("Include", r.Name);
var asm = project.AssemblyResolver.Resolve(r); 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); w.WriteElementString("HintPath", asm.FileName);
} }

4
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))) 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; continue;
} }
@ -265,7 +265,7 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
xml.WriteAttributeString("Include", reference.Name); xml.WriteAttributeString("Include", reference.Name);
var asembly = project.AssemblyResolver.Resolve(reference); 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)); xml.WriteElementString("HintPath", FileUtility.GetRelativePath(project.TargetDirectory, asembly.FileName));
} }

9
ICSharpCode.Decompiler/CSharp/ProjectDecompiler/WholeProjectDecompiler.cs

@ -66,6 +66,8 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
public IAssemblyResolver AssemblyResolver { get; } public IAssemblyResolver AssemblyResolver { get; }
public AssemblyReferenceClassifier AssemblyReferenceClassifier { get; }
public IDebugInfoProvider DebugInfoProvider { get; } public IDebugInfoProvider DebugInfoProvider { get; }
/// <summary> /// <summary>
@ -94,15 +96,16 @@ namespace ICSharpCode.Decompiler.CSharp.ProjectDecompiler
#endregion #endregion
public WholeProjectDecompiler(IAssemblyResolver assemblyResolver) public WholeProjectDecompiler(IAssemblyResolver assemblyResolver)
: this(new DecompilerSettings(), assemblyResolver, debugInfoProvider: null) : this(new DecompilerSettings(), assemblyResolver, assemblyReferenceClassifier: null, debugInfoProvider: null)
{ {
} }
public WholeProjectDecompiler( public WholeProjectDecompiler(
DecompilerSettings settings, DecompilerSettings settings,
IAssemblyResolver assemblyResolver, IAssemblyResolver assemblyResolver,
AssemblyReferenceClassifier assemblyReferenceClassifier,
IDebugInfoProvider debugInfoProvider) 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, DecompilerSettings settings,
Guid projectGuid, Guid projectGuid,
IAssemblyResolver assemblyResolver, IAssemblyResolver assemblyResolver,
AssemblyReferenceClassifier assemblyReferenceClassifier,
IDebugInfoProvider debugInfoProvider) IDebugInfoProvider debugInfoProvider)
{ {
Settings = settings ?? throw new ArgumentNullException(nameof(settings)); Settings = settings ?? throw new ArgumentNullException(nameof(settings));
ProjectGuid = projectGuid; ProjectGuid = projectGuid;
AssemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver)); AssemblyResolver = assemblyResolver ?? throw new ArgumentNullException(nameof(assemblyResolver));
AssemblyReferenceClassifier = assemblyReferenceClassifier ?? new AssemblyReferenceClassifier();
DebugInfoProvider = debugInfoProvider; DebugInfoProvider = debugInfoProvider;
projectWriter = Settings.UseSdkStyleProjectFormat ? ProjectFileWriterSdkStyle.Create() : ProjectFileWriterDefault.Create(); projectWriter = Settings.UseSdkStyleProjectFormat ? ProjectFileWriterSdkStyle.Create() : ProjectFileWriterDefault.Create();
} }

24
ICSharpCode.Decompiler/Metadata/AssemblyReferences.cs

@ -48,8 +48,28 @@ namespace ICSharpCode.Decompiler.Metadata
PEFile Resolve(IAssemblyReference reference); PEFile Resolve(IAssemblyReference reference);
PEFile ResolveModule(PEFile mainModule, string moduleName); PEFile ResolveModule(PEFile mainModule, string moduleName);
#endif #endif
bool IsGacAssembly(IAssemblyReference reference); }
bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack);
public class AssemblyReferenceClassifier
{
/// <summary>
/// For GAC assembly references, the WholeProjectDecompiler will omit the HintPath in the
/// generated .csproj file.
/// </summary>
public virtual bool IsGacAssembly(IAssemblyReference reference)
{
return UniversalAssemblyResolver.GetAssemblyInGac(reference) != null;
}
/// <summary>
/// For .NET Core framework references, the WholeProjectDecompiler will omit the
/// assembly reference if the runtimePack is already included as an SDK.
/// </summary>
public virtual bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack)
{
runtimePack = null;
return false;
}
} }
public interface IAssemblyReference public interface IAssemblyReference

9
ICSharpCode.Decompiler/Metadata/UniversalAssemblyResolver.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler.Metadata
} }
// This is inspired by Mono.Cecil's BaseAssemblyResolver/DefaultAssemblyResolver. // This is inspired by Mono.Cecil's BaseAssemblyResolver/DefaultAssemblyResolver.
public class UniversalAssemblyResolver : IAssemblyResolver public class UniversalAssemblyResolver : AssemblyReferenceClassifier, IAssemblyResolver
{ {
static UniversalAssemblyResolver() static UniversalAssemblyResolver()
{ {
@ -184,12 +184,7 @@ namespace ICSharpCode.Decompiler.Metadata
} }
#endif #endif
public virtual bool IsGacAssembly(IAssemblyReference reference) public override bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack)
{
return GetAssemblyInGac(reference) != null;
}
public virtual bool IsSharedAssembly(IAssemblyReference reference, out string runtimePack)
{ {
return dotNetCorePathFinder.TryResolveDotNetCoreShared(reference, out runtimePack) != null; return dotNetCorePathFinder.TryResolveDotNetCoreShared(reference, out runtimePack) != null;
} }

4
ILSpy/AssemblyList.cs

@ -204,7 +204,7 @@ namespace ICSharpCode.ILSpy
return asm; return asm;
} }
var newAsm = new LoadedAssembly(this, file, Task.FromResult(stream)); var newAsm = new LoadedAssembly(this, file, stream: Task.FromResult(stream));
newAsm.IsAutoLoaded = isAutoLoaded; newAsm.IsAutoLoaded = isAutoLoaded;
lock (assemblies) lock (assemblies)
{ {
@ -227,7 +227,7 @@ namespace ICSharpCode.ILSpy
return null; return null;
var index = this.assemblies.IndexOf(target); 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; newAsm.IsAutoLoaded = target.IsAutoLoaded;
lock (assemblies) lock (assemblies)
{ {

2
ILSpy/Languages/CSharpLanguage.cs

@ -489,7 +489,7 @@ namespace ICSharpCode.ILSpy
readonly DecompilationOptions options; readonly DecompilationOptions options;
public ILSpyWholeProjectDecompiler(LoadedAssembly assembly, 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.assembly = assembly;
this.options = options; this.options = options;

44
ILSpy/LoadedAssembly.cs

@ -41,7 +41,9 @@ namespace ICSharpCode.ILSpy
/// <summary> /// <summary>
/// Represents a file loaded into 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 LoadedAssembly can refer to:
/// * a .NET module (single-file) loaded into ILSpy /// * a .NET module (single-file) loaded into ILSpy
/// * a non-existant file /// * a non-existant file
@ -79,17 +81,27 @@ namespace ICSharpCode.ILSpy
readonly AssemblyList assemblyList; readonly AssemblyList assemblyList;
readonly string fileName; readonly string fileName;
readonly string shortName; readonly string shortName;
readonly IAssemblyResolver providedAssemblyResolver;
public LoadedAssembly ParentBundle { get; }
public LoadedAssembly(AssemblyList assemblyList, string fileName, Task<Stream> stream = null) public LoadedAssembly(AssemblyList assemblyList, string fileName, Task<Stream> stream = null, IAssemblyResolver assemblyResolver = null)
{ {
this.assemblyList = assemblyList ?? throw new ArgumentNullException(nameof(assemblyList)); this.assemblyList = assemblyList ?? throw new ArgumentNullException(nameof(assemblyList));
this.fileName = fileName ?? throw new ArgumentNullException(nameof(fileName)); this.fileName = fileName ?? throw new ArgumentNullException(nameof(fileName));
this.providedAssemblyResolver = assemblyResolver;
this.loadingTask = Task.Run(() => LoadAsync(stream)); // requires that this.fileName is set this.loadingTask = Task.Run(() => LoadAsync(stream)); // requires that this.fileName is set
this.shortName = Path.GetFileNameWithoutExtension(fileName); this.shortName = Path.GetFileNameWithoutExtension(fileName);
this.resolver = new MyAssemblyResolver(this); this.resolver = new MyAssemblyResolver(this);
} }
public LoadedAssembly(LoadedAssembly bundle, string fileName, Task<Stream> stream, IAssemblyResolver assemblyResolver = null)
: this(bundle.assemblyList, fileName, stream, assemblyResolver)
{
this.ParentBundle = bundle;
}
/// <summary> /// <summary>
/// Returns a target framework identifier in the form '&lt;framework&gt;Version=v&lt;version&gt;'. /// Returns a target framework identifier in the form '&lt;framework&gt;Version=v&lt;version&gt;'.
/// Returns an empty string if no TargetFrameworkAttribute was found or the file doesn't contain an assembly header, i.e., is only a module. /// 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); var bundle = LoadedPackage.FromBundle(fileName);
if (bundle != null) if (bundle != null)
{ {
bundle.LoadedAssembly = this;
return new LoadResult(loadAssemblyException, bundle); return new LoadResult(loadAssemblyException, bundle);
} }
// If it's not a .NET module, maybe it's a zip archive (e.g. .nupkg) // If it's not a .NET module, maybe it's a zip archive (e.g. .nupkg)
try try
{ {
var zip = LoadedPackage.FromZipFile(fileName); var zip = LoadedPackage.FromZipFile(fileName);
zip.LoadedAssembly = this;
return new LoadResult(loadAssemblyException, zip); return new LoadResult(loadAssemblyException, zip);
} }
catch (InvalidDataException) catch (InvalidDataException)
@ -364,24 +378,19 @@ namespace ICSharpCode.ILSpy
this.parent = parent; this.parent = parent;
} }
public bool IsGacAssembly(IAssemblyReference reference) public PEFile Resolve(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)
{ {
var module = parent.providedAssemblyResolver?.Resolve(reference);
if (module != null)
return module;
return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull(); return parent.LookupReferencedAssembly(reference)?.GetPEFileOrNull();
} }
public PEFile ResolveModule(PEFile mainModule, string moduleName) 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(); return parent.LookupReferencedModule(mainModule, moduleName)?.GetPEFileOrNull();
} }
} }
@ -393,6 +402,11 @@ namespace ICSharpCode.ILSpy
return resolver; return resolver;
} }
public AssemblyReferenceClassifier GetAssemblyReferenceClassifier()
{
return universalResolver;
}
/// <summary> /// <summary>
/// Returns the debug info for this assembly. Returns null in case of load errors or no debug info is available. /// Returns the debug info for this assembly. Returns null in case of load errors or no debug info is available.
/// </summary> /// </summary>
@ -439,6 +453,8 @@ namespace ICSharpCode.ILSpy
MyUniversalResolver universalResolver; MyUniversalResolver universalResolver;
/// <summary> /// <summary>
/// 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 /// 1) try to find exact match by tfm + full asm name in loaded assemblies
/// 2) try to find match in search paths /// 2) try to find match in search paths
/// 3) if a.deps.json is found: search %USERPROFILE%/.nuget/packages/* as well /// 3) if a.deps.json is found: search %USERPROFILE%/.nuget/packages/* as well

74
ILSpy/LoadedPackage.cs

@ -16,6 +16,7 @@
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER // OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
using System.IO; using System.IO;
@ -23,6 +24,7 @@ using System.IO.Compression;
using System.IO.MemoryMappedFiles; using System.IO.MemoryMappedFiles;
using System.Linq; using System.Linq;
using System.Reflection; using System.Reflection;
using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
@ -40,6 +42,11 @@ namespace ICSharpCode.ILSpy
Bundle, Bundle,
} }
/// <summary>
/// Gets the LoadedAssembly instance representing this bundle.
/// </summary>
internal LoadedAssembly LoadedAssembly { get; set; }
public PackageKind Kind { get; } public PackageKind Kind { get; }
/// <summary> /// <summary>
@ -47,8 +54,7 @@ namespace ICSharpCode.ILSpy
/// </summary> /// </summary>
public IReadOnlyList<PackageEntry> Entries { get; } public IReadOnlyList<PackageEntry> Entries { get; }
internal IReadOnlyList<PackageEntry> TopLevelEntries { get; } internal PackageFolder RootFolder { get; }
internal IReadOnlyList<PackageFolder> TopLevelFolders { get; }
public LoadedPackage(PackageKind kind, IEnumerable<PackageEntry> entries) public LoadedPackage(PackageKind kind, IEnumerable<PackageEntry> entries)
{ {
@ -56,15 +62,14 @@ namespace ICSharpCode.ILSpy
this.Entries = entries.ToArray(); this.Entries = entries.ToArray();
var topLevelEntries = new List<PackageEntry>(); var topLevelEntries = new List<PackageEntry>();
var folders = new Dictionary<string, PackageFolder>(); var folders = new Dictionary<string, PackageFolder>();
var rootFolder = new PackageFolder(""); var rootFolder = new PackageFolder(this, null, "");
folders.Add("", rootFolder); folders.Add("", rootFolder);
foreach (var entry in this.Entries) foreach (var entry in this.Entries)
{ {
var (dirname, filename) = SplitName(entry.Name); var (dirname, filename) = SplitName(entry.Name);
GetFolder(dirname).Entries.Add(new FolderEntry(filename, entry)); GetFolder(dirname).Entries.Add(new FolderEntry(filename, entry));
} }
this.TopLevelEntries = rootFolder.Entries; this.RootFolder = rootFolder;
this.TopLevelFolders = rootFolder.Folders;
static (string, string) SplitName(string filename) static (string, string) SplitName(string filename)
{ {
@ -81,7 +86,7 @@ namespace ICSharpCode.ILSpy
return result; return result;
var (dirname, basename) = SplitName(name); var (dirname, basename) = SplitName(name);
PackageFolder parent = GetFolder(dirname); PackageFolder parent = GetFolder(dirname);
result = new PackageFolder(basename); result = new PackageFolder(this, parent, basename);
parent.Folders.Add(result); parent.Folders.Add(result);
folders.Add(name, result); folders.Add(name, result);
return result; return result;
@ -205,19 +210,72 @@ namespace ICSharpCode.ILSpy
public abstract string FullName { get; } public abstract string FullName { get; }
} }
class PackageFolder class PackageFolder : IAssemblyResolver
{ {
/// <summary> /// <summary>
/// Gets the short name of the folder. /// Gets the short name of the folder.
/// </summary> /// </summary>
public string Name { get; } 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; this.Name = name;
} }
public List<PackageFolder> Folders { get; } = new List<PackageFolder>(); public List<PackageFolder> Folders { get; } = new List<PackageFolder>();
public List<PackageEntry> Entries { get; } = new List<PackageEntry>(); public List<PackageEntry> Entries { get; } = new List<PackageEntry>();
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<string, LoadedAssembly> assemblies = new Dictionary<string, LoadedAssembly>(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;
}
}
} }
} }

4
ILSpy/Properties/AssemblyInfo.template.cs

@ -36,8 +36,8 @@ using System.Runtime.InteropServices;
internal static class RevisionClass internal static class RevisionClass
{ {
public const string Major = "6"; public const string Major = "7";
public const string Minor = "3"; public const string Minor = "0";
public const string Build = "0"; public const string Build = "0";
public const string Revision = "$INSERTREVISION$"; public const string Revision = "$INSERTREVISION$";
public const string VersionName = "preview1"; public const string VersionName = "preview1";

29
ILSpy/TreeNodes/AssemblyListTreeNode.cs

@ -25,6 +25,7 @@ using System.Windows;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Metadata; using ICSharpCode.Decompiler.Metadata;
using ICSharpCode.Decompiler.TypeSystem; using ICSharpCode.Decompiler.TypeSystem;
using ICSharpCode.Decompiler.Util;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.TreeNodes namespace ICSharpCode.ILSpy.TreeNodes
@ -182,13 +183,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
if (module == null) if (module == null)
return null; return null;
App.Current.Dispatcher.VerifyAccess(); return FindAssemblyNode(module.GetLoadedAssembly());
foreach (AssemblyTreeNode node in this.Children)
{
if (node.LoadedAssembly.IsLoaded && node.LoadedAssembly.GetPEFileOrNull()?.FileName == module.FileName)
return node;
}
return null;
} }
public AssemblyTreeNode FindAssemblyNode(LoadedAssembly asm) public AssemblyTreeNode FindAssemblyNode(LoadedAssembly asm)
@ -196,10 +191,24 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (asm == null) if (asm == null)
return null; return null;
App.Current.Dispatcher.VerifyAccess(); 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<AssemblyTreeNode>())
{
if (node.LoadedAssembly == asm)
return node;
}
}
else
{ {
if (node.LoadedAssembly == asm) foreach (AssemblyTreeNode node in this.Children)
return node; {
if (node.LoadedAssembly == asm)
return node;
}
} }
return null; return null;
} }

23
ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs

@ -56,29 +56,22 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void ActivateItem(System.Windows.RoutedEventArgs e) public override void ActivateItem(System.Windows.RoutedEventArgs e)
{ {
var assemblyListNode = parentAssembly.Parent as AssemblyListTreeNode; if (parentAssembly.Parent is AssemblyListTreeNode assemblyListNode)
if (assemblyListNode != null)
{ {
assemblyListNode.Select(assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedAssembly(r))); var resolver = parentAssembly.LoadedAssembly.GetAssemblyResolver();
assemblyListNode.Select(assemblyListNode.FindAssemblyNode(resolver.Resolve(r)));
e.Handled = true; e.Handled = true;
} }
} }
protected override void LoadChildren() protected override void LoadChildren()
{ {
var assemblyListNode = parentAssembly.Parent as AssemblyListTreeNode; var resolver = parentAssembly.LoadedAssembly.GetAssemblyResolver();
if (assemblyListNode != null) var module = resolver.Resolve(r);
if (module != null)
{ {
var refNode = assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedAssembly(r)); foreach (var childRef in module.AssemblyReferences)
if (refNode != null) this.Children.Add(new AssemblyReferenceTreeNode(childRef, parentAssembly));
{
var module = refNode.LoadedAssembly.GetPEFileOrNull();
if (module != null)
{
foreach (var childRef in module.AssemblyReferences)
this.Children.Add(new AssemblyReferenceTreeNode(childRef, refNode));
}
}
} }
} }

5
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -182,7 +182,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
else if (loadResult.Package != null) else if (loadResult.Package != null)
{ {
var package = loadResult.Package; 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) foreach (var node in context.SelectedTreeNodes)
{ {
var la = ((AssemblyTreeNode)node).LoadedAssembly; var la = ((AssemblyTreeNode)node).LoadedAssembly;
var resolver = la.GetAssemblyResolver();
var module = la.GetPEFileOrNull(); var module = la.GetPEFileOrNull();
if (module != null) if (module != null)
{ {
var metadata = module.Metadata; var metadata = module.Metadata;
foreach (var assyRef in metadata.AssemblyReferences) foreach (var assyRef in metadata.AssemblyReferences)
{ {
la.LookupReferencedAssembly(new AssemblyReference(module, assyRef)); resolver.Resolve(new AssemblyReference(module, assyRef));
} }
} }
} }

21
ILSpy/TreeNodes/PackageFolderTreeNode.cs

@ -19,7 +19,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
@ -48,12 +47,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
protected override void LoadChildren() protected override void LoadChildren()
{ {
this.Children.AddRange(LoadChildrenForFolder(folder.Folders, folder.Entries)); this.Children.AddRange(LoadChildrenForFolder(folder));
} }
internal static IEnumerable<SharpTreeNode> LoadChildrenForFolder(IReadOnlyList<PackageFolder> folders, IReadOnlyList<PackageEntry> entries) internal static IEnumerable<SharpTreeNode> 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; string newName = folder.Name;
var subfolder = folder; var subfolder = folder;
@ -65,13 +64,19 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
yield return new PackageFolderTreeNode(subfolder, newName); 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)) if (entry.Name.EndsWith(".dll", StringComparison.OrdinalIgnoreCase))
{ {
var asmList = MainWindow.Instance.CurrentAssemblyList; var asm = root.ResolveFileName(entry.Name);
var asm = new LoadedAssembly(asmList, entry.Name, Task.Run(entry.TryOpenStream)); if (asm != null)
yield return new AssemblyTreeNode(asm); {
yield return new AssemblyTreeNode(asm);
}
else
{
yield return ResourceTreeNode.Create(entry);
}
} }
else else
{ {

Loading…
Cancel
Save