Browse Source

Merge branch 'master' of git://github.com/icsharpcode/ILSpy into Debugger

pull/191/merge
Eusebiu Marcu 14 years ago
parent
commit
077d5b3046
  1. 19
      ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs
  2. 51
      ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs
  3. 6
      ILSpy/ILSpy.csproj
  4. 1
      ILSpy/Images/Images.cs
  5. 52
      ILSpy/MainWindow.xaml
  6. 62
      ILSpy/MainWindow.xaml.cs
  7. 3
      ILSpy/SessionSettings.cs
  8. 15
      ILSpy/TextView/DecompilerTextView.cs
  9. 55
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
  10. 103
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
  11. 64
      ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs
  12. 8
      ILSpy/TreeNodes/AssemblyListTreeNode.cs
  13. 28
      ILSpy/TreeNodes/DerivedTypesTreeNode.cs
  14. 2
      ILSpy/TreeNodes/ILSpyTreeNode.cs
  15. 59
      ILSpy/TreeNodes/MethodTreeNode.cs
  16. 105
      ILSpy/TreeNodes/ThreadedTreeNode.cs
  17. 139
      ILSpy/TreeNodes/ThreadingSupport.cs
  18. 4
      ILSpy/themes/generic.xaml
  19. 2
      SharpTreeView/SharpTreeNodeCollection.cs

19
ICSharpCode.Decompiler/Ast/AstMethodBodyBuilder.cs

@ -116,20 +116,11 @@ namespace Decompiler @@ -116,20 +116,11 @@ namespace Decompiler
yield return (Statement)TransformExpression(ilLoop.PostLoopGoto);
} else if (node is ILCondition) {
ILCondition conditionalNode = (ILCondition)node;
if (conditionalNode.FalseBlock.Body.Any()) {
// Swap bodies
yield return new Ast.IfElseStatement {
Condition = new UnaryOperatorExpression(UnaryOperatorType.Not, MakeBranchCondition(conditionalNode.Condition)),
TrueStatement = TransformBlock(conditionalNode.FalseBlock),
FalseStatement = TransformBlock(conditionalNode.TrueBlock)
};
} else {
yield return new Ast.IfElseStatement {
Condition = MakeBranchCondition(conditionalNode.Condition),
TrueStatement = TransformBlock(conditionalNode.TrueBlock),
FalseStatement = TransformBlock(conditionalNode.FalseBlock)
};
}
yield return new Ast.IfElseStatement {
Condition = MakeBranchCondition(conditionalNode.Condition),
TrueStatement = TransformBlock(conditionalNode.TrueBlock),
FalseStatement = TransformBlock(conditionalNode.FalseBlock)
};
} else if (node is ILSwitch) {
ILSwitch ilSwitch = (ILSwitch)node;
SwitchStatement switchStmt = new SwitchStatement() { Expression = (Expression)TransformExpression(ilSwitch.Condition.Arguments[0]) };

51
ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs

@ -314,7 +314,7 @@ namespace Decompiler.ControlFlow @@ -314,7 +314,7 @@ namespace Decompiler.ControlFlow
&& node.DominanceFrontier.Contains(node)
&& (node != entryPoint || !excludeEntryPoint))
{
HashSet<ControlFlowNode> loopContents = FindDominatedNodes(scope, node);
HashSet<ControlFlowNode> loopContents = FindLoopContent(scope, node);
ILWhileLoop loop = new ILWhileLoop();
@ -484,6 +484,35 @@ namespace Decompiler.ControlFlow @@ -484,6 +484,35 @@ namespace Decompiler.ControlFlow
scope.ExceptWith(content);
ilCond.FalseBlock.Body.AddRange(FindConditions(content, falseTarget));
}
if (scope.Count == 0) {
// We have removed the whole scope - eliminte one of the condition bodies
int trueSize = ilCond.TrueBlock.GetSelfAndChildrenRecursive<ILNode>().Count();
int falseSize = ilCond.FalseBlock.GetSelfAndChildrenRecursive<ILNode>().Count();
// The block are protected
Debug.Assert(ilCond.TrueBlock.EntryGoto != null);
Debug.Assert(ilCond.FalseBlock.EntryGoto != null);
if (falseSize > trueSize) {
// Move the false body out
result.AddRange(ilCond.FalseBlock.Body);
ilCond.FalseBlock.Body.Clear();
} else {
// Move the true body out
result.AddRange(ilCond.TrueBlock.Body);
ilCond.TrueBlock.Body.Clear();
}
}
// If true body is empty, swap bodies.
// Might happend because there was not any to start with or we moved it out.
if (ilCond.TrueBlock.Body.Count == 0 && ilCond.FalseBlock.Body.Count > 0) {
ILBlock tmp = ilCond.TrueBlock;
ilCond.TrueBlock = ilCond.FalseBlock;
ilCond.FalseBlock = tmp;
ilCond.Condition = new ILExpression(ILCode.LogicNot, null, ilCond.Condition);
}
}
}
@ -509,6 +538,26 @@ namespace Decompiler.ControlFlow @@ -509,6 +538,26 @@ namespace Decompiler.ControlFlow
}
static HashSet<ControlFlowNode> FindDominatedNodes(HashSet<ControlFlowNode> scope, ControlFlowNode head)
{
HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>();
HashSet<ControlFlowNode> result = new HashSet<ControlFlowNode>();
agenda.Add(head);
while(agenda.Count > 0) {
ControlFlowNode addNode = agenda.First();
agenda.Remove(addNode);
if (scope.Contains(addNode) && head.Dominates(addNode) && result.Add(addNode)) {
foreach (var successor in addNode.Successors) {
agenda.Add(successor);
}
}
}
return result;
}
static HashSet<ControlFlowNode> FindLoopContent(HashSet<ControlFlowNode> scope, ControlFlowNode head)
{
var exitNodes = head.DominanceFrontier.SelectMany(n => n.Predecessors);
HashSet<ControlFlowNode> agenda = new HashSet<ControlFlowNode>(exitNodes);

6
ILSpy/ILSpy.csproj

@ -136,6 +136,9 @@ @@ -136,6 +136,9 @@
<Compile Include="TextView\ReferenceElementGenerator.cs" />
<Compile Include="TextView\AvalonEditTextOutput.cs" />
<Compile Include="TextView\UIElementGenerator.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzedMethodUsedByTreeNode.cs" />
<Compile Include="TreeNodes\Analyzer\AnalyzerTreeNode.cs" />
<Compile Include="TreeNodes\AssemblyListTreeNode.cs" />
<Compile Include="TreeNodes\AssemblyReferenceTreeNode.cs" />
<Compile Include="TreeNodes\AssemblyTreeNode.cs" />
@ -151,7 +154,7 @@ @@ -151,7 +154,7 @@
<Compile Include="TreeNodes\ReferenceFolderTreeNode.cs" />
<Compile Include="TreeNodes\ResourceEntryNode.cs" />
<Compile Include="TreeNodes\ResourceListTreeNode.cs" />
<Compile Include="TreeNodes\ThreadedTreeNode.cs" />
<Compile Include="TreeNodes\ThreadingSupport.cs" />
<Compile Include="TreeNodes\TypeTreeNode.cs" />
<EmbeddedResource Include="TextView\ILAsm-Mode.xshd" />
</ItemGroup>
@ -240,6 +243,7 @@ @@ -240,6 +243,7 @@
<Folder Include="Controls" />
<Folder Include="TreeNodes" />
<Folder Include="TextView" />
<Folder Include="TreeNodes\Analyzer" />
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSharp.Targets" />
</Project>

1
ILSpy/Images/Images.cs

@ -67,5 +67,6 @@ namespace ICSharpCode.ILSpy @@ -67,5 +67,6 @@ namespace ICSharpCode.ILSpy
public static readonly BitmapImage ProtectedStruct = LoadBitmap("ProtectedStruct");
public static readonly BitmapImage Delete = LoadBitmap("Delete");
public static readonly BitmapImage Search = LoadBitmap("Search");
}
}

52
ILSpy/MainWindow.xaml

@ -14,11 +14,7 @@ @@ -14,11 +14,7 @@
FocusManager.FocusedElement="{Binding ElementName=treeView}"
>
<Window.Resources>
<ResourceDictionary>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="Controls/SearchBoxStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>
<BooleanToVisibilityConverter x:Key="BooleanToVisibilityConverter" />
</Window.Resources>
<Window.CommandBindings>
<CommandBinding
@ -87,6 +83,7 @@ @@ -87,6 +83,7 @@
<Image Width="16" Height="16" Source="Images/PrivateInternal.png" />
</MenuItem.Icon>
</MenuItem>
<MenuItem Header="Show _analyzer" Name="showAnalyzer" IsCheckable="True" Checked="ShowAnalyzer_Checked" Unchecked="ShowAnalyzer_Unchecked" />
</MenuItem>
<MenuItem Header="_Debugger">
<MenuItem x:Name="AttachMenuItem" Header="Attach to _running application" Command="routedCommands:RoutedUICommands.AttachToProcess">
@ -207,15 +204,24 @@ @@ -207,15 +204,24 @@
<GridSplitter
Grid.ZIndex="1"
Grid.Column="1"
Margin="-2,0"
BorderThickness="2,0"
BorderBrush="Transparent"
HorizontalAlignment="Stretch" />
Margin="-5,0"
BorderThickness="5,0"
HorizontalAlignment="Center"
VerticalAlignment="Stretch"
BorderBrush="Transparent" />
<!-- Right pane: Text Editor -->
<DockPanel
Grid.Column="2">
<Border BorderBrush="Black" BorderThickness="1" DockPanel.Dock="Top" Name="updateAvailablePanel" Visibility="Collapsed">
<Grid Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions>
<RowDefinition Height="Auto" />
<RowDefinition Height="0.7*" MinHeight="100" Name="textViewRow" />
<RowDefinition Height="1" />
<RowDefinition Height="0" Name="analyzerRow" />
</Grid.RowDefinitions>
<Border BorderBrush="Black" BorderThickness="1" Name="updateAvailablePanel" Visibility="Collapsed">
<DockPanel>
<Button DockPanel.Dock="Right" Click="updateAvailablePanelCloseButtonClick" MinWidth="0">X</Button>
<StackPanel Orientation="Horizontal">
@ -225,8 +231,24 @@ @@ -225,8 +231,24 @@
</DockPanel>
</Border>
<textView:DecompilerTextView x:Name="decompilerTextView" />
</DockPanel>
<textView:DecompilerTextView x:Name="decompilerTextView" Grid.Row="1" />
<GridSplitter
Grid.ZIndex="1"
Grid.Row="2"
Margin="0,-2,0,-5"
BorderThickness="0,2,0,5"
BorderBrush="Transparent"
HorizontalAlignment="Stretch"
VerticalAlignment="Center"
Visibility="{Binding IsChecked, ElementName=showAnalyzer, Converter={StaticResource BooleanToVisibilityConverter}}" />
<DockPanel Grid.Row="3"
Visibility="{Binding IsChecked, ElementName=showAnalyzer, Converter={StaticResource BooleanToVisibilityConverter}}">
<Label DockPanel.Dock="Top">Analyzer</Label>
<tv:SharpTreeView Name="analyzerTree" ShowRoot="False" />
</DockPanel>
</Grid>
</Grid>
</DockPanel>
</Window>

62
ILSpy/MainWindow.xaml.cs

@ -27,15 +27,17 @@ using System.Windows; @@ -27,15 +27,17 @@ using System.Windows;
using System.Windows.Controls;
using System.Windows.Input;
using System.Windows.Media.Imaging;
using ICSharpCode.Decompiler;
using ICSharpCode.Decompiler.FlowAnalysis;
using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.TreeNodes.Analyzer;
using ICSharpCode.TreeView;
using ILSpy.Debugger.AvalonEdit;
using ILSpy.Debugger.Bookmarks;
using ILSpy.Debugger.Services;
using ILSpy.Debugger.UI;
using Microsoft.Win32;
using Mono.Cecil;
namespace ICSharpCode.ILSpy
{
@ -51,8 +53,15 @@ namespace ICSharpCode.ILSpy @@ -51,8 +53,15 @@ namespace ICSharpCode.ILSpy
AssemblyList assemblyList;
AssemblyListTreeNode assemblyListTreeNode;
static MainWindow instance;
public static MainWindow Instance {
get { return instance; }
}
public MainWindow()
{
instance = this;
spySettings = ILSpySettings.Load();
this.sessionSettings = new SessionSettings(spySettings);
this.assemblyListManager = new AssemblyListManager(spySettings);
@ -256,6 +265,23 @@ namespace ICSharpCode.ILSpy @@ -256,6 +265,23 @@ namespace ICSharpCode.ILSpy
path.Reverse();
return path.ToArray();
}
public void JumpToReference(object reference)
{
if (reference is TypeReference) {
SelectNode(assemblyListTreeNode.FindTypeNode(((TypeReference)reference).Resolve()));
} else if (reference is MethodReference) {
SelectNode(assemblyListTreeNode.FindMethodNode(((MethodReference)reference).Resolve()));
} else if (reference is FieldReference) {
SelectNode(assemblyListTreeNode.FindFieldNode(((FieldReference)reference).Resolve()));
} else if (reference is PropertyReference) {
SelectNode(assemblyListTreeNode.FindPropertyNode(((PropertyReference)reference).Resolve()));
} else if (reference is EventReference) {
SelectNode(assemblyListTreeNode.FindEventNode(((EventReference)reference).Resolve()));
} else if (reference is AssemblyDefinition) {
SelectNode(assemblyListTreeNode.FindAssemblyNode((AssemblyDefinition)reference));
}
}
#endregion
#region Open/Refresh
@ -480,6 +506,22 @@ namespace ICSharpCode.ILSpy @@ -480,6 +506,22 @@ namespace ICSharpCode.ILSpy
}
#endregion
#region Analyzer
public void AddToAnalyzer(AnalyzerTreeNode node)
{
if (analyzerTree.Root == null)
analyzerTree.Root = new AnalyzerTreeNode { Language = sessionSettings.FilterSettings.Language };
if (!showAnalyzer.IsChecked)
showAnalyzer.IsChecked = true;
node.IsExpanded = true;
analyzerTree.Root.Children.Add(node);
analyzerTree.SelectedItem = node;
analyzerTree.FocusNode(node);
}
#endregion
protected override void OnStateChanged(EventArgs e)
{
base.OnStateChanged(e);
@ -495,9 +537,27 @@ namespace ICSharpCode.ILSpy @@ -495,9 +537,27 @@ namespace ICSharpCode.ILSpy
sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
sessionSettings.WindowBounds = this.RestoreBounds;
sessionSettings.SplitterPosition = leftColumn.Width.Value / (leftColumn.Width.Value + rightColumn.Width.Value);
if (showAnalyzer.IsChecked)
sessionSettings.AnalyzerSplitterPosition = analyzerRow.Height.Value / (analyzerRow.Height.Value + textViewRow.Height.Value);
sessionSettings.Save();
}
void ShowAnalyzer_Checked(object sender, RoutedEventArgs e)
{
analyzerRow.MinHeight = 100;
if (sessionSettings.AnalyzerSplitterPosition > 0 && sessionSettings.AnalyzerSplitterPosition < 1) {
textViewRow.Height = new GridLength(1 - sessionSettings.AnalyzerSplitterPosition, GridUnitType.Star);
analyzerRow.Height = new GridLength(sessionSettings.AnalyzerSplitterPosition, GridUnitType.Star);
}
}
void ShowAnalyzer_Unchecked(object sender, RoutedEventArgs e)
{
sessionSettings.AnalyzerSplitterPosition = analyzerRow.Height.Value / (analyzerRow.Height.Value + textViewRow.Height.Value);
analyzerRow.MinHeight = 0;
analyzerRow.Height = new GridLength(0);
}
void LanguageComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e)
{
DebuggerService.CurrentDebugger.Language =

3
ILSpy/SessionSettings.cs

@ -49,6 +49,7 @@ namespace ICSharpCode.ILSpy @@ -49,6 +49,7 @@ namespace ICSharpCode.ILSpy
this.WindowState = FromString((string)doc.Element("WindowState"), WindowState.Normal);
this.WindowBounds = FromString((string)doc.Element("WindowBounds"), new Rect(10, 10, 750, 550));
this.SplitterPosition = FromString((string)doc.Element("SplitterPosition"), 0.4);
this.AnalyzerSplitterPosition = FromString((string)doc.Element("AnalyzerSplitterPosition"), 0.3);
}
public event PropertyChangedEventHandler PropertyChanged;
@ -68,6 +69,7 @@ namespace ICSharpCode.ILSpy @@ -68,6 +69,7 @@ namespace ICSharpCode.ILSpy
public WindowState WindowState = WindowState.Normal;
public Rect WindowBounds;
public double SplitterPosition;
public double AnalyzerSplitterPosition;
public void Save()
{
@ -82,6 +84,7 @@ namespace ICSharpCode.ILSpy @@ -82,6 +84,7 @@ namespace ICSharpCode.ILSpy
doc.Add(new XElement("WindowState", ToString(this.WindowState)));
doc.Add(new XElement("WindowBounds", ToString(this.WindowBounds)));
doc.Add(new XElement("SplitterPosition", ToString(this.SplitterPosition)));
doc.Add(new XElement("AnalyzerSplitterPosition", ToString(this.AnalyzerSplitterPosition)));
ILSpySettings.SaveSettings(doc);
}

15
ILSpy/TextView/DecompilerTextView.cs

@ -379,20 +379,7 @@ namespace ICSharpCode.ILSpy.TextView @@ -379,20 +379,7 @@ namespace ICSharpCode.ILSpy.TextView
return;
}
}
var assemblyListTreeNode = mainWindow.AssemblyListTreeNode;
if (reference is TypeReference) {
mainWindow.SelectNode(assemblyListTreeNode.FindTypeNode(((TypeReference)reference).Resolve()));
} else if (reference is MethodReference) {
mainWindow.SelectNode(assemblyListTreeNode.FindMethodNode(((MethodReference)reference).Resolve()));
} else if (reference is FieldReference) {
mainWindow.SelectNode(assemblyListTreeNode.FindFieldNode(((FieldReference)reference).Resolve()));
} else if (reference is PropertyReference) {
mainWindow.SelectNode(assemblyListTreeNode.FindPropertyNode(((PropertyReference)reference).Resolve()));
} else if (reference is EventReference) {
mainWindow.SelectNode(assemblyListTreeNode.FindEventNode(((EventReference)reference).Resolve()));
} else if (reference is AssemblyDefinition) {
mainWindow.SelectNode(assemblyListTreeNode.FindAssemblyNode((AssemblyDefinition)reference));
}
mainWindow.JumpToReference(reference);
}
#endregion

55
ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs

@ -0,0 +1,55 @@ @@ -0,0 +1,55 @@
// 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
{
class AnalyzedMethodTreeNode : AnalyzerTreeNode
{
MethodDefinition analyzedMethod;
public AnalyzedMethodTreeNode(MethodDefinition analyzedMethod)
{
if (analyzedMethod == null)
throw new ArgumentNullException("analyzedMethod");
this.analyzedMethod = analyzedMethod;
this.LazyLoading = true;
}
public override object Icon {
get { return MethodTreeNode.GetIcon(analyzedMethod); }
}
public override object Text {
get { return Language.TypeToString(analyzedMethod.DeclaringType, true) + "." + MethodTreeNode.GetText(analyzedMethod, Language); }
}
public override void ActivateItem(System.Windows.RoutedEventArgs e)
{
e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedMethod);
}
protected override void LoadChildren()
{
this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));
}
}
}

103
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -0,0 +1,103 @@ @@ -0,0 +1,103 @@
// 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 System.Threading.Tasks;
using ICSharpCode.NRefactory.Utils;
using ICSharpCode.TreeView;
using Mono.Cecil;
using Mono.Cecil.Cil;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzedMethodUsedByTreeNode : AnalyzerTreeNode
{
MethodDefinition analyzedMethod;
ThreadingSupport threading;
public AnalyzedMethodUsedByTreeNode(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 "Used 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();
}
}
IEnumerable<SharpTreeNode> FetchChildren(CancellationToken ct)
{
return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
}
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct)
{
// use parallelism only on the assembly level (avoid locks within Cecil)
return assemblies.AsParallel().WithCancellation(ct).SelectMany((LoadedAssembly asm) => FindReferences(asm, ct));
}
IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly asm, CancellationToken ct)
{
string name = analyzedMethod.Name;
string declTypeName = analyzedMethod.DeclaringType.FullName;
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested();
foreach (MethodDefinition method in type.Methods) {
ct.ThrowIfCancellationRequested();
bool found = false;
if (!method.HasBody)
continue;
foreach (Instruction instr in method.Body.Instructions) {
MethodReference mr = instr.Operand as MethodReference;
if (mr != null && mr.Name == name && mr.DeclaringType.FullName == declTypeName && mr.Resolve() == analyzedMethod) {
found = true;
break;
}
}
if (found)
yield return new AnalyzedMethodTreeNode(method);
}
}
}
}
}

64
ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs

@ -0,0 +1,64 @@ @@ -0,0 +1,64 @@
// 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.Linq;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{
class AnalyzerTreeNode : SharpTreeNode
{
Language language;
public Language Language {
get { return language; }
set {
if (language != value) {
language = value;
foreach (var child in this.Children.OfType<AnalyzerTreeNode>())
child.Language = value;
}
}
}
public override bool CanDelete()
{
return Parent != null && Parent.IsRoot;
}
public override void DeleteCore()
{
Parent.Children.Remove(this);
}
public override void Delete()
{
DeleteCore();
}
protected override void OnChildrenChanged(System.Collections.Specialized.NotifyCollectionChangedEventArgs e)
{
if (e.NewItems != null) {
foreach (AnalyzerTreeNode a in e.NewItems.OfType<AnalyzerTreeNode>())
a.Language = this.Language;
}
base.OnChildrenChanged(e);
}
}
}

8
ILSpy/TreeNodes/AssemblyListTreeNode.cs

@ -186,6 +186,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -186,6 +186,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (def == null)
return null;
TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
if (typeNode == null)
return null;
typeNode.EnsureLazyChildren();
MethodTreeNode methodNode = typeNode.Children.OfType<MethodTreeNode>().FirstOrDefault(m => m.MethodDefinition == def && !m.IsHidden);
if (methodNode != null)
@ -212,6 +214,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -212,6 +214,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (def == null)
return null;
TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
if (typeNode == null)
return null;
typeNode.EnsureLazyChildren();
return typeNode.Children.OfType<FieldTreeNode>().FirstOrDefault(m => m.FieldDefinition == def && !m.IsHidden);
}
@ -225,6 +229,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -225,6 +229,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (def == null)
return null;
TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
if (typeNode == null)
return null;
typeNode.EnsureLazyChildren();
return typeNode.Children.OfType<PropertyTreeNode>().FirstOrDefault(m => m.PropertyDefinition == def && !m.IsHidden);
}
@ -238,6 +244,8 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -238,6 +244,8 @@ namespace ICSharpCode.ILSpy.TreeNodes
if (def == null)
return null;
TypeTreeNode typeNode = FindTypeNode(def.DeclaringType);
if (typeNode == null)
return null;
typeNode.EnsureLazyChildren();
return typeNode.Children.OfType<EventTreeNode>().FirstOrDefault(m => m.EventDefinition == def && !m.IsHidden);
}

28
ILSpy/TreeNodes/DerivedTypesTreeNode.cs

@ -15,15 +15,18 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -15,15 +15,18 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// <summary>
/// Lists the super types of a class.
/// </summary>
sealed class DerivedTypesTreeNode : ThreadedTreeNode
sealed class DerivedTypesTreeNode : ILSpyTreeNode
{
readonly AssemblyList list;
readonly TypeDefinition type;
ThreadingSupport threading;
public DerivedTypesTreeNode(AssemblyList list, TypeDefinition type)
{
this.list = list;
this.type = type;
this.LazyLoading = true;
this.threading = new ThreadingSupport();
}
public override object Text {
@ -34,7 +37,12 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -34,7 +37,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
get { return Images.SubTypes; }
}
protected override IEnumerable<ILSpyTreeNode> FetchChildren(CancellationToken cancellationToken)
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
IEnumerable<ILSpyTreeNode> FetchChildren(CancellationToken cancellationToken)
{
// FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread
var assemblies = list.GetAssemblies().Select(node => node.AssemblyDefinition).Where(asm => asm != null).ToArray();
@ -62,17 +70,24 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -62,17 +70,24 @@ namespace ICSharpCode.ILSpy.TreeNodes
{
return typeRef.FullName == type.FullName;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
threading.Decompile(language, output, options, EnsureLazyChildren);
}
}
class DerivedTypesEntryNode : ThreadedTreeNode
class DerivedTypesEntryNode : ILSpyTreeNode
{
TypeDefinition def;
AssemblyDefinition[] assemblies;
ThreadingSupport threading;
public DerivedTypesEntryNode(TypeDefinition def, AssemblyDefinition[] assemblies)
{
this.def = def;
this.assemblies = assemblies;
threading = new ThreadingSupport();
}
public override bool ShowExpander {
@ -91,7 +106,12 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -91,7 +106,12 @@ namespace ICSharpCode.ILSpy.TreeNodes
}
}
protected override IEnumerable<ILSpyTreeNode> FetchChildren(CancellationToken ct)
protected override void LoadChildren()
{
threading.LoadChildren(this, FetchChildren);
}
IEnumerable<ILSpyTreeNode> FetchChildren(CancellationToken ct)
{
// FetchChildren() runs on the main thread; but the enumerator will be consumed on a background thread
return DerivedTypesTreeNode.FindDerivedTypes(def, assemblies, ct);

2
ILSpy/TreeNodes/ILSpyTreeNode.cs

@ -56,7 +56,7 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -56,7 +56,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
return FilterResult.Hidden;
}
protected object HighlightSearchMatch(string text, string suffix = null)
protected static object HighlightSearchMatch(string text, string suffix = null)
{
// TODO: implement highlighting the search match
return text + suffix;

59
ILSpy/TreeNodes/MethodTreeNode.cs

@ -18,7 +18,10 @@ @@ -18,7 +18,10 @@
using System;
using System.Text;
using System.Windows.Controls;
using System.Windows.Media.Imaging;
using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TreeNodes.Analyzer;
using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes
@ -43,30 +46,41 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -43,30 +46,41 @@ namespace ICSharpCode.ILSpy.TreeNodes
public override object Text {
get {
StringBuilder b = new StringBuilder();
b.Append('(');
for (int i = 0; i < method.Parameters.Count; i++) {
if (i > 0) b.Append(", ");
b.Append(this.Language.TypeToString(method.Parameters[i].ParameterType, false, method.Parameters[i]));
}
b.Append(") : ");
b.Append(this.Language.TypeToString(method.ReturnType, false, method.MethodReturnType));
return HighlightSearchMatch(method.Name, b.ToString());
return GetText(method, Language);
}
}
public static object GetText(MethodDefinition method, Language language)
{
StringBuilder b = new StringBuilder();
b.Append('(');
for (int i = 0; i < method.Parameters.Count; i++) {
if (i > 0)
b.Append(", ");
b.Append(language.TypeToString(method.Parameters[i].ParameterType, false, method.Parameters[i]));
}
b.Append(") : ");
b.Append(language.TypeToString(method.ReturnType, false, method.MethodReturnType));
return HighlightSearchMatch(method.Name, b.ToString());
}
public override object Icon {
get {
if (method.IsSpecialName && method.Name.StartsWith("op_", StringComparison.Ordinal))
return Images.Operator;
if (method.IsStatic && method.HasCustomAttributes) {
foreach (var ca in method.CustomAttributes) {
if (ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
return Images.ExtensionMethod;
}
return GetIcon(method);
}
}
public static BitmapImage GetIcon(MethodDefinition method)
{
if (method.IsSpecialName && method.Name.StartsWith("op_", StringComparison.Ordinal))
return Images.Operator;
if (method.IsStatic && method.HasCustomAttributes) {
foreach (var ca in method.CustomAttributes) {
if (ca.AttributeType.FullName == "System.Runtime.CompilerServices.ExtensionAttribute")
return Images.ExtensionMethod;
}
return Images.Method;
}
return Images.Method;
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
@ -81,5 +95,16 @@ namespace ICSharpCode.ILSpy.TreeNodes @@ -81,5 +95,16 @@ namespace ICSharpCode.ILSpy.TreeNodes
else
return FilterResult.Hidden;
}
public override System.Windows.Controls.ContextMenu GetContextMenu()
{
ContextMenu menu = new ContextMenu();
MenuItem item = new MenuItem() { Header = "Analyze", Icon = new Image() { Source = Images.Search } };
item.Click += delegate { MainWindow.Instance.AddToAnalyzer(new AnalyzedMethodTreeNode(method)); };
menu.Items.Add(item);
return menu;
}
}
}

105
ILSpy/TreeNodes/ThreadedTreeNode.cs

@ -1,105 +0,0 @@ @@ -1,105 +0,0 @@
// 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.Collections.Generic;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
namespace ICSharpCode.ILSpy.TreeNodes
{
/// <summary>
/// Node that is lazy-loaded and loads its children on a background thread.
/// </summary>
abstract class ThreadedTreeNode : ILSpyTreeNode
{
Task<List<ILSpyTreeNode>> loadChildrenTask;
public ThreadedTreeNode()
{
this.LazyLoading = true;
}
public void Invalidate()
{
this.LazyLoading = true;
this.Children.Clear();
loadChildrenTask = null;
}
/// <summary>
/// FetchChildren() runs on the main thread; but the enumerator is consumed on a background thread
/// </summary>
protected abstract IEnumerable<ILSpyTreeNode> FetchChildren(CancellationToken ct);
protected override sealed void LoadChildren()
{
this.Children.Add(new LoadingTreeNode());
CancellationToken ct = CancellationToken.None;
var fetchChildrenEnumerable = FetchChildren(ct);
Task<List<ILSpyTreeNode>> thisTask = null;
thisTask = new Task<List<ILSpyTreeNode>>(
delegate {
List<ILSpyTreeNode> result = new List<ILSpyTreeNode>();
foreach (ILSpyTreeNode child in fetchChildrenEnumerable) {
ct.ThrowIfCancellationRequested();
result.Add(child);
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action<ILSpyTreeNode>(
delegate (ILSpyTreeNode newChild) {
// don't access "child" here the
// background thread might already be running the next loop iteration
if (loadChildrenTask == thisTask) {
this.Children.Insert(this.Children.Count - 1, newChild);
}
}), child);
}
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(
delegate {
if (loadChildrenTask == thisTask) {
this.Children.RemoveAt(this.Children.Count - 1); // remove 'Loading...'
}
}));
return result;
}, ct);
loadChildrenTask = thisTask;
thisTask.Start();
// Give the task a bit time to complete before we return to WPF - this keeps "Loading..."
// from showing up for very short waits.
thisTask.Wait(TimeSpan.FromMilliseconds(200));
}
public override void Decompile(Language language, ITextOutput output, DecompilationOptions options)
{
var loadChildrenTask = this.loadChildrenTask;
if (loadChildrenTask == null) {
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, new Action(EnsureLazyChildren));
loadChildrenTask = this.loadChildrenTask;
}
if (loadChildrenTask != null) {
foreach (var child in loadChildrenTask.Result) {
child.Decompile(language, output, options);
}
}
}
sealed class LoadingTreeNode : ILSpyTreeNode
{
public override object Text {
get { return "Loading..."; }
}
public override FilterResult Filter(FilterSettings settings)
{
return FilterResult.Match;
}
public override void Decompile(Language language, ICSharpCode.Decompiler.ITextOutput output, DecompilationOptions options)
{
}
}
}
}

139
ILSpy/TreeNodes/ThreadingSupport.cs

@ -0,0 +1,139 @@ @@ -0,0 +1,139 @@
// 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.Collections.Generic;
using System.Linq;
using System.Threading;
using System.Threading.Tasks;
using System.Windows.Threading;
using ICSharpCode.Decompiler;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.TreeNodes
{
/// <summary>
/// Adds threading support to nodes
/// </summary>
class ThreadingSupport
{
Task<List<SharpTreeNode>> loadChildrenTask;
CancellationTokenSource cancellationTokenSource = new CancellationTokenSource();
public bool IsRunning {
get { return !loadChildrenTask.IsCompleted; }
}
public void Cancel()
{
cancellationTokenSource.Cancel();
loadChildrenTask = null;
cancellationTokenSource = new CancellationTokenSource();
}
/// <summary>
/// Starts loading the children of the specified node.
/// </summary>
public void LoadChildren(SharpTreeNode node, Func<CancellationToken, IEnumerable<SharpTreeNode>> fetchChildren)
{
node.Children.Add(new LoadingTreeNode());
CancellationToken ct = cancellationTokenSource.Token;
var fetchChildrenEnumerable = fetchChildren(ct);
Task<List<SharpTreeNode>> thisTask = null;
thisTask = new Task<List<SharpTreeNode>>(
delegate {
List<SharpTreeNode> result = new List<SharpTreeNode>();
foreach (SharpTreeNode child in fetchChildrenEnumerable) {
ct.ThrowIfCancellationRequested();
result.Add(child);
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action<SharpTreeNode>(
delegate (SharpTreeNode newChild) {
// don't access "child" here the
// background thread might already be running the next loop iteration
if (loadChildrenTask == thisTask) {
node.Children.Insert(node.Children.Count - 1, newChild);
}
}), child);
}
return result;
}, ct);
loadChildrenTask = thisTask;
thisTask.Start();
thisTask.ContinueWith(
delegate (Task continuation) {
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(
delegate {
if (loadChildrenTask == thisTask) {
node.Children.RemoveAt(node.Children.Count - 1); // remove 'Loading...'
}
if (continuation.Exception != null) { // observe exception even when task isn't current
if (loadChildrenTask == thisTask) {
foreach (Exception ex in continuation.Exception.InnerExceptions) {
node.Children.Add(new ErrorTreeNode(ex.ToString()));
}
}
}
}));
});
// Give the task a bit time to complete before we return to WPF - this keeps "Loading..."
// from showing up for very short waits.
thisTask.Wait(TimeSpan.FromMilliseconds(200));
}
public void Decompile(Language language, ITextOutput output, DecompilationOptions options, Action ensureLazyChildren)
{
var loadChildrenTask = this.loadChildrenTask;
if (loadChildrenTask == null) {
App.Current.Dispatcher.Invoke(DispatcherPriority.Normal, ensureLazyChildren);
loadChildrenTask = this.loadChildrenTask;
}
if (loadChildrenTask != null) {
foreach (ILSpyTreeNode child in loadChildrenTask.Result.Cast<ILSpyTreeNode>()) {
child.Decompile(language, output, options);
}
}
}
sealed class LoadingTreeNode : ILSpyTreeNode
{
public override object Text {
get { return "Loading..."; }
}
public override FilterResult Filter(FilterSettings settings)
{
return FilterResult.Match;
}
public override void Decompile(Language language, ICSharpCode.Decompiler.ITextOutput output, DecompilationOptions options)
{
}
}
sealed class ErrorTreeNode : ILSpyTreeNode
{
string text;
public override object Text {
get { return text; }
}
public ErrorTreeNode(string text)
{
this.text = text;
}
public override FilterResult Filter(FilterSettings settings)
{
return FilterResult.Match;
}
public override void Decompile(Language language, ICSharpCode.Decompiler.ITextOutput output, DecompilationOptions options)
{
}
}
}
}

4
ILSpy/themes/generic.xaml

@ -22,4 +22,8 @@ @@ -22,4 +22,8 @@
Data = "M 5,5 L 10,10 L 15,5 L 5,5"/>
</StackPanel>
</DataTemplate>
<ResourceDictionary.MergedDictionaries>
<ResourceDictionary Source="../Controls/SearchBoxStyle.xaml" />
</ResourceDictionary.MergedDictionaries>
</ResourceDictionary>

2
SharpTreeView/SharpTreeNodeCollection.cs

@ -140,7 +140,7 @@ namespace ICSharpCode.TreeView @@ -140,7 +140,7 @@ namespace ICSharpCode.TreeView
ThrowOnReentrancy();
var oldList = list;
list = new List<SharpTreeNode>();
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, list, 0));
OnCollectionChanged(new NotifyCollectionChangedEventArgs(NotifyCollectionChangedAction.Remove, oldList, 0));
}
public bool Contains(SharpTreeNode node)

Loading…
Cancel
Save