From 0a07af27886517aa7a131f0637285776257697af Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?David=20Srbeck=C3=BD?= Date: Mon, 5 Mar 2012 23:15:36 +0000 Subject: [PATCH] Completely changed how debugger keeps state for nodes in local variables pad and in tooltips. The old method was to keep a NRefactory expression for each node. The new method is create a lambda expression for each node. The main motivation for this change is to get ready for NR5 which does not allow any sharing of AST nodes. This would mean that we would have to create a complete AST for each node, which might get expensive for deeply nested nodes. Caching of already evaluated expression would also be more difficult with separate ASTs. ILSpy is based on NR5 so we need this solution for it right now. Another disadvantage was that every operation had to go though AST so we had to support it in the evaluator, we had to generate the AST, and we had to hope that nothing breaks on the way. This is particularly complex for types - with lambda expression we simply keep around the reference to the type or to whatever we need. Some things like "current exception object" do not exist in the AST so we had to hack around it. On the other had, it was nice to have accurate C# expression for all nodes - for pretty printing, editing, or saving/loading it. --- .../Debugger.AddIn/Debugger.AddIn.csproj | 19 +- .../NRefactory}/ExpressionEvaluator.cs | 18 +- .../NRefactory}/ExpressionExtensionMethods.cs | 0 .../Options/DebuggingOptions.cs | 1 - .../Pads/Commands/WatchPadCommands.cs | 73 +------ .../Pads/Controls/TreeNodeWrapper.cs | 18 +- .../Debugger.AddIn/Pads/LocalVarPad.cs | 2 +- .../Debugger/Debugger.AddIn/Pads/WatchPad.cs | 32 ++- .../Debugger.AddIn/Pads/WatchPadModel.cs | 49 ----- .../Debugger.AddIn/Service/WindowsDebugger.cs | 25 +-- .../Tooltips/DebuggerTooltipControl.xaml.cs | 5 +- .../Tooltips/PinDebuggerControl.xaml.cs | 10 +- .../Debugger.AddIn/Tooltips/PinningBinding.cs | 13 +- .../TreeModel/ArrayRangeNode.cs | 76 ++----- .../TreeModel/ChildNodesOfObject.cs | 107 ++++------ .../TreeModel/DebuggerResourceService.cs | 25 --- .../TreeModel/ExpressionNode.cs | 135 +++++------- .../Debugger.AddIn/TreeModel/IContextMenu.cs | 12 -- .../Debugger.AddIn/TreeModel/ICorDebug.cs | 158 -------------- .../TreeModel/IEnumerableNode.cs | 32 --- .../Debugger.AddIn/TreeModel/IListNode.cs | 33 --- .../Debugger.AddIn/TreeModel/ISetText.cs | 12 -- .../Debugger.AddIn/TreeModel/SavedTreeNode.cs | 31 --- .../TreeModel/StackFrameNode.cs | 50 ++--- .../Debugger.AddIn/TreeModel/TreeNode.cs | 115 +++------- .../Commands/ExpressionVisualizerCommand.cs | 10 +- .../Commands/GridVisualizerCommand.cs | 13 +- .../Commands/GridVisualizerMenuCommand.cs | 4 +- .../Commands/IVisualizerDescriptor.cs | 2 +- .../Commands/ObjectGraphVisualizerCommand.cs | 12 +- .../Commands/TextVisualizerCommand.cs | 12 +- .../Commands/XmlVisualizerCommand.cs | 13 +- .../Visualizers/Common/IListValuesProvider.cs | 16 -- .../Common/VirtualizingCollection.cs | 16 +- .../Layout/TreeModel/ContentPropertyNode.cs | 4 +- .../GridVisualizer/GridVisualizerWindow.xaml | 3 - .../GridVisualizerWindow.xaml.cs | 199 ++++++------------ .../Visualizers/GridVisualizer/ObjectValue.cs | 85 -------- .../EnumerableValuesProvider.cs | 50 ----- .../ValueProviders/GridValuesProvider.cs | 42 ---- .../ValueProviders/ListValuesProvider.cs | 59 ------ .../TextVisualizer/TextVisualizerMode.cs | 12 -- .../TextVisualizerWindow.xaml.cs | 48 +---- .../Visualizers/Utils/DebuggerHelpers.cs | 13 +- .../Debugger.Core/Debugger.Core.csproj | 12 -- src/AddIns/Debugger/Debugger.Core/Eval.cs | 14 +- .../Debugger.Core/GetValueException.cs | 34 --- .../Debugger/Debugger.Core/ManagedCallback.cs | 4 +- .../Debugger.Core/MetaData/DebugMethodInfo.cs | 18 +- .../Debugger.Core/MetaData/DebugType.cs | 1 - src/AddIns/Debugger/Debugger.Core/Process.cs | 17 -- .../Debugger/Debugger.Core/StackFrame.cs | 10 + src/AddIns/Debugger/Debugger.Core/Value.cs | 1 + .../Debugger.Tests/Debugger.Tests.csproj | 4 + .../Src/Bookmarks/BookmarkConverter.cs | 2 +- .../Services/Debugger/Tooltips/ITreeNode.cs | 12 +- .../Services/Debugger/Tooltips/PinBookmark.cs | 4 +- 57 files changed, 360 insertions(+), 1437 deletions(-) rename src/AddIns/Debugger/{Debugger.Core/NRefactory/Visitors => Debugger.AddIn/NRefactory}/ExpressionEvaluator.cs (98%) rename src/AddIns/Debugger/{Debugger.Core/NRefactory/Ast => Debugger.AddIn/NRefactory}/ExpressionExtensionMethods.cs (100%) delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs delete mode 100644 src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs diff --git a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj index bd536316c0..cb9112ac80 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj +++ b/src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj @@ -97,6 +97,8 @@ + + DebuggingOptionsPanel.xaml Code @@ -161,7 +163,6 @@ Component - Form @@ -192,11 +193,6 @@ VisualizerPicker.xaml - - - - - @@ -209,7 +205,6 @@ - @@ -253,12 +248,10 @@ - - TextVisualizerWindow.xaml Code @@ -288,8 +281,6 @@ - - @@ -312,9 +303,6 @@ GridVisualizerWindow.xaml Code - - - @@ -324,7 +312,6 @@ - @@ -408,6 +395,7 @@ ICSharpCode.Core.WinForms False + @@ -423,7 +411,6 @@ - diff --git a/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs similarity index 98% rename from src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs rename to src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs index 633d7563ab..84f5ba51fb 100644 --- a/src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs @@ -15,8 +15,8 @@ namespace ICSharpCode.NRefactory.Visitors { public class EvaluateException: GetValueException { - public EvaluateException(INode code, string msg):base(code, msg) {} - public EvaluateException(INode code, string msgFmt, params string[] msgArgs):base(code, string.Format(msgFmt, msgArgs)) {} + public EvaluateException(INode code, string msg):base(msg) {} + public EvaluateException(INode code, string msgFmt, params string[] msgArgs):base(string.Format(msgFmt, msgArgs)) {} } class TypedValue @@ -163,13 +163,7 @@ namespace ICSharpCode.NRefactory.Visitors TypedValue Evaluate(INode expression, bool permRef, object data = null) { - // Try to get the value from cache - // (the cache is cleared when the process is resumed) TypedValue val; - if (context.Process.ExpressionsCache.TryGetValue(expression, out val)) { - if (val == null || !val.Value.IsInvalid) - return val; - } System.Diagnostics.Stopwatch watch = new System.Diagnostics.Stopwatch(); watch.Start(); @@ -177,11 +171,8 @@ namespace ICSharpCode.NRefactory.Visitors val = (TypedValue)expression.AcceptVisitor(this, data); if (val != null && permRef) val = new TypedValue(val.Value.GetPermanentReference(), val.Type); - } catch (GetValueException e) { - e.Expression = expression; - throw; } catch (NotImplementedException e) { - throw new GetValueException(expression, "Language feature not implemented: " + e.Message); + throw new EvaluateException(expression, "Language feature not implemented: " + e.Message); } finally { watch.Stop(); context.Process.TraceMessage("Evaluated: {0} in {1} ms total", expression.PrettyPrint(), watch.ElapsedMilliseconds); @@ -190,9 +181,6 @@ namespace ICSharpCode.NRefactory.Visitors if (val != null && val.Value.IsInvalid) throw new DebuggerException("Expression \"" + expression.PrettyPrint() + "\" is invalid right after evaluation"); - // Add the result to cache - context.Process.ExpressionsCache[expression] = val; - return val; } diff --git a/src/AddIns/Debugger/Debugger.Core/NRefactory/Ast/ExpressionExtensionMethods.cs b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionExtensionMethods.cs similarity index 100% rename from src/AddIns/Debugger/Debugger.Core/NRefactory/Ast/ExpressionExtensionMethods.cs rename to src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionExtensionMethods.cs diff --git a/src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs b/src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs index 216aab5df9..17ab1144f6 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs @@ -28,7 +28,6 @@ namespace ICSharpCode.SharpDevelop.Services DebuggeeExceptionWindowState = FormWindowState.Normal; } - public bool ICorDebugVisualizerEnabled { get; set; } public ShowIntegersAs ShowIntegersAs { get; set; } public bool ShowArgumentNames { get; set; } public bool ShowArgumentValues { get; set; } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs index 8faa9a6054..b391df174f 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs @@ -2,18 +2,12 @@ // This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) using System; -using System.Collections.Generic; using System.Linq; -using System.Windows.Forms; - using Debugger.AddIn.Pads; using Debugger.AddIn.Pads.Controls; using Debugger.AddIn.TreeModel; using ICSharpCode.Core; -using ICSharpCode.Core.Presentation; using ICSharpCode.Core.WinForms; -using ICSharpCode.NRefactory; -using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Gui.Pads; using ICSharpCode.SharpDevelop.Project; @@ -41,11 +35,10 @@ namespace Debugger.AddIn string language = ProjectService.CurrentProject.Language; - var text = new TextNode(null, input, - language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp).ToSharpTreeNode(); + var text = new TreeNode(input, null).ToSharpTreeNode(); var list = pad.WatchList; - if(!list.WatchItems.Any(n => text.Node.FullName == ((TreeNodeWrapper)n).Node.FullName)) + if(!list.WatchItems.Any(n => text.Node.Name == ((TreeNodeWrapper)n).Node.Name)) list.WatchItems.Add(text); } @@ -108,66 +101,4 @@ namespace Debugger.AddIn } } } - - public class WatchScriptingLanguageMenuBuilder : ISubmenuBuilder, IMenuItemBuilder - { - public ToolStripItem[] BuildSubmenu(Codon codon, object owner) - { - List items = new List(); - - if (owner is WatchPad) { - WatchPad pad = (WatchPad)owner; - - if (pad.WatchList.SelectedNode == null) - return items.ToArray(); - - var node = pad.WatchList.SelectedNode.Node; - - while (node.Parent != null && node.Parent.Parent != null) - { - node = node.Parent; - } - - if (!(node is TextNode)) - return items.ToArray(); - - foreach (string item in SupportedLanguage.GetNames(typeof(SupportedLanguage))) { - items.Add(MakeItem(item, item, node as TextNode, (sender, e) => HandleItem(sender))); - } - } - - return items.ToArray(); - } - - ToolStripMenuItem MakeItem(string title, string name, TextNode tag, EventHandler onClick) - { - ToolStripMenuItem menuItem = new ToolStripMenuItem(StringParser.Parse(title)); - menuItem.Click += onClick; - menuItem.Name = name; - menuItem.Tag = tag; - - if (name == tag.Language.ToString()) - menuItem.Checked = true; - - return menuItem; - } - - - void HandleItem(object sender) - { - ToolStripMenuItem item = null; - if (sender is ToolStripMenuItem) - item = (ToolStripMenuItem)sender; - - if (item != null) { - TextNode node = (TextNode)item.Tag; - node.Language = (SupportedLanguage)SupportedLanguage.Parse(typeof(SupportedLanguage), item.Text); - } - } - - public System.Collections.ICollection BuildItems(Codon codon, object owner) - { - return BuildSubmenu(codon, owner).TranslateToWpf(); - } - } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/TreeNodeWrapper.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/TreeNodeWrapper.cs index 6c8dd6ac22..3bd353e36c 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/TreeNodeWrapper.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/TreeNodeWrapper.cs @@ -28,22 +28,22 @@ namespace Debugger.AddIn.Pads.Controls public TreeNode Node { get; private set; } public override object Text { - get { return Node.Name; } + get { return this.Node.Name; } } public override object Icon { - get { return Node.ImageSource; } + get { return this.Node.ImageSource; } } public override bool ShowExpander { - get { return Node.HasChildNodes; } + get { return this.Node.GetChildren != null; } } protected override void LoadChildren() { - if (Node.HasChildNodes) { - ((WindowsDebugger)DebuggerService.CurrentDebugger).DebuggedProcess - .EnqueueWork(Dispatcher.CurrentDispatcher, () => Children.AddRange(Node.ChildNodes.Select(node => node.ToSharpTreeNode()))); + if (this.Node.GetChildren != null) { + var process = ((WindowsDebugger)DebuggerService.CurrentDebugger).DebuggedProcess; + process.EnqueueWork(Dispatcher.CurrentDispatcher, () => Children.AddRange(this.Node.GetChildren().Select(node => node.ToSharpTreeNode()))); } } } @@ -69,12 +69,10 @@ namespace Debugger.AddIn.Pads.Controls string language = ProjectService.CurrentProject.Language; - // FIXME languages - TextNode text = new TextNode(null, e.Data.GetData(DataFormats.StringFormat).ToString(), - language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp); + var text = new TreeNode(e.Data.GetData(DataFormats.StringFormat).ToString(), null); var node = text.ToSharpTreeNode(); - if (!WatchPad.Instance.WatchList.WatchItems.Any(n => text.FullName == ((TreeNodeWrapper)n).Node.FullName)) + if (!WatchPad.Instance.WatchList.WatchItems.Any(n => text.Name == ((TreeNodeWrapper)n).Node.Name)) WatchPad.Instance.WatchList.WatchItems.Add(node); WatchPad.Instance.InvalidatePad(); diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs index 3b870d7418..d1fb38c508 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs @@ -71,7 +71,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads debuggedProcess.EnqueueForEach( Dispatcher.CurrentDispatcher, - new StackFrameNode(frame).ChildNodes.ToList(), + Utils.GetLocalVariableNodes(frame).ToList(), n => localVarList.WatchItems.Add(n.ToSharpTreeNode()) ); } catch (Exception ex) { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs index 77da1ed9f5..99b236f3b1 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs @@ -17,6 +17,7 @@ using Debugger.AddIn.TreeModel; using ICSharpCode.Core; using ICSharpCode.Core.Presentation; using ICSharpCode.NRefactory; +using ICSharpCode.NRefactory.Ast; using ICSharpCode.SharpDevelop.Debugging; using ICSharpCode.SharpDevelop.Project; using Exception = System.Exception; @@ -78,29 +79,26 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads return; foreach (var element in props.Elements) { - watchList.WatchItems.Add(new TextNode(null, element, (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), props[element])).ToSharpTreeNode()); + watchList.WatchItems.Add(new TreeNode(element, null).ToSharpTreeNode()); } } void OnWatchItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e) { - if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems.Count > 0) { + var props = GetSavedVariablesProperties(); + if (props == null) return; + + if (e.Action == NotifyCollectionChangedAction.Add) { // add to saved data - var data = e.NewItems.OfType().FirstOrDefault(); - if (data != null) { - var props = GetSavedVariablesProperties(); - if (props == null) return; - props.Set(data.FullName, data.Language.ToString()); + foreach(var data in e.NewItems.OfType()) { + props.Set(data.Name, (object)null); } } if (e.Action == NotifyCollectionChangedAction.Remove) { // remove from saved data - var data = e.OldItems.OfType().FirstOrDefault(); - if (data != null) { - var props = GetSavedVariablesProperties(); - if (props == null) return; - props.Remove(data.FullName); + foreach(var data in e.OldItems.OfType()) { + props.Remove(data.Name); } } } @@ -162,9 +160,7 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads // rebuild list var nodes = new List(); foreach (var nod in watchList.WatchItems.OfType()) - nodes.Add(new TextNode(null, nod.Node.Name, - language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp) - .ToSharpTreeNode()); + nodes.Add(new TreeNode(nod.Node.Name, null).ToSharpTreeNode()); watchList.WatchItems.Clear(); foreach (var nod in nodes) @@ -194,13 +190,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads { try { LoggingService.Info("Evaluating: " + (string.IsNullOrEmpty(node.Node.Name) ? "is null or empty!" : node.Node.Name)); - var nodExpression = debugger.GetExpression(node.Node.Name); + //Value val = ExpressionEvaluator.Evaluate(nod.Name, nod.Language, debuggedProcess.SelectedStackFrame); - ExpressionNode valNode = new ExpressionNode(null, null, node.Node.Name, nodExpression); + ExpressionNode valNode = new ExpressionNode(null, node.Node.Name, () => debugger.GetExpression(node.Node.Name).Evaluate(debuggedProcess)); return valNode.ToSharpTreeNode(); } catch (GetValueException) { string error = String.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Watch.InvalidExpression}"), node.Node.Name); - ErrorInfoNode infoNode = new ErrorInfoNode(node.Node.Name, error); + TreeNode infoNode = new TreeNode("Icons.16x16.Error", node.Node.Name, error, string.Empty, null); return infoNode.ToSharpTreeNode(); } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs deleted file mode 100644 index 2357c06e6b..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs +++ /dev/null @@ -1,49 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System; -using System.Text; -using Debugger.AddIn.TreeModel; -using ICSharpCode.NRefactory; -using ICSharpCode.SharpDevelop.Project; - -namespace ICSharpCode.SharpDevelop.Gui.Pads -{ - public class TextNode : TreeNode, ISetText - { - public TextNode(TreeNode parent, string text, SupportedLanguage language) - : base(parent) - { - this.Name = text; - this.Language = language; - } - - public override bool CanSetText { - get { - return true; - } - } - - public override bool SetText(string text) - { - this.Text = text; - return true; - } - - public bool SetName(string name) - { - this.Name = name; - return true; - } - - public SupportedLanguage Language { get; set; } - } - - public class ErrorInfoNode : ICorDebug.InfoNode - { - public ErrorInfoNode(string name, string text) : base(null, name, text) - { - IconImage = DebuggerResourceService.GetImage("Icons.16x16.Error"); - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index e498cfc91d..acf29b606b 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -491,10 +491,7 @@ namespace ICSharpCode.SharpDevelop.Services { try { var tooltipExpression = GetExpression(variableName); - string imageName; - var image = ExpressionNode.GetImageForLocalVariable(out imageName); - ExpressionNode expressionNode = new ExpressionNode(null, image, variableName, tooltipExpression); - expressionNode.ImageName = imageName; + ExpressionNode expressionNode = new ExpressionNode("Icons.16x16.Local", variableName, () => tooltipExpression.Evaluate(this.DebuggedProcess)); return new DebuggerTooltipControl(logicalPosition, expressionNode) { ShowPins = debuggedProcess.GetCurrentExecutingFrame().HasSymbols }; } catch (System.Exception ex) { LoggingService.Error("Error on GetTooltipControl: " + ex.Message); @@ -505,19 +502,7 @@ namespace ICSharpCode.SharpDevelop.Services public ITreeNode GetNode(string variable, string currentImageName = null) { try { - var expression = GetExpression(variable); - string imageName; - IImage image; - if (string.IsNullOrEmpty(currentImageName)) { - image = ExpressionNode.GetImageForLocalVariable(out imageName); - } - else { - image = new ResourceServiceImage(currentImageName); - imageName = currentImageName; - } - ExpressionNode expressionNode = new ExpressionNode(null, image, variable, expression); - expressionNode.ImageName = imageName; - return expressionNode; + return new ExpressionNode(currentImageName ?? "Icons.16x16.Local", variable, () => GetExpression(variable).Evaluate(this.DebuggedProcess)); } catch (GetValueException) { return null; } @@ -827,9 +812,9 @@ namespace ICSharpCode.SharpDevelop.Services { OnIsProcessRunningChanged(EventArgs.Empty); - using(new PrintTimes("Jump to current line")) { - JumpToCurrentLine(); - } + LoggingService.Info("Jump to current line"); + JumpToCurrentLine(); + // TODO update tooltip /*if (currentTooltipRow != null && currentTooltipRow.IsShown) { using(new PrintTimes("Update tooltip")) { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs index cd217e85b9..62f76b5141 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs @@ -4,6 +4,7 @@ using System; using System.Collections.Generic; using System.Globalization; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; @@ -228,8 +229,8 @@ namespace Debugger.AddIn.Tooltips this.childPopup.IsLeaf = true; this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet; this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet; - if (clickedNode.ChildNodes != null) { - this.childPopup.ItemsSource = clickedNode.ChildNodes; + if (clickedNode.GetChildren != null) { + this.childPopup.ItemsSource = clickedNode.GetChildren().ToList(); this.childPopup.Open(); } } else { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs index 132d996603..a32e1a5ec9 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs @@ -4,13 +4,13 @@ using System; using System.Collections.Generic; using System.Collections.ObjectModel; +using System.Linq; using System.Windows; using System.Windows.Controls; using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media.Animation; using System.Windows.Shapes; - using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Bookmarks; using ICSharpCode.SharpDevelop.Debugging; @@ -207,8 +207,8 @@ namespace Debugger.AddIn.Tooltips this.childPopup.IsLeaf = true; this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet; this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet; - if (clickedNode.ChildNodes != null) { - this.childPopup.ItemsSource = clickedNode.ChildNodes; + if (clickedNode.GetChildren != null) { + this.childPopup.ItemsSource = clickedNode.GetChildren().ToList(); this.childPopup.Open(); } } else { @@ -300,14 +300,14 @@ namespace Debugger.AddIn.Tooltips // refresh content ITreeNode node = ((FrameworkElement)e.OriginalSource).DataContext as ITreeNode; - var resultNode = currentDebugger.GetNode(node.FullName, node.ImageName); + var resultNode = currentDebugger.GetNode(node.Name, node.ImageName); if (resultNode == null) return; // HACK for updating the pins in tooltip var observable = new ObservableCollection(); var source = lazyGrid.ItemsSource; source.ForEach(item => { - if (item.CompareTo(node) == 0) + if (item.Name == node.Name) observable.Add(resultNode); else observable.Add(item); diff --git a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs index 9811669d03..ca3282af2a 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs @@ -60,12 +60,13 @@ namespace Debugger.AddIn.Tooltips var nodes = new ObservableCollection(); foreach (var tuple in pin.SavedNodes) { - string imageName = !string.IsNullOrEmpty(tuple.Item1) ? tuple.Item1 : "Icons.16x16.Field"; - var node = new Debugger.AddIn.TreeModel.SavedTreeNode( - new ResourceServiceImage(imageName), + var node = new Debugger.AddIn.TreeModel.TreeNode( + !string.IsNullOrEmpty(tuple.Item1) ? tuple.Item1 : "Icons.16x16.Field", tuple.Item2, - tuple.Item3); - node.ImageName = imageName; + tuple.Item3, + string.Empty, + null + ); nodes.Add(node); } @@ -96,7 +97,7 @@ namespace Debugger.AddIn.Tooltips pin.SavedNodes.Add( new Tuple( "Icons.16x16.Field", - node.FullName, + node.Name, node.Text)); } diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs index 309071608c..15bb0d764f 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs @@ -10,41 +10,10 @@ using ICSharpCode.SharpDevelop.Debugging; namespace Debugger.AddIn.TreeModel { public partial class Utils - { - public static IEnumerable LazyGetChildNodesOfArray(TreeNode parent, Expression expression, ArrayDimensions dimensions) - { - if (dimensions.TotalElementCount == 0) - return new TreeNode[] { new TreeNode(null, "(empty)", null, null, parent, _ => null) }; - - return new ArrayRangeNode(parent, expression, dimensions, dimensions).ChildNodes; - } - } - - /// This is a partent node for all elements within a given bounds - public class ArrayRangeNode: TreeNode { const int MaxElementCount = 100; - Expression arrayTarget; - ArrayDimensions bounds; - ArrayDimensions originalBounds; - - public ArrayRangeNode(TreeNode parent, Expression arrayTarget, ArrayDimensions bounds, ArrayDimensions originalBounds) - : base(parent) - { - this.arrayTarget = arrayTarget; - this.bounds = bounds; - this.originalBounds = originalBounds; - - this.Name = GetName(); - this.childNodes = LazyGetChildren(); - } - - public override IEnumerable ChildNodes { - get { return base.ChildNodes; } - } - - string GetName() + public static TreeNode GetArrayRangeNode(ExpressionNode expr, ArrayDimensions bounds, ArrayDimensions originalBounds) { StringBuilder name = new StringBuilder(); bool isFirst = true; @@ -56,7 +25,7 @@ namespace Debugger.AddIn.TreeModel ArrayDimension originalDim = originalBounds[i]; if (dim.Count == 0) { - throw new DebuggerException("Empty dimension"); + name.Append("-"); } else if (dim.Count == 1) { name.Append(dim.LowerBound.ToString()); } else if (dim.Equals(originalDim)) { @@ -68,33 +37,32 @@ namespace Debugger.AddIn.TreeModel } } name.Append("]"); - return name.ToString(); + + return new TreeNode(name.ToString(), () => GetChildNodesOfArray(expr, bounds, originalBounds)); } - static string GetName(int[] indices) + public static IEnumerable GetChildNodesOfArray(ExpressionNode arrayTarget, ArrayDimensions bounds, ArrayDimensions originalBounds) { - StringBuilder sb = new StringBuilder(indices.Length * 4); - sb.Append("["); - bool isFirst = true; - foreach(int index in indices) { - if (!isFirst) sb.Append(", "); - sb.Append(index.ToString()); - isFirst = false; + if (bounds.TotalElementCount == 0) + { + yield return new TreeNode("(empty)", null); + yield break; } - sb.Append("]"); - return sb.ToString(); - } - - IEnumerable LazyGetChildren() - { + // The whole array is small - just add all elements as childs if (bounds.TotalElementCount <= MaxElementCount) { foreach(int[] indices in bounds.Indices) { - string imageName; - var image = ExpressionNode.GetImageForArrayIndexer(out imageName); - var expression = new ExpressionNode(this, image, GetName(indices), arrayTarget.AppendIndexer(indices)); - expression.ImageName = imageName; - yield return expression; + StringBuilder sb = new StringBuilder(indices.Length * 4); + sb.Append("["); + bool isFirst = true; + foreach(int index in indices) { + if (!isFirst) sb.Append(", "); + sb.Append(index.ToString()); + isFirst = false; + } + sb.Append("]"); + int[] indicesCopy = indices; + yield return new ExpressionNode("Icons.16x16.Field", sb.ToString(), () => arrayTarget.Evaluate().GetArrayElement(indicesCopy)); } yield break; } @@ -117,7 +85,7 @@ namespace Debugger.AddIn.TreeModel for(int i = splitDim.LowerBound; i <= splitDim.UpperBound; i += elementsPerSegment) { List newDims = new List(bounds); newDims[splitDimensionIndex] = new ArrayDimension(i, Math.Min(i + elementsPerSegment - 1, splitDim.UpperBound)); - yield return new ArrayRangeNode(this, arrayTarget, new ArrayDimensions(newDims), originalBounds); + yield return GetArrayRangeNode(arrayTarget, new ArrayDimensions(newDims), originalBounds); } yield break; } diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs index 7463c29cae..0a9eeff33a 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs @@ -1,10 +1,11 @@ // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) +using System; using System.Collections; using System.Collections.Generic; using System.Reflection; - +using System.Linq; using Debugger.AddIn.Visualizers.Utils; using Debugger.MetaData; using ICSharpCode.Core; @@ -17,7 +18,7 @@ namespace Debugger.AddIn.TreeModel { public partial class Utils { - public static IEnumerable LazyGetChildNodesOfObject(TreeNode current, Expression targetObject, DebugType shownType) + public static IEnumerable GetChildNodesOfObject(ExpressionNode expr, DebugType shownType) { MemberInfo[] publicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly); MemberInfo[] publicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly); @@ -27,116 +28,94 @@ namespace Debugger.AddIn.TreeModel DebugType baseType = (DebugType)shownType.BaseType; if (baseType != null) { yield return new TreeNode( - DebuggerResourceService.GetImage("Icons.16x16.Class"), + "Icons.16x16.Class", StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.BaseClass}"), baseType.Name, baseType.FullName, - current, - newNode => baseType.FullName == "System.Object" ? null : Utils.LazyGetChildNodesOfObject(newNode, targetObject, baseType) + baseType.FullName == "System.Object" ? (Func>) null : () => Utils.GetChildNodesOfObject(expr, baseType) ); } if (nonPublicInstance.Length > 0) { yield return new TreeNode( - null, StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicMembers}"), - string.Empty, - string.Empty, - current, - newNode => Utils.LazyGetMembersOfObject(newNode, targetObject, nonPublicInstance) + () => GetMembersOfObject(expr, nonPublicInstance) ); } if (publicStatic.Length > 0 || nonPublicStatic.Length > 0) { yield return new TreeNode( - null, StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.StaticMembers}"), - string.Empty, - string.Empty, - current, - p => { - var children = Utils.LazyGetMembersOfObject(p, targetObject, publicStatic); + () => { + var children = GetMembersOfObject(expr, publicStatic).ToList(); if (nonPublicStatic.Length > 0) { - TreeNode nonPublicStaticNode = new TreeNode( - null, + children.Insert(0, new TreeNode( StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicStaticMembers}"), - string.Empty, - string.Empty, - p, - newNode => Utils.LazyGetMembersOfObject(newNode, targetObject, nonPublicStatic) - ); - children = Utils.PrependNode(nonPublicStaticNode, children); + () => GetMembersOfObject(expr, nonPublicStatic) + )); } return children; } ); } - DebugType iListType = (DebugType)shownType.GetInterface(typeof(IList).FullName); - if (iListType != null) { - yield return new IListNode(current, targetObject); + if (shownType.GetInterface(typeof(IList).FullName) != null) { + yield return new TreeNode( + "IList", + () => GetItemsOfIList(() => expr.Evaluate()) + ); } else { - DebugType iEnumerableType, itemType; + DebugType listType, iEnumerableType, itemType; if (shownType.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) { - yield return new IEnumerableNode(current, targetObject, itemType); + yield return new TreeNode( + null, + "IEnumerable", + "Expanding will enumerate the IEnumerable", + string.Empty, + () => GetItemsOfIList(() => DebuggerHelpers.CreateListFromIEnumeralbe(expr.Evaluate(), itemType, out listType)) + ); } } - foreach(TreeNode node in LazyGetMembersOfObject(current, targetObject, publicInstance)) { + foreach(TreeNode node in GetMembersOfObject(expr, publicInstance)) { yield return node; } } - public static IEnumerable LazyGetMembersOfObject(TreeNode parent, Expression expression, MemberInfo[] members) + public static IEnumerable GetMembersOfObject(ExpressionNode expr, MemberInfo[] members) { - List nodes = new List(); - foreach(MemberInfo memberInfo in members) { - string imageName; - var image = ExpressionNode.GetImageForMember((IDebugMemberInfo)memberInfo, out imageName); - var exp = new ExpressionNode(parent, image, memberInfo.Name, expression.AppendMemberReference((IDebugMemberInfo)memberInfo)); - exp.ImageName = imageName; - nodes.Add(exp); + foreach(MemberInfo memberInfo in members.OrderBy(m => m.Name)) { + var memberInfoCopy = memberInfo; + string imageName = ExpressionNode.GetImageForMember((IDebugMemberInfo)memberInfo); + yield return new ExpressionNode(imageName, memberInfo.Name, () => expr.Evaluate().GetMemberValue(memberInfoCopy)); } - nodes.Sort(); - return nodes; } - - public static IEnumerable LazyGetItemsOfIList(TreeNode parent, Expression targetObject) + public static IEnumerable GetItemsOfIList(Func getValue) { - // Add a cast, so that we are sure the expression has an indexer. - // (The expression can be e.g. of type 'object' but its value is a List. - // Without the cast, evaluating "expr[i]" would fail, because object does not have an indexer). - targetObject = targetObject.CastToIList(); + Value list = null; + DebugType iListType = null; int count = 0; GetValueException error = null; try { - count = targetObject.GetIListCount(); + // We use lambda for the value just so that we can get it in this try-catch block + list = getValue().GetPermanentReference(); + iListType = (DebugType)list.Type.GetInterface(typeof(IList).FullName); + // Do not get string representation since it can be printed in hex + count = (int)list.GetPropertyValue(iListType.GetProperty("Count")).PrimitiveValue; } catch (GetValueException e) { // Cannot yield a value in the body of a catch clause (CS1631) error = e; } if (error != null) { - yield return new TreeNode(null, "(error)", error.Message, null, null, _ => null); + yield return new TreeNode(null, "(error)", error.Message, string.Empty, null); } else if (count == 0) { - yield return new TreeNode(null, "(empty)", null, null, null, _ => null); + yield return new TreeNode("(empty)", null); } else { + PropertyInfo pi = iListType.GetProperty("Item"); for(int i = 0; i < count; i++) { - string imageName; - var image = ExpressionNode.GetImageForArrayIndexer(out imageName); - var itemNode = new ExpressionNode(parent, image, "[" + i + "]", targetObject.AppendIndexer(i)); - itemNode.ImageName = imageName; - yield return itemNode; - } - } - } - - public static IEnumerable PrependNode(TreeNode node, IEnumerable rest) - { - yield return node; - if (rest != null) { - foreach(TreeNode absNode in rest) { - yield return absNode; + int iCopy = i; + yield return new ExpressionNode("Icons.16x16.Field", "[" + i + "]", () => list.GetPropertyValue(pi, Eval.CreateValue(list.AppDomain, iCopy))); } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs deleted file mode 100644 index 1f5e272874..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs +++ /dev/null @@ -1,25 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using ICSharpCode.SharpDevelop; -using System; -using System.Collections.Generic; -using System.Linq; - -namespace Debugger.AddIn.TreeModel -{ - /// - /// Gets resources the way suitable for Debugger.AddIn. - /// - public static class DebuggerResourceService - { - /// - /// Gets image with given name from resources. - /// - /// Resource name of the image. - public static IImage GetImage(string resourceName) - { - return new ResourceServiceImage(resourceName); - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs index 91ab606863..2b5fdc4753 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs @@ -4,17 +4,18 @@ using System; using System.Collections.Generic; using System.ComponentModel; +using System.Diagnostics; using System.Globalization; using System.Linq; using System.Reflection; using System.Runtime.InteropServices; using System.Text; using System.Windows.Forms; - using Debugger.AddIn.Visualizers; using Debugger.MetaData; using ICSharpCode.Core; using ICSharpCode.NRefactory.Ast; +using ICSharpCode.NRefactory.Visitors; using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Debugging; using ICSharpCode.SharpDevelop.Services; @@ -26,11 +27,12 @@ namespace Debugger.AddIn.TreeModel /// Node in the tree which can be defined by a debugger expression. /// The expression will be lazily evaluated when needed. /// - public class ExpressionNode: TreeNode, ISetText, INotifyPropertyChanged + public class ExpressionNode: TreeNode, INotifyPropertyChanged { bool evaluated; - Expression expression; + Func valueGetter; + Value permanentValue; bool canSetText; GetValueException error; string fullText; @@ -40,10 +42,6 @@ namespace Debugger.AddIn.TreeModel set { evaluated = value; } } - public Expression Expression { - get { return expression; } - } - public override bool CanSetText { get { if (!evaluated) EvaluateExpression(); @@ -75,12 +73,6 @@ namespace Debugger.AddIn.TreeModel } } - public override string FullName { - get { - return this.expression.PrettyPrint() ?? Name.Trim(); - } - } - public override string Type { get { if (!evaluated) EvaluateExpression(); @@ -88,17 +80,13 @@ namespace Debugger.AddIn.TreeModel } } - public override IEnumerable ChildNodes { + public override Func> GetChildren { get { if (!evaluated) EvaluateExpression(); - return base.ChildNodes; + return base.GetChildren; } - } - - public override bool HasChildNodes { - get { - if (!evaluated) EvaluateExpression(); - return base.HasChildNodes; + protected set { + base.GetChildren = value; } } @@ -136,42 +124,47 @@ namespace Debugger.AddIn.TreeModel foreach (var descriptor in VisualizerDescriptors.GetAllDescriptors()) { if (descriptor.IsVisualizerAvailable(this.expressionType)) { - yield return descriptor.CreateVisualizerCommand(this.Expression); + yield return descriptor.CreateVisualizerCommand(this.Name, () => this.Evaluate()); } } } - public ExpressionNode(TreeNode parent, IImage image, string name, Expression expression) - : base(parent) + public ExpressionNode(string imageName, string name, Func valueGetter) + : base(imageName, name, string.Empty, string.Empty, null) { - this.IconImage = image; - this.Name = name; - this.expression = expression; + this.valueGetter = valueGetter; } + /// + /// Get the value of the node and cache it as long-lived reference. + /// We assume that the user will need this value a lot. + /// + public Value Evaluate() + { + if (permanentValue == null) + { + Stopwatch watch = new Stopwatch(); + watch.Start(); + permanentValue = valueGetter().GetPermanentReference(); + LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms (result cached for future use)", this.Name, watch.ElapsedMilliseconds); + } + return permanentValue; + } + + /// + /// Get the value of the node and update the UI text fields. + /// void EvaluateExpression() { evaluated = true; + Stopwatch watch = new Stopwatch(); + watch.Start(); + Value val; try { - var process = WindowsDebugger.DebuggedProcess; - if (process == null) return; - StackFrame frame = process.GetCurrentExecutingFrame(); - if (frame == null) return; - var debugger = (WindowsDebugger)DebuggerService.CurrentDebugger; - object data = debugger.debuggerDecompilerService.GetLocalVariableIndex(frame.MethodInfo.DeclaringType.MetadataToken, - frame.MethodInfo.MetadataToken, - Name); - - if (expression is MemberReferenceExpression) { - var memberExpression = (MemberReferenceExpression)expression; - memberExpression.TargetObject.UserData = data; - } else { - expression.UserData = data; - } - // evaluate expression - val = expression.Evaluate(process); + // Do not keep permanent reference + val = valueGetter(); } catch (GetValueException e) { error = e; this.Text = e.Message; @@ -188,27 +181,24 @@ namespace Debugger.AddIn.TreeModel if (val.IsNull) { } else if (val.Type.IsPrimitive || val.Type.FullName == typeof(string).FullName) { // Must be before IsClass } else if (val.Type.IsArray) { // Must be before IsClass - if (val.ArrayLength > 0) - this.childNodes = Utils.LazyGetChildNodesOfArray(this, this.Expression, val.ArrayDimensions); + if (val.ArrayLength > 0) { + var dims = val.ArrayDimensions; // Eval now + this.GetChildren = () => Utils.GetChildNodesOfArray(this, dims, dims); + } } else if (val.Type.IsClass || val.Type.IsValueType) { if (val.Type.FullNameWithoutGenericArguments == typeof(List<>).FullName) { if ((int)val.GetMemberValue("_size").PrimitiveValue > 0) - this.childNodes = Utils.LazyGetItemsOfIList(this, this.expression); + this.GetChildren = () => Utils.GetItemsOfIList(() => this.Evaluate()); } else { - this.childNodes = Utils.LazyGetChildNodesOfObject(this, this.Expression, val.Type); + this.GetChildren = () => Utils.GetChildNodesOfObject(this, val.Type); } } else if (val.Type.IsPointer) { Value deRef = val.Dereference(); if (deRef != null) { - this.childNodes = new ExpressionNode [] { new ExpressionNode(this, this.IconImage, "*" + this.Name, this.Expression.AppendDereference()) }; + this.GetChildren = () => new ExpressionNode [] { new ExpressionNode(this.ImageName, "*" + this.Name, () => this.Evaluate().Dereference()) }; } } - if (DebuggingOptions.Instance.ICorDebugVisualizerEnabled) { - TreeNode info = ICorDebug.GetDebugInfoRoot(val.AppDomain, val.CorValue); - this.childNodes = Utils.PrependNode(info, this.ChildNodes); - } - // Do last since it may expire the object if (val.Type.IsInteger) { fullText = FormatInteger(val.PrimitiveValue); @@ -236,6 +226,8 @@ namespace Debugger.AddIn.TreeModel } this.Text = (fullText.Length > 256) ? fullText.Substring(0, 256) + "..." : fullText; + + LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms", this.Name, watch.ElapsedMilliseconds); } string Escape(string source) @@ -308,11 +300,9 @@ namespace Debugger.AddIn.TreeModel public override bool SetText(string newText) { - string fullName = FullName; - Value val = null; try { - val = this.Expression.Evaluate(WindowsDebugger.DebuggedProcess); + val = this.Evaluate(); if (val.Type.IsInteger && newText.StartsWith("0x")) { try { val.PrimitiveValue = long.Parse(newText.Substring(2), NumberStyles.HexNumber); @@ -339,33 +329,10 @@ namespace Debugger.AddIn.TreeModel return false; } - public static IImage GetImageForThis(out string imageName) - { - imageName = "Icons.16x16.Parameter"; - return DebuggerResourceService.GetImage(imageName); - } - - public static IImage GetImageForParameter(out string imageName) - { - imageName = "Icons.16x16.Parameter"; - return DebuggerResourceService.GetImage(imageName); - } - - public static IImage GetImageForLocalVariable(out string imageName) - { - imageName = "Icons.16x16.Local"; - return DebuggerResourceService.GetImage(imageName); - } - - public static IImage GetImageForArrayIndexer(out string imageName) - { - imageName = "Icons.16x16.Field"; - return DebuggerResourceService.GetImage(imageName); - } - - public static IImage GetImageForMember(IDebugMemberInfo memberInfo, out string imageName) + public static string GetImageForMember(IDebugMemberInfo memberInfo) { string name = string.Empty; + if (memberInfo.IsPublic) { } else if (memberInfo.IsAssembly) { name += "Internal"; @@ -374,6 +341,7 @@ namespace Debugger.AddIn.TreeModel } else if (memberInfo.IsPrivate) { name += "Private"; } + if (memberInfo is FieldInfo) { name += "Field"; } else if (memberInfo is PropertyInfo) { @@ -384,8 +352,7 @@ namespace Debugger.AddIn.TreeModel throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName); } - imageName = "Icons.16x16." + name; - return DebuggerResourceService.GetImage(imageName); + return "Icons.16x16." + name; } // public ContextMenuStrip GetContextMenu() diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs deleted file mode 100644 index 0830a6d0b9..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System.Windows.Forms; - -namespace Debugger.AddIn.TreeModel -{ - public interface IContextMenu - { - ContextMenuStrip GetContextMenu(); - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs deleted file mode 100644 index fe054da52d..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs +++ /dev/null @@ -1,158 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using Debugger.Interop.CorDebug; -using System; -using System.Collections.Generic; -using Debugger.MetaData; -using ICSharpCode.SharpDevelop.Debugging; - -namespace Debugger.AddIn.TreeModel -{ - public class ICorDebug - { - public class InfoNode: TreeNode - { - List children; - - public InfoNode(TreeNode parent, string name, string text) - : this(parent, name, text, _ => null) - { - - } - - public InfoNode(TreeNode parent, string name, string text, Func> children) - : base(parent) - { - this.Name = name; - this.Text = text; - this.children = children(this); - } - - public override IEnumerable ChildNodes { - get { return children; } - } - - public void AddChild(string name, string text) - { - if (children == null) { - children = new List(); - } - children.Add(new InfoNode(this, name, text)); - } - - public void AddChild(string name, string text, Func> subChildren) - { - if (children == null) { - children = new List(); - } - children.Add(new InfoNode(this, name, text, p => subChildren(p))); - } - } - - public static InfoNode GetDebugInfoRoot(AppDomain appDomain, ICorDebugValue corValue) - { - return new InfoNode(null, "ICorDebug", "", p => GetDebugInfo(p, appDomain, corValue)); - } - - public static List GetDebugInfo(TreeNode parent, AppDomain appDomain, ICorDebugValue corValue) - { - List items = new List(); - - if (corValue is ICorDebugValue) { - InfoNode info = new InfoNode(parent, "ICorDebugValue", ""); - info.AddChild("Address", corValue.GetAddress().ToString("X8")); - info.AddChild("Type", ((CorElementType)corValue.GetTheType()).ToString()); - info.AddChild("Size", corValue.GetSize().ToString()); - items.Add(info); - } - if (corValue is ICorDebugValue2) { - InfoNode info = new InfoNode(parent, "ICorDebugValue2", ""); - ICorDebugValue2 corValue2 = (ICorDebugValue2)corValue; - string fullname; - try { - fullname = DebugType.CreateFromCorType(appDomain, corValue2.GetExactType()).FullName; - } catch (DebuggerException e) { - fullname = e.Message; - } - info.AddChild("ExactType", fullname); - items.Add(info); - } - if (corValue is ICorDebugGenericValue) { - InfoNode info = new InfoNode(parent, "ICorDebugGenericValue", ""); - try { - byte[] bytes = ((ICorDebugGenericValue)corValue).GetRawValue(); - for(int i = 0; i < bytes.Length; i += 8) { - string val = ""; - for(int j = i; j < bytes.Length && j < i + 8; j++) { - val += bytes[j].ToString("X2") + " "; - } - info.AddChild("Value" + i.ToString("X2"), val); - } - } catch (ArgumentException) { - info.AddChild("Value", "N/A"); - } - items.Add(info); - } - if (corValue is ICorDebugReferenceValue) { - InfoNode info = new InfoNode(parent, "ICorDebugReferenceValue", ""); - ICorDebugReferenceValue refValue = (ICorDebugReferenceValue)corValue; - info.AddChild("IsNull", (refValue.IsNull() != 0).ToString()); - if (refValue.IsNull() == 0) { - info.AddChild("Value", refValue.GetValue().ToString("X8")); - if (refValue.Dereference() != null) { - info.AddChild("Dereference", "", p => GetDebugInfo(p, appDomain, refValue.Dereference())); - } else { - info.AddChild("Dereference", "N/A"); - } - } - items.Add(info); - } - if (corValue is ICorDebugHeapValue) { - InfoNode info = new InfoNode(parent, "ICorDebugHeapValue", ""); - items.Add(info); - } - if (corValue is ICorDebugHeapValue2) { - InfoNode info = new InfoNode(parent, "ICorDebugHeapValue2", ""); - items.Add(info); - } - if (corValue is ICorDebugObjectValue) { - InfoNode info = new InfoNode(parent, "ICorDebugObjectValue", ""); - ICorDebugObjectValue objValue = (ICorDebugObjectValue)corValue; - info.AddChild("Class", objValue.GetClass().GetToken().ToString("X8")); - info.AddChild("IsValueClass", (objValue.IsValueClass() != 0).ToString()); - items.Add(info); - } - if (corValue is ICorDebugObjectValue2) { - InfoNode info = new InfoNode(parent, "ICorDebugObjectValue2", ""); - items.Add(info); - } - if (corValue is ICorDebugBoxValue) { - InfoNode info = new InfoNode(parent, "ICorDebugBoxValue", ""); - ICorDebugBoxValue boxValue = (ICorDebugBoxValue)corValue; - info.AddChild("Object", "", p => GetDebugInfo(p, appDomain, boxValue.GetObject())); - items.Add(info); - } - if (corValue is ICorDebugStringValue) { - InfoNode info = new InfoNode(parent, "ICorDebugStringValue", ""); - ICorDebugStringValue stringValue = (ICorDebugStringValue)corValue; - info.AddChild("Length", stringValue.GetLength().ToString()); - info.AddChild("String", stringValue.GetString()); - items.Add(info); - } - if (corValue is ICorDebugArrayValue) { - InfoNode info = new InfoNode(parent, "ICorDebugArrayValue", ""); - info.AddChild("...", "..."); - items.Add(info); - } - if (corValue is ICorDebugHandleValue) { - InfoNode info = new InfoNode(parent, "ICorDebugHandleValue", ""); - ICorDebugHandleValue handleValue = (ICorDebugHandleValue)corValue; - info.AddChild("HandleType", handleValue.GetHandleType().ToString()); - items.Add(info); - } - - return items; - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs deleted file mode 100644 index 35845151c9..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System; -using Debugger.AddIn.Visualizers.Utils; -using Debugger.MetaData; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.SharpDevelop.Debugging; - -namespace Debugger.AddIn.TreeModel -{ - /// - /// IEnumerable node in the variable tree. - /// - public class IEnumerableNode : TreeNode - { - Expression targetObject; - Expression debugListExpression; - - public IEnumerableNode(TreeNode parent, Expression targetObject, DebugType itemType) - : base(parent) - { - this.targetObject = targetObject; - - this.Name = "IEnumerable"; - this.Text = "Expanding will enumerate the IEnumerable"; - DebugType debugListType; - this.debugListExpression = DebuggerHelpers.CreateDebugListExpression(targetObject, itemType, out debugListType); - this.childNodes = Utils.LazyGetItemsOfIList(this, this.debugListExpression); - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs deleted file mode 100644 index 41d21d86ac..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs +++ /dev/null @@ -1,33 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using Debugger.AddIn.Visualizers.Utils; -using ICSharpCode.NRefactory.Ast; -using System.Collections; -using System.Collections.Generic; -using Debugger.MetaData; -using ICSharpCode.SharpDevelop.Debugging; -using ICSharpCode.SharpDevelop.Services; - -namespace Debugger.AddIn.TreeModel -{ - public class IListNode : TreeNode - { - Expression targetList; - int listCount; - - public IListNode(TreeNode parent, Expression targetListObject) - : base(parent) - { - this.targetList = targetListObject; - - this.Name = "IList"; - this.listCount = this.targetList.GetIListCount(); - this.childNodes = Utils.LazyGetItemsOfIList(this, this.targetList); - } - - public override bool HasChildNodes { - get { return this.listCount > 0; } - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs deleted file mode 100644 index 99978cd589..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -namespace Debugger.AddIn.TreeModel -{ - public interface ISetText - { - bool CanSetText { get; } - - bool SetText(string text); - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs deleted file mode 100644 index 40a6e5bb5d..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs +++ /dev/null @@ -1,31 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the GNU LGPL (for details please see \doc\license.txt) - -using System; -using ICSharpCode.SharpDevelop; - -namespace Debugger.AddIn.TreeModel -{ - /// - /// Description of SavedTreeNode. - /// - public class SavedTreeNode : TreeNode - { - public override bool CanSetText { - get { return true; } - } - - public SavedTreeNode(IImage image, string fullname, string text) - : base(null) - { - base.IconImage = image; - FullName = fullname; - Text = text; - } - - public override bool SetText(string newValue) { - Text = newValue; - return false; - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs index 176b2d0d26..9c002e1358 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs @@ -11,56 +11,32 @@ using ICSharpCode.SharpDevelop.Services; namespace Debugger.AddIn.TreeModel { - public class StackFrameNode: TreeNode + public partial class Utils { - StackFrame stackFrame; - - public StackFrame StackFrame { - get { return stackFrame; } - } - - public StackFrameNode(StackFrame stackFrame) - : base(null) - { - this.stackFrame = stackFrame; - - this.Name = stackFrame.MethodInfo.Name; - this.childNodes = LazyGetChildNodes(); - } - - IEnumerable LazyGetChildNodes() + public static IEnumerable GetLocalVariableNodes(StackFrame stackFrame) { foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) { - string imageName; - var image = ExpressionNode.GetImageForParameter(out imageName); - var expression = new ExpressionNode(this, image, par.Name, par.GetExpression()); - expression.ImageName = imageName; - yield return expression; + var parCopy = par; + yield return new ExpressionNode("Icons.16x16.Parameter", par.Name, () => parCopy.GetValue(stackFrame)); } - if (this.stackFrame.HasSymbols) { - foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(this.StackFrame.IP)) { - string imageName; - var image = ExpressionNode.GetImageForLocalVariable(out imageName); - var expression = new ExpressionNode(this, image, locVar.Name, locVar.GetExpression()); - expression.ImageName = imageName; - yield return expression; + if (stackFrame.HasSymbols) { + foreach(DebugLocalVariableInfo locVar in stackFrame.MethodInfo.GetLocalVariables(stackFrame.IP)) { + var locVarCopy = locVar; + yield return new ExpressionNode("Icons.16x16.Local", locVar.Name, () => locVarCopy.GetValue(stackFrame)); } } else { WindowsDebugger debugger = (WindowsDebugger)DebuggerService.CurrentDebugger; if (debugger.debuggerDecompilerService != null) { - int typeToken = this.stackFrame.MethodInfo.DeclaringType.MetadataToken; - int methodToken = this.stackFrame.MethodInfo.MetadataToken; + int typeToken = stackFrame.MethodInfo.DeclaringType.MetadataToken; + int methodToken = stackFrame.MethodInfo.MetadataToken; foreach (var localVar in debugger.debuggerDecompilerService.GetLocalVariables(typeToken, methodToken)) { - string imageName; - var image = ExpressionNode.GetImageForLocalVariable(out imageName); - var expression = new ExpressionNode(this, image, localVar, ExpressionEvaluator.ParseExpression(localVar, SupportedLanguage.CSharp)); - expression.ImageName = imageName; - yield return expression; + int index = ((int[])debugger.debuggerDecompilerService.GetLocalVariableIndex(typeToken, methodToken, localVar))[0]; + yield return new ExpressionNode("Icons.16x16.Local", localVar, () => stackFrame.GetLocalVariableValue((uint)index)); } } } if (stackFrame.Thread.CurrentException != null) { - yield return new ExpressionNode(this, null, "__exception", new IdentifierExpression("__exception")); + yield return new ExpressionNode(null, "$exception", () => stackFrame.Thread.CurrentException.Value); } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs index d00eb1df01..4bdabbdb65 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs @@ -15,31 +15,22 @@ namespace Debugger.AddIn.TreeModel { /// /// A node in the variable tree. - /// The node is immutable. /// public class TreeNode : ITreeNode { - IImage iconImage = null; - string name = string.Empty; - string imageName = string.Empty; - string text = string.Empty; - string type = string.Empty; - protected IEnumerable childNodes = null; - - /// - /// The image displayed for this node. - /// - public IImage IconImage { - get { return iconImage; } - protected set { iconImage = value; } - } + public IImage IconImage { get; protected set; } + public string ImageName { get; set; } + public string Name { get; set; } + public virtual string Text { get; set; } + public virtual string Type { get; protected set; } + public virtual Func> GetChildren { get; protected set; } /// /// System.Windows.Media.ImageSource version of . /// public ImageSource ImageSource { get { - return iconImage == null ? null : iconImage.ImageSource; + return this.IconImage == null ? null : this.IconImage.ImageSource; } } @@ -48,54 +39,26 @@ namespace Debugger.AddIn.TreeModel /// public Image Image { get { - return iconImage == null ? null : iconImage.Bitmap; + return this.IconImage == null ? null : this.IconImage.Bitmap; } } - public string Name { - get { return name; } - set { name = value; } - } - - public string ImageName { - get { return imageName; } - set { imageName = value; } - } - - public virtual string FullName { - get { return name; } - set { name = value; } - } - - public virtual string Text - { - get { return text; } - set { text = value; } - } - - public virtual string Type { - get { return type; } - protected set { type = value; } - } - - public virtual TreeNode Parent { get; protected set; } - - public virtual IEnumerable ChildNodes { - get { return childNodes; } + public virtual bool CanSetText { + get { return false; } } - IEnumerable ITreeNode.ChildNodes { - get { return childNodes; } + Func> ITreeNode.GetChildren { + get { + if (this.GetChildren == null) + return null; + return () => this.GetChildren(); + } } public virtual bool HasChildNodes { - get { return childNodes != null; } - } - - public virtual bool CanSetText { - get { return false; } + get { return this.GetChildren != null; } } - + public virtual IEnumerable VisualizerCommands { get { return null; @@ -110,41 +73,21 @@ namespace Debugger.AddIn.TreeModel public bool IsPinned { get; set; } - public TreeNode(TreeNode parent) - { - this.Parent = parent; - } - - public TreeNode(IImage iconImage, string name, string text, string type, TreeNode parent, Func> childNodes) - : this(parent) - { - if (childNodes == null) - throw new ArgumentNullException("childNodes"); - this.iconImage = iconImage; - this.name = name; - this.text = text; - this.type = type; - this.childNodes = childNodes(this); - } - - #region Equals and GetHashCode implementation - public override bool Equals(object obj) + public TreeNode(string name, Func> getChildren) { - TreeNode other = obj as TreeNode; - if (other == null) - return false; - return this.FullName == other.FullName; + this.Name = name; + this.GetChildren = getChildren; } - public override int GetHashCode() - { - return this.FullName.GetHashCode(); - } - #endregion - - public int CompareTo(ITreeNode other) + public TreeNode(string imageName, string name, string text, string type, Func> getChildren) { - return this.FullName.CompareTo(other.FullName); + this.ImageName = imageName; + if (imageName != null) + this.IconImage = new ResourceServiceImage(imageName); + this.Name = name; + this.Text = text; + this.Type = type; + this.GetChildren = getChildren; } public virtual bool SetText(string newValue) { diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs index 0a77ff8d44..daf3fffc81 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs @@ -16,11 +16,15 @@ namespace Debugger.AddIn.Visualizers // should we make visualizer command available for Expression, or any TreeNode? public abstract class ExpressionVisualizerCommand : IVisualizerCommand { - public Expression Expression { get; private set; } + public string ValueName { get; private set; } + public Func GetValue { get; private set; } - public ExpressionVisualizerCommand(Expression expression) + public ExpressionVisualizerCommand(string valueName, Func getValue) { - this.Expression = expression; + if (getValue == null) + throw new ArgumentNullException("getValue"); + this.ValueName = valueName; + this.GetValue = getValue; } public abstract void Execute(); diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs index 5a62f133ee..5387c98922 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs @@ -25,9 +25,9 @@ namespace Debugger.AddIn.Visualizers return type.ResolveIEnumerableImplementation(out collectionType, out itemType); } - public IVisualizerCommand CreateVisualizerCommand(Expression expression) + public IVisualizerCommand CreateVisualizerCommand(string valueName, Func getValue) { - return new GridVisualizerCommand(expression); + return new GridVisualizerCommand(valueName, getValue); } } @@ -36,8 +36,7 @@ namespace Debugger.AddIn.Visualizers /// public class GridVisualizerCommand : ExpressionVisualizerCommand { - public GridVisualizerCommand(Expression expression) - :base(expression) + public GridVisualizerCommand(string valueName, Func getValue) : base(valueName, getValue) { } @@ -48,10 +47,8 @@ namespace Debugger.AddIn.Visualizers public override void Execute() { - if (this.Expression == null) - return; - var gridVisualizerWindow = GridVisualizerWindow.EnsureShown(); - gridVisualizerWindow.ShownExpression = this.Expression; + GridVisualizerWindow window = new GridVisualizerWindow(this.ValueName, this.GetValue); + window.ShowDialog(); } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs index c4dcbefcbf..2b480fc5c6 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs @@ -14,9 +14,7 @@ namespace Debugger.AddIn.Visualizers { public override void Run() { - GridVisualizerWindow window = new GridVisualizerWindow(); - window.Topmost = true; - window.Show(); + } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs index 3ffb8114f9..b87da05866 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs @@ -16,6 +16,6 @@ namespace Debugger.AddIn.Visualizers public interface IVisualizerDescriptor { bool IsVisualizerAvailable(DebugType type); - IVisualizerCommand CreateVisualizerCommand(Expression expression); + IVisualizerCommand CreateVisualizerCommand(string valueName, Func getValue); } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs index 877880b5e8..a12f9aeb4e 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs @@ -21,9 +21,9 @@ namespace Debugger.AddIn.Visualizers return !type.IsAtomic() && !type.IsSystemDotObject(); } - public IVisualizerCommand CreateVisualizerCommand(Expression expression) + public IVisualizerCommand CreateVisualizerCommand(string valueName, Func getValue) { - return new ObjectGraphVisualizerCommand(expression); + return new ObjectGraphVisualizerCommand(valueName, getValue); } } @@ -32,8 +32,7 @@ namespace Debugger.AddIn.Visualizers /// public class ObjectGraphVisualizerCommand : ExpressionVisualizerCommand { - public ObjectGraphVisualizerCommand(Expression expression) - :base(expression) + public ObjectGraphVisualizerCommand(string valueName, Func getValue) : base(valueName, getValue) { } @@ -44,10 +43,9 @@ namespace Debugger.AddIn.Visualizers public override void Execute() { - if (this.Expression == null) - return; var objectGraphWindow = ObjectGraphWindow.EnsureShown(); - objectGraphWindow.ShownExpression = this.Expression; + // TODO: This only works on the root level + objectGraphWindow.ShownExpression = new IdentifierExpression(this.ValueName); } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs index 7b1747882d..1c31cc2df6 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs @@ -20,16 +20,15 @@ namespace Debugger.AddIn.Visualizers return type.FullName == typeof(string).FullName; } - public IVisualizerCommand CreateVisualizerCommand(Expression expression) + public IVisualizerCommand CreateVisualizerCommand(string valueName, Func getValue) { - return new TextVisualizerCommand(expression); + return new TextVisualizerCommand(valueName, getValue); } } public class TextVisualizerCommand : ExpressionVisualizerCommand { - public TextVisualizerCommand(Expression expression) - :base(expression) + public TextVisualizerCommand(string valueName, Func getValue) : base(valueName, getValue) { } @@ -40,10 +39,7 @@ namespace Debugger.AddIn.Visualizers public override void Execute() { - if (this.Expression == null) - return; - string expressionValue = this.Expression.Evaluate(WindowsDebugger.CurrentProcess).AsString(); - var textVisualizerWindow = new TextVisualizerWindow(this.Expression.PrettyPrint(), expressionValue); + var textVisualizerWindow = new TextVisualizerWindow(this.ValueName, this.GetValue().AsString()); textVisualizerWindow.ShowDialog(); } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs index 77f8ba988e..665e002482 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs @@ -20,9 +20,9 @@ namespace Debugger.AddIn.Visualizers return type.FullName == typeof(string).FullName; } - public IVisualizerCommand CreateVisualizerCommand(Expression expression) + public IVisualizerCommand CreateVisualizerCommand(string valueName, Func getValue) { - return new XmlVisualizerCommand(expression); + return new XmlVisualizerCommand(valueName, getValue); } } @@ -31,8 +31,7 @@ namespace Debugger.AddIn.Visualizers /// public class XmlVisualizerCommand : ExpressionVisualizerCommand { - public XmlVisualizerCommand(Expression expression) - :base(expression) + public XmlVisualizerCommand(string valueName, Func getValue) : base(valueName, getValue) { } @@ -43,11 +42,7 @@ namespace Debugger.AddIn.Visualizers public override void Execute() { - if (this.Expression == null) - return; - var textVisualizerWindow = new TextVisualizerWindow( - this.Expression.PrettyPrint(), this.Expression.Evaluate(WindowsDebugger.CurrentProcess).AsString()); - textVisualizerWindow.Mode = TextVisualizerMode.Xml; + var textVisualizerWindow = new TextVisualizerWindow(this.ValueName, this.GetValue().AsString(), ".xml"); textVisualizerWindow.ShowDialog(); } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs deleted file mode 100644 index d373860ad4..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs +++ /dev/null @@ -1,16 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System; - -namespace Debugger.AddIn.Visualizers -{ - /// - /// Can provide individial items for a lazy collection, as well as total count of items. - /// - public interface IListValuesProvider - { - int GetCount(); - T GetItemAt(int index); - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs index 6ec03cb2ab..cb87dcb028 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs @@ -8,21 +8,23 @@ using System.Collections.Generic; namespace Debugger.AddIn.Visualizers { /// - /// IList<T> with data vitualization - the indexer is lazy, uses IListValuesProvider to obtain values when needed. + /// IList<T> with data vitualization - the indexer is lazy, uses lamda function to obtain values when needed. /// public class VirtualizingCollection : IList, IList { - private IListValuesProvider valueProvider; - private Dictionary itemCache = new Dictionary(); + int count; + Func getItem; + Dictionary itemCache = new Dictionary(); - public VirtualizingCollection(IListValuesProvider valueProvider) + public VirtualizingCollection(int count, Func getItem) { - this.valueProvider = valueProvider; + this.count = count; + this.getItem = getItem; } public int Count { - get { return this.valueProvider.GetCount(); } + get { return count; } } public T this[int index] @@ -32,7 +34,7 @@ namespace Debugger.AddIn.Visualizers T cachedItem; if (!itemCache.TryGetValue(index, out cachedItem)) { - cachedItem = this.valueProvider.GetItemAt(index); + cachedItem = getItem(index); this.itemCache[index] = cachedItem; } return cachedItem; diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs index 53b4a1e2db..53b7b1c643 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs @@ -6,6 +6,7 @@ using System.ComponentModel; using Debugger.AddIn.TreeModel; using Debugger.AddIn.Visualizers.Graph.Drawing; using Debugger.MetaData; +using ICSharpCode.SharpDevelop; namespace Debugger.AddIn.Visualizers.Graph.Layout { @@ -77,8 +78,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout if ((this.Property != null) && (this.Property.ObjectGraphProperty != null)) { var memberInfo = (IDebugMemberInfo)this.Property.ObjectGraphProperty.MemberInfo; if (memberInfo != null) { - string imageName; - var image = ExpressionNode.GetImageForMember(memberInfo, out imageName); + var image = new ResourceServiceImage(ExpressionNode.GetImageForMember(memberInfo)); this.MemberIcon = image.ImageSource; } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml index 664da36dd7..954552e85d 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml @@ -27,9 +27,6 @@ - Expression: - - diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs index 80703cd997..d03a78198a 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs @@ -2,26 +2,16 @@ // This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) using System; -using System.Collections; -using System.Collections.Generic; -using System.Linq; using System.Reflection; -using System.Text; using System.Windows; using System.Windows.Controls; using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; -using Debugger.AddIn.TreeModel; + using Debugger.AddIn.Visualizers.PresentationBindings; using Debugger.AddIn.Visualizers.Utils; using Debugger.MetaData; using ICSharpCode.Core; -using ICSharpCode.NRefactory.Ast; using ICSharpCode.SharpDevelop; -using ICSharpCode.SharpDevelop.Debugging; -using ICSharpCode.SharpDevelop.Services; namespace Debugger.AddIn.Visualizers.GridVisualizer { @@ -30,160 +20,93 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer /// public partial class GridVisualizerWindow : Window { - WindowsDebugger debuggerService; - GridViewColumnHider columnHider; + Func getValue; - public GridVisualizerWindow() + public GridVisualizerWindow(string valueName, Func getValue) { InitializeComponent(); - this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger; - if (debuggerService == null) - throw new ApplicationException("Only windows debugger is currently supported"); + this.Title = valueName; + this.getValue = getValue; - instance = this; - this.Deactivated += GridVisualizerWindow_Deactivated; - } - - void GridVisualizerWindow_Deactivated(object sender, EventArgs e) - { - this.Close(); - } - - private ICSharpCode.NRefactory.Ast.Expression shownExpression; - public ICSharpCode.NRefactory.Ast.Expression ShownExpression - { - get { - return shownExpression; - } - set { - if (value == null) { - shownExpression = null; - txtExpression.Text = null; - - Refresh(); - return; - } - if (shownExpression == null || value.PrettyPrint() != shownExpression.PrettyPrint()) { - txtExpression.Text = value.PrettyPrint(); - Refresh(); - } - } - } - - static GridVisualizerWindow instance; - /// When Window is visible, returns reference to the Window. Otherwise returns null. - public static GridVisualizerWindow Instance - { - get { return instance; } - } - - public static GridVisualizerWindow EnsureShown() - { - var window = GridVisualizerWindow.Instance ?? new GridVisualizerWindow(); - window.Topmost = true; - window.Show(); - return window; - } - - protected override void OnClosing(System.ComponentModel.CancelEventArgs e) - { - this.Deactivated -= GridVisualizerWindow_Deactivated; - base.OnClosing(e); - } - - protected override void OnClosed(EventArgs e) - { - base.OnClosed(e); - instance = null; - } - - private void btnInspect_Click(object sender, RoutedEventArgs e) - { Refresh(); } - + public void Refresh() { - try { + try { // clear ListView listView.ItemsSource = null; - ScrollViewer listViewScroller = listView.GetScrollViewer(); - if (listViewScroller != null) { - listViewScroller.ScrollToVerticalOffset(0); - } - Value shownValue = null; - ICSharpCode.NRefactory.Ast.Expression shownExpr = null; - try { - shownExpr = debuggerService.GetExpression(txtExpression.Text); - shownValue = shownExpr.Evaluate(debuggerService.DebuggedProcess); - } catch(GetValueException e) { - MessageService.ShowMessage(e.Message); - } - if (shownValue != null && !shownValue.IsNull) { - GridValuesProvider gridValuesProvider; - // Value is IList - DebugType iListType, listItemType; - if (shownValue.Type.ResolveIListImplementation(out iListType, out listItemType)) { - gridValuesProvider = CreateListValuesProvider(shownExpr.CastToIList(), listItemType); + + Value shownValue = getValue(); + + DebugType iListType, iEnumerableType, itemType; + // Value is IList + if (shownValue.Type.ResolveIListImplementation(out iListType, out itemType)) { + // Ok + } else { + // Value is IEnumerable + if (shownValue.Type.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) { + shownValue = DebuggerHelpers.CreateListFromIEnumeralbe(shownValue, itemType, out iListType); } else { - // Value is IEnumerable - DebugType iEnumerableType, itemType; - if (shownValue.Type.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) { - DebugType debugListType; - var debugListExpression = DebuggerHelpers.CreateDebugListExpression(shownExpr, itemType, out debugListType); - gridValuesProvider = CreateListValuesProvider(debugListExpression, itemType); - } else { - // Not IList or IEnumerable - can't be displayed in GridVisualizer - return; - } + // Not IList or IEnumerable - can't be displayed in GridVisualizer + return; } - - IList itemTypeMembers = gridValuesProvider.GetItemTypeMembers(); - InitializeColumns((GridView)this.listView.View, itemTypeMembers); - this.columnHider = new GridViewColumnHider((GridView)this.listView.View); - cmbColumns.ItemsSource = this.columnHider.HideableColumns; } - } catch (GetValueException e) { - MessageService.ShowMessage(e.Message); - } catch (DebuggerVisualizerException e) { + shownValue = shownValue.GetPermanentReference(); + + MemberInfo[] members = itemType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance); + PropertyInfo itemGetter = iListType.GetProperty("Item"); + int rowCount = (int)shownValue.GetPropertyValue(iListType.GetProperty("Count")).PrimitiveValue; + int columnCount = members.Length + 1; + + var rowCollection = new VirtualizingCollection>( + rowCount, + (rowIndex) => new VirtualizingCollection( + columnCount, + (columnIndex) => { + if (columnIndex == members.Length) + return "[" + rowIndex + "]"; + try { + var rowValue = shownValue.GetPropertyValue(itemGetter, Eval.CreateValue(shownValue.AppDomain, rowIndex)); + return rowValue.GetMemberValue(members[columnIndex]).InvokeToString(); + } catch (GetValueException e) { + return "Exception: " + e.Message; + } + } + ) + ); + this.listView.ItemsSource = rowCollection; + + InitializeColumns((GridView)this.listView.View, members); + + GridViewColumnHider columnHider = new GridViewColumnHider((GridView)this.listView.View); + cmbColumns.ItemsSource = columnHider.HideableColumns; + + } catch(GetValueException e) { MessageService.ShowMessage(e.Message); } } - ListValuesProvider CreateListValuesProvider(ICSharpCode.NRefactory.Ast.Expression targetExpression, DebugType listItemType) - { - var listValuesProvider = new ListValuesProvider(targetExpression, listItemType); - var virtCollection = new VirtualizingCollection(listValuesProvider); - this.listView.ItemsSource = virtCollection; - return listValuesProvider; - } - - void InitializeColumns(GridView gridView, IList itemTypeMembers) + void InitializeColumns(GridView gridView, MemberInfo[] members) { gridView.Columns.Clear(); - AddIndexColumn(gridView); - AddMembersColumns(gridView, itemTypeMembers); - } - - void AddIndexColumn(GridView gridView) - { + + // Index column var indexColumn = new GridViewHideableColumn(); indexColumn.CanBeHidden = false; indexColumn.Width = 36; indexColumn.Header = string.Empty; - indexColumn.DisplayMemberBinding = new Binding("Index"); + indexColumn.DisplayMemberBinding = new Binding("[" + members.Length + "]"); gridView.Columns.Add(indexColumn); - } - - void AddMembersColumns(GridView gridView, IList itemTypeMembers) - { - foreach (var member in itemTypeMembers) { + + // Member columns + for (int i = 0; i < members.Length; i++) { var memberColumn = new GridViewHideableColumn(); memberColumn.CanBeHidden = true; - memberColumn.Header = member.Name; - // "{Binding Path=[Name].Value}" - memberColumn.DisplayMemberBinding = new Binding("[" + member.Name + "].Value"); + memberColumn.Header = members[i].Name; + memberColumn.IsVisibleDefault = ((IDebugMemberInfo)members[i]).IsPublic; + memberColumn.DisplayMemberBinding = new Binding("[" + i + "]"); gridView.Columns.Add(memberColumn); } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs deleted file mode 100644 index 6663528bca..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs +++ /dev/null @@ -1,85 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System; -using System.Collections.Generic; -using Debugger.AddIn.Visualizers.Utils; -using Debugger.MetaData; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.SharpDevelop.Services; -using System.Reflection; - -namespace Debugger.AddIn.Visualizers.GridVisualizer -{ - /// - /// Item of a collection in the debugee, with lazy evaluated properties. - /// - public class ObjectValue - { - /// Index of this item in the collection. - public int Index { get; private set; } - - // PermanentReference for one row. - public Value PermanentReference { get; private set; } - - private Dictionary properties = new Dictionary(); - - /// Used to quickly find MemberInfo by member name - DebugType.GetMember(name) uses a loop to search members - private Dictionary memberForNameMap; - - internal ObjectValue(int index, Dictionary memberFromNameMap) - { - this.Index = index; - this.memberForNameMap = memberFromNameMap; - } - - /// - /// Returns property with given name. - /// - public ObjectProperty this[string propertyName] - { - get - { - ObjectProperty property; - // has property with name 'propertyName' already been evaluated? - if(!this.properties.TryGetValue(propertyName, out property)) - { - if (this.PermanentReference == null) { - throw new DebuggerVisualizerException("Cannot get member of this ObjectValue - ObjectValue.PermanentReference is null"); - } - MemberInfo memberInfo = this.memberForNameMap.GetValue(propertyName); - if (memberInfo == null) { - throw new DebuggerVisualizerException("Cannot get member value - no member found with name " + propertyName); - } - property = CreatePropertyFromValue(propertyName, this.PermanentReference.GetMemberValue(memberInfo)); - this.properties.Add(propertyName, property); - } - return property; - } - } - - public static ObjectValue Create(Debugger.Value value, int index, Dictionary memberFromName) - { - ObjectValue result = new ObjectValue(index, memberFromName); - - // remember PermanentReference for expanding IEnumerable - Value permanentReference = value.GetPermanentReference(); - result.PermanentReference = permanentReference; - - return result; - } - - private static ObjectProperty CreatePropertyFromValue(string propertyName, Value value) - { - ObjectProperty property = new ObjectProperty(); - property.Name = propertyName; - // property.Expression = ?.Age - // - cannot use expression, - // if the value is returned from an enumerator, it has no meaningful expression - property.IsAtomic = value.Type.IsPrimitive; - property.IsNull = value.IsNull; - property.Value = value.IsNull ? "" : value.InvokeToString(); - return property; - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs deleted file mode 100644 index 09b9a5cf9f..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs +++ /dev/null @@ -1,50 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System; -using System.Collections; -using System.Collections.Generic; - -using Debugger.AddIn.Visualizers.Utils; -using Debugger.MetaData; -using ICSharpCode.Core; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.SharpDevelop.Services; -using System.Reflection; - -namespace Debugger.AddIn.Visualizers.GridVisualizer -{ - /// - /// Provides s for debugee objects implementing IEnumerable. - /// - /*public class EnumerableValuesProvider : GridValuesProvider - { - public EnumerableValuesProvider(Expression targetObject, DebugType iEnumerableType, DebugType itemType) - :base(targetObject, iEnumerableType, itemType) - { - this.itemsSource = enumerateItems(); - } - - private IEnumerable itemsSource; - public IEnumerable ItemsSource - { - get { return this.itemsSource; } - } - - private IEnumerable enumerateItems() - { - MethodInfo enumeratorMethod = collectionType.GetMethod("GetEnumerator"); - Value enumerator = targetObject.Evaluate(WindowsDebugger.CurrentProcess).InvokeMethod(enumeratorMethod, null).GetPermanentReference(); - - MethodInfo moveNextMethod = enumerator.Type.GetMethod("MoveNext"); - PropertyInfo currentproperty = enumerator.Type.GetInterface(typeof(IEnumerator).FullName).GetProperty("Current"); - - int index = 0; - while ((bool)enumerator.InvokeMethod(moveNextMethod, null).PrimitiveValue) - { - Value currentValue = enumerator.GetPropertyValue(currentproperty); - yield return ObjectValue.Create(currentValue, index++, this.memberFromNameMap); - } - } - }*/ -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs deleted file mode 100644 index f656934db6..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs +++ /dev/null @@ -1,42 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System; -using System.Collections.Generic; -using Debugger.AddIn.Visualizers.Utils; -using Debugger.MetaData; -using ICSharpCode.NRefactory.Ast; -using System.Reflection; - -namespace Debugger.AddIn.Visualizers.GridVisualizer -{ - /// - /// Provides s to be displayed in Grid visualizer. - /// Descandants implement getting values for IList and IEnumerable. - /// - public class GridValuesProvider - { - /// Used to quickly find MemberInfo by member name - DebugType.GetMember(name) uses a loop to search members - protected Dictionary memberFromNameMap; - - protected Expression targetObject; - protected DebugType itemType; - - public GridValuesProvider(Expression targetObject, DebugType itemType) - { - this.targetObject = targetObject; - this.itemType = itemType; - - this.memberFromNameMap = this.GetItemTypeMembers().MakeDictionary(memberInfo => memberInfo.Name); - } - - /// - /// Gets members that will be displayed as columns. - /// - public IList GetItemTypeMembers() - { - var publicPropetiesAndFields = itemType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance); - return publicPropetiesAndFields; - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs deleted file mode 100644 index 457566d0cf..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs +++ /dev/null @@ -1,59 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System; -using System.Collections.Generic; -using System.Linq; -using System.Reflection; -using Debugger.AddIn.Visualizers.Utils; -using Debugger.MetaData; -using ICSharpCode.Core; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.SharpDevelop.Services; - -namespace Debugger.AddIn.Visualizers.GridVisualizer -{ - /// - /// Provides s for debugee objects implementing IList. - /// - public class ListValuesProvider : GridValuesProvider, IListValuesProvider - { - int? listCount = null; - /// - /// After evaluating how many items to clear debugger Expression cache, - /// so that the cache does not keep too many PermanentReferences. - /// - static readonly int ClearCacheThreshold = 50; - - public ListValuesProvider(Expression targetObject, DebugType listItemType) - :base(targetObject, listItemType) - { - } - - public int GetCount() - { - if (this.listCount == null) { - this.listCount = this.targetObject.GetIListCount(); - } - return this.listCount.Value; - } - - /// When this reaches ClearCacheThreshold, the debugger Expression cache is cleared. - int itemClearCacheCounter = 0; - - public ObjectValue GetItemAt(int index) - { - if (itemClearCacheCounter++ > ClearCacheThreshold) { - // clear debugger Expression cache to avoid holding too many PermanentReferences - WindowsDebugger.CurrentProcess.ClearExpressionCache(); - LoggingService.Info("Cleared debugger Expression cache."); - itemClearCacheCounter = 0; - } - return ObjectValue.Create( - targetObject.AppendIndexer(index).Evaluate(WindowsDebugger.CurrentProcess), - //targetObject.AppendIndexer(index), // use Expression instead of value - possible only for IList though - index, - this.memberFromNameMap); - } - } -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs deleted file mode 100644 index f084773b26..0000000000 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs +++ /dev/null @@ -1,12 +0,0 @@ -// Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) -// This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) - -using System.Collections.Generic; -using System.Linq; -using System; - -public enum TextVisualizerMode -{ - PlainText, - Xml -} diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs index 56c8a75dc3..ab35e503ca 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs @@ -1,17 +1,9 @@ // Copyright (c) AlphaSierraPapa for the SharpDevelop Team (for details please see \doc\copyright.txt) // This code is distributed under the BSD license (for details please see \src\AddIns\Debugger\Debugger.AddIn\license.txt) -using ICSharpCode.AvalonEdit.Highlighting; using System; -using System.Collections.Generic; -using System.Linq; -using System.Text; using System.Windows; -using System.Windows.Controls; -using System.Windows.Data; -using System.Windows.Documents; -using System.Windows.Input; -using System.Windows.Media; +using ICSharpCode.AvalonEdit.Highlighting; namespace Debugger.AddIn.Visualizers.TextVisualizer { @@ -20,42 +12,14 @@ namespace Debugger.AddIn.Visualizers.TextVisualizer /// public partial class TextVisualizerWindow : Window { - public TextVisualizerWindow() - { - InitializeComponent(); - Mode = TextVisualizerMode.PlainText; - textEditor.IsReadOnly = true; - } - - public TextVisualizerWindow(string title, string text) + public TextVisualizerWindow(string title, string text, string highlighting = null) { InitializeComponent(); - Title= title; - Text = text; - } - - public string Text - { - get { return this.textEditor.Text; } - set { this.textEditor.Text = value; } - } - - private TextVisualizerMode mode; - public TextVisualizerMode Mode - { - get { return mode; } - set { - mode = value; - switch (mode) { - case TextVisualizerMode.PlainText: - textEditor.SyntaxHighlighting = null; - break; - case TextVisualizerMode.Xml: - textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(".xml"); - break; - } - } + Title = title; + this.textEditor.Text = text; + if (highlighting != null) + this.textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(highlighting); } void CheckBox_CheckedChanged(object sender, RoutedEventArgs e) diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs index c962d91625..ba4e3c4136 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs @@ -33,6 +33,17 @@ namespace Debugger.AddIn.Visualizers.Utils return new ObjectCreateExpression(listType.GetTypeReference(), iEnumerableVariableExplicitCast.SingleItemList()); } + + public static Value CreateListFromIEnumeralbe(Value iEnumerableValue, DebugType itemType, out DebugType listType) + { + listType = DebugType.CreateFromType(iEnumerableValue.AppDomain, typeof(System.Collections.Generic.List<>), itemType); + DebugType iEnumerableType = DebugType.CreateFromType(itemType.AppDomain, typeof(IEnumerable<>), itemType); + ConstructorInfo ctor = listType.GetConstructor(BindingFlags.Default, null, CallingConventions.Any, new System.Type[] { iEnumerableType }, null); + if (ctor == null) + throw new DebuggerException("List constructor not found"); + return (Value)ctor.Invoke(new object[] { iEnumerableValue }); + } + /// /// Gets underlying address of object in the debuggee. /// @@ -120,7 +131,7 @@ namespace Debugger.AddIn.Visualizers.Utils Value list = targetObject.Evaluate(WindowsDebugger.CurrentProcess); var iCollectionType = list.Type.GetInterface(typeof(System.Collections.ICollection).FullName); if (iCollectionType == null) - throw new GetValueException(targetObject, targetObject.PrettyPrint() + " does not implement System.Collections.ICollection"); + throw new GetValueException("Object does not implement System.Collections.ICollection"); // Do not get string representation since it can be printed in hex return (int)list.GetPropertyValue(iCollectionType.GetProperty("Count")).PrimitiveValue; } diff --git a/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj b/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj index d59af38cff..3b6c2aa1ea 100644 --- a/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj +++ b/src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj @@ -144,8 +144,6 @@ - - @@ -198,17 +196,7 @@ - - - - - - {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195} - NRefactory - False - - \ No newline at end of file diff --git a/src/AddIns/Debugger/Debugger.Core/Eval.cs b/src/AddIns/Debugger/Debugger.Core/Eval.cs index 4c70596375..497d36c378 100644 --- a/src/AddIns/Debugger/Debugger.Core/Eval.cs +++ b/src/AddIns/Debugger/Debugger.Core/Eval.cs @@ -273,24 +273,24 @@ namespace Debugger ); } - public static Value CreateValue(AppDomain appDomain, object value) - { - if (value == null) { + public static Value CreateValue(AppDomain appDomain, object value) + { + if (value == null) { ICorDebugClass corClass = appDomain.ObjectType.CorType.GetClass(); Thread thread = GetEvaluationThread(appDomain); ICorDebugEval corEval = thread.CorThread.CreateEval(); ICorDebugValue corValue = corEval.CreateValue((uint)CorElementType.CLASS, corClass); return new Value(appDomain, corValue); } else if (value is string) { - return Eval.NewString(appDomain, (string)value); + return Eval.NewString(appDomain, (string)value); } else { - if (!value.GetType().IsPrimitive) - throw new DebuggerException("Value must be primitve type. Seen " + value.GetType()); + if (!value.GetType().IsPrimitive) + throw new DebuggerException("Value must be primitve type. Seen " + value.GetType()); Value val = Eval.NewObjectNoConstructor(DebugType.CreateFromType(appDomain.Mscorlib, value.GetType())); val.PrimitiveValue = value; return val; } - } + } /* // The following function create values only for the purpuse of evalutaion diff --git a/src/AddIns/Debugger/Debugger.Core/GetValueException.cs b/src/AddIns/Debugger/Debugger.Core/GetValueException.cs index a1adb2fa4f..0183d9d199 100644 --- a/src/AddIns/Debugger/Debugger.Core/GetValueException.cs +++ b/src/AddIns/Debugger/Debugger.Core/GetValueException.cs @@ -2,55 +2,21 @@ // This code is distributed under the GNU LGPL (for details please see \doc\license.txt) using System; -using ICSharpCode.NRefactory.Ast; namespace Debugger { public class GetValueException: DebuggerException { - INode expression; - string error; - - /// Expression that has caused this exception to occur - public INode Expression { - get { return expression; } - set { expression = value; } - } - - public string Error { - get { return error; } - } - - public override string Message { - get { - if (expression == null) { - return error; - } else { - return error; - // return String.Format("Error evaluating \"{0}\": {1}", expression.PrettyPrint(), error); - } - } - } - - public GetValueException(INode expression, string error):base(error) - { - this.expression = expression; - this.error = error; - } - public GetValueException(string error, System.Exception inner):base(error, inner) { - this.error = error; } public GetValueException(string errorFmt, params object[] args):base(string.Format(errorFmt, args)) { - this.error = string.Format(errorFmt, args); } public GetValueException(string error):base(error) { - this.error = error; } } } diff --git a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs index 1ac7c330b5..d0076d569d 100644 --- a/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs +++ b/src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs @@ -246,14 +246,14 @@ namespace Debugger public void EvalException(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval corEval) { - EnterCallback(PausedReason.EvalComplete, "EvalException", pThread); + EnterCallback(PausedReason.EvalComplete, "EvalException (" + process.ActiveEvals[corEval].Description + ")", pThread); HandleEvalComplete(pAppDomain, pThread, corEval, true); } public void EvalComplete(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval corEval) { - EnterCallback(PausedReason.EvalComplete, "EvalComplete", pThread); + EnterCallback(PausedReason.EvalComplete, "EvalComplete (" + process.ActiveEvals[corEval].Description + ")", pThread); HandleEvalComplete(pAppDomain, pThread, corEval, false); } diff --git a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs index 37a0fed063..4e6b8e15d3 100644 --- a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs +++ b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs @@ -639,7 +639,7 @@ namespace Debugger.MetaData { List vars = new List(); foreach (ISymUnmanagedVariable symVar in symScope.GetLocals()) { - ISymUnmanagedVariable symVarCopy = symVar; + uint address = (uint)symVar.GetAddressField1(); int start; SignatureReader sigReader = new SignatureReader(symVar.GetSignature()); LocalVarSig.LocalVariable locVarSig = sigReader.ReadLocalVariable(sigReader.Blob, 0, out start); @@ -654,7 +654,7 @@ namespace Debugger.MetaData (int)symScope.GetStartOffset(), (int)symScope.GetEndOffset(), delegate(StackFrame context) { - return GetLocalVariableValue(context, symVarCopy); + return context.GetLocalVariableValue(address); }, locVarType ); @@ -668,7 +668,7 @@ namespace Debugger.MetaData (int)symScope.GetEndOffset(), locVarType, delegate(StackFrame context) { - return GetLocalVariableValue(context, symVarCopy); + return context.GetLocalVariableValue(address); } ); vars.Add(locVar); @@ -680,18 +680,6 @@ namespace Debugger.MetaData return vars; } - static Value GetLocalVariableValue(StackFrame context, ISymUnmanagedVariable symVar) - { - ICorDebugValue corVal; - try { - corVal = context.CorILFrame.GetLocalVariable((uint)symVar.GetAddressField1()); - } catch (COMException e) { - if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Unavailable in optimized code"); - throw; - } - return new Value(context.AppDomain, corVal); - } - /// public override string ToString() { diff --git a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugType.cs b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugType.cs index fa6b205543..a152d02dba 100644 --- a/src/AddIns/Debugger/Debugger.Core/MetaData/DebugType.cs +++ b/src/AddIns/Debugger/Debugger.Core/MetaData/DebugType.cs @@ -9,7 +9,6 @@ using System.Text; using Debugger.Interop.CorDebug; using Debugger.Interop.MetaData; -using ICSharpCode.NRefactory.Ast; using Mono.Cecil.Signatures; namespace Debugger.MetaData diff --git a/src/AddIns/Debugger/Debugger.Core/Process.cs b/src/AddIns/Debugger/Debugger.Core/Process.cs index 3ca68f7a06..933ecdb8f4 100644 --- a/src/AddIns/Debugger/Debugger.Core/Process.cs +++ b/src/AddIns/Debugger/Debugger.Core/Process.cs @@ -7,8 +7,6 @@ using System.Runtime.InteropServices; using Debugger.Interop.CorDebug; using Debugger.Interop.CorSym; -using ICSharpCode.NRefactory.Ast; -using ICSharpCode.NRefactory.Visitors; namespace Debugger { @@ -251,7 +249,6 @@ namespace Debugger internal bool TerminateCommandIssued = false; internal Queue BreakpointHitEventQueue = new Queue(); - internal Dictionary ExpressionsCache = new Dictionary(); #region Events @@ -330,7 +327,6 @@ namespace Debugger if (action == DebuggeeStateAction.Clear) { if (debuggeeState == null) throw new DebuggerException("Debugee state already cleared"); debuggeeState = null; - this.ExpressionsCache.Clear(); } } @@ -557,19 +553,6 @@ namespace Debugger // This is done once ExitProcess callback is received } - /// - /// Clears the internal Expression cache used too speed up Expression evaluation. - /// Use this if your code evaluates expressions in a way which would cause - /// the cache to grow too large. The cache holds PermanentReferences so it - /// shouldn't grow larger than a few hundred items. - /// - public void ClearExpressionCache() - { - if (this.ExpressionsCache != null ){ - this.ExpressionsCache.Clear(); - } - } - void SelectSomeThread() { if (this.SelectedThread != null && !this.SelectedThread.IsInValidState) { diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index 0b6cf9e53b..6e96d8dee8 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -380,6 +380,16 @@ namespace Debugger return loc.GetValue(this); } + public Value GetLocalVariableValue(uint address) + { + try { + return new Value(this.AppDomain, this.CorILFrame.GetLocalVariable(address)); + } catch (COMException e) { + if ((uint)e.ErrorCode == 0x80131304) throw new GetValueException("Unavailable in optimized code"); + throw; + } + } + /// Get instance of 'this'. It works well with delegates and enumerators. [Debugger.Tests.Ignore] public Value GetLocalVariableThis() diff --git a/src/AddIns/Debugger/Debugger.Core/Value.cs b/src/AddIns/Debugger/Debugger.Core/Value.cs index e104f05c19..25b51d861b 100644 --- a/src/AddIns/Debugger/Debugger.Core/Value.cs +++ b/src/AddIns/Debugger/Debugger.Core/Value.cs @@ -613,6 +613,7 @@ namespace Debugger /// Invoke the ToString() method public string InvokeToString(int maxLength = int.MaxValue) { + if (this.IsNull) return AsString(maxLength); if (this.Type.IsPrimitive) return AsString(maxLength); if (this.Type.FullName == typeof(string).FullName) return AsString(maxLength); if (this.Type.IsPointer) return "0x" + this.PointerAddress.ToString("X"); diff --git a/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj b/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj index 82684e0616..9c117cdddf 100644 --- a/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj +++ b/src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj @@ -77,6 +77,10 @@ {3A9AE6AA-BC07-4A2F-972C-581E3AE2F195} NRefactory + + {EC06F96A-AEEC-49D6-B03D-AB87C6EB674C} + Debugger.AddIn + {1D18D788-F7EE-4585-A23B-34DC8EC63CB8} Debugger.Core diff --git a/src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs b/src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs index 5424a6551d..4df0ee1db7 100644 --- a/src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs +++ b/src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs @@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks b.Append('|'); b.Append(node.ImageName); b.Append('|'); - b.Append(node.FullName); + b.Append(node.Name); b.Append('|'); b.Append(node.Text); } diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs index 59762e5870..6beb519b07 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs @@ -10,14 +10,12 @@ namespace ICSharpCode.SharpDevelop.Debugging /// /// Node that can be bound to . /// - public interface ITreeNode : IComparable + public interface ITreeNode { - string Name { get; } - - string FullName { get; } - string ImageName { get; } + string Name { get; } + string Text { get; } bool CanSetText { get; } @@ -26,9 +24,7 @@ namespace ICSharpCode.SharpDevelop.Debugging ImageSource ImageSource { get; } - IEnumerable ChildNodes { get; } - - bool HasChildNodes { get; } + Func> GetChildren { get; } IEnumerable VisualizerCommands { get; } diff --git a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs index 7a422636a0..a26defcd4b 100644 --- a/src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs +++ b/src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs @@ -77,7 +77,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks throw new ArgumentNullException("Node is null"); foreach (var currentNode in mark.Nodes) { - if (node.FullName == currentNode.FullName) + if (node.Name == currentNode.Name) return true; } @@ -92,7 +92,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks throw new ArgumentNullException("Node is null"); foreach (var currentNode in mark.Nodes) { - if (node.FullName == currentNode.FullName) { + if (node.Name == currentNode.Name) { mark.Nodes.Remove(currentNode); return; }