diff --git a/ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs b/ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs index 763fef4dc..1b76f300f 100644 --- a/ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs +++ b/ICSharpCode.Decompiler/FlowAnalysis/OpCodeInfo.cs @@ -22,7 +22,7 @@ using System.Linq; using Mono.Cecil.Cil; -namespace ICSharpCode.Decompiler +namespace ICSharpCode.Decompiler.FlowAnalysis { /// /// Additional info about opcodes. diff --git a/ILSpy/Decompiler/CSharpLanguage.cs b/ILSpy/CSharpLanguage.cs similarity index 97% rename from ILSpy/Decompiler/CSharpLanguage.cs rename to ILSpy/CSharpLanguage.cs index 14de05a28..af2a6d707 100644 --- a/ILSpy/Decompiler/CSharpLanguage.cs +++ b/ILSpy/CSharpLanguage.cs @@ -20,7 +20,7 @@ using System; using ICSharpCode.Decompiler; using Mono.Cecil; -namespace ICSharpCode.ILSpy.Decompiler +namespace ICSharpCode.ILSpy { /// /// Decompiler logic for C#. diff --git a/ILSpy/FilterSettings.cs b/ILSpy/FilterSettings.cs index 49556dedb..df6213104 100644 --- a/ILSpy/FilterSettings.cs +++ b/ILSpy/FilterSettings.cs @@ -62,6 +62,18 @@ namespace ICSharpCode.ILSpy } } + Language language = Languages.AllLanguages[0]; + + public Language Language { + get { return language; } + set { + if (language != value) { + language = value; + OnPropertyChanged("Language"); + } + } + } + public event PropertyChangedEventHandler PropertyChanged; protected virtual void OnPropertyChanged(string propertyName) diff --git a/ILSpy/Disassembler/ILLanguage.cs b/ILSpy/ILLanguage.cs similarity index 98% rename from ILSpy/Disassembler/ILLanguage.cs rename to ILSpy/ILLanguage.cs index 86362f08b..2b1984524 100644 --- a/ILSpy/Disassembler/ILLanguage.cs +++ b/ILSpy/ILLanguage.cs @@ -24,7 +24,7 @@ using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.Disassembler; using Mono.Cecil; -namespace ICSharpCode.ILSpy.Disassembler +namespace ICSharpCode.ILSpy { public class ILLanguage : Language { diff --git a/ILSpy/ILSpy.csproj b/ILSpy/ILSpy.csproj index 95f65bef3..d49ac75a4 100644 --- a/ILSpy/ILSpy.csproj +++ b/ILSpy/ILSpy.csproj @@ -81,14 +81,14 @@ App.xaml + - - + @@ -122,7 +122,6 @@ - diff --git a/ILSpy/Language.cs b/ILSpy/Language.cs index 213c2951a..3f8876d62 100644 --- a/ILSpy/Language.cs +++ b/ILSpy/Language.cs @@ -28,8 +28,6 @@ namespace ICSharpCode.ILSpy /// public abstract class Language { - public static Language Current = new Decompiler.CSharpLanguage(); - public abstract string Name { get; } public virtual ICSharpCode.AvalonEdit.Highlighting.IHighlightingDefinition SyntaxHighlighting { @@ -74,4 +72,13 @@ namespace ICSharpCode.ILSpy return Name; } } + + public static class Languages + { + public static readonly Language[] AllLanguages = { + new CSharpLanguage(), + new ILLanguage(false), + new ILLanguage(true) + }; + } } diff --git a/ILSpy/MainWindow.xaml b/ILSpy/MainWindow.xaml index 582927e3a..1a63c6319 100644 --- a/ILSpy/MainWindow.xaml +++ b/ILSpy/MainWindow.xaml @@ -64,7 +64,9 @@ - + diff --git a/ILSpy/MainWindow.xaml.cs b/ILSpy/MainWindow.xaml.cs index f4b6b5eac..2f6750a79 100644 --- a/ILSpy/MainWindow.xaml.cs +++ b/ILSpy/MainWindow.xaml.cs @@ -17,24 +17,17 @@ // DEALINGS IN THE SOFTWARE. using System; -using System.Collections.Generic; +using System.ComponentModel; using System.Diagnostics; using System.IO; using System.Linq; -using System.Threading; -using System.Threading.Tasks; using System.Windows; using System.Windows.Controls; using System.Windows.Input; -using System.Windows.Threading; using ICSharpCode.Decompiler; using ICSharpCode.Decompiler.FlowAnalysis; -using ICSharpCode.ILSpy.Disassembler; -using ICSharpCode.ILSpy.TextView; using ICSharpCode.TreeView; using Microsoft.Win32; -using Mono.Cecil; -using Mono.Cecil.Cil; using Mono.Cecil.Rocks; namespace ICSharpCode.ILSpy @@ -45,6 +38,7 @@ namespace ICSharpCode.ILSpy public partial class MainWindow : Window { AssemblyList assemblyList = new AssemblyList(); + AssemblyListTreeNode assemblyListTreeNode; FilterSettings filterSettings = new FilterSettings(); static readonly System.Reflection.Assembly[] initialAssemblies = { @@ -68,19 +62,9 @@ namespace ICSharpCode.ILSpy InitializeComponent(); decompilerTextView.mainWindow = this; - languageComboBox.Items.Add(new Decompiler.CSharpLanguage()); - languageComboBox.Items.Add(new Disassembler.ILLanguage(false)); - languageComboBox.Items.Add(new Disassembler.ILLanguage(true)); - languageComboBox.SelectedItem = languageComboBox.Items[0]; - - AssemblyListTreeNode assemblyListTreeNode = new AssemblyListTreeNode(assemblyList); + assemblyListTreeNode = new AssemblyListTreeNode(assemblyList); assemblyListTreeNode.FilterSettings = filterSettings.Clone(); - filterSettings.PropertyChanged += delegate { - // filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable. - // Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main - // mutable instance changes. - assemblyListTreeNode.FilterSettings = filterSettings.Clone(); - }; + filterSettings.PropertyChanged += new PropertyChangedEventHandler(filterSettings_PropertyChanged); treeView.Root = assemblyListTreeNode; assemblyListTreeNode.Select = SelectNode; @@ -92,21 +76,20 @@ namespace ICSharpCode.ILSpy } #if DEBUG - toolBar.Items.Add(new Separator()); - - Button cfg = new Button() { Content = "CFG" }; - cfg.Click += new RoutedEventHandler(cfg_Click); - toolBar.Items.Add(cfg); - - Button ssa = new Button() { Content = "SSA" }; - ssa.Click += new RoutedEventHandler(ssa_Click); - toolBar.Items.Add(ssa); - - Button varGraph = new Button() { Content = "Var" }; - varGraph.Click += new RoutedEventHandler(varGraph_Click); - toolBar.Items.Add(varGraph); + AddDebugItemsToToolbar(); #endif } + + void filterSettings_PropertyChanged(object sender, PropertyChangedEventArgs e) + { + // filterSettings is mutable; but the ILSpyTreeNode filtering assumes that filter settings are immutable. + // Thus, the main window will use one mutable instance (for data-binding), and assign a new clone to the ILSpyTreeNodes whenever the main + // mutable instance changes. + assemblyListTreeNode.FilterSettings = filterSettings.Clone(); + if (e.PropertyName == "Language") { + TreeView_SelectionChanged(null, null); + } + } internal AssemblyList AssemblyList { get { return assemblyList; } @@ -122,6 +105,23 @@ namespace ICSharpCode.ILSpy #region Debugging CFG #if DEBUG + void AddDebugItemsToToolbar() + { + toolBar.Items.Add(new Separator()); + + Button cfg = new Button() { Content = "CFG" }; + cfg.Click += new RoutedEventHandler(cfg_Click); + toolBar.Items.Add(cfg); + + Button ssa = new Button() { Content = "SSA" }; + ssa.Click += new RoutedEventHandler(ssa_Click); + toolBar.Items.Add(ssa); + + Button varGraph = new Button() { Content = "Var" }; + varGraph.Click += new RoutedEventHandler(varGraph_Click); + toolBar.Items.Add(varGraph); + } + void cfg_Click(object sender, RoutedEventArgs e) { MethodTreeNode node = treeView.SelectedItem as MethodTreeNode; @@ -213,13 +213,7 @@ namespace ICSharpCode.ILSpy void TreeView_SelectionChanged(object sender, SelectionChangedEventArgs e) { - decompilerTextView.Decompile(treeView.SelectedItems.OfType()); - } - - void LanguageComboBox_SelectionChanged(object sender, SelectionChangedEventArgs e) - { - ILSpy.Language.Current = (ILSpy.Language)languageComboBox.SelectedItem; - TreeView_SelectionChanged(null, null); + decompilerTextView.Decompile(filterSettings.Language, treeView.SelectedItems.OfType()); } } } \ No newline at end of file diff --git a/ILSpy/Mono.Cecil.Rocks/MethodBodyRocks.cs b/ILSpy/Mono.Cecil.Rocks/MethodBodyRocks.cs index d12cc80bf..dc25967c9 100644 --- a/ILSpy/Mono.Cecil.Rocks/MethodBodyRocks.cs +++ b/ILSpy/Mono.Cecil.Rocks/MethodBodyRocks.cs @@ -32,9 +32,6 @@ using Mono.Cecil.Cil; namespace Mono.Cecil.Rocks { -#if INSIDE_ROCKS - public -#endif static class MethodBodyRocks { public static ParameterDefinition GetParameter (this MethodBody self, int index) diff --git a/ILSpy/TextView/DecompilerTextView.cs b/ILSpy/TextView/DecompilerTextView.cs index 1fb76156c..dd3fe6f3c 100644 --- a/ILSpy/TextView/DecompilerTextView.cs +++ b/ILSpy/TextView/DecompilerTextView.cs @@ -66,7 +66,7 @@ namespace ICSharpCode.ILSpy.TextView foldingManager = FoldingManager.Install(textEditor.TextArea); } - public void Decompile(IEnumerable treeNodes) + public void Decompile(ILSpy.Language language, IEnumerable treeNodes) { if (waitAdorner.Visibility != Visibility.Visible) { waitAdorner.Visibility = Visibility.Visible; @@ -82,7 +82,7 @@ namespace ICSharpCode.ILSpy.TextView DecompilationOptions options = new DecompilationOptions(); options.CancellationToken = myCancellationTokenSource.Token; - var task = RunDecompiler(ILSpy.Language.Current, treeNodes.ToArray(), options); + var task = RunDecompiler(language, treeNodes.ToArray(), options); Action continuation = delegate { try { if (currentCancellationTokenSource == myCancellationTokenSource) { @@ -94,7 +94,7 @@ namespace ICSharpCode.ILSpy.TextView SmartTextOutput textOutput = task.Result; referenceElementGenerator.References = textOutput.References; definitionLookup = textOutput.DefinitionLookup; - textEditor.SyntaxHighlighting = ILSpy.Language.Current.SyntaxHighlighting; + textEditor.SyntaxHighlighting = language.SyntaxHighlighting; textEditor.Text = textOutput.ToString(); foldingManager.UpdateFoldings(textOutput.Foldings.OrderBy(f => f.StartOffset), -1); } catch (AggregateException ex) { diff --git a/ILSpy/TextView/DecompilerTextView.xaml b/ILSpy/TextView/DecompilerTextView.xaml index d5852ff2d..161d8c8d5 100644 --- a/ILSpy/TextView/DecompilerTextView.xaml +++ b/ILSpy/TextView/DecompilerTextView.xaml @@ -13,7 +13,7 @@ IsReadOnly="True" Background="{DynamicResource {x:Static SystemColors.InfoBrushKey}}" Foreground="{DynamicResource {x:Static SystemColors.InfoTextBrushKey}}" /> - + Decompiling... diff --git a/ILSpy/TreeNodes/EventTreeNode.cs b/ILSpy/TreeNodes/EventTreeNode.cs index 28af0cda5..1054d5cde 100644 --- a/ILSpy/TreeNodes/EventTreeNode.cs +++ b/ILSpy/TreeNodes/EventTreeNode.cs @@ -42,7 +42,7 @@ namespace ICSharpCode.ILSpy } public override object Text { - get { return ev.Name + " : " + Language.Current.TypeToString(ev.EventType); } + get { return ev.Name + " : " + this.Language.TypeToString(ev.EventType); } } public override object Icon { diff --git a/ILSpy/TreeNodes/FieldTreeNode.cs b/ILSpy/TreeNodes/FieldTreeNode.cs index 02733f40e..e109d63db 100644 --- a/ILSpy/TreeNodes/FieldTreeNode.cs +++ b/ILSpy/TreeNodes/FieldTreeNode.cs @@ -41,7 +41,7 @@ namespace ICSharpCode.ILSpy } public override object Text { - get { return field.Name + " : " + Language.Current.TypeToString(field.FieldType); } + get { return field.Name + " : " + this.Language.TypeToString(field.FieldType); } } public override object Icon { diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs index 7437c3fe4..b0960e592 100644 --- a/ILSpy/TreeNodes/ILSpyTreeNode.cs +++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs @@ -40,6 +40,10 @@ namespace ICSharpCode.ILSpy } } + public Language Language { + get { return filterSettings.Language; } + } + public SharpTreeNodeCollection VisibleChildren { get { return base.Children; } } @@ -93,16 +97,20 @@ namespace ICSharpCode.ILSpy { if (children == null) throw new ArgumentNullException("children"); - this.Children = children; - children.CollectionChanged += children_CollectionChanged; + this.allChildren = children; + children.CollectionChanged += allChildren_CollectionChanged; } - void children_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) + void allChildren_CollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { + var visibleChildren = this.VisibleChildren; + switch (e.Action) { case NotifyCollectionChangedAction.Add: - if (e.NewItems.Count == 1 && e.NewStartingIndex == this.Children.Count - 1) { - FilterChild((T)e.NewItems[0]); + if (e.NewItems.Count == 1 && e.NewStartingIndex == allChildren.Count - 1) { + T newChild = (T)e.NewItems[0]; + if (FilterChild(newChild)) + visibleChildren.Add(newChild); break; } else { goto default; @@ -115,13 +123,16 @@ namespace ICSharpCode.ILSpy void ResetChildren() { - base.Children.Clear(); - foreach (T child in this.Children) { - FilterChild(child); + var visibleChildren = this.VisibleChildren; + + visibleChildren.Clear(); + foreach (T child in allChildren) { + if (FilterChild(child)) + visibleChildren.Add(child); } } - void FilterChild(T child) + bool FilterChild(T child) { FilterResult r; if (this.FilterSettings == null) @@ -130,24 +141,18 @@ namespace ICSharpCode.ILSpy r = child.Filter(this.FilterSettings); switch (r) { case FilterResult.Hidden: - // don't add to base.Children - break; + return false; case FilterResult.Match: child.FilterSettings = StripSearchTerm(this.FilterSettings); - base.Children.Add(child); - break; + return true; case FilterResult.Recurse: child.FilterSettings = this.FilterSettings; child.EnsureLazyChildren(); - if (child.VisibleChildren.Count > 0) - base.Children.Add(child); - break; + return child.VisibleChildren.Count > 0; case FilterResult.MatchAndRecurse: child.FilterSettings = StripSearchTerm(this.FilterSettings); child.EnsureLazyChildren(); - if (child.VisibleChildren.Count > 0) - base.Children.Add(child); - break; + return child.VisibleChildren.Count > 0; default: throw new InvalidEnumArgumentException(); } @@ -166,10 +171,34 @@ namespace ICSharpCode.ILSpy protected override void OnFilterSettingsChanged() { - ResetChildren(); + var visibleChildren = this.VisibleChildren; + var allChildren = this.Children; + int j = 0; + for (int i = 0; i < allChildren.Count; i++) { + T child = allChildren[i]; + if (j < visibleChildren.Count && visibleChildren[j] == child) { + // it was visible before + if (FilterChild(child)) { + j++; // keep it visible + } else { + visibleChildren.RemoveAt(j); // hide it + } + } else { + // it wasn't visible before + if (FilterChild(child)) { + // make it visible + visibleChildren.Insert(j++, child); + } + } + } + RaisePropertyChanged("Text"); } - public new readonly ObservableCollection Children; + readonly ObservableCollection allChildren; + + public new ObservableCollection Children { + get { return allChildren; } + } } class ILSpyTreeNode : ILSpyTreeNode {} diff --git a/ILSpy/TreeNodes/MethodTreeNode.cs b/ILSpy/TreeNodes/MethodTreeNode.cs index c6cbb86fe..92a4f891a 100644 --- a/ILSpy/TreeNodes/MethodTreeNode.cs +++ b/ILSpy/TreeNodes/MethodTreeNode.cs @@ -48,10 +48,10 @@ namespace ICSharpCode.ILSpy b.Append('('); for (int i = 0; i < method.Parameters.Count; i++) { if (i > 0) b.Append(", "); - b.Append(Language.Current.TypeToString(method.Parameters[i].ParameterType)); + b.Append(this.Language.TypeToString(method.Parameters[i].ParameterType)); } b.Append(") : "); - b.Append(Language.Current.TypeToString(method.ReturnType)); + b.Append(this.Language.TypeToString(method.ReturnType)); return b.ToString(); } } diff --git a/ILSpy/TreeNodes/PropertyTreeNode.cs b/ILSpy/TreeNodes/PropertyTreeNode.cs index 244ec88e4..068f52f08 100644 --- a/ILSpy/TreeNodes/PropertyTreeNode.cs +++ b/ILSpy/TreeNodes/PropertyTreeNode.cs @@ -44,7 +44,7 @@ namespace ICSharpCode.ILSpy } public override object Text { - get { return property.Name + " : " + Language.Current.TypeToString(property.PropertyType); } + get { return property.Name + " : " + this.Language.TypeToString(property.PropertyType); } } public override object Icon { diff --git a/ILSpy/TreeTraversal.cs b/ILSpy/TreeTraversal.cs deleted file mode 100644 index ed1312b54..000000000 --- a/ILSpy/TreeTraversal.cs +++ /dev/null @@ -1,112 +0,0 @@ -// 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; - -namespace ICSharpCode.ILSpy -{ - /// - /// Static helper methods for traversing trees. - /// - public static class TreeTraversal - { - /// - /// Converts a tree data structure into a flat list by traversing it in pre-order. - /// - /// The root element of the tree. - /// The function that gets the children of an element. - /// Iterator that enumerates the tree structure in pre-order. - public static IEnumerable PreOrder(T root, Func> recursion) - { - return PreOrder(new T[] { root }, recursion); - } - - /// - /// Converts a tree data structure into a flat list by traversing it in pre-order. - /// - /// The root elements of the forest. - /// The function that gets the children of an element. - /// Iterator that enumerates the tree structure in pre-order. - public static IEnumerable PreOrder(IEnumerable input, Func> recursion) - { - Stack> stack = new Stack>(); - try { - stack.Push(input.GetEnumerator()); - while (stack.Count > 0) { - while (stack.Peek().MoveNext()) { - T element = stack.Peek().Current; - yield return element; - IEnumerable children = recursion(element); - if (children != null) { - stack.Push(children.GetEnumerator()); - } - } - stack.Pop().Dispose(); - } - } finally { - while (stack.Count > 0) { - stack.Pop().Dispose(); - } - } - } - - /// - /// Converts a tree data structure into a flat list by traversing it in post-order. - /// - /// The root element of the tree. - /// The function that gets the children of an element. - /// Iterator that enumerates the tree structure in post-order. - public static IEnumerable PostOrder(T root, Func> recursion) - { - return PostOrder(new T[] { root }, recursion); - } - - /// - /// Converts a tree data structure into a flat list by traversing it in post-order. - /// - /// The root elements of the forest. - /// The function that gets the children of an element. - /// Iterator that enumerates the tree structure in post-order. - public static IEnumerable PostOrder(IEnumerable input, Func> recursion) - { - Stack> stack = new Stack>(); - try { - stack.Push(input.GetEnumerator()); - while (stack.Count > 0) { - while (stack.Peek().MoveNext()) { - T element = stack.Peek().Current; - IEnumerable children = recursion(element); - if (children != null) { - stack.Push(children.GetEnumerator()); - } else { - yield return element; - } - } - stack.Pop().Dispose(); - if (stack.Count > 0) - yield return stack.Peek().Current; - } - } finally { - while (stack.Count > 0) { - stack.Pop().Dispose(); - } - } - } - } -}