Browse Source

Improvements for the analyzer.

pull/70/head
Daniel Grunwald 15 years ago
parent
commit
e9ad53a607
  1. 41
      ILSpy/MainWindow.xaml
  2. 54
      ILSpy/MainWindow.xaml.cs
  3. 3
      ILSpy/SessionSettings.cs
  4. 15
      ILSpy/TextView/DecompilerTextView.cs
  5. 6
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs
  6. 57
      ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs
  7. 38
      ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs
  8. 3
      ILSpy/TreeNodes/MethodTreeNode.cs
  9. 78
      ILSpy/TreeNodes/ThreadingSupport.cs

41
ILSpy/MainWindow.xaml

@ -61,7 +61,7 @@
<Image Width="16" Height="16" Source="Images/PrivateInternal.png" /> <Image Width="16" Height="16" Source="Images/PrivateInternal.png" />
</MenuItem.Icon> </MenuItem.Icon>
</MenuItem> </MenuItem>
<MenuItem Header="Show _analyzer" Name="showAnalyzer" IsCheckable="True" /> <MenuItem Header="Show _analyzer" Name="showAnalyzer" IsCheckable="True" Checked="ShowAnalyzer_Checked" Unchecked="ShowAnalyzer_Unchecked" />
</MenuItem> </MenuItem>
<MenuItem Header="_Help"> <MenuItem Header="_Help">
<MenuItem Header="_About" Click="AboutClick" /> <MenuItem Header="_About" Click="AboutClick" />
@ -139,16 +139,22 @@
<GridSplitter <GridSplitter
Grid.ZIndex="1" Grid.ZIndex="1"
Grid.Column="1" Grid.Column="1"
Margin="-2,0" Margin="-5,0"
BorderThickness="2,0" BorderThickness="5,0"
BorderBrush="Transparent" HorizontalAlignment="Center"
HorizontalAlignment="Stretch" /> VerticalAlignment="Stretch"
BorderBrush="Transparent" />
<!-- Right pane: Text Editor --> <!-- Right pane: Text Editor -->
<Grid Grid.Column="2"> <Grid Grid.Column="2">
<Grid.ColumnDefinitions>
<ColumnDefinition
Width="*" />
</Grid.ColumnDefinitions>
<Grid.RowDefinitions> <Grid.RowDefinitions>
<RowDefinition Height="Auto" /> <RowDefinition Height="Auto" />
<RowDefinition Height="*" /> <RowDefinition Height="0.7*" MinHeight="100" Name="textViewRow" />
<RowDefinition Height="Auto" /> <RowDefinition Height="1" />
<RowDefinition Height="0" Name="analyzerRow" />
</Grid.RowDefinitions> </Grid.RowDefinitions>
<Border BorderBrush="Black" BorderThickness="1" Name="updateAvailablePanel" Visibility="Collapsed"> <Border BorderBrush="Black" BorderThickness="1" Name="updateAvailablePanel" Visibility="Collapsed">
<DockPanel> <DockPanel>
@ -163,21 +169,20 @@
<textView:DecompilerTextView x:Name="decompilerTextView" Grid.Row="1" /> <textView:DecompilerTextView x:Name="decompilerTextView" Grid.Row="1" />
<GridSplitter <GridSplitter
Grid.ZIndex="2" Grid.ZIndex="1"
Grid.Row="1" Grid.Row="2"
Margin="0,-2" Margin="0,-2,0,-5"
BorderThickness="0,2" BorderThickness="0,2,0,5"
BorderBrush="Transparent" BorderBrush="Transparent"
HorizontalAlignment="Stretch" HorizontalAlignment="Stretch"
VerticalAlignment="Bottom" VerticalAlignment="Center"
Visibility="{Binding IsChecked, ElementName=showAnalyzer, Converter={StaticResource BooleanToVisibilityConverter}}" /> Visibility="{Binding IsChecked, ElementName=showAnalyzer, Converter={StaticResource BooleanToVisibilityConverter}}" />
<Border BorderBrush="Gray" BorderThickness="1" Grid.Row="2" Name="analyzerPanel" Visibility="{Binding IsChecked, ElementName=showAnalyzer, Converter={StaticResource BooleanToVisibilityConverter}}" MinHeight="100"> <DockPanel Grid.Row="3"
<DockPanel> Visibility="{Binding IsChecked, ElementName=showAnalyzer, Converter={StaticResource BooleanToVisibilityConverter}}">
<Label DockPanel.Dock="Top">Analyzer</Label> <Label DockPanel.Dock="Top">Analyzer</Label>
<tv:SharpTreeView Name="analyzerTree" ShowRoot="False" /> <tv:SharpTreeView Name="analyzerTree" ShowRoot="False" />
</DockPanel> </DockPanel>
</Border>
</Grid> </Grid>
</Grid> </Grid>
</DockPanel> </DockPanel>

54
ILSpy/MainWindow.xaml.cs

@ -33,6 +33,7 @@ using ICSharpCode.ILSpy.TreeNodes;
using ICSharpCode.ILSpy.TreeNodes.Analyzer; using ICSharpCode.ILSpy.TreeNodes.Analyzer;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
using Microsoft.Win32; using Microsoft.Win32;
using Mono.Cecil;
namespace ICSharpCode.ILSpy namespace ICSharpCode.ILSpy
{ {
@ -260,6 +261,23 @@ namespace ICSharpCode.ILSpy
path.Reverse(); path.Reverse();
return path.ToArray(); 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 #endregion
#region Open/Refresh #region Open/Refresh
@ -380,20 +398,18 @@ namespace ICSharpCode.ILSpy
#endregion #endregion
#region Analyzer #region Analyzer
public void Analyze(MethodTreeNode method) public void AddToAnalyzer(AnalyzerTreeNode node)
{ {
if (analyzerTree.Root == null) if (analyzerTree.Root == null)
analyzerTree.Root = new SharpTreeNode(); analyzerTree.Root = new AnalyzerTreeNode { Language = sessionSettings.FilterSettings.Language };
if (analyzerPanel.Visibility != Visibility.Visible) if (!showAnalyzer.IsChecked)
analyzerPanel.Visibility = Visibility.Visible; showAnalyzer.IsChecked = true;
var newNode = new AnalyzedMethodTreeNode(method.MethodDefinition) { node.IsExpanded = true;
Language = sessionSettings.FilterSettings.Language, analyzerTree.Root.Children.Add(node);
IsExpanded = true analyzerTree.SelectedItem = node;
}; analyzerTree.FocusNode(node);
analyzerTree.Root.Children.Add(newNode);
} }
#endregion #endregion
@ -412,7 +428,25 @@ namespace ICSharpCode.ILSpy
sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode); sessionSettings.ActiveTreeViewPath = GetPathForNode(treeView.SelectedItem as SharpTreeNode);
sessionSettings.WindowBounds = this.RestoreBounds; sessionSettings.WindowBounds = this.RestoreBounds;
sessionSettings.SplitterPosition = leftColumn.Width.Value / (leftColumn.Width.Value + rightColumn.Width.Value); 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(); 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);
}
} }
} }

3
ILSpy/SessionSettings.cs

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

15
ILSpy/TextView/DecompilerTextView.cs

@ -359,20 +359,7 @@ namespace ICSharpCode.ILSpy.TextView
return; return;
} }
} }
var assemblyListTreeNode = mainWindow.AssemblyListTreeNode; mainWindow.JumpToReference(reference);
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));
}
} }
#endregion #endregion

6
ILSpy/TreeNodes/Analyzer/AnalyzedMethodTreeNode.cs

@ -41,6 +41,12 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
get { return MethodTreeNode.GetText(analyzedMethod, Language); } get { return MethodTreeNode.GetText(analyzedMethod, Language); }
} }
public override void ActivateItem(System.Windows.RoutedEventArgs e)
{
e.Handled = true;
MainWindow.Instance.JumpToReference(analyzedMethod);
}
protected override void LoadChildren() protected override void LoadChildren()
{ {
this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod)); this.Children.Add(new AnalyzedMethodUsedByTreeNode(analyzedMethod));

57
ILSpy/TreeNodes/Analyzer/AnalyzedMethodUsedByTreeNode.cs

@ -18,15 +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.NRefactory.Utils;
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 : ILSpyTreeNode class AnalyzedMethodUsedByTreeNode : AnalyzerTreeNode
{ {
MethodDefinition analyzedMethod; MethodDefinition analyzedMethod;
ThreadingSupport threading; ThreadingSupport threading;
@ -54,39 +56,46 @@ namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
threading.LoadChildren(this, FetchChildren); threading.LoadChildren(this, FetchChildren);
} }
IEnumerable<ILSpyTreeNode> FetchChildren(CancellationToken ct) 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); return FindReferences(MainWindow.Instance.AssemblyList.GetAssemblies(), ct);
} }
IEnumerable<ILSpyTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct) IEnumerable<SharpTreeNode> FindReferences(LoadedAssembly[] assemblies, CancellationToken ct)
{ {
foreach (LoadedAssembly asm in assemblies) { // 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)
{
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
foreach (TypeDefinition type in TreeTraversal.PreOrder(asm.AssemblyDefinition.MainModule.Types, t => t.NestedTypes)) { foreach (MethodDefinition method in type.Methods) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
foreach (MethodDefinition method in type.Methods) { bool found = false;
ct.ThrowIfCancellationRequested(); if (!method.HasBody)
bool found = false; continue;
if (!method.HasBody) foreach (Instruction instr in method.Body.Instructions) {
continue; if (instr.Operand is MethodReference
foreach (Instruction instr in method.Body.Instructions) { && ((MethodReference)instr.Operand).Resolve() == analyzedMethod) {
if (instr.Operand is MethodReference found = true;
&& ((MethodReference)instr.Operand).Resolve() == analyzedMethod) { break;
found = true;
break;
}
} }
if (found)
yield return new MethodTreeNode(method);
} }
if (found)
yield return new AnalyzedMethodTreeNode(method);
} }
} }
} }
public override void Decompile(Language language, ICSharpCode.Decompiler.ITextOutput output, DecompilationOptions options)
{
throw new NotImplementedException();
}
} }
} }

38
ILSpy/TreeNodes/Analyzer/AnalyzerTreeNode.cs

@ -17,12 +17,48 @@
// DEALINGS IN THE SOFTWARE. // DEALINGS IN THE SOFTWARE.
using System; using System;
using System.Linq;
using ICSharpCode.TreeView; using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.TreeNodes.Analyzer namespace ICSharpCode.ILSpy.TreeNodes.Analyzer
{ {
class AnalyzerTreeNode : SharpTreeNode class AnalyzerTreeNode : SharpTreeNode
{ {
public Language Language { get; set; } 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);
}
} }
} }

3
ILSpy/TreeNodes/MethodTreeNode.cs

@ -21,6 +21,7 @@ using System.Text;
using System.Windows.Controls; using System.Windows.Controls;
using System.Windows.Media.Imaging; using System.Windows.Media.Imaging;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.ILSpy.TreeNodes.Analyzer;
using Mono.Cecil; using Mono.Cecil;
namespace ICSharpCode.ILSpy.TreeNodes namespace ICSharpCode.ILSpy.TreeNodes
@ -99,7 +100,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
ContextMenu menu = new ContextMenu(); ContextMenu menu = new ContextMenu();
MenuItem item = new MenuItem() { Header = "Analyze", Icon = new Image() { Source = Images.Search } }; MenuItem item = new MenuItem() { Header = "Analyze", Icon = new Image() { Source = Images.Search } };
item.Click += delegate { MainWindow.Instance.Analyze(this); }; item.Click += delegate { MainWindow.Instance.AddToAnalyzer(new AnalyzedMethodTreeNode(method)); };
menu.Items.Add(item); menu.Items.Add(item);

78
ILSpy/TreeNodes/ThreadingSupport.cs

@ -3,10 +3,12 @@
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 System.Threading.Tasks;
using System.Windows.Threading; using System.Windows.Threading;
using ICSharpCode.Decompiler; using ICSharpCode.Decompiler;
using ICSharpCode.TreeView;
namespace ICSharpCode.ILSpy.TreeNodes namespace ICSharpCode.ILSpy.TreeNodes
{ {
@ -15,27 +17,39 @@ namespace ICSharpCode.ILSpy.TreeNodes
/// </summary> /// </summary>
class ThreadingSupport class ThreadingSupport
{ {
Task<List<ILSpyTreeNode>> loadChildrenTask; 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> /// <summary>
/// /// Starts loading the children of the specified node.
/// </summary> /// </summary>
public void LoadChildren(ILSpyTreeNode node, Func<CancellationToken, IEnumerable<ILSpyTreeNode>> fetchChildren) public void LoadChildren(SharpTreeNode node, Func<CancellationToken, IEnumerable<SharpTreeNode>> fetchChildren)
{ {
node.Children.Add(new LoadingTreeNode()); node.Children.Add(new LoadingTreeNode());
CancellationToken ct = CancellationToken.None; CancellationToken ct = cancellationTokenSource.Token;
var fetchChildrenEnumerable = fetchChildren(ct); var fetchChildrenEnumerable = fetchChildren(ct);
Task<List<ILSpyTreeNode>> thisTask = null; Task<List<SharpTreeNode>> thisTask = null;
thisTask = new Task<List<ILSpyTreeNode>>( thisTask = new Task<List<SharpTreeNode>>(
delegate { delegate {
List<ILSpyTreeNode> result = new List<ILSpyTreeNode>(); List<SharpTreeNode> result = new List<SharpTreeNode>();
foreach (ILSpyTreeNode child in fetchChildrenEnumerable) { foreach (SharpTreeNode child in fetchChildrenEnumerable) {
ct.ThrowIfCancellationRequested(); ct.ThrowIfCancellationRequested();
result.Add(child); result.Add(child);
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action<ILSpyTreeNode>( App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action<SharpTreeNode>(
delegate (ILSpyTreeNode newChild) { delegate (SharpTreeNode newChild) {
// don't access "child" here the // don't access "child" here the
// background thread might already be running the next loop iteration // background thread might already be running the next loop iteration
if (loadChildrenTask == thisTask) { if (loadChildrenTask == thisTask) {
@ -43,16 +57,27 @@ namespace ICSharpCode.ILSpy.TreeNodes
} }
}), child); }), child);
} }
return result;
}, ct);
loadChildrenTask = thisTask;
thisTask.Start();
thisTask.ContinueWith(
delegate (Task continuation) {
App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action( App.Current.Dispatcher.BeginInvoke(DispatcherPriority.Normal, new Action(
delegate { delegate {
if (loadChildrenTask == thisTask) { if (loadChildrenTask == thisTask) {
node.Children.RemoveAt(node.Children.Count - 1); // remove 'Loading...' 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()));
}
}
}
})); }));
return result; });
}, ct);
loadChildrenTask = thisTask;
thisTask.Start();
// Give the task a bit time to complete before we return to WPF - this keeps "Loading..." // Give the task a bit time to complete before we return to WPF - this keeps "Loading..."
// from showing up for very short waits. // from showing up for very short waits.
thisTask.Wait(TimeSpan.FromMilliseconds(200)); thisTask.Wait(TimeSpan.FromMilliseconds(200));
@ -66,7 +91,7 @@ namespace ICSharpCode.ILSpy.TreeNodes
loadChildrenTask = this.loadChildrenTask; loadChildrenTask = this.loadChildrenTask;
} }
if (loadChildrenTask != null) { if (loadChildrenTask != null) {
foreach (var child in loadChildrenTask.Result) { foreach (ILSpyTreeNode child in loadChildrenTask.Result.Cast<ILSpyTreeNode>()) {
child.Decompile(language, output, options); child.Decompile(language, output, options);
} }
} }
@ -87,5 +112,28 @@ namespace ICSharpCode.ILSpy.TreeNodes
{ {
} }
} }
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)
{
}
}
} }
} }

Loading…
Cancel
Save