Browse Source

Refactoring of LookupReferencedAssemblyInternal

pull/1012/head
Siegfried Pammer 8 years ago
parent
commit
0e0291a113
  1. 2
      ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs
  2. 35
      ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs
  3. 5
      ILSpy/AssemblyList.cs
  4. 2
      ILSpy/Languages/CSharpLanguage.cs
  5. 103
      ILSpy/LoadedAssembly.cs
  6. 2
      ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
  7. 2
      ILSpy/TreeNodes/AssemblyTreeNode.cs

2
ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinder.cs

@ -43,7 +43,7 @@ namespace ICSharpCode.Decompiler
readonly string version; readonly string version;
readonly string dotnetBasePath = FindDotNetExeDirectory(); readonly string dotnetBasePath = FindDotNetExeDirectory();
public DotNetCorePathFinder(string parentAssemblyFileName, string targetFrameworkId, string version, Dictionary<string, UnresolvedAssemblyNameReference> loadInfo = null) public DotNetCorePathFinder(string parentAssemblyFileName, string targetFrameworkId, string version, ReferenceLoadInfo loadInfo = null)
{ {
this.assemblyName = Path.GetFileNameWithoutExtension(parentAssemblyFileName); this.assemblyName = Path.GetFileNameWithoutExtension(parentAssemblyFileName);
this.basePath = Path.GetDirectoryName(parentAssemblyFileName); this.basePath = Path.GetDirectoryName(parentAssemblyFileName);

35
ICSharpCode.Decompiler/DotNetCore/DotNetCorePathFinderExtensions.cs

@ -1,5 +1,6 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using ICSharpCode.Decompiler.TypeSystem.Implementation; using ICSharpCode.Decompiler.TypeSystem.Implementation;
using Mono.Cecil; using Mono.Cecil;
@ -25,16 +26,36 @@ namespace ICSharpCode.Decompiler
return string.Empty; return string.Empty;
} }
}
public class ReferenceLoadInfo
{
readonly Dictionary<string, UnresolvedAssemblyNameReference> loadedAssemblyReferences = new Dictionary<string, UnresolvedAssemblyNameReference>();
public void AddMessage(string fullName, MessageKind kind, string message)
{
lock (loadedAssemblyReferences) {
if (!loadedAssemblyReferences.TryGetValue(fullName, out var referenceInfo)) {
referenceInfo = new UnresolvedAssemblyNameReference(fullName);
loadedAssemblyReferences.Add(fullName, referenceInfo);
}
referenceInfo.Messages.Add((kind, message));
}
}
public static void AddMessage(this Dictionary<string, UnresolvedAssemblyNameReference> container, string fullName, MessageKind kind, string message) public bool TryGetInfo(string fullName, out UnresolvedAssemblyNameReference info)
{ {
if (container == null) lock (loadedAssemblyReferences) {
throw new ArgumentNullException(nameof(container)); return loadedAssemblyReferences.TryGetValue(fullName, out info);
if (!container.TryGetValue(fullName, out var referenceInfo)) { }
referenceInfo = new UnresolvedAssemblyNameReference(fullName); }
container.Add(fullName, referenceInfo);
public bool HasErrors {
get {
lock (loadedAssemblyReferences) {
return loadedAssemblyReferences.Any(i => i.Value.HasErrors);
}
} }
referenceInfo.Messages.Add((kind, message));
} }
} }
} }

5
ILSpy/AssemblyList.cs

@ -23,6 +23,7 @@ using System.Collections.ObjectModel;
using System.Collections.Specialized; using System.Collections.Specialized;
using System.IO; using System.IO;
using System.Linq; using System.Linq;
using System.Threading.Tasks;
using System.Windows.Threading; using System.Windows.Threading;
using System.Xml.Linq; using System.Xml.Linq;
@ -38,8 +39,7 @@ namespace ICSharpCode.ILSpy
/// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary> /// <summary>Dirty flag, used to mark modifications so that the list is saved later</summary>
bool dirty; bool dirty;
internal readonly ConcurrentDictionary<string, LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<string, LoadedAssembly>(); internal readonly ConcurrentDictionary<(string assemblyName, bool isWinRT), LoadedAssembly> assemblyLookupCache = new ConcurrentDictionary<(string assemblyName, bool isWinRT), LoadedAssembly>();
internal readonly ConcurrentDictionary<string, LoadedAssembly> winRTMetadataLookupCache = new ConcurrentDictionary<string, LoadedAssembly>();
/// <summary> /// <summary>
/// The assemblies in this list. /// The assemblies in this list.
@ -136,7 +136,6 @@ namespace ICSharpCode.ILSpy
internal void ClearCache() internal void ClearCache()
{ {
assemblyLookupCache.Clear(); assemblyLookupCache.Clear();
winRTMetadataLookupCache.Clear();
} }
public LoadedAssembly Open(string assemblyUri, bool isAutoLoaded = false) public LoadedAssembly Open(string assemblyUri, bool isAutoLoaded = false)

2
ILSpy/Languages/CSharpLanguage.cs

@ -289,7 +289,7 @@ namespace ICSharpCode.ILSpy
void AddReferenceWarningMessage(AssemblyDefinition assembly, ITextOutput output) void AddReferenceWarningMessage(AssemblyDefinition assembly, ITextOutput output)
{ {
var loadedAssembly = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.GetAssemblyDefinitionAsync().Result == assembly); var loadedAssembly = MainWindow.Instance.CurrentAssemblyList.GetAssemblies().FirstOrDefault(la => la.GetAssemblyDefinitionAsync().Result == assembly);
if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.Any(i => i.Value.HasErrors)) if (loadedAssembly == null || !loadedAssembly.LoadedAssemblyReferencesInfo.HasErrors)
return; return;
const string line1 = "Warning: Some assembly references could not be loaded. This might lead to incorrect decompilation of some parts,"; const string line1 = "Warning: Some assembly references could not be loaded. This might lead to incorrect decompilation of some parts,";
const string line2 = "for ex. property getter/setter access. To get optimal decompilation results, please manually add the references to the list of loaded assemblies."; const string line2 = "for ex. property getter/setter access. To get optimal decompilation results, please manually add the references to the list of loaded assemblies.";

103
ILSpy/LoadedAssembly.cs

@ -38,7 +38,6 @@ namespace ICSharpCode.ILSpy
readonly AssemblyList assemblyList; readonly AssemblyList assemblyList;
readonly string fileName; readonly string fileName;
readonly string shortName; readonly string shortName;
readonly Dictionary<string, UnresolvedAssemblyNameReference> loadedAssemblyReferences = new Dictionary<string, UnresolvedAssemblyNameReference>();
public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null) public LoadedAssembly(AssemblyList assemblyList, string fileName, Stream stream = null)
{ {
@ -63,7 +62,7 @@ namespace ICSharpCode.ILSpy
return assembly?.DetectTargetFrameworkId() ?? string.Empty; return assembly?.DetectTargetFrameworkId() ?? string.Empty;
} }
public Dictionary<string, UnresolvedAssemblyNameReference> LoadedAssemblyReferencesInfo => loadedAssemblyReferences; public ReferenceLoadInfo LoadedAssemblyReferencesInfo { get; } = new ReferenceLoadInfo();
/// <summary> /// <summary>
/// Gets the Cecil ModuleDefinition. /// Gets the Cecil ModuleDefinition.
@ -207,18 +206,6 @@ namespace ICSharpCode.ILSpy
return node != null ? node.GetAssemblyDefinitionAsync().Result : null; return node != null ? node.GetAssemblyDefinitionAsync().Result : null;
} }
public AssemblyDefinition Resolve(string fullName)
{
var node = parent.LookupReferencedAssembly(fullName);
return node != null ? node.GetAssemblyDefinitionAsync().Result : null;
}
public AssemblyDefinition Resolve(string fullName, ReaderParameters parameters)
{
var node = parent.LookupReferencedAssembly(fullName);
return node != null ? node.GetAssemblyDefinitionAsync().Result : null;
}
public void Dispose() public void Dispose()
{ {
} }
@ -234,17 +221,12 @@ namespace ICSharpCode.ILSpy
if (name == null) if (name == null)
throw new ArgumentNullException(nameof(name)); throw new ArgumentNullException(nameof(name));
if (name.IsWindowsRuntime) { if (name.IsWindowsRuntime) {
return assemblyList.winRTMetadataLookupCache.GetOrAdd(name.Name, LookupWinRTMetadata); return assemblyList.assemblyLookupCache.GetOrAdd((name.Name, true), LookupReferencedAssemblyInternal);
} else { } else {
return assemblyList.assemblyLookupCache.GetOrAdd(name.FullName, LookupReferencedAssemblyInternal); return assemblyList.assemblyLookupCache.GetOrAdd((name.FullName, false), LookupReferencedAssemblyInternal);
} }
} }
public LoadedAssembly LookupReferencedAssembly(string fullName)
{
return assemblyList.assemblyLookupCache.GetOrAdd(fullName, LookupReferencedAssemblyInternal);
}
class MyUniversalResolver : UniversalAssemblyResolver class MyUniversalResolver : UniversalAssemblyResolver
{ {
public MyUniversalResolver(LoadedAssembly assembly) public MyUniversalResolver(LoadedAssembly assembly)
@ -253,55 +235,52 @@ namespace ICSharpCode.ILSpy
} }
} }
LoadedAssembly LookupReferencedAssemblyInternal(string fullName) static Dictionary<string, LoadedAssembly> loadingAssemblies = new Dictionary<string, LoadedAssembly>();
LoadedAssembly LookupReferencedAssemblyInternal((string fullName, bool isWinRT) data)
{ {
foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) { string file;
var asmDef = asm.GetAssemblyDefinitionAsync().Result; LoadedAssembly asm;
if (asmDef != null && fullName.Equals(asmDef.FullName, StringComparison.OrdinalIgnoreCase)) { lock (loadingAssemblies) {
return asm; foreach (LoadedAssembly loaded in assemblyList.GetAssemblies()) {
var asmDef = loaded.GetAssemblyDefinitionAsync().Result;
if (asmDef != null && data.fullName.Equals(data.isWinRT ? asmDef.Name.Name : asmDef.FullName, StringComparison.OrdinalIgnoreCase)) {
return loaded;
}
} }
}
if (assemblyLoadDisableCount > 0)
return null;
if (!App.Current.Dispatcher.CheckAccess()) {
// Call this method on the GUI thread.
return (LoadedAssembly)App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Func<string, LoadedAssembly>(LookupReferencedAssembly), fullName);
}
var resolver = new MyUniversalResolver(this) { TargetFramework = GetTargetFrameworkIdAsync().Result }; if (assemblyLoadDisableCount > 0)
var name = AssemblyNameReference.Parse(fullName); return null;
var file = resolver.FindAssemblyFile(name);
if (file != null) { if (data.isWinRT) {
loadedAssemblyReferences.AddMessage(fullName, MessageKind.Info, "Success - Loading from: " + file); file = Path.Combine(Environment.SystemDirectory, "WinMetadata", data.fullName + ".winmd");
return assemblyList.OpenAssembly(file, true); } else {
} else { var resolver = new MyUniversalResolver(this) { TargetFramework = GetTargetFrameworkIdAsync().Result };
loadedAssemblyReferences.AddMessage(fullName, MessageKind.Error, "Could not find reference: " + fullName); var name = AssemblyNameReference.Parse(data.fullName);
return null; file = resolver.FindAssemblyFile(name);
} }
}
LoadedAssembly LookupWinRTMetadata(string name) if (loadingAssemblies.TryGetValue(file, out asm))
{
foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) {
var asmDef = asm.GetAssemblyDefinitionAsync().Result;
if (asmDef!= null && name.Equals(asmDef.Name.Name, StringComparison.OrdinalIgnoreCase))
return asm; return asm;
}
if (assemblyLoadDisableCount > 0)
return null;
if (!App.Current.Dispatcher.CheckAccess()) {
// Call this method on the GUI thread.
return (LoadedAssembly)App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Func<string, LoadedAssembly>(LookupWinRTMetadata), name);
}
string file = Path.Combine(Environment.SystemDirectory, "WinMetadata", name + ".winmd"); if (file != null) {
if (File.Exists(file)) { LoadedAssemblyReferencesInfo.AddMessage(data.fullName, MessageKind.Info, "Success - Loading from: " + file);
return assemblyList.OpenAssembly(file, true); asm = new LoadedAssembly(assemblyList, file) { IsAutoLoaded = true };
} else { } else {
return null; LoadedAssemblyReferencesInfo.AddMessage(data.fullName, MessageKind.Error, "Could not find reference: " + data.fullName);
return null;
}
loadingAssemblies.Add(file, asm);
} }
App.Current.Dispatcher.BeginInvoke((Action)delegate() {
lock (assemblyList.assemblies) {
assemblyList.assemblies.Add(asm);
}
lock (loadingAssemblies) {
loadingAssemblies.Remove(file);
}
});
return asm;
} }
public Task ContinueWhenLoaded(Action<Task<ModuleDefinition>> onAssemblyLoaded, TaskScheduler taskScheduler) public Task ContinueWhenLoaded(Action<Task<ModuleDefinition>> onAssemblyLoaded, TaskScheduler taskScheduler)

2
ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs

@ -88,7 +88,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{ {
var loaded = parentAssembly.LoadedAssembly.LoadedAssemblyReferencesInfo.TryGetValue(r.FullName, out var info); var loaded = parentAssembly.LoadedAssembly.LoadedAssemblyReferencesInfo.TryGetInfo(r.FullName, out var info);
if (r.IsWindowsRuntime) { if (r.IsWindowsRuntime) {
language.WriteCommentLine(output, r.Name + " [WinRT]" + (!loaded ? " (unresolved)" : "")); language.WriteCommentLine(output, r.Name + " [WinRT]" + (!loaded ? " (unresolved)" : ""));
} else { } else {

2
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -384,7 +384,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
var la = ((AssemblyTreeNode)node).LoadedAssembly; var la = ((AssemblyTreeNode)node).LoadedAssembly;
if (!la.HasLoadError) { if (!la.HasLoadError) {
foreach (var assyRef in la.GetModuleDefinitionAsync().Result.AssemblyReferences) { foreach (var assyRef in la.GetModuleDefinitionAsync().Result.AssemblyReferences) {
la.LookupReferencedAssembly(assyRef.FullName); la.LookupReferencedAssembly(assyRef);
} }
} }
} }

Loading…
Cancel
Save