diff --git a/ILSpy/AssemblyList.cs b/ILSpy/AssemblyList.cs
index 82a3efdaf..7fa82293b 100644
--- a/ILSpy/AssemblyList.cs
+++ b/ILSpy/AssemblyList.cs
@@ -45,15 +45,10 @@ namespace ICSharpCode.ILSpy
/// Write accesses are allowed on the GUI thread only (but still need locking!)
///
///
- /// Technically read accesses need locking on when done on non-GUI threads... but whenever possible, use the
+ /// Technically read accesses need locking when done on non-GUI threads... but whenever possible, use the
/// thread-safe method.
///
- internal readonly ObservableCollection assemblies = new ObservableCollection();
-
- ///
- /// Dictionary for quickly finding types (used in hyperlink navigation)
- ///
- readonly ConcurrentDictionary typeDict = new ConcurrentDictionary();
+ internal readonly ObservableCollection assemblies = new ObservableCollection();
public AssemblyList(string listName)
{
@@ -76,7 +71,7 @@ namespace ICSharpCode.ILSpy
///
/// Gets the loaded assemblies. This method is thread-safe.
///
- public AssemblyTreeNode[] GetAssemblies()
+ public LoadedAssembly[] GetAssemblies()
{
lock (assemblies) {
return assemblies.ToArray();
@@ -119,129 +114,24 @@ namespace ICSharpCode.ILSpy
}
}
- ///
- /// Registers a type node in the dictionary for quick type lookup.
- ///
- /// This method is called by the assembly loading code (on a background thread)
- public void RegisterTypeNode(TypeTreeNode node)
- {
- // called on background loading thread, so we need to use a ConcurrentDictionary
- typeDict[node.TypeDefinition] = node;
- }
-
- #region Find*Node
- ///
- /// Looks up the type node corresponding to the type definition.
- /// Returns null if no matching node is found.
- ///
- public TypeTreeNode FindTypeNode(TypeDefinition def)
- {
- if (def == null)
- return null;
- App.Current.Dispatcher.VerifyAccess();
- if (def.DeclaringType != null) {
- TypeTreeNode decl = FindTypeNode(def.DeclaringType);
- if (decl != null) {
- decl.EnsureLazyChildren();
- return decl.Children.OfType().FirstOrDefault(t => t.TypeDefinition == def && !t.IsHidden);
- }
- } else {
- TypeTreeNode node;
- if (typeDict.TryGetValue(def, out node)) {
- // Ensure that the node is connected to the tree
- node.ParentAssemblyNode.EnsureLazyChildren();
- // Validate that the node wasn't removed due to visibility settings:
- if (node.Ancestors().OfType().Any(n => n.AssemblyList == this))
- return node;
- }
- }
- return null;
- }
-
- ///
- /// Looks up the method node corresponding to the method definition.
- /// Returns null if no matching node is found.
- ///
- public MethodTreeNode FindMethodNode(MethodDefinition def)
- {
- if (def == null)
- return null;
- TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
- typeNode.EnsureLazyChildren();
- MethodTreeNode methodNode = typeNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition == def && !m.IsHidden);
- if (methodNode != null)
- return methodNode;
- foreach (var p in typeNode.Children.OfType()) {
- if (p.IsHidden)
- continue;
- // method might be a child or a property or events
- p.EnsureLazyChildren();
- methodNode = p.Children.OfType().FirstOrDefault(m => m.MethodDefinition == def && !m.IsHidden);
- if (methodNode != null)
- return methodNode;
- }
-
- return null;
- }
-
- ///
- /// Looks up the field node corresponding to the field definition.
- /// Returns null if no matching node is found.
- ///
- public FieldTreeNode FindFieldNode(FieldDefinition def)
- {
- if (def == null)
- return null;
- TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
- typeNode.EnsureLazyChildren();
- return typeNode.Children.OfType().FirstOrDefault(m => m.FieldDefinition == def && !m.IsHidden);
- }
-
- ///
- /// Looks up the property node corresponding to the property definition.
- /// Returns null if no matching node is found.
- ///
- public PropertyTreeNode FindPropertyNode(PropertyDefinition def)
- {
- if (def == null)
- return null;
- TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
- typeNode.EnsureLazyChildren();
- return typeNode.Children.OfType().FirstOrDefault(m => m.PropertyDefinition == def && !m.IsHidden);
- }
-
- ///
- /// Looks up the event node corresponding to the event definition.
- /// Returns null if no matching node is found.
- ///
- public EventTreeNode FindEventNode(EventDefinition def)
- {
- if (def == null)
- return null;
- TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
- typeNode.EnsureLazyChildren();
- return typeNode.Children.OfType().FirstOrDefault(m => m.EventDefinition == def && !m.IsHidden);
- }
- #endregion
-
///
/// Opens an assembly from disk.
/// Returns the existing assembly node if it is already loaded.
///
- public AssemblyTreeNode OpenAssembly(string file)
+ public LoadedAssembly OpenAssembly(string file)
{
App.Current.Dispatcher.VerifyAccess();
file = Path.GetFullPath(file);
- foreach (AssemblyTreeNode node in this.assemblies) {
- if (file.Equals(node.FileName, StringComparison.OrdinalIgnoreCase))
- return node;
+ foreach (LoadedAssembly asm in this.assemblies) {
+ if (file.Equals(asm.FileName, StringComparison.OrdinalIgnoreCase))
+ return asm;
}
- var newNode = new AssemblyTreeNode(file, this);
- this.assemblies.Add(newNode);
- return newNode;
+ var newAsm = new LoadedAssembly(this, file);
+ this.assemblies.Add(newAsm);
+ return newAsm;
}
}
}
diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj
index 8eed57475..db01ba487 100644
--- a/ILSpy/ILSpy.csproj
+++ b/ILSpy/ILSpy.csproj
@@ -93,6 +93,7 @@
+
diff --git a/ILSpy/LoadedAssembly.cs b/ILSpy/LoadedAssembly.cs
new file mode 100644
index 000000000..6e9752b1b
--- /dev/null
+++ b/ILSpy/LoadedAssembly.cs
@@ -0,0 +1,147 @@
+// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt)
+// This code is distributed under MIT X11 license (for details please see \doc\license.txt)
+
+using System;
+using System.IO;
+using System.Linq;
+using System.Threading.Tasks;
+using System.Windows.Threading;
+
+using Mono.Cecil;
+
+namespace ICSharpCode.ILSpy
+{
+ ///
+ /// Represents an assembly loaded into ILSpy.
+ ///
+ sealed class LoadedAssembly
+ {
+ readonly Task assemblyTask;
+ readonly AssemblyList assemblyList;
+ readonly string fileName;
+ string shortName;
+
+ public LoadedAssembly(AssemblyList assemblyList, string fileName)
+ {
+ if (assemblyList == null)
+ throw new ArgumentNullException("assemblyList");
+ if (fileName == null)
+ throw new ArgumentNullException("fileName");
+ this.assemblyList = assemblyList;
+ this.fileName = fileName;
+
+ this.assemblyTask = Task.Factory.StartNew(LoadAssembly); // requires that this.fileName is set
+ this.shortName = Path.GetFileNameWithoutExtension(fileName);
+ }
+
+ public AssemblyDefinition AssemblyDefinition {
+ get {
+ try {
+ return assemblyTask.Result;
+ } catch (AggregateException) {
+ return null;
+ }
+ }
+ }
+
+ public AssemblyList AssemblyList {
+ get { return assemblyList; }
+ }
+
+ public string FileName {
+ get { return fileName; }
+ }
+
+ public string ShortName {
+ get { return shortName; }
+ }
+
+ public bool IsLoaded {
+ get { return assemblyTask.IsCompleted; }
+ }
+
+ public bool HasLoadError {
+ get { return assemblyTask.IsFaulted; }
+ }
+
+ AssemblyDefinition LoadAssembly()
+ {
+ // runs on background thread
+ ReaderParameters p = new ReaderParameters();
+ p.AssemblyResolver = new MyAssemblyResolver(this);
+ return AssemblyDefinition.ReadAssembly(fileName, p);
+ }
+
+ sealed class MyAssemblyResolver : IAssemblyResolver
+ {
+ readonly LoadedAssembly parent;
+
+ public MyAssemblyResolver(LoadedAssembly parent)
+ {
+ this.parent = parent;
+ }
+
+ public AssemblyDefinition Resolve(AssemblyNameReference name)
+ {
+ var node = parent.LookupReferencedAssembly(name.FullName);
+ return node != null ? node.AssemblyDefinition : null;
+ }
+
+ public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
+ {
+ var node = parent.LookupReferencedAssembly(name.FullName);
+ return node != null ? node.AssemblyDefinition : null;
+ }
+
+ public AssemblyDefinition Resolve(string fullName)
+ {
+ var node = parent.LookupReferencedAssembly(fullName);
+ return node != null ? node.AssemblyDefinition : null;
+ }
+
+ public AssemblyDefinition Resolve(string fullName, ReaderParameters parameters)
+ {
+ var node = parent.LookupReferencedAssembly(fullName);
+ return node != null ? node.AssemblyDefinition : null;
+ }
+ }
+
+ public LoadedAssembly LookupReferencedAssembly(string fullName)
+ {
+ foreach (LoadedAssembly asm in assemblyList.GetAssemblies()) {
+ if (asm.AssemblyDefinition != null && fullName.Equals(asm.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))
+ return asm;
+ }
+
+ if (!App.Current.Dispatcher.CheckAccess()) {
+ // Call this method on the GUI thread.
+ return (LoadedAssembly)App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Func(LookupReferencedAssembly), fullName);
+ }
+
+ var name = AssemblyNameReference.Parse(fullName);
+ string file = GacInterop.FindAssemblyInNetGac(name);
+ if (file == null) {
+ string dir = Path.GetDirectoryName(this.fileName);
+ if (File.Exists(Path.Combine(dir, name.Name + ".dll")))
+ file = Path.Combine(dir, name.Name + ".dll");
+ else if (File.Exists(Path.Combine(dir, name.Name + ".exe")))
+ file = Path.Combine(dir, name.Name + ".exe");
+ }
+ if (file != null) {
+ return assemblyList.OpenAssembly(file);
+ } else {
+ return null;
+ }
+ }
+
+ public Task ContinueWhenLoaded(Action> onAssemblyLoaded, TaskScheduler taskScheduler)
+ {
+ return this.assemblyTask.ContinueWith(onAssemblyLoaded, taskScheduler);
+ }
+
+ public void WaitUntilLoaded()
+ {
+ assemblyTask.Wait();
+ }
+ }
+}
diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs
index 333dffb09..9abe7a2a0 100644
--- a/ILSpy/MainWindow.xaml.cs
+++ b/ILSpy/MainWindow.xaml.cs
@@ -155,8 +155,8 @@ namespace ICSharpCode.ILSpy
void assemblyList_Assemblies_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
if (e.OldItems != null)
- foreach (AssemblyTreeNode node in e.OldItems)
- history.RemoveAll(n => n.AncestorsAndSelf().Contains(node));
+ foreach (LoadedAssembly asm in e.OldItems)
+ history.RemoveAll(n => n.AncestorsAndSelf().OfType().Any(a => a.LoadedAssembly == asm));
}
void LoadInitialAssemblies()
@@ -198,6 +198,10 @@ namespace ICSharpCode.ILSpy
get { return assemblyList; }
}
+ internal AssemblyListTreeNode AssemblyListTreeNode {
+ get { return assemblyListTreeNode; }
+ }
+
#region Node Selection
internal void SelectNode(SharpTreeNode obj, bool recordNavigationInHistory = true)
{
@@ -330,8 +334,11 @@ namespace ICSharpCode.ILSpy
foreach (string file in fileNames) {
var asm = assemblyList.OpenAssembly(file);
if (asm != null) {
- treeView.SelectedItems.Add(asm);
- lastNode = asm;
+ var node = assemblyListTreeNode.FindAssemblyNode(asm);
+ if (node != null) {
+ treeView.SelectedItems.Add(node);
+ lastNode = node;
+ }
}
}
if (lastNode != null)
diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs
index 9621bcec4..a652c618c 100644
--- a/ILSpy/TextView/DecompilerTextView.cs
+++ b/ILSpy/TextView/DecompilerTextView.cs
@@ -348,19 +348,19 @@ namespace ICSharpCode.ILSpy.TextView
return;
}
}
- var assemblyList = mainWindow.AssemblyList;
+ var assemblyListTreeNode = mainWindow.AssemblyListTreeNode;
if (reference is TypeReference) {
- mainWindow.SelectNode(assemblyList.FindTypeNode(((TypeReference)reference).Resolve()));
+ mainWindow.SelectNode(assemblyListTreeNode.FindTypeNode(((TypeReference)reference).Resolve()));
} else if (reference is MethodReference) {
- mainWindow.SelectNode(assemblyList.FindMethodNode(((MethodReference)reference).Resolve()));
+ mainWindow.SelectNode(assemblyListTreeNode.FindMethodNode(((MethodReference)reference).Resolve()));
} else if (reference is FieldReference) {
- mainWindow.SelectNode(assemblyList.FindFieldNode(((FieldReference)reference).Resolve()));
+ mainWindow.SelectNode(assemblyListTreeNode.FindFieldNode(((FieldReference)reference).Resolve()));
} else if (reference is PropertyReference) {
- mainWindow.SelectNode(assemblyList.FindPropertyNode(((PropertyReference)reference).Resolve()));
+ mainWindow.SelectNode(assemblyListTreeNode.FindPropertyNode(((PropertyReference)reference).Resolve()));
} else if (reference is EventReference) {
- mainWindow.SelectNode(assemblyList.FindEventNode(((EventReference)reference).Resolve()));
+ mainWindow.SelectNode(assemblyListTreeNode.FindEventNode(((EventReference)reference).Resolve()));
} else if (reference is AssemblyDefinition) {
- mainWindow.SelectNode(assemblyList.GetAssemblies().FirstOrDefault(node => node.AssemblyDefinition == reference));
+ mainWindow.SelectNode(assemblyListTreeNode.FindAssemblyNode((AssemblyDefinition)reference));
}
}
#endregion
diff --git a/ILSpy/TreeNodes/AssemblyListTreeNode.cs b/ILSpy/TreeNodes/AssemblyListTreeNode.cs
index 594e4f1ae..0530055c3 100644
--- a/ILSpy/TreeNodes/AssemblyListTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyListTreeNode.cs
@@ -17,11 +17,13 @@
// DEALINGS IN THE SOFTWARE.
using System;
+using System.Collections.ObjectModel;
+using System.Collections.Specialized;
using System.Linq;
using System.Windows;
-
using ICSharpCode.Decompiler;
using ICSharpCode.TreeView;
+using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes
{
@@ -42,13 +44,38 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (assemblyList == null)
throw new ArgumentNullException("assemblyList");
this.assemblyList = assemblyList;
- this.Children.BindToObservableCollection(assemblyList.assemblies);
+ BindToObservableCollection(assemblyList.assemblies);
}
public override object Text {
get { return assemblyList.ListName; }
}
+ void BindToObservableCollection(ObservableCollection collection)
+ {
+ this.Children.Clear();
+ this.Children.AddRange(collection.Select(a => new AssemblyTreeNode(a)));
+ collection.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e) {
+ switch (e.Action) {
+ case NotifyCollectionChangedAction.Add:
+ this.Children.InsertRange(e.NewStartingIndex, e.NewItems.Cast().Select(a => new AssemblyTreeNode(a)));
+ break;
+ case NotifyCollectionChangedAction.Remove:
+ this.Children.RemoveRange(e.OldStartingIndex, e.OldItems.Count);
+ break;
+ case NotifyCollectionChangedAction.Replace:
+ case NotifyCollectionChangedAction.Move:
+ throw new NotImplementedException();
+ case NotifyCollectionChangedAction.Reset:
+ this.Children.Clear();
+ this.Children.AddRange(collection.Select(a => new AssemblyTreeNode(a)));
+ break;
+ default:
+ throw new NotSupportedException("Invalid value for NotifyCollectionChangedAction");
+ }
+ };
+ }
+
public override bool CanDrop(DragEventArgs e, int index)
{
e.Effects = DragDropEffects.Move;
@@ -69,20 +96,20 @@ namespace ICSharpCode.ILSpy.TreeNodes
files = e.Data.GetData(DataFormats.FileDrop) as string[];
if (files != null) {
lock (assemblyList.assemblies) {
- var nodes = (from file in files
- where file != null
- select assemblyList.OpenAssembly(file) into node
- where node != null
- select node).Distinct().ToList();
- foreach (AssemblyTreeNode node in nodes) {
- int nodeIndex = assemblyList.assemblies.IndexOf(node);
+ var assemblies = (from file in files
+ where file != null
+ select assemblyList.OpenAssembly(file) into node
+ where node != null
+ select node).Distinct().ToList();
+ foreach (LoadedAssembly asm in assemblies) {
+ int nodeIndex = assemblyList.assemblies.IndexOf(asm);
if (nodeIndex < index)
index--;
assemblyList.assemblies.RemoveAt(nodeIndex);
}
- nodes.Reverse();
- foreach (AssemblyTreeNode node in nodes) {
- assemblyList.assemblies.Insert(index, node);
+ assemblies.Reverse();
+ foreach (LoadedAssembly asm in assemblies) {
+ assemblyList.assemblies.Insert(index, asm);
}
}
}
@@ -94,11 +121,126 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
language.WriteCommentLine(output, "List: " + assemblyList.ListName);
output.WriteLine();
- foreach (AssemblyTreeNode asm in assemblyList.GetAssemblies()) {
+ foreach (AssemblyTreeNode asm in this.Children) {
language.WriteCommentLine(output, new string('-', 60));
output.WriteLine();
asm.Decompile(language, output, options);
}
}
+
+ #region Find*Node
+
+ public AssemblyTreeNode FindAssemblyNode(AssemblyDefinition asm)
+ {
+ if (asm == null)
+ return null;
+ App.Current.Dispatcher.VerifyAccess();
+ foreach (AssemblyTreeNode node in this.Children) {
+ if (node.LoadedAssembly.IsLoaded && node.LoadedAssembly.AssemblyDefinition == asm)
+ return node;
+ }
+ return null;
+ }
+
+ public AssemblyTreeNode FindAssemblyNode(LoadedAssembly asm)
+ {
+ if (asm == null)
+ return null;
+ App.Current.Dispatcher.VerifyAccess();
+ foreach (AssemblyTreeNode node in this.Children) {
+ if (node.LoadedAssembly == asm)
+ return node;
+ }
+ return null;
+ }
+
+ ///
+ /// Looks up the type node corresponding to the type definition.
+ /// Returns null if no matching node is found.
+ ///
+ public TypeTreeNode FindTypeNode(TypeDefinition def)
+ {
+ if (def == null)
+ return null;
+ if (def.DeclaringType != null) {
+ TypeTreeNode decl = FindTypeNode(def.DeclaringType);
+ if (decl != null) {
+ decl.EnsureLazyChildren();
+ return decl.Children.OfType().FirstOrDefault(t => t.TypeDefinition == def && !t.IsHidden);
+ }
+ } else {
+ AssemblyTreeNode asm = FindAssemblyNode(def.Module.Assembly);
+ if (asm != null) {
+ return asm.FindTypeNode(def);
+ }
+ }
+ return null;
+ }
+
+ ///
+ /// Looks up the method node corresponding to the method definition.
+ /// Returns null if no matching node is found.
+ ///
+ public MethodTreeNode FindMethodNode(MethodDefinition def)
+ {
+ if (def == null)
+ return null;
+ TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
+ typeNode.EnsureLazyChildren();
+ MethodTreeNode methodNode = typeNode.Children.OfType().FirstOrDefault(m => m.MethodDefinition == def && !m.IsHidden);
+ if (methodNode != null)
+ return methodNode;
+ foreach (var p in typeNode.Children.OfType()) {
+ if (p.IsHidden)
+ continue;
+ // method might be a child or a property or events
+ p.EnsureLazyChildren();
+ methodNode = p.Children.OfType().FirstOrDefault(m => m.MethodDefinition == def && !m.IsHidden);
+ if (methodNode != null)
+ return methodNode;
+ }
+
+ return null;
+ }
+
+ ///
+ /// Looks up the field node corresponding to the field definition.
+ /// Returns null if no matching node is found.
+ ///
+ public FieldTreeNode FindFieldNode(FieldDefinition def)
+ {
+ if (def == null)
+ return null;
+ TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
+ typeNode.EnsureLazyChildren();
+ return typeNode.Children.OfType().FirstOrDefault(m => m.FieldDefinition == def && !m.IsHidden);
+ }
+
+ ///
+ /// Looks up the property node corresponding to the property definition.
+ /// Returns null if no matching node is found.
+ ///
+ public PropertyTreeNode FindPropertyNode(PropertyDefinition def)
+ {
+ if (def == null)
+ return null;
+ TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
+ typeNode.EnsureLazyChildren();
+ return typeNode.Children.OfType().FirstOrDefault(m => m.PropertyDefinition == def && !m.IsHidden);
+ }
+
+ ///
+ /// Looks up the event node corresponding to the event definition.
+ /// Returns null if no matching node is found.
+ ///
+ public EventTreeNode FindEventNode(EventDefinition def)
+ {
+ if (def == null)
+ return null;
+ TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
+ typeNode.EnsureLazyChildren();
+ return typeNode.Children.OfType().FirstOrDefault(m => m.EventDefinition == def && !m.IsHidden);
+ }
+ #endregion
}
}
diff --git a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
index c0af4ae79..13704127d 100644
--- a/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyReferenceTreeNode.cs
@@ -63,19 +63,22 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
var assemblyListNode = parentAssembly.Parent as AssemblyListTreeNode;
if (assemblyListNode != null) {
- assemblyListNode.Select(parentAssembly.LookupReferencedAssembly(r.FullName));
+ assemblyListNode.Select(assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedAssembly(r.FullName)));
e.Handled = true;
}
}
protected override void LoadChildren()
{
- var refNode = parentAssembly.LookupReferencedAssembly(r.FullName);
- if (refNode != null) {
- AssemblyDefinition asm = refNode.AssemblyDefinition;
- if (asm != null) {
- foreach (var childRef in asm.MainModule.AssemblyReferences)
- this.Children.Add(new AssemblyReferenceTreeNode(childRef, refNode));
+ var assemblyListNode = parentAssembly.Parent as AssemblyListTreeNode;
+ if (assemblyListNode != null) {
+ var refNode = assemblyListNode.FindAssemblyNode(parentAssembly.LoadedAssembly.LookupReferencedAssembly(r.FullName));
+ if (refNode != null) {
+ AssemblyDefinition asm = refNode.LoadedAssembly.AssemblyDefinition;
+ if (asm != null) {
+ foreach (var childRef in asm.MainModule.AssemblyReferences)
+ this.Children.Add(new AssemblyReferenceTreeNode(childRef, refNode));
+ }
}
}
}
diff --git a/ILSpy/TreeNodes/AssemblyTreeNode.cs b/ILSpy/TreeNodes/AssemblyTreeNode.cs
index 78006ec04..7b9136717 100644
--- a/ILSpy/TreeNodes/AssemblyTreeNode.cs
+++ b/ILSpy/TreeNodes/AssemblyTreeNode.cs
@@ -38,55 +38,38 @@ namespace ICSharpCode.ILSpy.TreeNodes
///
sealed class AssemblyTreeNode : ILSpyTreeNode
{
-
- readonly AssemblyList assemblyList;
- readonly string fileName;
- string shortName;
- readonly Task assemblyTask;
+ readonly LoadedAssembly assembly;
readonly List classes = new List();
readonly Dictionary namespaces = new Dictionary();
- public AssemblyTreeNode(string fileName, AssemblyList assemblyList)
+ public AssemblyTreeNode(LoadedAssembly assembly)
{
- if (fileName == null)
- throw new ArgumentNullException("fileName");
+ if (assembly == null)
+ throw new ArgumentNullException("assembly");
- this.fileName = fileName;
- this.assemblyList = assemblyList;
- this.assemblyTask = Task.Factory.StartNew(LoadAssembly); // requires that this.fileName is set
- this.shortName = Path.GetFileNameWithoutExtension(fileName);
+ this.assembly = assembly;
- assemblyTask.ContinueWith(OnAssemblyLoaded, TaskScheduler.FromCurrentSynchronizationContext());
+ assembly.ContinueWhenLoaded(OnAssemblyLoaded, TaskScheduler.FromCurrentSynchronizationContext());
this.LazyLoading = true;
}
- public string FileName {
- get { return fileName; }
- }
-
public AssemblyList AssemblyList {
- get { return assemblyList; }
+ get { return assembly.AssemblyList; }
}
- public AssemblyDefinition AssemblyDefinition {
- get {
- try {
- return assemblyTask.Result;
- } catch {
- return null;
- }
- }
+ public LoadedAssembly LoadedAssembly {
+ get { return assembly; }
}
public override object Text {
- get { return HighlightSearchMatch(shortName); }
+ get { return HighlightSearchMatch(assembly.ShortName); }
}
public override object Icon {
get {
- if (assemblyTask.IsCompleted) {
- return assemblyTask.IsFaulted ? Images.AssemblyWarning : Images.Assembly;
+ if (assembly.IsLoaded) {
+ return assembly.HasLoadError ? Images.AssemblyWarning : Images.Assembly;
} else {
return Images.AssemblyLoading;
}
@@ -94,22 +77,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
public override bool ShowExpander {
- get { return !assemblyTask.IsFaulted; }
- }
-
- AssemblyDefinition LoadAssembly()
- {
- // runs on background thread
- ReaderParameters p = new ReaderParameters();
- p.AssemblyResolver = new MyAssemblyResolver(this);
- AssemblyDefinition assembly = AssemblyDefinition.ReadAssembly(fileName, p);
- foreach (TypeDefinition type in assembly.MainModule.Types.OrderBy(t => t.FullName)) {
- TypeTreeNode node = new TypeTreeNode(type, this);
- classes.Add(node);
- assemblyList.RegisterTypeNode(node);
- }
-
- return assembly;
+ get { return !assembly.HasLoadError; }
}
void OnAssemblyLoaded(Task assemblyTask)
@@ -120,45 +88,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (assemblyTask.IsFaulted) {
RaisePropertyChanged("ShowExpander"); // cannot expand assemblies with load error
} else {
- AssemblyDefinition assembly = assemblyTask.Result;
- if (shortName != assembly.Name.Name) {
- shortName = assembly.Name.Name;
- RaisePropertyChanged("Text");
- }
- }
- }
-
- sealed class MyAssemblyResolver : IAssemblyResolver
- {
- readonly AssemblyTreeNode parent;
-
- public MyAssemblyResolver(AssemblyTreeNode parent)
- {
- this.parent = parent;
- }
-
- public AssemblyDefinition Resolve(AssemblyNameReference name)
- {
- var node = parent.LookupReferencedAssembly(name.FullName);
- return node != null ? node.AssemblyDefinition : null;
- }
-
- public AssemblyDefinition Resolve(AssemblyNameReference name, ReaderParameters parameters)
- {
- var node = parent.LookupReferencedAssembly(name.FullName);
- return node != null ? node.AssemblyDefinition : null;
- }
-
- public AssemblyDefinition Resolve(string fullName)
- {
- var node = parent.LookupReferencedAssembly(fullName);
- return node != null ? node.AssemblyDefinition : null;
- }
-
- public AssemblyDefinition Resolve(string fullName, ReaderParameters parameters)
- {
- var node = parent.LookupReferencedAssembly(fullName);
- return node != null ? node.AssemblyDefinition : null;
+ RaisePropertyChanged("Text"); // shortname might have changed
}
}
@@ -177,28 +107,32 @@ namespace ICSharpCode.ILSpy.TreeNodes
return menu;
}
+ Dictionary typeDict = new Dictionary();
+
protected override void LoadChildren()
{
- try {
- assemblyTask.Wait();
- } catch (AggregateException) {
+ AssemblyDefinition assemblyDefinition = assembly.AssemblyDefinition;
+ if (assemblyDefinition == null) {
// if we crashed on loading, then we don't have any children
return;
}
- ModuleDefinition mainModule = assemblyTask.Result.MainModule;
+ ModuleDefinition mainModule = assemblyDefinition.MainModule;
+
this.Children.Add(new ReferenceFolderTreeNode(mainModule, this));
if (mainModule.HasResources)
this.Children.Add(new ResourceListTreeNode(mainModule));
foreach (NamespaceTreeNode ns in namespaces.Values) {
ns.Children.Clear();
}
- foreach (TypeTreeNode type in classes) {
+ foreach (TypeDefinition type in mainModule.Types.OrderBy(t => t.FullName)) {
NamespaceTreeNode ns;
if (!namespaces.TryGetValue(type.Namespace, out ns)) {
ns = new NamespaceTreeNode(type.Namespace);
namespaces[type.Namespace] = ns;
}
- ns.Children.Add(type);
+ TypeTreeNode node = new TypeTreeNode(type, this);
+ typeDict[type] = node;
+ ns.Children.Add(node);
}
foreach (NamespaceTreeNode ns in namespaces.Values.OrderBy(n => n.Name)) {
if (ns.Children.Count > 0)
@@ -206,6 +140,18 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
+ public TypeTreeNode FindTypeNode(TypeDefinition def)
+ {
+ if (def == null)
+ return null;
+ EnsureLazyChildren();
+ TypeTreeNode node;
+ if (typeDict.TryGetValue(def, out node))
+ return node;
+ else
+ return null;
+ }
+
public override bool CanDrag(SharpTreeNode[] nodes)
{
return nodes.All(n => n is AssemblyTreeNode);
@@ -228,8 +174,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void DeleteCore()
{
- lock (assemblyList.assemblies) {
- assemblyList.assemblies.Remove(this);
+ lock (assembly.AssemblyList.assemblies) {
+ assembly.AssemblyList.assemblies.Remove(assembly);
}
}
@@ -238,41 +184,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override IDataObject Copy(SharpTreeNode[] nodes)
{
DataObject dataObject = new DataObject();
- dataObject.SetData(DataFormat, nodes.OfType().Select(n => n.fileName).ToArray());
+ dataObject.SetData(DataFormat, nodes.OfType().Select(n => n.LoadedAssembly.FileName).ToArray());
return dataObject;
}
- public AssemblyTreeNode LookupReferencedAssembly(string fullName)
- {
- foreach (AssemblyTreeNode node in assemblyList.GetAssemblies()) {
- if (node.AssemblyDefinition != null && fullName.Equals(node.AssemblyDefinition.FullName, StringComparison.OrdinalIgnoreCase))
- return node;
- }
-
- if (!App.Current.Dispatcher.CheckAccess()) {
- // Call this method on the GUI thread.
- return (AssemblyTreeNode)App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Func(LookupReferencedAssembly), fullName);
- }
-
- var name = AssemblyNameReference.Parse(fullName);
- string file = GacInterop.FindAssemblyInNetGac(name);
- if (file == null) {
- string dir = Path.GetDirectoryName(this.fileName);
- if (File.Exists(Path.Combine(dir, name.Name + ".dll")))
- file = Path.Combine(dir, name.Name + ".dll");
- else if (File.Exists(Path.Combine(dir, name.Name + ".exe")))
- file = Path.Combine(dir, name.Name + ".exe");
- }
- if (file != null) {
- return assemblyList.OpenAssembly(file);
- } else {
- return null;
- }
- }
-
public override FilterResult Filter(FilterSettings settings)
{
- if (settings.SearchTermMatches(shortName))
+ if (settings.SearchTermMatches(assembly.ShortName))
return FilterResult.Match;
else
return FilterResult.Recurse;
@@ -280,8 +198,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
- // use assemblyTask.Result instead of this.AssemblyDefinition so that load errors are passed on to the caller
- language.DecompileAssembly(assemblyTask.Result, fileName, output, options);
+ assembly.WaitUntilLoaded(); // necessary so that load errors are passed on to the caller
+ language.DecompileAssembly(assembly.AssemblyDefinition, assembly.FileName, output, options);
}
}
}
diff --git a/ILSpy/TreeNodes/BaseTypesTreeNode.cs b/ILSpy/TreeNodes/BaseTypesTreeNode.cs
index 447b782a5..ff3f82c43 100644
--- a/ILSpy/TreeNodes/BaseTypesTreeNode.cs
+++ b/ILSpy/TreeNodes/BaseTypesTreeNode.cs
@@ -128,7 +128,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (def != null) {
var assemblyListNode = node.Ancestors().OfType().FirstOrDefault();
if (assemblyListNode != null) {
- assemblyListNode.Select(assemblyListNode.AssemblyList.FindTypeNode(def));
+ assemblyListNode.Select(assemblyListNode.FindTypeNode(def));
return true;
}
}
diff --git a/SharpTreeView/SharpTreeNodeCollection.cs b/SharpTreeView/SharpTreeNodeCollection.cs
index f598a0f2b..57d13124e 100644
--- a/SharpTreeView/SharpTreeNodeCollection.cs
+++ b/SharpTreeView/SharpTreeNodeCollection.cs
@@ -173,30 +173,5 @@ namespace ICSharpCode.TreeView
{
return list.GetEnumerator();
}
-
- public void BindToObservableCollection(ObservableCollection collection) where T : SharpTreeNode
- {
- Clear();
- AddRange(collection);
- collection.CollectionChanged += delegate(object sender, NotifyCollectionChangedEventArgs e) {
- switch (e.Action) {
- case NotifyCollectionChangedAction.Add:
- InsertRange(e.NewStartingIndex, e.NewItems.Cast());
- break;
- case NotifyCollectionChangedAction.Remove:
- RemoveRange(e.OldStartingIndex, e.OldItems.Count);
- break;
- case NotifyCollectionChangedAction.Replace:
- case NotifyCollectionChangedAction.Move:
- throw new NotImplementedException();
- case NotifyCollectionChangedAction.Reset:
- Clear();
- AddRange(collection);
- break;
- default:
- throw new NotSupportedException("Invalid value for NotifyCollectionChangedAction");
- }
- };
- }
}
}