From d39a806795ddcec457d3dfcb9f0439765ad90f79 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 17 Feb 2011 18:02:18 +0100 Subject: [PATCH 1/3] Scroll down automatically when expanding a tree node. --- SharpTreeView/SharpTreeNodeView.cs | 4 +++- SharpTreeView/SharpTreeView.cs | 29 ++++++++++++++++++++++++++--- 2 files changed, 29 insertions(+), 4 deletions(-) diff --git a/SharpTreeView/SharpTreeNodeView.cs b/SharpTreeView/SharpTreeNodeView.cs index 135e6158c..4a0980943 100644 --- a/SharpTreeView/SharpTreeNodeView.cs +++ b/SharpTreeView/SharpTreeNodeView.cs @@ -95,7 +95,9 @@ namespace ICSharpCode.TreeView } } } else if (e.PropertyName == "IsExpanded") { - if (Node.IsExpanded == false) + if (Node.IsExpanded) + ParentTreeView.HandleExpanding(Node); + else ParentTreeView.HandleCollapsing(Node); } } diff --git a/SharpTreeView/SharpTreeView.cs b/SharpTreeView/SharpTreeView.cs index 4d1112736..d9409b79b 100644 --- a/SharpTreeView/SharpTreeView.cs +++ b/SharpTreeView/SharpTreeView.cs @@ -151,12 +151,35 @@ namespace ICSharpCode.TreeView container.ParentTreeView = this; } - internal void HandleCollapsing(SharpTreeNode Node) + internal void HandleExpanding(SharpTreeNode node) + { + SharpTreeNode lastVisibleChild = node; + while (true) { + SharpTreeNode tmp = lastVisibleChild.Children.LastOrDefault(c => c.IsVisible); + if (tmp != null) { + lastVisibleChild = tmp; + } else { + break; + } + } + if (lastVisibleChild != node) { + // Make the the expanded children are visible; but don't scroll down + // to much (keep node itself visible) + base.ScrollIntoView(lastVisibleChild); + // For some reason, this only works properly when delaying it... + Dispatcher.BeginInvoke(DispatcherPriority.Loaded, new Action( + delegate { + base.ScrollIntoView(node); + })); + } + } + + internal void HandleCollapsing(SharpTreeNode node) { - var selectedChilds = Node.VisibleDescendants().Where(n => n.IsSelected); + var selectedChilds = node.VisibleDescendants().Where(n => n.IsSelected); if (selectedChilds.Any()) { var list = SelectedItems.Cast().Except(selectedChilds).ToList(); - list.AddOnce(Node); + list.AddOnce(node); SetSelectedItems(list); } } From 56faf465977c43473e2a06d512556b47a4748319 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 17 Feb 2011 18:24:25 +0100 Subject: [PATCH 2/3] Avoid loading children when they aren't needed. --- ILSpy/TreeNodes/ILSpyTreeNode.cs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/ILSpy/TreeNodes/ILSpyTreeNode.cs b/ILSpy/TreeNodes/ILSpyTreeNode.cs index 44a9483d3..c8563c533 100644 --- a/ILSpy/TreeNodes/ILSpyTreeNode.cs +++ b/ILSpy/TreeNodes/ILSpyTreeNode.cs @@ -157,7 +157,8 @@ namespace ICSharpCode.ILSpy.TreeNodes void EnsureChildrenFiltered() { - EnsureLazyChildren(); + // No need to ensure lazy children here: + // if the children get lazy-loaded later, they'll still be filtered. if (childrenNeedFiltering) { childrenNeedFiltering = false; foreach (ILSpyTreeNode node in this.Children.OfType()) From ea0c2df3ffc18ce53315f4d74ddbf6c914dd16f1 Mon Sep 17 00:00:00 2001 From: Daniel Grunwald Date: Thu, 17 Feb 2011 20:17:38 +0100 Subject: [PATCH 3/3] Allow viewing the intermediate ILAst steps. --- .../ILAst/ILAstOptimizer.cs | 19 ++++++++++++++- ICSharpCode.Decompiler/ILAst/ILAstTypes.cs | 3 ++- ILSpy/ILAstLanguage.cs | 24 +++++++++++++++---- 3 files changed, 40 insertions(+), 6 deletions(-) diff --git a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs index 18cc956a0..233e00d84 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstOptimizer.cs @@ -8,16 +8,29 @@ using Decompiler.Rocks; namespace Decompiler.ControlFlow { + public enum ILAstOptimizationStep + { + SplitToMovableBlocks, + FindLoops, + FindConditions, + FlattenNestedMovableBlocks, + SimpleGotoRemoval, + RemoveDeadLabels, + None + } + public class ILAstOptimizer { Dictionary labelToCfNode = new Dictionary(); - public void Optimize(ILBlock method) + public void Optimize(ILBlock method, ILAstOptimizationStep abortBeforeStep = ILAstOptimizationStep.None) { + if (abortBeforeStep == ILAstOptimizationStep.SplitToMovableBlocks) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive().ToList()) { SplitToMovableBlocks(block); } + if (abortBeforeStep == ILAstOptimizationStep.FindLoops) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive().Where(b => !(b is ILMoveableBlock)).ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, block.EntryPoint); @@ -26,6 +39,7 @@ namespace Decompiler.ControlFlow block.Body = FindLoops(new HashSet(graph.Nodes.Skip(3)), graph.EntryPoint, true); } + if (abortBeforeStep == ILAstOptimizationStep.FindConditions) return; foreach(ILBlock block in method.GetSelfAndChildrenRecursive().Where(b => !(b is ILMoveableBlock)).ToList()) { ControlFlowGraph graph; graph = BuildGraph(block.Body, block.EntryPoint); @@ -35,8 +49,11 @@ namespace Decompiler.ControlFlow } // OrderNodes(method); + if (abortBeforeStep == ILAstOptimizationStep.FlattenNestedMovableBlocks) return; FlattenNestedMovableBlocks(method); + if (abortBeforeStep == ILAstOptimizationStep.SimpleGotoRemoval) return; SimpleGotoRemoval(method); + if (abortBeforeStep == ILAstOptimizationStep.RemoveDeadLabels) return; RemoveDeadLabels(method); } diff --git a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs index dea38d3c9..0361aad76 100644 --- a/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs +++ b/ICSharpCode.Decompiler/ILAst/ILAstTypes.cs @@ -85,7 +85,8 @@ namespace Decompiler public override void WriteTo(ITextOutput output) { - EntryPoint.WriteTo(output); + if (EntryPoint != null) + EntryPoint.WriteTo(output); foreach(ILNode child in this.Body) { child.WriteTo(output); output.WriteLine(); diff --git a/ILSpy/ILAstLanguage.cs b/ILSpy/ILAstLanguage.cs index 34fd5a037..5478c24a8 100644 --- a/ILSpy/ILAstLanguage.cs +++ b/ILSpy/ILAstLanguage.cs @@ -21,6 +21,7 @@ using System.Collections.Generic; using System.IO; using System.Linq; using Decompiler; +using Decompiler.ControlFlow; using Decompiler.Transforms; using ICSharpCode.Decompiler; using ICSharpCode.NRefactory.CSharp; @@ -33,17 +34,26 @@ namespace ICSharpCode.ILSpy /// public class ILAstLanguage : Language { + string name; + bool inlineVariables = true; + ILAstOptimizationStep? abortBeforeStep; + public override string Name { get { - return "ILAst"; + return name; } } public override void DecompileMethod(MethodDefinition method, ITextOutput output, DecompilationOptions options) { - var body = new ILAstBuilder().Build(method, false); + ILBlock ilMethod = new ILBlock(); + ilMethod.Body = new ILAstBuilder().Build(method, inlineVariables); + + if (abortBeforeStep != null) { + new ILAstOptimizer().Optimize(ilMethod, abortBeforeStep.Value); + } - foreach (ILNode node in body) { + foreach (ILNode node in ilMethod.Body) { node.WriteTo(output); output.WriteLine(); } @@ -52,7 +62,13 @@ namespace ICSharpCode.ILSpy #if DEBUG internal static IEnumerable GetDebugLanguages() { - yield return new ILAstLanguage(); + yield return new ILAstLanguage { name = "ILAst (unoptimized)", inlineVariables = false }; + string nextName = "ILAst (variable inlining)"; + foreach (ILAstOptimizationStep step in Enum.GetValues(typeof(ILAstOptimizationStep))) { + yield return new ILAstLanguage { name = nextName, abortBeforeStep = step }; + nextName = "ILAst (after " + step + ")"; + + } } #endif