diff --git a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs index 5a5abb8ac..04aed0d43 100644 --- a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs +++ b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs @@ -40,16 +40,19 @@ namespace ICSharpCode.Decompiler readonly string targetFrameworkId; readonly string version; readonly string dotnetBasePath = FindDotNetExeDirectory(); + readonly Dictionary loadInfo; - public DotNetCorePathFinder(string parentAssemblyFileName, string targetFrameworkId, string version) + public DotNetCorePathFinder(string parentAssemblyFileName, string targetFrameworkId, string version, Dictionary loadInfo) { this.assemblyName = Path.GetFileNameWithoutExtension(parentAssemblyFileName); this.basePath = Path.GetDirectoryName(parentAssemblyFileName); this.targetFrameworkId = targetFrameworkId; this.version = version; + this.loadInfo = loadInfo; var depsJsonFileName = Path.Combine(basePath, $"{assemblyName}.deps.json"); if (!File.Exists(depsJsonFileName)) { + loadInfo.AddMessage(assemblyName, MessageKind.Error, $"{assemblyName}.deps.json could not be found!"); return; } diff --git a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs index e054348d3..ced78ebf2 100644 --- a/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs +++ b/ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs @@ -29,5 +29,16 @@ namespace ICSharpCode.Decompiler return string.Empty; } + + public static void AddMessage(this Dictionary container, string fullName, MessageKind kind, string message) + { + if (container == null) + throw new ArgumentNullException(nameof(container)); + if (!container.TryGetValue(fullName, out var referenceInfo)) { + referenceInfo = new UnresolvedAssemblyNameReference(fullName); + container.Add(fullName, referenceInfo); + } + referenceInfo.Messages.Add((kind, message)); + } } } diff --git a/ICSharpCode.Decompiler/DotNetCore/UnresolvedAssemblyNameReference.cs b/ICSharpCode.Decompiler/DotNetCore/UnresolvedAssemblyNameReference.cs new file mode 100644 index 000000000..986e82785 --- /dev/null +++ b/ICSharpCode.Decompiler/DotNetCore/UnresolvedAssemblyNameReference.cs @@ -0,0 +1,24 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +using System.Threading.Tasks; + +namespace ICSharpCode.Decompiler +{ + public sealed class UnresolvedAssemblyNameReference + { + public string FullName { get; } + + public bool HasErrors => Messages.Any(m => m.Item1 == MessageKind.Error); + + public List<(MessageKind, string)> Messages { get; } = new List<(MessageKind, string)>(); + + public UnresolvedAssemblyNameReference(string fullName) + { + this.FullName = fullName; + } + } + + public enum MessageKind { Error, Warning, Info } +} diff --git a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj index 387a1a1a3..fdc122927 100644 --- a/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj +++ b/ICSharpCode.Decompiler/ICSharpCode.Decompiler.csproj @@ -260,6 +260,7 @@ + @@ -274,6 +275,7 @@ + diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs index c6c0182f1..e99e3159a 100644 --- a/ILSpy/LoadedAssembly.cs +++ b/ILSpy/LoadedAssembly.cs @@ -17,7 +17,9 @@ // DEALINGS IN THE SOFTWARE. using System; +using System.Collections.Generic; using System.IO; +using System.Linq; using System.Threading.Tasks; using System.Windows.Threading; using ICSharpCode.Decompiler; @@ -36,6 +38,7 @@ namespace ICSharpCode.ILSpy readonly string fileName; readonly string shortName; readonly Lazy targetFrameworkId; + readonly Dictionary loadedAssemblyReferences = new Dictionary(); public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null) { @@ -51,8 +54,13 @@ namespace ICSharpCode.ILSpy this.targetFrameworkId = new Lazy(AssemblyDefinition.DetectTargetFrameworkId, false); } + /// + /// Returns a target framework identifier in the form '<framework>Version=v<version>'. + /// public string TargetFrameworkId => targetFrameworkId.Value; + public Dictionary LoadedAssemblyReferencesInfo => loadedAssemblyReferences; + /// /// Gets the Cecil ModuleDefinition. /// Can be null when there was a load error. @@ -77,18 +85,12 @@ namespace ICSharpCode.ILSpy return module != null ? module.Assembly : null; } } - - public AssemblyList AssemblyList { - get { return assemblyList; } - } - - public string FileName { - get { return fileName; } - } - - public string ShortName { - get { return shortName; } - } + + public AssemblyList AssemblyList => assemblyList; + + public string FileName => fileName; + + public string ShortName => shortName; public string Text { get { @@ -99,14 +101,10 @@ namespace ICSharpCode.ILSpy } } } - - public bool IsLoaded { - get { return assemblyTask.IsCompleted; } - } - - public bool HasLoadError { - get { return assemblyTask.IsFaulted; } - } + + public bool IsLoaded => assemblyTask.IsCompleted; + + public bool HasLoadError => assemblyTask.IsFaulted; public bool IsAutoLoaded { get; set; } @@ -266,7 +264,7 @@ namespace ICSharpCode.ILSpy if (targetFramework.Length != 2) break; if (dotNetCorePathFinder == null) { var version = targetFramework[1].Length == 3 ? targetFramework[1] + ".0" : targetFramework[1]; - dotNetCorePathFinder = new DotNetCorePathFinder(fileName, TargetFrameworkId, version); + dotNetCorePathFinder = new DotNetCorePathFinder(fileName, TargetFrameworkId, version, this.loadedAssemblyReferences); } file = dotNetCorePathFinder.TryResolveDotNetCore(name); break; @@ -282,8 +280,10 @@ namespace ICSharpCode.ILSpy file = Path.Combine(dir, name.Name + ".exe"); } if (file != null) { + loadedAssemblyReferences.AddMessage(fullName, MessageKind.Info, "Success - Loading from: " + file); return assemblyList.OpenAssembly(file, true); } else { + loadedAssemblyReferences.AddMessage(fullName, MessageKind.Error, "Could not find reference: " + fullName); return null; } } diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs index 1893e32d7..91b136bd9 100644 --- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs +++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs @@ -88,10 +88,22 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { + var loaded = parentAssembly.LoadedAssembly.LoadedAssemblyReferencesInfo.TryGetValue(r.FullName, out var info); if (r.IsWindowsRuntime) { - language.WriteCommentLine(output, r.Name + " [WinRT]"); + language.WriteCommentLine(output, r.Name + " [WinRT]" + (!loaded ? " (unresolved)" : "")); } else { - language.WriteCommentLine(output, r.FullName); + language.WriteCommentLine(output, r.FullName + (!loaded ? " (unresolved)" : "")); + } + if (loaded) { + output.Indent(); + language.WriteCommentLine(output, "Assembly reference loading information:"); + if (info.HasErrors) + language.WriteCommentLine(output, "There were some problems during assembly reference load, see below for more information!"); + foreach (var item in info.Messages) { + language.WriteCommentLine(output, $"{item.Item1}: {item.Item2}"); + } + output.Unindent(); + output.WriteLine(); } } } diff --git a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs index 3af19248d..674e87022 100644 --- a/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs +++ b/ILSpy/TreeNodes/ReferenceFolderTreeNode.cs @@ -61,7 +61,10 @@ namespace ICSharpCode.ILSpy.TreeNodes public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) { + language.WriteCommentLine(output, $"Detected Target-Framework-Id: {parentAssembly.LoadedAssembly.TargetFrameworkId}"); App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren)); + output.WriteLine(); + language.WriteCommentLine(output, "Referenced assemblies (in metadata order):"); // Show metadata order of references foreach (var r in module.AssemblyReferences) new AssemblyReferenceTreeNode(r, parentAssembly).Decompile(language, output, options);