Browse Source

Merge remote branch 'EdHarvey/Analysis'

pull/166/head
Daniel Grunwald 16 years ago
parent
commit
ad685e0e35
  1. 16
      ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs
  2. 4
      ILSpy/BamlDecompiler.cs
  3. 15
      ILSpy/ILSpy.csproj
  4. 17
      ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs
  5. 9
      ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs
  6. 18
      ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.cs
  7. 39
      ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs
  8. 26
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs
  9. 34
      ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs
  10. 105
      ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs
  11. 101
      ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs
  12. 105
      ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs
  13. 29
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs
  14. 41
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
  15. 21
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
  16. 33
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs
  17. 32
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorsTreeNode.cs
  18. 16
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.cs
  19. 45
      ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs
  20. 184
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs
  21. 93
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs
  22. 118
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs
  23. 72
      ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs
  24. 18
      ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs
  25. 2
      ILSpy/TreeNodes/Analyzer/Helpers.cs
  26. 23
      ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs
  27. 78
      ILSpy/TreeNodes/AssemblyTreeNode.cs
  28. 46
      ILSpy/TreeNodes/ResourceEntryNode.cs
  29. 2
      ILSpy/TreeNodes/XamlResourceNode.cs

16
ICSharpCode.Decompiler/Ast/TypesHierarchyHelpers.cs

@ -182,6 +182,22 @@ namespace ICSharpCode.Decompiler.Ast
return true; return true;
} }
public static bool MatchInterfaceMethod(MethodDefinition candidate, MethodDefinition method, TypeReference interfaceContextType)
{
var candidateContext = CreateGenericContext(candidate.DeclaringType);
var gCandidate = candidateContext.ApplyTo(candidate);
if (interfaceContextType is GenericInstanceType) {
var methodContext = new GenericContext<TypeDefinition>(interfaceContextType.Resolve(), ((GenericInstanceType)interfaceContextType).GenericArguments);
var gMethod = methodContext.ApplyTo(method);
return MatchMethod(gCandidate, gMethod);
} else {
var methodContext = CreateGenericContext(interfaceContextType.Resolve());
var gMethod = candidateContext.ApplyTo(method);
return MatchMethod(gCandidate, gMethod);
}
}
private static bool MatchProperty(GenericContext<PropertyDefinition> candidate, GenericContext<PropertyDefinition> property) private static bool MatchProperty(GenericContext<PropertyDefinition> candidate, GenericContext<PropertyDefinition> property)
{ {
var mCandidate = candidate.Item; var mCandidate = candidate.Item;

4
ILSpy/BamlDecompiler.cs

@ -415,8 +415,8 @@ namespace ICSharpCode.ILSpy.Baml
BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName); BamlDecompiler decompiler = CreateBamlDecompilerInAppDomain(ref bamlDecompilerAppDomain, asm.FileName);
MemoryStream bamlStream = new MemoryStream(); MemoryStream bamlStream = new MemoryStream();
data.Position = 0; Data.Position = 0;
data.CopyTo(bamlStream); Data.CopyTo(bamlStream);
output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm))); output.Write(decompiler.DecompileBaml(bamlStream, asm.FileName, new ConnectMethodDecompiler(asm), new AssemblyResolver(asm)));
return true; return true;

15
ILSpy/ILSpy.csproj

@ -135,6 +135,13 @@
<Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorsTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedEventAccessorsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedEventOverridesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedEventTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedEventTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfacePropertyImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceMethodImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedInterfaceEventImplementedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExposedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeExtensionMethodsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeInstantiationsTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedTypeTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\Helpers.cs" /> <Compile Include="TreeNodes\Analyzer\Helpers.cs" />
<Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" /> <Compile Include="TreeNodes\Analyzer\ScopedWhereUsedAnalyzer.cs" />
<Compile Include="TreeNodes\IMemberTreeNode.cs" /> <Compile Include="TreeNodes\IMemberTreeNode.cs" />
@ -177,13 +184,13 @@
<Compile Include="TextView\ReferenceElementGenerator.cs" /> <Compile Include="TextView\ReferenceElementGenerator.cs" />
<Compile Include="TextView\AvalonEditTextOutput.cs" /> <Compile Include="TextView\AvalonEditTextOutput.cs" />
<Compile Include="TextView\UIElementGenerator.cs" /> <Compile Include="TextView\UIElementGenerator.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldAccessNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedFieldAccessTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedFieldNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedFieldTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedMethodTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsedByTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsesNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsesTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzerTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerMethodOverridesTreeNode.cs" /> <Compile Include="TreeNodes\Analyzer\AnalyzedMethodOverridesTreeNode.cs" />
<Compile Include="TreeNodes\AssemblyListTreeNode.cs" /> <Compile Include="TreeNodes\AssemblyListTreeNode.cs" />
<Compile Include="TreeNodes\AssemblyReferenceTreeNode.cs" /> <Compile Include="TreeNodes\AssemblyReferenceTreeNode.cs" />
<Compile Include="TreeNodes\AssemblyTreeNode.cs" /> <Compile Include="TreeNodes\AssemblyTreeNode.cs" />

17
ILSpy/TreeNodes/Analyzer/AnalyzeContextMenuEntry.cs

@ -24,38 +24,43 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
[ExportContextMenuEntry(Header = "Analyze", Icon = "images/Search.png")] [ExportContextMenuEntry(Header = "Analyze", Icon = "images/Search.png")]
sealed class AnalyzeContextMenuEntry : IContextMenuEntry internal sealed class AnalyzeContextMenuEntry : IContextMenuEntry
{ {
public bool IsVisible(SharpTreeNode[] selectedNodes) public bool IsVisible(SharpTreeNode[] selectedNodes)
{ {
return selectedNodes.All(n => n is IMemberTreeNode); return selectedNodes.All(n => n is IMemberTreeNode);
} }
public bool IsEnabled(SharpTreeNode[] selectedNodes) public bool IsEnabled(SharpTreeNode[] selectedNodes)
{ {
foreach (IMemberTreeNode node in selectedNodes) { foreach (IMemberTreeNode node in selectedNodes) {
if (!(node.Member is FieldDefinition if (!(node.Member is TypeDefinition
|| node.Member is FieldDefinition
|| node.Member is MethodDefinition || node.Member is MethodDefinition
|| Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member) || Analyzer.AnalyzedPropertyTreeNode.CanShow(node.Member)
|| Analyzer.AnalyzedEventTreeNode.CanShow(node.Member))) || Analyzer.AnalyzedEventTreeNode.CanShow(node.Member)))
return false; return false;
} }
return true; return true;
} }
public void Execute(SharpTreeNode[] selectedNodes) public void Execute(SharpTreeNode[] selectedNodes)
{ {
// TODO: figure out when equivalent nodes are already present // TODO: figure out when equivalent nodes are already present
// and focus those instead. // and focus those instead.
foreach (IMemberTreeNode node in selectedNodes) { foreach (IMemberTreeNode node in selectedNodes) {
TypeDefinition type = node.Member as TypeDefinition;
if (type != null)
MainWindow.Instance.AddToAnalyzer(new AnalyzedTypeTreeNode(type));
FieldDefinition field = node.Member as FieldDefinition; FieldDefinition field = node.Member as FieldDefinition;
if (field != null) if (field != null)
MainWindow.Instance.AddToAnalyzer(new AnalyzedFieldNode(field)); MainWindow.Instance.AddToAnalyzer(new AnalyzedFieldTreeNode(field));
MethodDefinition method = node.Member as MethodDefinition; MethodDefinition method = node.Member as MethodDefinition;
if (method != null) if (method != null)
MainWindow.Instance.AddToAnalyzer(new AnalyzedMethodTreeNode(method)); MainWindow.Instance.AddToAnalyzer(new AnalyzedMethodTreeNode(method));
var propertyAnalyzer = Analyzer.AnalyzedPropertyTreeNode.TryCreateAnalyzer(node.Member); var propertyAnalyzer = Analyzer.AnalyzedPropertyTreeNode.TryCreateAnalyzer(node.Member);
if(propertyAnalyzer != null) if (propertyAnalyzer != null)
MainWindow.Instance.AddToAnalyzer(propertyAnalyzer); MainWindow.Instance.AddToAnalyzer(propertyAnalyzer);
var eventAnalyzer = Analyzer.AnalyzedEventTreeNode.TryCreateAnalyzer(node.Member); var eventAnalyzer = Analyzer.AnalyzedEventTreeNode.TryCreateAnalyzer(node.Member);
if (eventAnalyzer != null) if (eventAnalyzer != null)

9
ILSpy/TreeNodes/Analyzer/AnalyzedEventAccessorsTreeNode.cs

@ -21,15 +21,12 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedEventAccessorsTreeNode : AnalyzerTreeNode internal sealed class AnalyzedEventAccessorsTreeNode : AnalyzerTreeNode
{ {
EventDefinition analyzedEvent;
public AnalyzedEventAccessorsTreeNode(EventDefinition analyzedEvent) public AnalyzedEventAccessorsTreeNode(EventDefinition analyzedEvent)
{ {
if (analyzedEvent == null) if (analyzedEvent == null)
throw new ArgumentNullException("analyzedEvent"); throw new ArgumentNullException("analyzedEvent");
this.analyzedEvent = analyzedEvent;
if (analyzedEvent.AddMethod != null) if (analyzedEvent.AddMethod != null)
this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add")); this.Children.Add(new AnalyzedEventAccessorTreeNode(analyzedEvent.AddMethod, "add"));
@ -54,9 +51,9 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return !MainWindow.Instance.CurrentLanguage.ShowMember(property.AddMethod ?? property.RemoveMethod); return !MainWindow.Instance.CurrentLanguage.ShowMember(property.AddMethod ?? property.RemoveMethod);
} }
class AnalyzedEventAccessorTreeNode : AnalyzedMethodTreeNode internal class AnalyzedEventAccessorTreeNode : AnalyzedMethodTreeNode
{ {
string name; private string name;
public AnalyzedEventAccessorTreeNode(MethodDefinition analyzedMethod, string name) public AnalyzedEventAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod) : base(analyzedMethod)

18
ILSpy/TreeNodes/Analyzer/AnalyzedEventOverridesTreeNode.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.Text;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
@ -28,10 +27,10 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedEventOverridesTreeNode : AnalyzerTreeNode internal sealed class AnalyzedEventOverridesTreeNode : AnalyzerTreeNode
{ {
readonly EventDefinition analyzedEvent; private readonly EventDefinition analyzedEvent;
readonly ThreadingSupport threading; private readonly ThreadingSupport threading;
public AnalyzedEventOverridesTreeNode(EventDefinition analyzedEvent) public AnalyzedEventOverridesTreeNode(EventDefinition analyzedEvent)
{ {
@ -45,7 +44,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
public override object Text public override object Text
{ {
get { return "Overriden By"; } get { return "Overridden By"; }
} }
public override object Icon public override object Icon
@ -67,19 +66,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct);
} }
IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct)
{ {
assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null); assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
// use parallelism only on the assembly level (avoid locks within Cecil) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
} }
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct)
{ {
string asmName = asm.AssemblyDefinition.Name.Name; string asmName = asm.AssemblyDefinition.Name.Name;
string name = analyzedEvent.Name; string name = analyzedEvent.Name;
@ -102,7 +102,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
public static bool CanShowAnalyzer(EventDefinition property) public static bool CanShow(EventDefinition property)
{ {
var accessor = property.AddMethod ?? property.RemoveMethod; var accessor = property.AddMethod ?? property.RemoveMethod;
return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface; return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface;

39
ILSpy/TreeNodes/Analyzer/AnalyzedEventTreeNode.cs

@ -18,46 +18,51 @@
using System; using System;
using Mono.Cecil; using Mono.Cecil;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedEventTreeNode : AnalyzerTreeNode internal sealed class AnalyzedEventTreeNode : AnalyzerTreeNode
{ {
EventDefinition analyzedEvent; private readonly EventDefinition analyzedEvent;
string prefix; private readonly string prefix;
public AnalyzedEventTreeNode(EventDefinition analyzedEvent, string prefix = "") public AnalyzedEventTreeNode(EventDefinition analyzedEvent, string prefix = "")
{ {
if (analyzedEvent == null) if (analyzedEvent == null)
throw new ArgumentNullException("analyzedMethod"); throw new ArgumentNullException("analyzedEvent");
this.analyzedEvent = analyzedEvent; this.analyzedEvent = analyzedEvent;
this.prefix = prefix; this.prefix = prefix;
this.LazyLoading = true; this.LazyLoading = true;
} }
public override object Icon { public override object Icon
{
get { return EventTreeNode.GetIcon(analyzedEvent); } get { return EventTreeNode.GetIcon(analyzedEvent); }
} }
public override object Text { public override object Text
get { {
get
{
// TODO: This way of formatting is not suitable for events which explicitly implement interfaces. // TODO: This way of formatting is not suitable for events which explicitly implement interfaces.
return prefix + Language.TypeToString(analyzedEvent.DeclaringType, true) + "." + EventTreeNode.GetText(analyzedEvent, Language); } return prefix + Language.TypeToString(analyzedEvent.DeclaringType, true) + "." + EventTreeNode.GetText(analyzedEvent, Language);
}
} }
public override void ActivateItem(System.Windows.RoutedEventArgs e) public override void ActivateItem(System.Windows.RoutedEventArgs e)
{ {
e.Handled = true; e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedEvent); MainWindow.Instance.JumpToReference(analyzedEvent);
} }
protected override void LoadChildren() protected override void LoadChildren()
{ {
if(AnalyzedEventAccessorsTreeNode.CanShow(analyzedEvent)) if (AnalyzedEventAccessorsTreeNode.CanShow(analyzedEvent))
this.Children.Add(new AnalyzedEventAccessorsTreeNode(analyzedEvent)); this.Children.Add(new AnalyzedEventAccessorsTreeNode(analyzedEvent));
if (AnalyzedEventOverridesTreeNode.CanShowAnalyzer(analyzedEvent)) if (AnalyzedEventOverridesTreeNode.CanShow(analyzedEvent))
this.Children.Add(new AnalyzedEventOverridesTreeNode(analyzedEvent)); this.Children.Add(new AnalyzedEventOverridesTreeNode(analyzedEvent));
if (AnalyzedInterfaceEventImplementedByTreeNode.CanShow(analyzedEvent))
this.Children.Add(new AnalyzedInterfaceEventImplementedByTreeNode(analyzedEvent));
} }
public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member) public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member)
@ -75,7 +80,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false; return false;
return AnalyzedEventAccessorsTreeNode.CanShow(property) return AnalyzedEventAccessorsTreeNode.CanShow(property)
|| AnalyzedEventOverridesTreeNode.CanShowAnalyzer(property); || AnalyzedEventOverridesTreeNode.CanShow(property);
} }
} }
} }

26
ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessNode.cs → ILSpy/TreeNodes/Analyzer/AnalyzedFieldAccessTreeNode.cs

@ -18,23 +18,20 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedFieldAccessNode : AnalyzerTreeNode internal sealed class AnalyzedFieldAccessTreeNode : AnalyzerTreeNode
{ {
readonly bool showWrites; // true: show writes; false: show read access private readonly bool showWrites; // true: show writes; false: show read access
readonly FieldDefinition analyzedField; private readonly FieldDefinition analyzedField;
readonly ThreadingSupport threading; private readonly ThreadingSupport threading;
public AnalyzedFieldAccessNode(FieldDefinition analyzedField, bool showWrites) public AnalyzedFieldAccessTreeNode(FieldDefinition analyzedField, bool showWrites)
{ {
if (analyzedField == null) if (analyzedField == null)
throw new ArgumentNullException("analyzedField"); throw new ArgumentNullException("analyzedField");
@ -69,13 +66,13 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
var analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedField, FindReferencesInType); var analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedField, FindReferencesInType);
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }
IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type) private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{ {
string name = analyzedField.Name; string name = analyzedField.Name;
string declTypeName = analyzedField.DeclaringType.FullName; string declTypeName = analyzedField.DeclaringType.FullName;
@ -87,18 +84,23 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (Instruction instr in method.Body.Instructions) { foreach (Instruction instr in method.Body.Instructions) {
if (CanBeReference(instr.OpCode.Code)) { if (CanBeReference(instr.OpCode.Code)) {
FieldReference fr = instr.Operand as FieldReference; FieldReference fr = instr.Operand as FieldReference;
if (fr != null && fr.Name == name && Helpers.IsReferencedBy(analyzedField.DeclaringType, fr.DeclaringType) && fr.Resolve() == analyzedField) { if (fr != null && fr.Name == name &&
Helpers.IsReferencedBy(analyzedField.DeclaringType, fr.DeclaringType) &&
fr.Resolve() == analyzedField) {
found = true; found = true;
break; break;
} }
} }
} }
method.Body = null;
if (found) if (found)
yield return new AnalyzedMethodTreeNode(method); yield return new AnalyzedMethodTreeNode(method);
} }
} }
bool CanBeReference(Code code) private bool CanBeReference(Code code)
{ {
switch (code) { switch (code) {
case Code.Ldfld: case Code.Ldfld:

34
ILSpy/TreeNodes/Analyzer/AnalyzedFieldNode.cs → ILSpy/TreeNodes/Analyzer/AnalyzedFieldTreeNode.cs

@ -21,43 +21,47 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedFieldNode : AnalyzerTreeNode, IMemberTreeNode internal class AnalyzedFieldTreeNode : AnalyzerTreeNode, IMemberTreeNode
{ {
FieldDefinition analyzedField; private readonly FieldDefinition analyzedField;
public AnalyzedFieldNode(FieldDefinition analyzedField) public AnalyzedFieldTreeNode(FieldDefinition analyzedField)
{ {
if (analyzedField == null) if (analyzedField == null)
throw new ArgumentNullException("analyzedField"); throw new ArgumentNullException("analyzedField");
this.analyzedField = analyzedField; this.analyzedField = analyzedField;
this.LazyLoading = true; this.LazyLoading = true;
} }
public override object Icon { public override object Icon
{
get { return FieldTreeNode.GetIcon(analyzedField); } get { return FieldTreeNode.GetIcon(analyzedField); }
} }
public override object Text { public override object Text
get { {
get
{
return Language.TypeToString(analyzedField.DeclaringType, true) + return Language.TypeToString(analyzedField.DeclaringType, true) +
"." + analyzedField.Name + " : " + this.Language.TypeToString(analyzedField.FieldType, false, analyzedField); "." + analyzedField.Name + " : " + this.Language.TypeToString(analyzedField.FieldType, false, analyzedField);
} }
} }
public override void ActivateItem(System.Windows.RoutedEventArgs e) public override void ActivateItem(System.Windows.RoutedEventArgs e)
{ {
e.Handled = true; e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedField); MainWindow.Instance.JumpToReference(analyzedField);
} }
protected override void LoadChildren() protected override void LoadChildren()
{ {
this.Children.Add(new AnalyzedFieldAccessNode(analyzedField, false)); this.Children.Add(new AnalyzedFieldAccessTreeNode(analyzedField, false));
if (!analyzedField.IsLiteral) if (!analyzedField.IsLiteral)
this.Children.Add(new AnalyzedFieldAccessNode(analyzedField, true)); this.Children.Add(new AnalyzedFieldAccessTreeNode(analyzedField, true));
} }
MemberReference IMemberTreeNode.Member { MemberReference IMemberTreeNode.Member
{
get { return analyzedField; } get { return analyzedField; }
} }
} }

105
ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceEventImplementedByTreeNode.cs

@ -0,0 +1,105 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// 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.Linq;
using System.Threading;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.TreeView;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedInterfaceEventImplementedByTreeNode : AnalyzerTreeNode
{
private readonly EventDefinition analyzedEvent;
private readonly MethodDefinition analyzedMethod;
private readonly ThreadingSupport threading;
public AnalyzedInterfaceEventImplementedByTreeNode(EventDefinition analyzedEvent)
{
if (analyzedEvent == null)
throw new ArgumentNullException("analyzedEvent");
this.analyzedEvent = analyzedEvent;
this.analyzedMethod = this.analyzedEvent.AddMethod ?? this.analyzedEvent.RemoveMethod;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
}
public override object Text
{
get { return "Implemented By"; }
}
public override object Icon
{
get { return Images.Search; }
}
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
protected override void OnCollapsing()
{
if (threading.IsRunning) {
this.LazyLoading = true;
threading.Cancel();
this.Children.Clear();
}
}
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
if (!type.HasInterfaces)
yield break;
TypeReference implementedInterfaceRef = type.Interfaces.FirstOrDefault(i => i.Resolve() == analyzedMethod.DeclaringType);
if (implementedInterfaceRef == null)
yield break;
foreach (EventDefinition ev in type.Events.Where(e => e.Name == analyzedEvent.Name)) {
MethodDefinition accessor = ev.AddMethod ?? ev.RemoveMethod;
if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef))
yield return new AnalyzedEventTreeNode(ev);
yield break;
}
foreach (EventDefinition ev in type.Events.Where(e => e.Name.EndsWith(analyzedEvent.Name))) {
MethodDefinition accessor = ev.AddMethod ?? ev.RemoveMethod;
if (accessor.HasOverrides && accessor.Overrides.Any(m => m.Resolve() == analyzedMethod)) {
yield return new AnalyzedEventTreeNode(ev);
}
}
}
public static bool CanShow(EventDefinition ev)
{
return ev.DeclaringType.IsInterface;
}
}
}

101
ILSpy/TreeNodes/Analyzer/AnalyzedInterfaceMethodImplementedByTreeNode.cs

@ -0,0 +1,101 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// 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.Linq;
using System.Threading;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.TreeView;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedInterfaceMethodImplementedByTreeNode : AnalyzerTreeNode
{
private readonly MethodDefinition analyzedMethod;
private readonly ThreadingSupport threading;
public AnalyzedInterfaceMethodImplementedByTreeNode(MethodDefinition analyzedMethod)
{
if (analyzedMethod == null)
throw new ArgumentNullException("analyzedMethod");
this.analyzedMethod = analyzedMethod;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
}
public override object Text
{
get { return "Implemented By"; }
}
public override object Icon
{
get { return Images.Search; }
}
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
protected override void OnCollapsing()
{
if (threading.IsRunning) {
this.LazyLoading = true;
threading.Cancel();
this.Children.Clear();
}
}
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
if (!type.HasInterfaces)
yield break;
TypeReference implementedInterfaceRef = type.Interfaces.FirstOrDefault(i => i.Resolve() == analyzedMethod.DeclaringType);
if (implementedInterfaceRef == null)
yield break;
foreach (MethodDefinition method in type.Methods.Where(m => m.Name == analyzedMethod.Name)) {
if (TypesHierarchyHelpers.MatchInterfaceMethod(method, analyzedMethod, implementedInterfaceRef))
yield return new AnalyzedMethodTreeNode(method);
yield break;
}
foreach (MethodDefinition method in type.Methods) {
if (method.HasOverrides && method.Overrides.Any(m => m.Resolve() == analyzedMethod)) {
yield return new AnalyzedMethodTreeNode(method);
}
}
}
public static bool CanShow(MethodDefinition method)
{
return method.DeclaringType.IsInterface;
}
}
}

105
ILSpy/TreeNodes/Analyzer/AnalyzedInterfacePropertyImplementedByTreeNode.cs

@ -0,0 +1,105 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// 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.Linq;
using System.Threading;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.TreeView;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedInterfacePropertyImplementedByTreeNode : AnalyzerTreeNode
{
private readonly PropertyDefinition analyzedProperty;
private readonly MethodDefinition analyzedMethod;
private readonly ThreadingSupport threading;
public AnalyzedInterfacePropertyImplementedByTreeNode(PropertyDefinition analyzedProperty)
{
if (analyzedProperty == null)
throw new ArgumentNullException("analyzedProperty");
this.analyzedProperty = analyzedProperty;
this.analyzedMethod = this.analyzedProperty.GetMethod ?? this.analyzedProperty.SetMethod;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
}
public override object Text
{
get { return "Implemented By"; }
}
public override object Icon
{
get { return Images.Search; }
}
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
protected override void OnCollapsing()
{
if (threading.IsRunning) {
this.LazyLoading = true;
threading.Cancel();
this.Children.Clear();
}
}
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedMethod, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
if (!type.HasInterfaces)
yield break;
TypeReference implementedInterfaceRef = type.Interfaces.FirstOrDefault(i => i.Resolve() == analyzedMethod.DeclaringType);
if (implementedInterfaceRef == null)
yield break;
foreach (PropertyDefinition property in type.Properties.Where(e => e.Name == analyzedProperty.Name)) {
MethodDefinition accessor = property.GetMethod ?? property.SetMethod;
if (TypesHierarchyHelpers.MatchInterfaceMethod(accessor, analyzedMethod, implementedInterfaceRef))
yield return new AnalyzedPropertyTreeNode(property);
yield break;
}
foreach (PropertyDefinition property in type.Properties.Where(e => e.Name.EndsWith(analyzedProperty.Name))) {
MethodDefinition accessor = property.GetMethod ?? property.SetMethod;
if (accessor.HasOverrides && accessor.Overrides.Any(m => m.Resolve() == analyzedMethod)) {
yield return new AnalyzedPropertyTreeNode(property);
}
}
}
public static bool CanShow(PropertyDefinition property)
{
return property.DeclaringType.IsInterface;
}
}
}

29
ILSpy/TreeNodes/Analyzer/AnalyzerMethodOverridesTreeNode.cs → ILSpy/TreeNodes/Analyzer/AnalyzedMethodOverridesTreeNode.cs

@ -32,12 +32,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/// <summary> /// <summary>
/// Searches for overrides of the analyzed method. /// Searches for overrides of the analyzed method.
/// </summary> /// </summary>
class AnalyzerMethodOverridesTreeNode : AnalyzerTreeNode internal sealed class AnalyzedMethodOverridesTreeNode : AnalyzerTreeNode
{ {
readonly MethodDefinition analyzedMethod; private readonly MethodDefinition analyzedMethod;
readonly ThreadingSupport threading; private readonly ThreadingSupport threading;
public AnalyzerMethodOverridesTreeNode(MethodDefinition analyzedMethod) public AnalyzedMethodOverridesTreeNode(MethodDefinition analyzedMethod)
{ {
if (analyzedMethod == null) if (analyzedMethod == null)
throw new ArgumentNullException("analyzedMethod"); throw new ArgumentNullException("analyzedMethod");
@ -64,33 +64,32 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
protected override void OnCollapsing() protected override void OnCollapsing()
{ {
if (threading.IsRunning) if (threading.IsRunning) {
{
this.LazyLoading = true; this.LazyLoading = true;
threading.Cancel(); threading.Cancel();
this.Children.Clear(); this.Children.Clear();
} }
} }
IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct);
} }
IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct)
{ {
assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null); assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
// use parallelism only on the assembly level (avoid locks within Cecil) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
} }
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct)
{ {
string asmName = asm.AssemblyDefinition.Name.Name; string asmName = asm.AssemblyDefinition.Name.Name;
string name = analyzedMethod.Name; string name = analyzedMethod.Name;
string declTypeName = analyzedMethod.DeclaringType.FullName; string declTypeName = analyzedMethod.DeclaringType.FullName;
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
{
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
SharpTreeNode newNode = null; SharpTreeNode newNode = null;
try { try {
@ -109,14 +108,18 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
catch (ReferenceResolvingException) { catch (ReferenceResolvingException) {
// ignore this type definition. maybe add a notification about such cases. // ignore this type definition. maybe add a notification about such cases.
} }
if (newNode != null) if (newNode != null)
yield return newNode; yield return newNode;
} }
} }
public static bool CanShowAnalyzer(MethodDefinition method) public static bool CanShow(MethodDefinition method)
{ {
return method.IsVirtual && !method.IsFinal && !method.DeclaringType.IsSealed && !method.DeclaringType.IsInterface; // interfaces are temporarly disabled return method.IsVirtual &&
!method.IsFinal &&
!method.DeclaringType.IsSealed &&
!method.DeclaringType.IsInterface; // interface methods are definitions not implementations - cannot be overridden
} }
} }
} }

41
ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs

@ -21,11 +21,11 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedMethodTreeNode : AnalyzerTreeNode, IMemberTreeNode internal class AnalyzedMethodTreeNode : AnalyzerTreeNode, IMemberTreeNode
{ {
MethodDefinition analyzedMethod; private readonly MethodDefinition analyzedMethod;
string prefix; private readonly string prefix;
public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod, string prefix = "") public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod, string prefix = "")
{ {
if (analyzedMethod == null) if (analyzedMethod == null)
@ -34,32 +34,39 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
this.prefix = prefix; this.prefix = prefix;
this.LazyLoading = true; this.LazyLoading = true;
} }
public override object Icon { public override object Icon
{
get { return MethodTreeNode.GetIcon(analyzedMethod); } get { return MethodTreeNode.GetIcon(analyzedMethod); }
} }
public override object Text { public override object Text
get { {
return prefix + Language.TypeToString(analyzedMethod.DeclaringType, true) + "." + MethodTreeNode.GetText(analyzedMethod, Language); } get
{
return prefix + Language.TypeToString(analyzedMethod.DeclaringType, true) + "." + MethodTreeNode.GetText(analyzedMethod, Language);
}
} }
public override void ActivateItem(System.Windows.RoutedEventArgs e) public override void ActivateItem(System.Windows.RoutedEventArgs e)
{ {
e.Handled = true; e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedMethod); MainWindow.Instance.JumpToReference(analyzedMethod);
} }
protected override void LoadChildren() protected override void LoadChildren()
{ {
if (analyzedMethod.HasBody) if (analyzedMethod.HasBody)
this.Children.Add(new AnalyzedMethodUsesNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodUsesTreeNode(analyzedMethod));
this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));
if (AnalyzerMethodOverridesTreeNode.CanShowAnalyzer(analyzedMethod)) if (AnalyzedMethodOverridesTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzerMethodOverridesTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodOverridesTreeNode(analyzedMethod));
if (AnalyzedInterfaceMethodImplementedByTreeNode.CanShow(analyzedMethod))
this.Children.Add(new AnalyzedInterfaceMethodImplementedByTreeNode(analyzedMethod));
} }
MemberReference IMemberTreeNode.Member { MemberReference IMemberTreeNode.Member
{
get { return analyzedMethod; } get { return analyzedMethod; }
} }
} }

21
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -18,20 +18,17 @@
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq;
using System.Threading; using System.Threading;
using System.Threading.Tasks;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Mono.Cecil; using Mono.Cecil;
using Mono.Cecil.Cil; using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedMethodUsedByTreeNode : AnalyzerTreeNode internal sealed class AnalyzedMethodUsedByTreeNode : AnalyzerTreeNode
{ {
MethodDefinition analyzedMethod; private readonly MethodDefinition analyzedMethod;
ThreadingSupport threading; private readonly ThreadingSupport threading;
public AnalyzedMethodUsedByTreeNode(MethodDefinition analyzedMethod) public AnalyzedMethodUsedByTreeNode(MethodDefinition analyzedMethod)
{ {
@ -67,7 +64,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer; ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
@ -75,7 +72,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return analyzer.PerformAnalysis(ct); return analyzer.PerformAnalysis(ct);
} }
IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type) private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{ {
string name = analyzedMethod.Name; string name = analyzedMethod.Name;
foreach (MethodDefinition method in type.Methods) { foreach (MethodDefinition method in type.Methods) {
@ -84,11 +81,17 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
continue; continue;
foreach (Instruction instr in method.Body.Instructions) { foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference; MethodReference mr = instr.Operand as MethodReference;
if (mr != null && mr.Name == name && Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) && mr.Resolve() == analyzedMethod) { if (mr != null &&
mr.Name == name &&
Helpers.IsReferencedBy(analyzedMethod.DeclaringType, mr.DeclaringType) &&
mr.Resolve() == analyzedMethod) {
found = true; found = true;
break; break;
} }
} }
method.Body = null;
if (found) if (found)
yield return new AnalyzedMethodTreeNode(method); yield return new AnalyzedMethodTreeNode(method);
} }

33
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesNode.cs → ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsesTreeNode.cs

@ -27,38 +27,41 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
/// <summary> /// <summary>
/// Shows the methods that are used by this method. /// Shows the methods that are used by this method.
/// </summary> /// </summary>
sealed class AnalyzedMethodUsesNode : AnalyzerTreeNode internal sealed class AnalyzedMethodUsesTreeNode : AnalyzerTreeNode
{ {
MethodDefinition analyzedMethod; private readonly MethodDefinition analyzedMethod;
public AnalyzedMethodUsesNode(MethodDefinition analyzedMethod) public AnalyzedMethodUsesTreeNode(MethodDefinition analyzedMethod)
{ {
if (analyzedMethod == null) if (analyzedMethod == null)
throw new ArgumentNullException("analyzedMethod"); throw new ArgumentNullException("analyzedMethod");
this.analyzedMethod = analyzedMethod; this.analyzedMethod = analyzedMethod;
this.LazyLoading = true; this.LazyLoading = true;
} }
public override object Text { public override object Text
{
get { return "Uses"; } get { return "Uses"; }
} }
public override object Icon { public override object Icon
{
get { return Images.Search; } get { return Images.Search; }
} }
protected override void LoadChildren() protected override void LoadChildren()
{ {
foreach (var f in GetUsedFields().Distinct()) { foreach (var f in GetUsedFields().Distinct()) {
this.Children.Add(new AnalyzedFieldNode(f)); this.Children.Add(new AnalyzedFieldTreeNode(f));
} }
foreach (var m in GetUsedMethods().Distinct()) { foreach (var m in GetUsedMethods().Distinct()) {
this.Children.Add(new AnalyzedMethodTreeNode(m)); this.Children.Add(new AnalyzedMethodTreeNode(m));
} }
analyzedMethod.Body = null;
} }
IEnumerable<MethodDefinition> GetUsedMethods() private IEnumerable<MethodDefinition> GetUsedMethods()
{ {
foreach (Instruction instr in analyzedMethod.Body.Instructions) { foreach (Instruction instr in analyzedMethod.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference; MethodReference mr = instr.Operand as MethodReference;
@ -69,8 +72,8 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
} }
IEnumerable<FieldDefinition> GetUsedFields() private IEnumerable<FieldDefinition> GetUsedFields()
{ {
foreach (Instruction instr in analyzedMethod.Body.Instructions) { foreach (Instruction instr in analyzedMethod.Body.Instructions) {
FieldReference fr = instr.Operand as FieldReference; FieldReference fr = instr.Operand as FieldReference;

32
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyAccessorsTreeNode.cs

@ -21,16 +21,13 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedPropertyAccessorsTreeNode : AnalyzerTreeNode public sealed class AnalyzedPropertyAccessorsTreeNode : AnalyzerTreeNode
{ {
PropertyDefinition analyzedProperty;
public AnalyzedPropertyAccessorsTreeNode(PropertyDefinition analyzedProperty) public AnalyzedPropertyAccessorsTreeNode(PropertyDefinition analyzedProperty)
{ {
if (analyzedProperty == null) if (analyzedProperty == null)
throw new ArgumentNullException("analyzedProperty"); throw new ArgumentNullException("analyzedProperty");
this.analyzedProperty = analyzedProperty;
if (analyzedProperty.GetMethod != null) if (analyzedProperty.GetMethod != null)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get")); this.Children.Add(new AnalyzedPropertyAccessorTreeNode(analyzedProperty.GetMethod, "get"));
if (analyzedProperty.SetMethod != null) if (analyzedProperty.SetMethod != null)
@ -38,31 +35,34 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
foreach (var accessor in analyzedProperty.OtherMethods) foreach (var accessor in analyzedProperty.OtherMethods)
this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null)); this.Children.Add(new AnalyzedPropertyAccessorTreeNode(accessor, null));
} }
public override object Icon { public override object Icon
{
get { return Images.Search; } get { return Images.Search; }
} }
public override object Text { public override object Text
{
get { return "Accessors"; } get { return "Accessors"; }
} }
public static bool CanShow(PropertyDefinition property) public static bool CanShow(PropertyDefinition property)
{ {
return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod ?? property.SetMethod); return !MainWindow.Instance.CurrentLanguage.ShowMember(property.GetMethod ?? property.SetMethod);
} }
class AnalyzedPropertyAccessorTreeNode : AnalyzedMethodTreeNode private class AnalyzedPropertyAccessorTreeNode : AnalyzedMethodTreeNode
{ {
string name; private readonly string name;
public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name) public AnalyzedPropertyAccessorTreeNode(MethodDefinition analyzedMethod, string name)
: base(analyzedMethod) : base(analyzedMethod)
{ {
this.name = name; this.name = name;
} }
public override object Text { public override object Text
{
get { return name ?? base.Text; } get { return name ?? base.Text; }
} }
} }

16
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyOverridesTreeNode.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.Text;
using System.Threading; using System.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.Ast; using ICSharpCode.Decompiler.Ast;
@ -29,10 +28,10 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedPropertyOverridesTreeNode : AnalyzerTreeNode internal sealed class AnalyzedPropertyOverridesTreeNode : AnalyzerTreeNode
{ {
readonly PropertyDefinition analyzedProperty; private readonly PropertyDefinition analyzedProperty;
readonly ThreadingSupport threading; private readonly ThreadingSupport threading;
public AnalyzedPropertyOverridesTreeNode(PropertyDefinition analyzedProperty) public AnalyzedPropertyOverridesTreeNode(PropertyDefinition analyzedProperty)
{ {
@ -68,19 +67,20 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct) private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{ {
return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct); return FindReferences(MainWindow.Instance.CurrentAssemblyList.GetAssemblies(), ct);
} }
IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferences(IEnumerable<LoadedAssembly> assemblies, CancellationToken ct)
{ {
assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null); assemblies = assemblies.Where(asm => asm.AssemblyDefinition != null);
// use parallelism only on the assembly level (avoid locks within Cecil) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
} }
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct) private IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct)
{ {
string asmName = asm.AssemblyDefinition.Name.Name; string asmName = asm.AssemblyDefinition.Name.Name;
string name = analyzedProperty.Name; string name = analyzedProperty.Name;
@ -111,7 +111,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
public static bool CanShowAnalyzer(PropertyDefinition property) public static bool CanShow(PropertyDefinition property)
{ {
var accessor = property.GetMethod ?? property.SetMethod; var accessor = property.GetMethod ?? property.SetMethod;
return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface; return accessor.IsVirtual && !accessor.IsFinal && !accessor.DeclaringType.IsInterface;

45
ILSpy/TreeNodes/Analyzer/AnalyzedPropertyTreeNode.cs

@ -17,52 +17,55 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using Mono.Cecil;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzedPropertyTreeNode : AnalyzerTreeNode internal sealed class AnalyzedPropertyTreeNode : AnalyzerTreeNode
{ {
PropertyDefinition analyzedProperty; private readonly PropertyDefinition analyzedProperty;
bool isIndexer; private readonly bool isIndexer;
string prefix; private readonly string prefix;
public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "") public AnalyzedPropertyTreeNode(PropertyDefinition analyzedProperty, string prefix = "")
{ {
if (analyzedProperty == null) if (analyzedProperty == null)
throw new ArgumentNullException("analyzedMethod"); throw new ArgumentNullException("analyzedProperty");
this.isIndexer = analyzedProperty.IsIndexer(); this.isIndexer = analyzedProperty.IsIndexer();
this.analyzedProperty = analyzedProperty; this.analyzedProperty = analyzedProperty;
this.prefix = prefix; this.prefix = prefix;
this.LazyLoading = true; this.LazyLoading = true;
} }
public override object Icon { public override object Icon
{
get { return PropertyTreeNode.GetIcon(analyzedProperty, isIndexer); } get { return PropertyTreeNode.GetIcon(analyzedProperty, isIndexer); }
} }
public override object Text { public override object Text
get { {
get
{
// TODO: This way of formatting is not suitable for properties which explicitly implement interfaces. // TODO: This way of formatting is not suitable for properties which explicitly implement interfaces.
return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language, isIndexer); } return prefix + Language.TypeToString(analyzedProperty.DeclaringType, true) + "." + PropertyTreeNode.GetText(analyzedProperty, Language, isIndexer);
}
} }
public override void ActivateItem(System.Windows.RoutedEventArgs e) public override void ActivateItem(System.Windows.RoutedEventArgs e)
{ {
e.Handled = true; e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedProperty); MainWindow.Instance.JumpToReference(analyzedProperty);
} }
protected override void LoadChildren() protected override void LoadChildren()
{ {
if(AnalyzedPropertyAccessorsTreeNode.CanShow(analyzedProperty)) if (AnalyzedPropertyAccessorsTreeNode.CanShow(analyzedProperty))
this.Children.Add(new AnalyzedPropertyAccessorsTreeNode(analyzedProperty)); this.Children.Add(new AnalyzedPropertyAccessorsTreeNode(analyzedProperty));
if (AnalyzedPropertyOverridesTreeNode.CanShowAnalyzer(analyzedProperty)) if (AnalyzedPropertyOverridesTreeNode.CanShow(analyzedProperty))
this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty)); this.Children.Add(new AnalyzedPropertyOverridesTreeNode(analyzedProperty));
//if (analyzedProperty.HasBody) if (AnalyzedInterfacePropertyImplementedByTreeNode.CanShow(analyzedProperty))
// this.Children.Add(new AnalyzedMethodUsesNode(analyzedProperty)); this.Children.Add(new AnalyzedInterfacePropertyImplementedByTreeNode(analyzedProperty));
//this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedProperty));
} }
public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member) public static AnalyzerTreeNode TryCreateAnalyzer(MemberReference member)
@ -80,7 +83,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return false; return false;
return AnalyzedPropertyAccessorsTreeNode.CanShow(property) return AnalyzedPropertyAccessorsTreeNode.CanShow(property)
|| AnalyzedPropertyOverridesTreeNode.CanShowAnalyzer(property); || AnalyzedPropertyOverridesTreeNode.CanShow(property);
} }
} }
} }

184
ILSpy/TreeNodes/Analyzer/AnalyzedTypeExposedByTreeNode.cs

@ -0,0 +1,184 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// 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.Threading;
using ICSharpCode.TreeView;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedTypeExposedByTreeNode : AnalyzerTreeNode
{
private readonly TypeDefinition analyzedType;
private readonly ThreadingSupport threading;
public AnalyzedTypeExposedByTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
}
public override object Text
{
get { return "Exposed By"; }
}
public override object Icon
{
get { return Images.Search; }
}
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
protected override void OnCollapsing()
{
if (threading.IsRunning) {
this.LazyLoading = true;
threading.Cancel();
this.Children.Clear();
}
}
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
if (analyzedType.IsEnum && type == analyzedType)
yield break;
if (!this.Language.ShowMember(type))
yield break;
foreach (FieldDefinition field in type.Fields) {
if (TypeIsExposedBy(field))
yield return new AnalyzedFieldTreeNode(field);
}
foreach (PropertyDefinition property in type.Properties) {
if (TypeIsExposedBy(property))
yield return new AnalyzedPropertyTreeNode(property);
}
foreach (EventDefinition eventDef in type.Events) {
if (TypeIsExposedBy(eventDef))
yield return new AnalyzedEventTreeNode(eventDef);
}
foreach (MethodDefinition method in type.Methods) {
if (TypeIsExposedBy(method))
yield return new AnalyzedMethodTreeNode(method);
}
}
private bool TypeIsExposedBy(FieldDefinition field)
{
if (field.IsPrivate)
return false;
if (field.FieldType.Resolve() == analyzedType)
return true;
return false;
}
private bool TypeIsExposedBy(PropertyDefinition property)
{
if (IsPrivate(property))
return false;
if (property.PropertyType.Resolve() == analyzedType)
return true;
return false;
}
private bool TypeIsExposedBy(EventDefinition eventDef)
{
if (IsPrivate(eventDef))
return false;
if (eventDef.EventType.Resolve() == analyzedType)
return true;
return false;
}
private bool TypeIsExposedBy(MethodDefinition method)
{
// if the method has overrides, it is probably an explicit interface member
// and should be considered part of the public API even though it is marked private.
if (method.IsPrivate) {
if (!method.HasOverrides)
return false;
else if (!method.Overrides[0].DeclaringType.Resolve().IsInterface)
return false;
}
// exclude methods with 'semantics'. for example, property getters & setters.
// HACK: this is a potentially fragile implementation, as the MethodSemantics may be extended to other uses at a later date.
if (method.SemanticsAttributes != MethodSemanticsAttributes.None)
return false;
if (method.ReturnType.Resolve() == analyzedType)
return true;
if (method.HasParameters) {
foreach (var parameter in method.Parameters) {
if (parameter.ParameterType.Resolve() == analyzedType)
return true;
}
}
return false;
}
private static bool IsPrivate(PropertyDefinition property)
{
bool isGetterPublic = (property.GetMethod != null && !property.GetMethod.IsPrivate);
bool isSetterPublic = (property.SetMethod != null && !property.SetMethod.IsPrivate);
return !(isGetterPublic || isSetterPublic);
}
private static bool IsPrivate(EventDefinition eventDef)
{
bool isAdderPublic = (eventDef.AddMethod != null && !eventDef.AddMethod.IsPrivate);
bool isRemoverPublic = (eventDef.RemoveMethod != null && !eventDef.RemoveMethod.IsPrivate);
return !(isAdderPublic || isRemoverPublic);
}
public static bool CanShow(TypeDefinition type)
{
return true;
}
}
}

93
ILSpy/TreeNodes/Analyzer/AnalyzedTypeExtensionMethodsTreeNode.cs

@ -0,0 +1,93 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// 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.Linq;
using System.Threading;
using ICSharpCode.TreeView;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal class AnalyzedTypeExtensionMethodsTreeNode : AnalyzerTreeNode
{
private readonly TypeDefinition analyzedType;
private readonly ThreadingSupport threading;
public AnalyzedTypeExtensionMethodsTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
}
public override object Text
{
get { return "Extension Methods"; }
}
public override object Icon
{
get { return Images.Search; }
}
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
protected override void OnCollapsing()
{
if (threading.IsRunning) {
this.LazyLoading = true;
threading.Cancel();
this.Children.Clear();
}
}
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
foreach (MethodDefinition method in type.Methods) {
if (method.IsStatic && method.HasCustomAttributes) {
if (method.CustomAttributes.Any(ca => ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")) {
if (method.HasParameters && method.Parameters[0].ParameterType.Resolve() == analyzedType) {
yield return new AnalyzedMethodTreeNode(method);
}
}
}
}
}
public static bool CanShow(TypeDefinition type)
{
return !(type.IsEnum);
}
}
}

118
ILSpy/TreeNodes/Analyzer/AnalyzedTypeInstantiationsTreeNode.cs

@ -0,0 +1,118 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// 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.Linq;
using System.Threading;
using ICSharpCode.Decompiler.Ast;
using ICSharpCode.TreeView;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal sealed class AnalyzedTypeInstantiationsTreeNode : AnalyzerTreeNode
{
private readonly TypeDefinition analyzedType;
private readonly ThreadingSupport threading;
private readonly bool isSystemObject;
public AnalyzedTypeInstantiationsTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.threading = new ThreadingSupport();
this.LazyLoading = true;
this.isSystemObject = (analyzedType.FullName == "System.Object");
}
public override object Text
{
get { return "Instantiated By"; }
}
public override object Icon
{
get { return Images.Search; }
}
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
protected override void OnCollapsing()
{
if (threading.IsRunning) {
this.LazyLoading = true;
threading.Cancel();
this.Children.Clear();
}
}
private IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
ScopedWhereUsedScopeAnalyzer<SharpTreeNode> analyzer;
analyzer = new ScopedWhereUsedScopeAnalyzer<SharpTreeNode>(analyzedType, FindReferencesInType);
return analyzer.PerformAnalysis(ct);
}
private IEnumerable<SharpTreeNode> FindReferencesInType(TypeDefinition type)
{
foreach (MethodDefinition method in type.Methods) {
bool found = false;
if (!method.HasBody)
continue;
// ignore chained constructors
// (since object is the root of everything, we can short circuit the test in this case)
if (method.Name == ".ctor" &&
(isSystemObject || analyzedType == type || TypesHierarchyHelpers.IsBaseType(analyzedType, type, false)))
continue;
foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference;
if (mr != null && mr.Name == ".ctor") {
if (Helpers.IsReferencedBy(analyzedType, mr.DeclaringType)) {
found = true;
break;
}
}
}
method.Body = null;
if (found)
yield return new AnalyzedMethodTreeNode(method);
}
}
public static bool CanShow(TypeDefinition type)
{
if (type.IsClass && !type.IsEnum) {
return type.Methods.Where(m => m.Name == ".ctor").Any(m => !m.IsPrivate);
}
return false;
}
}
}

72
ILSpy/TreeNodes/Analyzer/AnalyzedTypeTreeNode.cs

@ -0,0 +1,72 @@
// Copyright (c) 2011 AlphaSierraPapa for the SharpDevelop Team
//
// Permission is hereby granted, free of charge, to any person obtaining a copy of this
// software and associated documentation files (the "Software"), to deal in the Software
// without restriction, including without limitation the rights to use, copy, modify, merge,
// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons
// to whom the Software is furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in all copies or
// substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED,
// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR
// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE
// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR
// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
// DEALINGS IN THE SOFTWARE.
using System;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
internal class AnalyzedTypeTreeNode : AnalyzerTreeNode, IMemberTreeNode
{
private readonly TypeDefinition analyzedType;
public AnalyzedTypeTreeNode(TypeDefinition analyzedType)
{
if (analyzedType == null)
throw new ArgumentNullException("analyzedType");
this.analyzedType = analyzedType;
this.LazyLoading = true;
}
public override object Icon
{
get { return TypeTreeNode.GetIcon(analyzedType); }
}
public override object Text
{
get
{
return Language.TypeToString(analyzedType, true);
}
}
public override void ActivateItem(System.Windows.RoutedEventArgs e)
{
e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedType);
}
protected override void LoadChildren()
{
if (AnalyzedTypeInstantiationsTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeInstantiationsTreeNode(analyzedType));
if (AnalyzedTypeExposedByTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeExposedByTreeNode(analyzedType));
if (AnalyzedTypeExtensionMethodsTreeNode.CanShow(analyzedType))
this.Children.Add(new AnalyzedTypeExtensionMethodsTreeNode(analyzedType));
}
MemberReference IMemberTreeNode.Member
{
get { return analyzedType; }
}
}
}

18
ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs

@ -24,11 +24,13 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
public class AnalyzerTreeNode : SharpTreeNode public class AnalyzerTreeNode : SharpTreeNode
{ {
Language language; private Language language;
public Language Language { public Language Language
{
get { return language; } get { return language; }
set { set
{
if (language != value) { if (language != value) {
language = value; language = value;
foreach (var child in this.Children.OfType<AnalyzerTreeNode>()) foreach (var child in this.Children.OfType<AnalyzerTreeNode>())
@ -36,22 +38,22 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
} }
public override bool CanDelete() public override bool CanDelete()
{ {
return Parent != null && Parent.IsRoot; return Parent != null && Parent.IsRoot;
} }
public override void DeleteCore() public override void DeleteCore()
{ {
Parent.Children.Remove(this); Parent.Children.Remove(this);
} }
public override void Delete() public override void Delete()
{ {
DeleteCore(); DeleteCore();
} }
protected override void OnChildrenChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e) protected override void OnChildrenChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{ {
if (e.NewItems != null) { if (e.NewItems != null) {

2
ILSpy/TreeNodes/Analyzer/Helpers.cs

@ -24,7 +24,7 @@ using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
static class Helpers internal static class Helpers
{ {
public static bool IsReferencedBy(TypeDefinition type, TypeReference typeRef) public static bool IsReferencedBy(TypeDefinition type, TypeReference typeRef)
{ {

23
ILSpy/TreeNodes/Analyzer/ScopedWhereUsedAnalyzer.cs

@ -20,9 +20,8 @@ using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Linq; using System.Linq;
using System.Threading; using System.Threading;
using Mono.Cecil;
using ICSharpCode.NRefactory.Utils; using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView; using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
@ -38,7 +37,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
private Accessibility typeAccessibility = Accessibility.Public; private Accessibility typeAccessibility = Accessibility.Public;
private Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction; private Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction;
private ScopedWhereUsedScopeAnalyzer(TypeDefinition type, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction) public ScopedWhereUsedScopeAnalyzer(TypeDefinition type, Func<TypeDefinition, IEnumerable<T>> typeAnalysisFunction)
{ {
this.typeScope = type; this.typeScope = type;
this.assemblyScope = type.Module.Assembly; this.assemblyScope = type.Module.Assembly;
@ -109,7 +108,6 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
return FindReferencesInTypeScope(ct); return FindReferencesInTypeScope(ct);
} }
if (memberAccessibility == Accessibility.Internal || if (memberAccessibility == Accessibility.Internal ||
memberAccessibility == Accessibility.FamilyAndInternal || memberAccessibility == Accessibility.FamilyAndInternal ||
typeAccessibility == Accessibility.Internal || typeAccessibility == Accessibility.Internal ||
@ -137,7 +135,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
private Accessibility GetNestedTypeAccessibility(TypeDefinition type) private static Accessibility GetNestedTypeAccessibility(TypeDefinition type)
{ {
Accessibility result; Accessibility result;
switch (type.Attributes & TypeAttributes.VisibilityMask) { switch (type.Attributes & TypeAttributes.VisibilityMask) {
@ -178,22 +176,23 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
Public Public
} }
private IEnumerable<T> FindReferencesInAssemblyAndFriends(CancellationToken ct)
IEnumerable<T> FindReferencesInAssemblyAndFriends(CancellationToken ct)
{ {
var assemblies = GetAssemblyAndAnyFriends(assemblyScope, ct); var assemblies = GetAssemblyAndAnyFriends(assemblyScope, ct);
// use parallelism only on the assembly level (avoid locks within Cecil) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((AssemblyDefinition a) => FindReferencesInAssembly(a, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((AssemblyDefinition a) => FindReferencesInAssembly(a, ct));
} }
IEnumerable<T> FindReferencesGlobal(CancellationToken ct) private IEnumerable<T> FindReferencesGlobal(CancellationToken ct)
{ {
var assemblies = GetReferencingAssemblies(assemblyScope, ct); var assemblies = GetReferencingAssemblies(assemblyScope, ct);
// use parallelism only on the assembly level (avoid locks within Cecil) // use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((AssemblyDefinition asm) => FindReferencesInAssembly(asm, ct)); return assemblies.AsParallel().WithCancellation(ct).SelectMany((AssemblyDefinition asm) => FindReferencesInAssembly(asm, ct));
} }
IEnumerable<T> FindReferencesInAssembly(AssemblyDefinition asm, CancellationToken ct) private IEnumerable<T> FindReferencesInAssembly(AssemblyDefinition asm, CancellationToken ct)
{ {
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.MainModule.Types, t => t.NestedTypes)) { foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
@ -204,7 +203,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
IEnumerable<T> FindReferencesInTypeScope(CancellationToken ct) private IEnumerable<T> FindReferencesInTypeScope(CancellationToken ct)
{ {
foreach (TypeDefinition type in TreeTraversal.PreOrder(typeScope, t => t.NestedTypes)) { foreach (TypeDefinition type in TreeTraversal.PreOrder(typeScope, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
@ -215,7 +214,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
IEnumerable<AssemblyDefinition> GetReferencingAssemblies(AssemblyDefinition asm, CancellationToken ct) private IEnumerable<AssemblyDefinition> GetReferencingAssemblies(AssemblyDefinition asm, CancellationToken ct)
{ {
yield return asm; yield return asm;
@ -237,7 +236,7 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
} }
} }
IEnumerable<AssemblyDefinition> GetAssemblyAndAnyFriends(AssemblyDefinition asm, CancellationToken ct) private IEnumerable<AssemblyDefinition> GetAssemblyAndAnyFriends(AssemblyDefinition asm, CancellationToken ct)
{ {
yield return asm; yield return asm;

78
ILSpy/TreeNodes/AssemblyTreeNode.cs

@ -41,35 +41,39 @@ namespace ICSharpCode.ILSpy.TreeNodes
public sealed class AssemblyTreeNode : ILSpyTreeNode public sealed class AssemblyTreeNode : ILSpyTreeNode
{ {
readonly LoadedAssembly assembly; readonly LoadedAssembly assembly;
readonly List<TypeTreeNode> classes = new List<TypeTreeNode>();
readonly Dictionary<string, NamespaceTreeNode> namespaces = new Dictionary<string, NamespaceTreeNode>(); readonly Dictionary<string, NamespaceTreeNode> namespaces = new Dictionary<string, NamespaceTreeNode>();
public AssemblyTreeNode(LoadedAssembly assembly) public AssemblyTreeNode(LoadedAssembly assembly)
{ {
if (assembly == null) if (assembly == null)
throw new ArgumentNullException("assembly"); throw new ArgumentNullException("assembly");
this.assembly = assembly; this.assembly = assembly;
assembly.ContinueWhenLoaded(OnAssemblyLoaded, TaskScheduler.FromCurrentSynchronizationContext()); assembly.ContinueWhenLoaded(OnAssemblyLoaded, TaskScheduler.FromCurrentSynchronizationContext());
this.LazyLoading = true; this.LazyLoading = true;
} }
public AssemblyList AssemblyList { public AssemblyList AssemblyList
{
get { return assembly.AssemblyList; } get { return assembly.AssemblyList; }
} }
public LoadedAssembly LoadedAssembly { public LoadedAssembly LoadedAssembly
{
get { return assembly; } get { return assembly; }
} }
public override object Text { public override object Text
{
get { return HighlightSearchMatch(assembly.ShortName); } get { return HighlightSearchMatch(assembly.ShortName); }
} }
public override object Icon { public override object Icon
get { {
get
{
if (assembly.IsLoaded) { if (assembly.IsLoaded) {
return assembly.HasLoadError ? Images.AssemblyWarning : Images.Assembly; return assembly.HasLoadError ? Images.AssemblyWarning : Images.Assembly;
} else { } else {
@ -77,11 +81,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
} }
} }
public override bool ShowExpander { public override bool ShowExpander
{
get { return !assembly.HasLoadError; } get { return !assembly.HasLoadError; }
} }
void OnAssemblyLoaded(Task<AssemblyDefinition> assemblyTask) void OnAssemblyLoaded(Task<AssemblyDefinition> assemblyTask)
{ {
// change from "Loading" icon to final icon // change from "Loading" icon to final icon
@ -90,14 +95,15 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (assemblyTask.IsFaulted) { if (assemblyTask.IsFaulted) {
RaisePropertyChanged("ShowExpander"); // cannot expand assemblies with load error RaisePropertyChanged("ShowExpander"); // cannot expand assemblies with load error
// observe the exception so that the Task's finalizer doesn't re-throw it // observe the exception so that the Task's finalizer doesn't re-throw it
try { assemblyTask.Wait(); } catch (AggregateException) {} try { assemblyTask.Wait(); }
catch (AggregateException) { }
} else { } else {
RaisePropertyChanged("Text"); // shortname might have changed RaisePropertyChanged("Text"); // shortname might have changed
} }
} }
Dictionary<TypeDefinition, TypeTreeNode> typeDict = new Dictionary<TypeDefinition, TypeTreeNode>(); Dictionary<TypeDefinition, TypeTreeNode> typeDict = new Dictionary<TypeDefinition, TypeTreeNode>();
protected override void LoadChildren() protected override void LoadChildren()
{ {
AssemblyDefinition assemblyDefinition = assembly.AssemblyDefinition; AssemblyDefinition assemblyDefinition = assembly.AssemblyDefinition;
@ -106,7 +112,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return; return;
} }
ModuleDefinition mainModule = assemblyDefinition.MainModule; ModuleDefinition mainModule = assemblyDefinition.MainModule;
this.Children.Add(new ReferenceFolderTreeNode(mainModule, this)); this.Children.Add(new ReferenceFolderTreeNode(mainModule, this));
if (mainModule.HasResources) if (mainModule.HasResources)
this.Children.Add(new ResourceListTreeNode(mainModule)); this.Children.Add(new ResourceListTreeNode(mainModule));
@ -128,7 +134,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.Children.Add(ns); this.Children.Add(ns);
} }
} }
public TypeTreeNode FindTypeNode(TypeDefinition def) public TypeTreeNode FindTypeNode(TypeDefinition def)
{ {
if (def == null) if (def == null)
@ -140,41 +146,41 @@ namespace ICSharpCode.ILSpy.TreeNodes
else else
return null; return null;
} }
public override bool CanDrag(SharpTreeNode[] nodes) public override bool CanDrag(SharpTreeNode[] nodes)
{ {
return nodes.All(n => n is AssemblyTreeNode); return nodes.All(n => n is AssemblyTreeNode);
} }
public override void StartDrag(DependencyObject dragSource, SharpTreeNode[] nodes) public override void StartDrag(DependencyObject dragSource, SharpTreeNode[] nodes)
{ {
DragDrop.DoDragDrop(dragSource, Copy(nodes), DragDropEffects.All); DragDrop.DoDragDrop(dragSource, Copy(nodes), DragDropEffects.All);
} }
public override bool CanDelete() public override bool CanDelete()
{ {
return true; return true;
} }
public override void Delete() public override void Delete()
{ {
DeleteCore(); DeleteCore();
} }
public override void DeleteCore() public override void DeleteCore()
{ {
assembly.AssemblyList.Unload(assembly); assembly.AssemblyList.Unload(assembly);
} }
internal const string DataFormat = "ILSpyAssemblies"; internal const string DataFormat = "ILSpyAssemblies";
public override IDataObject Copy(SharpTreeNode[] nodes) public override IDataObject Copy(SharpTreeNode[] nodes)
{ {
DataObject dataObject = new DataObject(); DataObject dataObject = new DataObject();
dataObject.SetData(DataFormat, nodes.OfType<AssemblyTreeNode>().Select(n => n.LoadedAssembly.FileName).ToArray()); dataObject.SetData(DataFormat, nodes.OfType<AssemblyTreeNode>().Select(n => n.LoadedAssembly.FileName).ToArray());
return dataObject; return dataObject;
} }
public override FilterResult Filter(FilterSettings settings) public override FilterResult Filter(FilterSettings settings)
{ {
if (settings.SearchTermMatches(assembly.ShortName)) if (settings.SearchTermMatches(assembly.ShortName))
@ -182,13 +188,13 @@ namespace ICSharpCode.ILSpy.TreeNodes
else else
return FilterResult.Recurse; return FilterResult.Recurse;
} }
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{ {
assembly.WaitUntilLoaded(); // necessary so that load errors are passed on to the caller assembly.WaitUntilLoaded(); // necessary so that load errors are passed on to the caller
language.DecompileAssembly(assembly, output, options); language.DecompileAssembly(assembly, output, options);
} }
public override bool Save(DecompilerTextView textView) public override bool Save(DecompilerTextView textView)
{ {
Language language = this.Language; Language language = this.Language;
@ -215,12 +221,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
} }
} }
textView.SaveToDisk(language, new[]{this}, options, dlg.FileName); textView.SaveToDisk(language, new[] { this }, options, dlg.FileName);
} }
return true; return true;
} }
} }
[ExportContextMenuEntry(Header = "_Remove", Icon = "images/Delete.png")] [ExportContextMenuEntry(Header = "_Remove", Icon = "images/Delete.png")]
sealed class RemoveAssembly : IContextMenuEntry sealed class RemoveAssembly : IContextMenuEntry
{ {
@ -228,12 +234,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
return selectedNodes.All(n => n is AssemblyTreeNode); return selectedNodes.All(n => n is AssemblyTreeNode);
} }
public bool IsEnabled(SharpTreeNode[] selectedNodes) public bool IsEnabled(SharpTreeNode[] selectedNodes)
{ {
return true; return true;
} }
public void Execute(SharpTreeNode[] selectedNodes) public void Execute(SharpTreeNode[] selectedNodes)
{ {
foreach (var node in selectedNodes) { foreach (var node in selectedNodes) {

46
ILSpy/TreeNodes/ResourceEntryNode.cs

@ -37,17 +37,25 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// </summary> /// </summary>
public class ResourceEntryNode : ILSpyTreeNode public class ResourceEntryNode : ILSpyTreeNode
{ {
protected readonly string key; private readonly string key;
protected readonly Stream data; private readonly Stream data;
public override object Text { public override object Text
{
get { return key.ToString(); } get { return key.ToString(); }
} }
public override object Icon { public override object Icon
{
get { return Images.Resource; } get { return Images.Resource; }
} }
protected Stream Data
{
get { return data; }
}
public ResourceEntryNode(string key, Stream data) public ResourceEntryNode(string key, Stream data)
{ {
if (key == null) if (key == null)
@ -57,7 +65,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
this.key = key; this.key = key;
this.data = data; this.data = data;
} }
public static ILSpyTreeNode Create(string key, Stream data) public static ILSpyTreeNode Create(string key, Stream data)
{ {
ILSpyTreeNode result = null; ILSpyTreeNode result = null;
@ -68,12 +76,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
return result ?? new ResourceEntryNode(key, data); return result ?? new ResourceEntryNode(key, data);
} }
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options) public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{ {
language.WriteCommentLine(output, string.Format("{0} = {1}", key, data)); language.WriteCommentLine(output, string.Format("{0} = {1}", key, data));
} }
public override bool Save(DecompilerTextView textView) public override bool Save(DecompilerTextView textView)
{ {
SaveFileDialog dlg = new SaveFileDialog(); SaveFileDialog dlg = new SaveFileDialog();
@ -87,12 +95,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
return true; return true;
} }
} }
[Export(typeof(IResourceNodeFactory))] [Export(typeof(IResourceNodeFactory))]
sealed class ImageResourceNodeFactory : IResourceNodeFactory sealed class ImageResourceNodeFactory : IResourceNodeFactory
{ {
static readonly string[] imageFileExtensions = { ".png", ".gif", ".bmp", ".jpg", ".ico" }; static readonly string[] imageFileExtensions = { ".png", ".gif", ".bmp", ".jpg", ".ico" };
public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource) public ILSpyTreeNode CreateNode(Mono.Cecil.Resource resource)
{ {
EmbeddedResource er = resource as EmbeddedResource; EmbeddedResource er = resource as EmbeddedResource;
@ -101,7 +109,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
return null; return null;
} }
public ILSpyTreeNode CreateNode(string key, Stream data) public ILSpyTreeNode CreateNode(string key, Stream data)
{ {
foreach (string fileExt in imageFileExtensions) { foreach (string fileExt in imageFileExtensions) {
@ -111,10 +119,11 @@ namespace ICSharpCode.ILSpy.TreeNodes
return null; return null;
} }
} }
sealed class ImageResourceEntryNode : ResourceEntryNode sealed class ImageResourceEntryNode : ResourceEntryNode
{ {
public ImageResourceEntryNode(string key, Stream data) : base(key, data) public ImageResourceEntryNode(string key, Stream data)
: base(key, data)
{ {
} }
@ -127,17 +136,18 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
try { try {
AvalonEditTextOutput output = new AvalonEditTextOutput(); AvalonEditTextOutput output = new AvalonEditTextOutput();
data.Position = 0; Data.Position = 0;
BitmapImage image = new BitmapImage(); BitmapImage image = new BitmapImage();
image.BeginInit(); image.BeginInit();
image.StreamSource = data; image.StreamSource = Data;
image.EndInit(); image.EndInit();
output.AddUIElement(() => new Image { Source = image }); output.AddUIElement(() => new Image { Source = image });
output.WriteLine(); output.WriteLine();
output.AddButton(Images.Save, "Save", delegate { Save(null); }); output.AddButton(Images.Save, "Save", delegate { Save(null); });
textView.Show(output, null); textView.Show(output, null);
return true; return true;
} catch (Exception) { }
catch (Exception) {
return false; return false;
} }
} }

2
ILSpy/TreeNodes/XamlResourceNode.cs

@ -63,7 +63,7 @@ namespace ICSharpCode.ILSpy.Xaml
try { try {
// cache read XAML because stream will be closed after first read // cache read XAML because stream will be closed after first read
if (xaml == null) { if (xaml == null) {
using (var reader = new StreamReader(data)) { using (var reader = new StreamReader(Data)) {
xaml = reader.ReadToEnd(); xaml = reader.ReadToEnd();
} }
} }

Loading…
Cancel
Save