Browse Source

Revert David's debugger changes - they won't be part of SD 4.2.

This reverts commit 358b6cf691.
This reverts commit 62265526a4.
pull/18/head
Daniel Grunwald 14 years ago
parent
commit
6bd47b7611
  1. 24
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  2. 1
      src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs
  3. 25
      src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.xaml.cs
  4. 73
      src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs
  5. 18
      src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/TreeNodeWrapper.cs
  6. 40
      src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs
  7. 69
      src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackPad.cs
  8. 24
      src/AddIns/Debugger/Debugger.AddIn/Pads/RunningThreadsPad.cs
  9. 56
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs
  10. 49
      src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs
  11. 25
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  12. 5
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
  13. 10
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs
  14. 13
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs
  15. 125
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs
  16. 144
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs
  17. 25
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs
  18. 355
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs
  19. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs
  20. 158
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs
  21. 32
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs
  22. 33
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs
  23. 12
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs
  24. 31
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs
  25. 67
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs
  26. 113
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs
  27. 37
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/Utils.cs
  28. 10
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs
  29. 13
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs
  30. 4
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs
  31. 2
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs
  32. 12
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs
  33. 12
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs
  34. 13
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs
  35. 16
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs
  36. 16
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs
  37. 4
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs
  38. 3
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml
  39. 193
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs
  40. 85
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs
  41. 50
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs
  42. 42
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs
  43. 59
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs
  44. 12
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs
  45. 48
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs
  46. 13
      src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs
  47. 12
      src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj
  48. 14
      src/AddIns/Debugger/Debugger.Core/Eval.cs
  49. 34
      src/AddIns/Debugger/Debugger.Core/GetValueException.cs
  50. 4
      src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs
  51. 18
      src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs
  52. 1
      src/AddIns/Debugger/Debugger.Core/MetaData/DebugType.cs
  53. 0
      src/AddIns/Debugger/Debugger.Core/NRefactory/Ast/ExpressionExtensionMethods.cs
  54. 18
      src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs
  55. 17
      src/AddIns/Debugger/Debugger.Core/Process.cs
  56. 10
      src/AddIns/Debugger/Debugger.Core/StackFrame.cs
  57. 1
      src/AddIns/Debugger/Debugger.Core/Value.cs
  58. 4
      src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj
  59. 2
      src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs
  60. 12
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs
  61. 4
      src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs

24
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -97,8 +97,6 @@ @@ -97,8 +97,6 @@
</Reference>
</ItemGroup>
<ItemGroup>
<Compile Include="NRefactory\ExpressionEvaluator.cs" />
<Compile Include="NRefactory\ExpressionExtensionMethods.cs" />
<Compile Include="Options\DebuggingOptionsPanel.xaml.cs">
<DependentUpon>DebuggingOptionsPanel.xaml</DependentUpon>
<SubType>Code</SubType>
@ -163,6 +161,7 @@ @@ -163,6 +161,7 @@
<Compile Include="Pads\WatchPad.cs">
<SubType>Component</SubType>
</Compile>
<Compile Include="Pads\WatchPadModel.cs" />
<Compile Include="Service\AttachToProcessForm.cs">
<SubType>Form</SubType>
</Compile>
@ -193,6 +192,11 @@ @@ -193,6 +192,11 @@
<Compile Include="Tooltips\VisualizerPicker.cs">
<DependentUpon>VisualizerPicker.xaml</DependentUpon>
</Compile>
<Compile Include="TreeModel\DebuggerResourceService.cs" />
<Compile Include="TreeModel\ICorDebug.cs" />
<Compile Include="TreeModel\IEnumerableNode.cs" />
<Compile Include="TreeModel\IListNode.cs" />
<Compile Include="TreeModel\SavedTreeNode.cs" />
<Compile Include="TreeModel\TreeNode.cs" />
<Compile Include="Visualizers\Commands\ExpressionVisualizerCommand.cs" />
<Compile Include="Visualizers\Commands\GridVisualizerCommand.cs" />
@ -205,6 +209,7 @@ @@ -205,6 +209,7 @@
<Compile Include="Visualizers\Commands\XmlVisualizerCommand.cs" />
<Compile Include="Visualizers\Common\DebuggerVisualizerException.cs" />
<Compile Include="Visualizers\Common\IEvaluate.cs" />
<Compile Include="Visualizers\Common\IListValuesProvider.cs" />
<Compile Include="Visualizers\Common\ObjectProperty.cs" />
<Compile Include="Visualizers\Common\ObjectPropertyComparer.cs" />
<Compile Include="Visualizers\Common\VirtualizingCollection.cs" />
@ -248,10 +253,12 @@ @@ -248,10 +253,12 @@
<Compile Include="Visualizers\Graph\ObjectGraph\TreeModel\ThisNode.cs" />
<Compile Include="Visualizers\Graph\ObjectGraph\TreeModel\NonPublicMembersNode.cs" />
<Compile Include="Visualizers\Graph\ObjectGraph\TreeModel\PropertyNode.cs" />
<Compile Include="Visualizers\GridVisualizer\ValueProviders\GridValuesProvider.cs" />
<Compile Include="Visualizers\PresentationBindings\DragScrollViewer.cs" />
<Compile Include="Visualizers\PresentationBindings\GridViewColumnHider.cs" />
<Compile Include="Visualizers\PresentationBindings\GridViewHideableColumn.cs" />
<Compile Include="Visualizers\PresentationBindings\TooltipVisibilityConverter.cs" />
<Compile Include="Visualizers\TextVisualizer\TextVisualizerMode.cs" />
<Compile Include="Visualizers\TextVisualizer\TextVisualizerWindow.xaml.cs">
<DependentUpon>TextVisualizerWindow.xaml</DependentUpon>
<SubType>Code</SubType>
@ -279,7 +286,12 @@ @@ -279,7 +286,12 @@
</Compile>
<Compile Include="Pads\DebuggerPad.cs" />
<Compile Include="Pads\RunningThreadsPad.Menu.cs" />
<Compile Include="TreeModel\ValueNode.cs" />
<Compile Include="TreeModel\ArrayRangeNode.cs" />
<Compile Include="TreeModel\ExpressionNode.cs" />
<Compile Include="TreeModel\IContextMenu.cs" />
<Compile Include="TreeModel\ISetText.cs" />
<Compile Include="TreeModel\ChildNodesOfObject.cs" />
<Compile Include="TreeModel\StackFrameNode.cs" />
<Compile Include="TreeModel\Utils.cs" />
<Compile Include="Visualizers\Graph\Drawing\CanvasLocationAdapter.cs" />
<Compile Include="Visualizers\Graph\Drawing\GraphDrawer.cs" />
@ -300,6 +312,9 @@ @@ -300,6 +312,9 @@
<DependentUpon>GridVisualizerWindow.xaml</DependentUpon>
<SubType>Code</SubType>
</Compile>
<Compile Include="Visualizers\GridVisualizer\ObjectValue.cs" />
<Compile Include="Visualizers\GridVisualizer\ValueProviders\EnumerableValuesProvider.cs" />
<Compile Include="Visualizers\GridVisualizer\ValueProviders\ListValuesProvider.cs" />
<Compile Include="Visualizers\Utils\DebuggerHelpers.cs" />
<Compile Include="Visualizers\Utils\DictionaryExtensions.cs" />
<Compile Include="Visualizers\Utils\Lookup.cs" />
@ -309,6 +324,7 @@ @@ -309,6 +324,7 @@
</Compile>
<Compile Include="Visualizers\PresentationBindings\DisplayAttribute.cs" />
<Compile Include="Visualizers\PresentationBindings\EnumViewModel.cs" />
<None Include="COPYING" />
</ItemGroup>
<ItemGroup>
<Content Include="Debugger.AddIn.addin">
@ -392,7 +408,6 @@ @@ -392,7 +408,6 @@
<Name>ICSharpCode.Core.WinForms</Name>
<Private>False</Private>
</ProjectReference>
<Folder Include="NRefactory" />
<Folder Include="Pads\Commands" />
<Folder Include="Pads\Controls" />
<Folder Include="Pads\ParallelPad" />
@ -408,6 +423,7 @@ @@ -408,6 +423,7 @@
<Folder Include="Visualizers\Graph\ExpandedPaths" />
<Folder Include="Visualizers\Graph\ObjectGraph\TreeModel" />
<Folder Include="Visualizers\Graph\ObjectGraph" />
<Folder Include="Visualizers\GridVisualizer\ValueProviders" />
<Folder Include="Visualizers\Common" />
<Folder Include="Visualizers\Commands" />
<Folder Include="Visualizers\TextVisualizer" />

1
src/AddIns/Debugger/Debugger.AddIn/Options/DebuggingOptions.cs

@ -28,6 +28,7 @@ namespace ICSharpCode.SharpDevelop.Services @@ -28,6 +28,7 @@ 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; }

25
src/AddIns/Debugger/Debugger.AddIn/Pads/CallStackPad.xaml.cs

@ -148,20 +148,19 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -148,20 +148,19 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
}
List<CallStackItem> items = new List<CallStackItem>();
LoggingService.Info("Callstack refresh");
bool showExternalMethods = DebuggingOptions.Instance.ShowExternalMethods;
bool lastItemIsExternalMethod = false;
foreach (StackFrame frame in debuggedProcess.SelectedThread.GetCallstack(100)) {
StackFrame f = frame;
debuggedProcess.EnqueueWork(
Dispatcher,
delegate {
items.AddIfNotNull(CreateItem(f, showExternalMethods, ref lastItemIsExternalMethod));
});
using(new PrintTimes("Callstack refresh")) {
bool showExternalMethods = DebuggingOptions.Instance.ShowExternalMethods;
bool lastItemIsExternalMethod = false;
foreach (StackFrame frame in debuggedProcess.SelectedThread.GetCallstack(100)) {
StackFrame f = frame;
debuggedProcess.EnqueueWork(
Dispatcher,
delegate {
items.AddIfNotNull(CreateItem(f, showExternalMethods, ref lastItemIsExternalMethod));
});
}
}
view.ItemsSource = items;
}

73
src/AddIns/Debugger/Debugger.AddIn/Pads/Commands/WatchPadCommands.cs

@ -2,12 +2,18 @@ @@ -2,12 +2,18 @@
// 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;
@ -35,10 +41,11 @@ namespace Debugger.AddIn @@ -35,10 +41,11 @@ namespace Debugger.AddIn
string language = ProjectService.CurrentProject.Language;
var text = new TreeNode(input, null).ToSharpTreeNode();
var text = new TextNode(null, input,
language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp).ToSharpTreeNode();
var list = pad.WatchList;
if(!list.WatchItems.Any(n => text.Node.Name == ((TreeNodeWrapper)n).Node.Name))
if(!list.WatchItems.Any(n => text.Node.FullName == ((TreeNodeWrapper)n).Node.FullName))
list.WatchItems.Add(text);
}
@ -101,4 +108,66 @@ namespace Debugger.AddIn @@ -101,4 +108,66 @@ namespace Debugger.AddIn
}
}
}
public class WatchScriptingLanguageMenuBuilder : ISubmenuBuilder, IMenuItemBuilder
{
public ToolStripItem[] BuildSubmenu(Codon codon, object owner)
{
List<ToolStripItem> items = new List<ToolStripItem>();
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();
}
}
}

18
src/AddIns/Debugger/Debugger.AddIn/Pads/Controls/TreeNodeWrapper.cs

@ -28,22 +28,22 @@ namespace Debugger.AddIn.Pads.Controls @@ -28,22 +28,22 @@ namespace Debugger.AddIn.Pads.Controls
public TreeNode Node { get; private set; }
public override object Text {
get { return this.Node.Name; }
get { return Node.Name; }
}
public override object Icon {
get { return this.Node.ImageSource; }
get { return Node.ImageSource; }
}
public override bool ShowExpander {
get { return this.Node.GetChildren != null; }
get { return Node.HasChildNodes; }
}
protected override void LoadChildren()
{
if (this.Node.GetChildren != null) {
var process = ((WindowsDebugger)DebuggerService.CurrentDebugger).DebuggedProcess;
process.EnqueueWork(Dispatcher.CurrentDispatcher, () => Children.AddRange(this.Node.GetChildren().Select(node => node.ToSharpTreeNode())));
if (Node.HasChildNodes) {
((WindowsDebugger)DebuggerService.CurrentDebugger).DebuggedProcess
.EnqueueWork(Dispatcher.CurrentDispatcher, () => Children.AddRange(Node.ChildNodes.Select(node => node.ToSharpTreeNode())));
}
}
}
@ -69,10 +69,12 @@ namespace Debugger.AddIn.Pads.Controls @@ -69,10 +69,12 @@ namespace Debugger.AddIn.Pads.Controls
string language = ProjectService.CurrentProject.Language;
var text = new TreeNode(e.Data.GetData(DataFormats.StringFormat).ToString(), null);
// FIXME languages
TextNode text = new TextNode(null, e.Data.GetData(DataFormats.StringFormat).ToString(),
language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp);
var node = text.ToSharpTreeNode();
if (!WatchPad.Instance.WatchList.WatchItems.Any(n => text.Name == ((TreeNodeWrapper)n).Node.Name))
if (!WatchPad.Instance.WatchList.WatchItems.Any(n => text.FullName == ((TreeNodeWrapper)n).Node.FullName))
WatchPad.Instance.WatchList.WatchItems.Add(node);
WatchPad.Instance.InvalidatePad();

40
src/AddIns/Debugger/Debugger.AddIn/Pads/LocalVarPad.cs

@ -62,27 +62,29 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -62,27 +62,29 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
return;
}
LoggingService.Info("Local Variables refresh");
try {
StackFrame frame = debuggedProcess.GetCurrentExecutingFrame();
if (frame == null) return;
using(new PrintTimes("Local Variables refresh")) {
try {
StackFrame frame = debuggedProcess.GetCurrentExecutingFrame();
if (frame == null) return;
localVarList.WatchItems.Clear();
foreach (var n in Utils.GetLocalVariableNodes(frame)) {
var node = n;
debuggedProcess.EnqueueWork(
Dispatcher.CurrentDispatcher,
delegate {
localVarList.WatchItems.Add(node.ToSharpTreeNode());
}
);
localVarList.WatchItems.Clear();
foreach (var n in new StackFrameNode(frame).ChildNodes) {
var node = n;
debuggedProcess.EnqueueWork(
Dispatcher.CurrentDispatcher,
delegate {
localVarList.WatchItems.Add(node.ToSharpTreeNode());
}
);
}
}
}
catch(Exception ex) {
if (debuggedProcess == null || debuggedProcess.HasExited) {
// Process unexpectedly exited
} else {
MessageService.ShowException(ex);
catch(AbortedBecauseDebuggeeResumedException) { }
catch(Exception ex) {
if (debuggedProcess == null || debuggedProcess.HasExited) {
// Process unexpectedly exited
} else {
MessageService.ShowException(ex);
}
}
}
}

69
src/AddIns/Debugger/Debugger.AddIn/Pads/ParallelPad/ParallelStackPad.cs

@ -74,47 +74,50 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -74,47 +74,50 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
currentThreadStacks.Clear();
LoggingService.Info("Create stacks");
try {
// create all simple ThreadStacks
foreach (Thread thread in debuggedProcess.Threads) {
var t = thread;
debuggedProcess.EnqueueWork(Dispatcher.CurrentDispatcher, () => CreateThreadStack(t));
using(new PrintTimes("Create stacks")) {
try {
// create all simple ThreadStacks
foreach (Thread thread in debuggedProcess.Threads) {
var t = thread;
debuggedProcess.EnqueueWork(Dispatcher.CurrentDispatcher, () => CreateThreadStack(t));
}
}
catch(AbortedBecauseDebuggeeResumedException) { }
catch(System.Exception) {
if (debuggedProcess == null || debuggedProcess.HasExited) {
// Process unexpectedly exited
} else {
throw;
}
}
}
catch(System.Exception) {
if (debuggedProcess == null || debuggedProcess.HasExited) {
// Process unexpectedly exited
} else {
throw;
using(new PrintTimes("Run algorithm")) {
if (isMethodView)
{
// build method view for threads
CreateMethodViewStacks();
}
else
{
// normal view
CreateCommonStacks();
}
}
LoggingService.Info("Run algorithm");
if (isMethodView)
{
// build method view for threads
CreateMethodViewStacks();
}
else
{
// normal view
CreateCommonStacks();
}
using(new PrintTimes("Graph refresh")) {
// paint the ThreadStaks
graph = new ParallelStacksGraph();
foreach (var stack in this.currentThreadStacks.FindAll(ts => ts.ThreadStackParents == null ))
{
graph.AddVertex(stack);
LoggingService.Info("Graph refresh");
// paint the ThreadStaks
graph = new ParallelStacksGraph();
foreach (var stack in this.currentThreadStacks.FindAll(ts => ts.ThreadStackParents == null ))
{
graph.AddVertex(stack);
// add the children
AddChildren(stack);
}
// add the children
AddChildren(stack);
if (graph.VertexCount > 0)
surface.SetGraph(graph);
}
if (graph.VertexCount > 0)
surface.SetGraph(graph);
}
protected override ToolBar BuildToolBar()

24
src/AddIns/Debugger/Debugger.AddIn/Pads/RunningThreadsPad.cs

@ -91,17 +91,19 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -91,17 +91,19 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
return;
}
LoggingService.Info("Threads refresh");
try {
foreach (var t in debuggedProcess.Threads) {
var thread = t;
debuggedProcess.EnqueueWork(Dispatcher.CurrentDispatcher, () => AddThread(thread));
}
} catch(Exception) {
if (debuggedProcess == null || debuggedProcess.HasExited) {
// Process unexpectedly exited
} else {
throw;
using(new PrintTimes("Threads refresh")) {
try {
foreach (var t in debuggedProcess.Threads) {
var thread = t;
debuggedProcess.EnqueueWork(Dispatcher.CurrentDispatcher, () => AddThread(thread));
}
} catch(AbortedBecauseDebuggeeResumedException) {
} catch(Exception) {
if (debuggedProcess == null || debuggedProcess.HasExited) {
// Process unexpectedly exited
} else {
throw;
}
}
}
}

56
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPad.cs

@ -17,7 +17,6 @@ using Debugger.AddIn.TreeModel; @@ -17,7 +17,6 @@ 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;
@ -79,26 +78,29 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -79,26 +78,29 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
return;
foreach (var element in props.Elements) {
watchList.WatchItems.Add(new TreeNode(element, null).ToSharpTreeNode());
watchList.WatchItems.Add(new TextNode(null, element, (SupportedLanguage)Enum.Parse(typeof(SupportedLanguage), props[element])).ToSharpTreeNode());
}
}
void OnWatchItemsCollectionChanged(object sender, NotifyCollectionChangedEventArgs e)
{
var props = GetSavedVariablesProperties();
if (props == null) return;
if (e.Action == NotifyCollectionChangedAction.Add) {
if (e.Action == NotifyCollectionChangedAction.Add && e.NewItems.Count > 0) {
// add to saved data
foreach(var data in e.NewItems.OfType<TreeNode>()) {
props.Set(data.Name, (object)null);
var data = e.NewItems.OfType<TextNode>().FirstOrDefault();
if (data != null) {
var props = GetSavedVariablesProperties();
if (props == null) return;
props.Set(data.FullName, data.Language.ToString());
}
}
if (e.Action == NotifyCollectionChangedAction.Remove) {
// remove from saved data
foreach(var data in e.OldItems.OfType<TreeNode>()) {
props.Remove(data.Name);
var data = e.OldItems.OfType<TextNode>().FirstOrDefault();
if (data != null) {
var props = GetSavedVariablesProperties();
if (props == null) return;
props.Remove(data.FullName);
}
}
}
@ -160,7 +162,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -160,7 +162,9 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
// rebuild list
var nodes = new List<TreeNodeWrapper>();
foreach (var nod in watchList.WatchItems.OfType<TreeNodeWrapper>())
nodes.Add(new TreeNode(nod.Node.Name, null).ToSharpTreeNode());
nodes.Add(new TextNode(null, nod.Node.Name,
language == "VB" || language == "VBNet" ? SupportedLanguage.VBNet : SupportedLanguage.CSharp)
.ToSharpTreeNode());
watchList.WatchItems.Clear();
foreach (var nod in nodes)
@ -190,13 +194,13 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -190,13 +194,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, node.Node.Name, () => debugger.GetExpression(node.Node.Name).Evaluate(debuggedProcess));
ExpressionNode valNode = new ExpressionNode(null, null, node.Node.Name, nodExpression);
return valNode.ToSharpTreeNode();
} catch (GetValueException) {
string error = String.Format(StringParser.Parse("${res:MainWindow.Windows.Debug.Watch.InvalidExpression}"), node.Node.Name);
TreeNode infoNode = new TreeNode("Icons.16x16.Error", node.Node.Name, error, string.Empty, null);
ErrorInfoNode infoNode = new ErrorInfoNode(node.Node.Name, error);
return infoNode.ToSharpTreeNode();
}
}
@ -206,18 +210,18 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads @@ -206,18 +210,18 @@ namespace ICSharpCode.SharpDevelop.Gui.Pads
if (debuggedProcess == null || debuggedProcess.IsRunning)
return;
LoggingService.Info("Watch Pad refresh");
var nodes = watchList.WatchItems.OfType<TreeNodeWrapper>().ToArray();
watchList.WatchItems.Clear();
foreach (var n in nodes) {
var node = n;
debuggedProcess.EnqueueWork(
Dispatcher.CurrentDispatcher,
delegate {
watchList.WatchItems.Add(UpdateNode(node));
}
);
using(new PrintTimes("Watch Pad refresh")) {
var nodes = watchList.WatchItems.OfType<TreeNodeWrapper>().ToArray();
watchList.WatchItems.Clear();
foreach (var n in nodes) {
var node = n;
debuggedProcess.EnqueueWork(
Dispatcher.CurrentDispatcher,
delegate {
watchList.WatchItems.Add(UpdateNode(node));
}
);
}
}
}
}

49
src/AddIns/Debugger/Debugger.AddIn/Pads/WatchPadModel.cs

@ -0,0 +1,49 @@ @@ -0,0 +1,49 @@
// 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");
}
}
}

25
src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs

@ -489,7 +489,10 @@ namespace ICSharpCode.SharpDevelop.Services @@ -489,7 +489,10 @@ namespace ICSharpCode.SharpDevelop.Services
{
try {
var tooltipExpression = GetExpression(variableName);
ExpressionNode expressionNode = new ExpressionNode("Icons.16x16.Local", variableName, () => tooltipExpression.Evaluate(this.DebuggedProcess));
string imageName;
var image = ExpressionNode.GetImageForLocalVariable(out imageName);
ExpressionNode expressionNode = new ExpressionNode(null, image, variableName, tooltipExpression);
expressionNode.ImageName = imageName;
return new DebuggerTooltipControl(logicalPosition, expressionNode) { ShowPins = debuggedProcess.GetCurrentExecutingFrame().HasSymbols };
} catch (System.Exception ex) {
LoggingService.Error("Error on GetTooltipControl: " + ex.Message);
@ -500,7 +503,19 @@ namespace ICSharpCode.SharpDevelop.Services @@ -500,7 +503,19 @@ namespace ICSharpCode.SharpDevelop.Services
public ITreeNode GetNode(string variable, string currentImageName = null)
{
try {
return new ExpressionNode(currentImageName ?? "Icons.16x16.Local", variable, () => GetExpression(variable).Evaluate(this.DebuggedProcess));
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;
} catch (GetValueException) {
return null;
}
@ -810,9 +825,9 @@ namespace ICSharpCode.SharpDevelop.Services @@ -810,9 +825,9 @@ namespace ICSharpCode.SharpDevelop.Services
{
OnIsProcessRunningChanged(EventArgs.Empty);
LoggingService.Info("Jump to current line");
JumpToCurrentLine();
using(new PrintTimes("Jump to current line")) {
JumpToCurrentLine();
}
// TODO update tooltip
/*if (currentTooltipRow != null && currentTooltipRow.IsShown) {
using(new PrintTimes("Update tooltip")) {

5
src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs

@ -4,7 +4,6 @@ @@ -4,7 +4,6 @@
using System;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Controls.Primitives;
@ -229,8 +228,8 @@ namespace Debugger.AddIn.Tooltips @@ -229,8 +228,8 @@ namespace Debugger.AddIn.Tooltips
this.childPopup.IsLeaf = true;
this.childPopup.HorizontalOffset = buttonPos.X + ChildPopupOpenXOffet;
this.childPopup.VerticalOffset = buttonPos.Y + ChildPopupOpenYOffet;
if (clickedNode.GetChildren != null) {
this.childPopup.ItemsSource = clickedNode.GetChildren().ToList();
if (clickedNode.ChildNodes != null) {
this.childPopup.ItemsSource = clickedNode.ChildNodes;
this.childPopup.Open();
}
} else {

10
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinDebuggerControl.xaml.cs

@ -4,13 +4,13 @@ @@ -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 @@ -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.GetChildren != null) {
this.childPopup.ItemsSource = clickedNode.GetChildren().ToList();
if (clickedNode.ChildNodes != null) {
this.childPopup.ItemsSource = clickedNode.ChildNodes;
this.childPopup.Open();
}
} else {
@ -300,14 +300,14 @@ namespace Debugger.AddIn.Tooltips @@ -300,14 +300,14 @@ namespace Debugger.AddIn.Tooltips
// refresh content
ITreeNode node = ((FrameworkElement)e.OriginalSource).DataContext as ITreeNode;
var resultNode = currentDebugger.GetNode(node.Name, node.ImageName);
var resultNode = currentDebugger.GetNode(node.FullName, node.ImageName);
if (resultNode == null)
return;
// HACK for updating the pins in tooltip
var observable = new ObservableCollection<ITreeNode>();
var source = lazyGrid.ItemsSource;
source.ForEach(item => {
if (item.Name == node.Name)
if (item.CompareTo(node) == 0)
observable.Add(resultNode);
else
observable.Add(item);

13
src/AddIns/Debugger/Debugger.AddIn/Tooltips/PinningBinding.cs

@ -60,13 +60,12 @@ namespace Debugger.AddIn.Tooltips @@ -60,13 +60,12 @@ namespace Debugger.AddIn.Tooltips
var nodes = new ObservableCollection<ITreeNode>();
foreach (var tuple in pin.SavedNodes) {
var node = new Debugger.AddIn.TreeModel.TreeNode(
!string.IsNullOrEmpty(tuple.Item1) ? tuple.Item1 : "Icons.16x16.Field",
string imageName = !string.IsNullOrEmpty(tuple.Item1) ? tuple.Item1 : "Icons.16x16.Field";
var node = new Debugger.AddIn.TreeModel.SavedTreeNode(
new ResourceServiceImage(imageName),
tuple.Item2,
tuple.Item3,
string.Empty,
null
);
tuple.Item3);
node.ImageName = imageName;
nodes.Add(node);
}
@ -97,7 +96,7 @@ namespace Debugger.AddIn.Tooltips @@ -97,7 +96,7 @@ namespace Debugger.AddIn.Tooltips
pin.SavedNodes.Add(
new Tuple<string, string, string>(
"Icons.16x16.Field",
node.Name,
node.FullName,
node.Text));
}

125
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ArrayRangeNode.cs

@ -0,0 +1,125 @@ @@ -0,0 +1,125 @@
// 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.Text;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.TreeModel
{
public partial class Utils
{
public static IEnumerable<TreeNode> 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;
}
}
/// <summary> This is a partent node for all elements within a given bounds </summary>
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<TreeNode> ChildNodes {
get { return base.ChildNodes; }
}
string GetName()
{
StringBuilder name = new StringBuilder();
bool isFirst = true;
name.Append("[");
for(int i = 0; i < bounds.Count; i++) {
if (!isFirst) name.Append(", ");
isFirst = false;
ArrayDimension dim = bounds[i];
ArrayDimension originalDim = originalBounds[i];
if (dim.Count == 0) {
throw new DebuggerException("Empty dimension");
} else if (dim.Count == 1) {
name.Append(dim.LowerBound.ToString());
} else if (dim.Equals(originalDim)) {
name.Append("*");
} else {
name.Append(dim.LowerBound);
name.Append("..");
name.Append(dim.UpperBound);
}
}
name.Append("]");
return name.ToString();
}
static string GetName(int[] indices)
{
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("]");
return sb.ToString();
}
IEnumerable<TreeNode> 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;
}
yield break;
}
// Find a dimension of size at least 2
int splitDimensionIndex = bounds.Count - 1;
for(int i = 0; i < bounds.Count; i++) {
if (bounds[i].Count > 1) {
splitDimensionIndex = i;
break;
}
}
ArrayDimension splitDim = bounds[splitDimensionIndex];
// Split the dimension
int elementsPerSegment = 1;
while (splitDim.Count > elementsPerSegment * MaxElementCount) {
elementsPerSegment *= MaxElementCount;
}
for(int i = splitDim.LowerBound; i <= splitDim.UpperBound; i += elementsPerSegment) {
List<ArrayDimension> newDims = new List<ArrayDimension>(bounds);
newDims[splitDimensionIndex] = new ArrayDimension(i, Math.Min(i + elementsPerSegment - 1, splitDim.UpperBound));
yield return new ArrayRangeNode(this, arrayTarget, new ArrayDimensions(newDims), originalBounds);
}
yield break;
}
}
}

144
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ChildNodesOfObject.cs

@ -0,0 +1,144 @@ @@ -0,0 +1,144 @@
// 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;
using System.Collections.Generic;
using System.Reflection;
using Debugger.AddIn.Visualizers.Utils;
using Debugger.MetaData;
using ICSharpCode.Core;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.SharpDevelop;
using ICSharpCode.SharpDevelop.Services;
using ICSharpCode.SharpDevelop.Debugging;
namespace Debugger.AddIn.TreeModel
{
public partial class Utils
{
public static IEnumerable<TreeNode> LazyGetChildNodesOfObject(TreeNode current, Expression targetObject, DebugType shownType)
{
MemberInfo[] publicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] publicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
DebugType baseType = (DebugType)shownType.BaseType;
if (baseType != null) {
yield return new TreeNode(
DebuggerResourceService.GetImage("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)
);
}
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)
);
}
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);
if (nonPublicStatic.Length > 0) {
TreeNode nonPublicStaticNode = new TreeNode(
null,
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicStaticMembers}"),
string.Empty,
string.Empty,
p,
newNode => Utils.LazyGetMembersOfObject(newNode, targetObject, nonPublicStatic)
);
children = Utils.PrependNode(nonPublicStaticNode, children);
}
return children;
}
);
}
DebugType iListType = (DebugType)shownType.GetInterface(typeof(IList).FullName);
if (iListType != null) {
yield return new IListNode(current, targetObject);
} else {
DebugType iEnumerableType, itemType;
if (shownType.ResolveIEnumerableImplementation(out iEnumerableType, out itemType)) {
yield return new IEnumerableNode(current, targetObject, itemType);
}
}
foreach(TreeNode node in LazyGetMembersOfObject(current, targetObject, publicInstance)) {
yield return node;
}
}
public static IEnumerable<TreeNode> LazyGetMembersOfObject(TreeNode parent, Expression expression, MemberInfo[] members)
{
List<TreeNode> nodes = new List<TreeNode>();
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);
}
nodes.Sort();
return nodes;
}
public static IEnumerable<TreeNode> LazyGetItemsOfIList(TreeNode parent, Expression targetObject)
{
// 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();
int count = 0;
GetValueException error = null;
try {
count = targetObject.GetIListCount();
} 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);
} else if (count == 0) {
yield return new TreeNode(null, "(empty)", null, null, null, _ => null);
} else {
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<TreeNode> PrependNode(TreeNode node, IEnumerable<TreeNode> rest)
{
yield return node;
if (rest != null) {
foreach(TreeNode absNode in rest) {
yield return absNode;
}
}
}
}
}

25
src/AddIns/Debugger/Debugger.AddIn/TreeModel/DebuggerResourceService.cs

@ -0,0 +1,25 @@ @@ -0,0 +1,25 @@
// 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
{
/// <summary>
/// Gets resources the way suitable for Debugger.AddIn.
/// </summary>
public static class DebuggerResourceService
{
/// <summary>
/// Gets image with given name from resources.
/// </summary>
/// <param name="resourceName">Resource name of the image.</param>
public static IImage GetImage(string resourceName)
{
return new ResourceServiceImage(resourceName);
}
}
}

355
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs → src/AddIns/Debugger/Debugger.AddIn/TreeModel/ExpressionNode.cs

@ -2,10 +2,8 @@ @@ -2,10 +2,8 @@
// 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.ComponentModel;
using System.Diagnostics;
using System.Globalization;
using System.Linq;
using System.Reflection;
@ -14,11 +12,13 @@ using System.Text; @@ -14,11 +12,13 @@ using System.Text;
using System.Windows.Forms;
using Debugger.AddIn.Visualizers;
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;
using TreeNode = Debugger.AddIn.TreeModel.TreeNode;
namespace Debugger.AddIn.TreeModel
{
@ -26,12 +26,11 @@ namespace Debugger.AddIn.TreeModel @@ -26,12 +26,11 @@ namespace Debugger.AddIn.TreeModel
/// Node in the tree which can be defined by a debugger expression.
/// The expression will be lazily evaluated when needed.
/// </summary>
public class ExpressionNode: TreeNode, INotifyPropertyChanged
public class ExpressionNode: TreeNode, ISetText, INotifyPropertyChanged
{
bool evaluated;
Func<Value> valueGetter;
Value permanentValue;
Expression expression;
bool canSetText;
GetValueException error;
string fullText;
@ -41,6 +40,10 @@ namespace Debugger.AddIn.TreeModel @@ -41,6 +40,10 @@ namespace Debugger.AddIn.TreeModel
set { evaluated = value; }
}
public Expression Expression {
get { return expression; }
}
public override bool CanSetText {
get {
if (!evaluated) EvaluateExpression();
@ -72,6 +75,12 @@ namespace Debugger.AddIn.TreeModel @@ -72,6 +75,12 @@ namespace Debugger.AddIn.TreeModel
}
}
public override string FullName {
get {
return this.expression.PrettyPrint() ?? Name.Trim();
}
}
public override string Type {
get {
if (!evaluated) EvaluateExpression();
@ -79,13 +88,17 @@ namespace Debugger.AddIn.TreeModel @@ -79,13 +88,17 @@ namespace Debugger.AddIn.TreeModel
}
}
public override Func<IEnumerable<TreeNode>> GetChildren {
public override IEnumerable<TreeNode> ChildNodes {
get {
if (!evaluated) EvaluateExpression();
return base.GetChildren;
return base.ChildNodes;
}
protected set {
base.GetChildren = value;
}
public override bool HasChildNodes {
get {
if (!evaluated) EvaluateExpression();
return base.HasChildNodes;
}
}
@ -123,47 +136,42 @@ namespace Debugger.AddIn.TreeModel @@ -123,47 +136,42 @@ namespace Debugger.AddIn.TreeModel
foreach (var descriptor in VisualizerDescriptors.GetAllDescriptors()) {
if (descriptor.IsVisualizerAvailable(this.expressionType)) {
yield return descriptor.CreateVisualizerCommand(this.Name, () => this.Evaluate());
yield return descriptor.CreateVisualizerCommand(this.Expression);
}
}
}
public ExpressionNode(string imageName, string name, Func<Value> valueGetter)
: base(imageName, name, string.Empty, string.Empty, null)
public ExpressionNode(TreeNode parent, IImage image, string name, Expression expression)
: base(parent)
{
this.valueGetter = valueGetter;
this.IconImage = image;
this.Name = name;
this.expression = expression;
}
/// <summary>
/// Get the value of the node and cache it as long-lived reference.
/// We assume that the user will need this value a lot.
/// </summary>
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;
}
/// <summary>
/// Get the value of the node and update the UI text fields.
/// </summary>
void EvaluateExpression()
{
evaluated = true;
Stopwatch watch = new Stopwatch();
watch.Start();
Value val;
try {
// Do not keep permanent reference
val = valueGetter();
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);
} catch (GetValueException e) {
error = e;
this.Text = e.Message;
@ -180,24 +188,27 @@ namespace Debugger.AddIn.TreeModel @@ -180,24 +188,27 @@ 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) {
var dims = val.ArrayDimensions; // Eval now
this.GetChildren = () => Utils.GetChildNodesOfArray(this, dims, dims);
}
if (val.ArrayLength > 0)
this.childNodes = Utils.LazyGetChildNodesOfArray(this, this.Expression, val.ArrayDimensions);
} else if (val.Type.IsClass || val.Type.IsValueType) {
if (val.Type.FullNameWithoutGenericArguments == typeof(List<>).FullName) {
if ((int)val.GetMemberValue("_size").PrimitiveValue > 0)
this.GetChildren = () => Utils.GetItemsOfIList(() => this.Evaluate());
this.childNodes = Utils.LazyGetItemsOfIList(this, this.expression);
} else {
this.GetChildren = () => Utils.GetChildNodesOfObject(this, val.Type);
this.childNodes = Utils.LazyGetChildNodesOfObject(this, this.Expression, val.Type);
}
} else if (val.Type.IsPointer) {
Value deRef = val.Dereference();
if (deRef != null) {
this.GetChildren = () => new ExpressionNode [] { new ExpressionNode(this.ImageName, "*" + this.Name, () => this.Evaluate().Dereference()) };
this.childNodes = new ExpressionNode [] { new ExpressionNode(this, this.IconImage, "*" + this.Name, this.Expression.AppendDereference()) };
}
}
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);
@ -225,8 +236,6 @@ namespace Debugger.AddIn.TreeModel @@ -225,8 +236,6 @@ 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)
@ -299,9 +308,11 @@ namespace Debugger.AddIn.TreeModel @@ -299,9 +308,11 @@ namespace Debugger.AddIn.TreeModel
public override bool SetText(string newText)
{
string fullName = FullName;
Value val = null;
try {
val = this.Evaluate();
val = this.Expression.Evaluate(WindowsDebugger.DebuggedProcess);
if (val.Type.IsInteger && newText.StartsWith("0x")) {
try {
val.PrimitiveValue = long.Parse(newText.Substring(2), NumberStyles.HexNumber);
@ -328,10 +339,33 @@ namespace Debugger.AddIn.TreeModel @@ -328,10 +339,33 @@ namespace Debugger.AddIn.TreeModel
return false;
}
public static string GetImageForMember(IDebugMemberInfo memberInfo)
public static IImage GetImageForThis(out string imageName)
{
string name = string.Empty;
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)
{
string name = string.Empty;
if (memberInfo.IsPublic) {
} else if (memberInfo.IsAssembly) {
name += "Internal";
@ -340,7 +374,6 @@ namespace Debugger.AddIn.TreeModel @@ -340,7 +374,6 @@ namespace Debugger.AddIn.TreeModel
} else if (memberInfo.IsPrivate) {
name += "Private";
}
if (memberInfo is FieldInfo) {
name += "Field";
} else if (memberInfo is PropertyInfo) {
@ -351,7 +384,8 @@ namespace Debugger.AddIn.TreeModel @@ -351,7 +384,8 @@ namespace Debugger.AddIn.TreeModel
throw new DebuggerException("Unknown member type " + memberInfo.GetType().FullName);
}
return "Icons.16x16." + name;
imageName = "Icons.16x16." + name;
return DebuggerResourceService.GetImage(imageName);
}
// public ContextMenuStrip GetContextMenu()
@ -425,221 +459,4 @@ namespace Debugger.AddIn.TreeModel @@ -425,221 +459,4 @@ namespace Debugger.AddIn.TreeModel
}
}
}
public partial class Utils
{
public static IEnumerable<TreeNode> GetLocalVariableNodes(StackFrame stackFrame)
{
foreach(DebugParameterInfo par in stackFrame.MethodInfo.GetParameters()) {
var parCopy = par;
yield return new ExpressionNode("Icons.16x16.Parameter", par.Name, () => parCopy.GetValue(stackFrame));
}
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 = stackFrame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = stackFrame.MethodInfo.MetadataToken;
foreach (var localVar in debugger.debuggerDecompilerService.GetLocalVariables(typeToken, methodToken)) {
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(null, "$exception", () => stackFrame.Thread.CurrentException.Value);
}
}
}
public partial class Utils
{
public static IEnumerable<TreeNode> 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);
MemberInfo[] nonPublicStatic = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.DeclaredOnly);
MemberInfo[] nonPublicInstance = shownType.GetFieldsAndNonIndexedProperties(BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.DeclaredOnly);
DebugType baseType = (DebugType)shownType.BaseType;
if (baseType != null) {
yield return new TreeNode(
"Icons.16x16.Class",
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.BaseClass}"),
baseType.Name,
baseType.FullName,
baseType.FullName == "System.Object" ? (Func<IEnumerable<TreeNode>>) null : () => Utils.GetChildNodesOfObject(expr, baseType)
);
}
if (nonPublicInstance.Length > 0) {
yield return new TreeNode(
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicMembers}"),
() => GetMembersOfObject(expr, nonPublicInstance)
);
}
if (publicStatic.Length > 0 || nonPublicStatic.Length > 0) {
yield return new TreeNode(
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.StaticMembers}"),
() => {
var children = GetMembersOfObject(expr, publicStatic).ToList();
if (nonPublicStatic.Length > 0) {
children.Insert(0, new TreeNode(
StringParser.Parse("${res:MainWindow.Windows.Debug.LocalVariables.NonPublicStaticMembers}"),
() => GetMembersOfObject(expr, nonPublicStatic)
));
}
return children;
}
);
}
if (shownType.GetInterface(typeof(IList).FullName) != null) {
yield return new TreeNode(
"IList",
() => GetItemsOfIList(() => expr.Evaluate())
);
} else {
DebugType listType, iEnumerableType, itemType;
if (shownType.ResolveIEnumerableImplementation(out iEnumerableType, out 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 GetMembersOfObject(expr, publicInstance)) {
yield return node;
}
}
public static IEnumerable<TreeNode> GetMembersOfObject(ExpressionNode expr, MemberInfo[] members)
{
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));
}
}
public static IEnumerable<TreeNode> GetItemsOfIList(Func<Value> getValue)
{
Value list = null;
DebugType iListType = null;
int count = 0;
GetValueException error = null;
try {
// 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, string.Empty, null);
} else if (count == 0) {
yield return new TreeNode("(empty)", null);
} else {
PropertyInfo pi = iListType.GetProperty("Item");
for(int i = 0; i < count; i++) {
int iCopy = i;
yield return new ExpressionNode("Icons.16x16.Field", "[" + i + "]", () => list.GetPropertyValue(pi, Eval.CreateValue(list.AppDomain, iCopy)));
}
}
}
}
public partial class Utils
{
const int MaxElementCount = 100;
public static TreeNode GetArrayRangeNode(ExpressionNode expr, ArrayDimensions bounds, ArrayDimensions originalBounds)
{
StringBuilder name = new StringBuilder();
bool isFirst = true;
name.Append("[");
for(int i = 0; i < bounds.Count; i++) {
if (!isFirst) name.Append(", ");
isFirst = false;
ArrayDimension dim = bounds[i];
ArrayDimension originalDim = originalBounds[i];
if (dim.Count == 0) {
name.Append("-");
} else if (dim.Count == 1) {
name.Append(dim.LowerBound.ToString());
} else if (dim.Equals(originalDim)) {
name.Append("*");
} else {
name.Append(dim.LowerBound);
name.Append("..");
name.Append(dim.UpperBound);
}
}
name.Append("]");
return new TreeNode(name.ToString(), () => GetChildNodesOfArray(expr, bounds, originalBounds));
}
public static IEnumerable<TreeNode> GetChildNodesOfArray(ExpressionNode arrayTarget, ArrayDimensions bounds, ArrayDimensions originalBounds)
{
if (bounds.TotalElementCount == 0)
{
yield return new TreeNode("(empty)", null);
yield break;
}
// The whole array is small - just add all elements as childs
if (bounds.TotalElementCount <= MaxElementCount) {
foreach(int[] indices in bounds.Indices) {
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;
}
// Find a dimension of size at least 2
int splitDimensionIndex = bounds.Count - 1;
for(int i = 0; i < bounds.Count; i++) {
if (bounds[i].Count > 1) {
splitDimensionIndex = i;
break;
}
}
ArrayDimension splitDim = bounds[splitDimensionIndex];
// Split the dimension
int elementsPerSegment = 1;
while (splitDim.Count > elementsPerSegment * MaxElementCount) {
elementsPerSegment *= MaxElementCount;
}
for(int i = splitDim.LowerBound; i <= splitDim.UpperBound; i += elementsPerSegment) {
List<ArrayDimension> newDims = new List<ArrayDimension>(bounds);
newDims[splitDimensionIndex] = new ArrayDimension(i, Math.Min(i + elementsPerSegment - 1, splitDim.UpperBound));
yield return GetArrayRangeNode(arrayTarget, new ArrayDimensions(newDims), originalBounds);
}
yield break;
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/IContextMenu.cs

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
// 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();
}
}

158
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ICorDebug.cs

@ -0,0 +1,158 @@ @@ -0,0 +1,158 @@
// 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<TreeNode> children;
public InfoNode(TreeNode parent, string name, string text)
: this(parent, name, text, _ => null)
{
}
public InfoNode(TreeNode parent, string name, string text, Func<TreeNode, List<TreeNode>> children)
: base(parent)
{
this.Name = name;
this.Text = text;
this.children = children(this);
}
public override IEnumerable<TreeNode> ChildNodes {
get { return children; }
}
public void AddChild(string name, string text)
{
if (children == null) {
children = new List<TreeNode>();
}
children.Add(new InfoNode(this, name, text));
}
public void AddChild(string name, string text, Func<TreeNode, List<TreeNode>> subChildren)
{
if (children == null) {
children = new List<TreeNode>();
}
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<TreeNode> GetDebugInfo(TreeNode parent, AppDomain appDomain, ICorDebugValue corValue)
{
List<TreeNode> items = new List<TreeNode>();
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;
}
}
}

32
src/AddIns/Debugger/Debugger.AddIn/TreeModel/IEnumerableNode.cs

@ -0,0 +1,32 @@ @@ -0,0 +1,32 @@
// 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
{
/// <summary>
/// IEnumerable node in the variable tree.
/// </summary>
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);
}
}
}

33
src/AddIns/Debugger/Debugger.AddIn/TreeModel/IListNode.cs

@ -0,0 +1,33 @@ @@ -0,0 +1,33 @@
// 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; }
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ISetText.cs

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
// 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);
}
}

31
src/AddIns/Debugger/Debugger.AddIn/TreeModel/SavedTreeNode.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
// 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
{
/// <summary>
/// Description of SavedTreeNode.
/// </summary>
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;
}
}
}

67
src/AddIns/Debugger/Debugger.AddIn/TreeModel/StackFrameNode.cs

@ -0,0 +1,67 @@ @@ -0,0 +1,67 @@
// 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 Debugger.MetaData;
using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.TreeModel
{
public class StackFrameNode: TreeNode
{
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<TreeNode> LazyGetChildNodes()
{
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;
}
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;
}
} else {
WindowsDebugger debugger = (WindowsDebugger)DebuggerService.CurrentDebugger;
if (debugger.debuggerDecompilerService != null) {
int typeToken = this.stackFrame.MethodInfo.DeclaringType.MetadataToken;
int methodToken = this.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;
}
}
}
if (stackFrame.Thread.CurrentException != null) {
yield return new ExpressionNode(this, null, "__exception", new IdentifierExpression("__exception"));
}
}
}
}

113
src/AddIns/Debugger/Debugger.AddIn/TreeModel/TreeNode.cs

@ -15,22 +15,31 @@ namespace Debugger.AddIn.TreeModel @@ -15,22 +15,31 @@ namespace Debugger.AddIn.TreeModel
{
/// <summary>
/// A node in the variable tree.
/// The node is immutable.
/// </summary>
public class TreeNode : ITreeNode
{
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<IEnumerable<TreeNode>> GetChildren { get; protected set; }
IImage iconImage = null;
string name = string.Empty;
string imageName = string.Empty;
string text = string.Empty;
string type = string.Empty;
protected IEnumerable<TreeNode> childNodes = null;
/// <summary>
/// The image displayed for this node.
/// </summary>
public IImage IconImage {
get { return iconImage; }
protected set { iconImage = value; }
}
/// <summary>
/// System.Windows.Media.ImageSource version of <see cref="IconImage"/>.
/// </summary>
public ImageSource ImageSource {
get {
return this.IconImage == null ? null : this.IconImage.ImageSource;
return iconImage == null ? null : iconImage.ImageSource;
}
}
@ -39,24 +48,52 @@ namespace Debugger.AddIn.TreeModel @@ -39,24 +48,52 @@ namespace Debugger.AddIn.TreeModel
/// </summary>
public Image Image {
get {
return this.IconImage == null ? null : this.IconImage.Bitmap;
return iconImage == null ? null : iconImage.Bitmap;
}
}
public virtual bool CanSetText {
get { return false; }
public string Name {
get { return name; }
set { name = value; }
}
Func<IEnumerable<ITreeNode>> ITreeNode.GetChildren {
get {
if (this.GetChildren == null)
return null;
return () => this.GetChildren();
}
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<TreeNode> ChildNodes {
get { return childNodes; }
}
IEnumerable<ITreeNode> ITreeNode.ChildNodes {
get { return childNodes; }
}
public virtual bool HasChildNodes {
get { return this.GetChildren != null; }
get { return childNodes != null; }
}
public virtual bool CanSetText {
get { return false; }
}
public virtual IEnumerable<IVisualizerCommand> VisualizerCommands {
@ -73,21 +110,41 @@ namespace Debugger.AddIn.TreeModel @@ -73,21 +110,41 @@ namespace Debugger.AddIn.TreeModel
public bool IsPinned { get; set; }
public TreeNode(string name, Func<IEnumerable<TreeNode>> getChildren)
public TreeNode(TreeNode parent)
{
this.Parent = parent;
}
public TreeNode(IImage iconImage, string name, string text, string type, TreeNode parent, Func<TreeNode, IEnumerable<TreeNode>> 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)
{
TreeNode other = obj as TreeNode;
if (other == null)
return false;
return this.FullName == other.FullName;
}
public override int GetHashCode()
{
this.Name = name;
this.GetChildren = getChildren;
return this.FullName.GetHashCode();
}
#endregion
public TreeNode(string imageName, string name, string text, string type, Func<IEnumerable<TreeNode>> getChildren)
public int CompareTo(ITreeNode other)
{
this.ImageName = imageName;
if (imageName != null)
this.IconImage = new ResourceServiceImage(imageName);
this.Name = name;
this.Text = text;
this.Type = type;
this.GetChildren = getChildren;
return this.FullName.CompareTo(other.FullName);
}
public virtual bool SetText(string newValue) {

37
src/AddIns/Debugger/Debugger.AddIn/TreeModel/Utils.cs

@ -40,7 +40,44 @@ namespace Debugger.AddIn.TreeModel @@ -40,7 +40,44 @@ namespace Debugger.AddIn.TreeModel
}
);
}
}
public class AbortedBecauseDebuggeeResumedException: System.Exception
{
public AbortedBecauseDebuggeeResumedException(): base()
{
}
}
public class PrintTimes: PrintTime
{
public PrintTimes(string text): base(text + " - end")
{
LoggingService.InfoFormatted("{0} - start", text);
}
}
public class PrintTime: IDisposable
{
string text;
System.Diagnostics.Stopwatch stopwatch = new System.Diagnostics.Stopwatch();
public PrintTime(string text)
{
this.text = text;
stopwatch.Start();
}
public void Dispose()
{
stopwatch.Stop();
LoggingService.InfoFormatted("{0} ({1} ms)", text, stopwatch.ElapsedMilliseconds);
}
}
public static class ExtensionMethods
{
public static TreeNodeWrapper ToSharpTreeNode(this TreeNode node)
{
return new TreeNodeWrapper(node);

10
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ExpressionVisualizerCommand.cs

@ -16,15 +16,11 @@ namespace Debugger.AddIn.Visualizers @@ -16,15 +16,11 @@ namespace Debugger.AddIn.Visualizers
// should we make visualizer command available for Expression, or any TreeNode?
public abstract class ExpressionVisualizerCommand : IVisualizerCommand
{
public string ValueName { get; private set; }
public Func<Value> GetValue { get; private set; }
public Expression Expression { get; private set; }
public ExpressionVisualizerCommand(string valueName, Func<Value> getValue)
public ExpressionVisualizerCommand(Expression expression)
{
if (getValue == null)
throw new ArgumentNullException("getValue");
this.ValueName = valueName;
this.GetValue = getValue;
this.Expression = expression;
}
public abstract void Execute();

13
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerCommand.cs

@ -25,9 +25,9 @@ namespace Debugger.AddIn.Visualizers @@ -25,9 +25,9 @@ namespace Debugger.AddIn.Visualizers
return type.ResolveIEnumerableImplementation(out collectionType, out itemType);
}
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
{
return new GridVisualizerCommand(valueName, getValue);
return new GridVisualizerCommand(expression);
}
}
@ -36,7 +36,8 @@ namespace Debugger.AddIn.Visualizers @@ -36,7 +36,8 @@ namespace Debugger.AddIn.Visualizers
/// </summary>
public class GridVisualizerCommand : ExpressionVisualizerCommand
{
public GridVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
public GridVisualizerCommand(Expression expression)
:base(expression)
{
}
@ -47,8 +48,10 @@ namespace Debugger.AddIn.Visualizers @@ -47,8 +48,10 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
GridVisualizerWindow window = new GridVisualizerWindow(this.ValueName, this.GetValue);
window.ShowDialog();
if (this.Expression == null)
return;
var gridVisualizerWindow = GridVisualizerWindow.EnsureShown();
gridVisualizerWindow.ShownExpression = this.Expression;
}
}
}

4
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/GridVisualizerMenuCommand.cs

@ -14,7 +14,9 @@ namespace Debugger.AddIn.Visualizers @@ -14,7 +14,9 @@ namespace Debugger.AddIn.Visualizers
{
public override void Run()
{
GridVisualizerWindow window = new GridVisualizerWindow();
window.Topmost = true;
window.Show();
}
}
}

2
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/IVisualizerDescriptor.cs

@ -16,6 +16,6 @@ namespace Debugger.AddIn.Visualizers @@ -16,6 +16,6 @@ namespace Debugger.AddIn.Visualizers
public interface IVisualizerDescriptor
{
bool IsVisualizerAvailable(DebugType type);
IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue);
IVisualizerCommand CreateVisualizerCommand(Expression expression);
}
}

12
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/ObjectGraphVisualizerCommand.cs

@ -21,9 +21,9 @@ namespace Debugger.AddIn.Visualizers @@ -21,9 +21,9 @@ namespace Debugger.AddIn.Visualizers
return !type.IsAtomic() && !type.IsSystemDotObject();
}
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
{
return new ObjectGraphVisualizerCommand(valueName, getValue);
return new ObjectGraphVisualizerCommand(expression);
}
}
@ -32,7 +32,8 @@ namespace Debugger.AddIn.Visualizers @@ -32,7 +32,8 @@ namespace Debugger.AddIn.Visualizers
/// </summary>
public class ObjectGraphVisualizerCommand : ExpressionVisualizerCommand
{
public ObjectGraphVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
public ObjectGraphVisualizerCommand(Expression expression)
:base(expression)
{
}
@ -43,9 +44,10 @@ namespace Debugger.AddIn.Visualizers @@ -43,9 +44,10 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
if (this.Expression == null)
return;
var objectGraphWindow = ObjectGraphWindow.EnsureShown();
// TODO: This only works on the root level
objectGraphWindow.ShownExpression = new IdentifierExpression(this.ValueName);
objectGraphWindow.ShownExpression = this.Expression;
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/TextVisualizerCommand.cs

@ -20,15 +20,16 @@ namespace Debugger.AddIn.Visualizers @@ -20,15 +20,16 @@ namespace Debugger.AddIn.Visualizers
return type.FullName == typeof(string).FullName;
}
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
{
return new TextVisualizerCommand(valueName, getValue);
return new TextVisualizerCommand(expression);
}
}
public class TextVisualizerCommand : ExpressionVisualizerCommand
{
public TextVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
public TextVisualizerCommand(Expression expression)
:base(expression)
{
}
@ -39,7 +40,10 @@ namespace Debugger.AddIn.Visualizers @@ -39,7 +40,10 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
var textVisualizerWindow = new TextVisualizerWindow(this.ValueName, this.GetValue().AsString());
if (this.Expression == null)
return;
string expressionValue = this.Expression.Evaluate(WindowsDebugger.CurrentProcess).AsString();
var textVisualizerWindow = new TextVisualizerWindow(this.Expression.PrettyPrint(), expressionValue);
textVisualizerWindow.ShowDialog();
}
}

13
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Commands/XmlVisualizerCommand.cs

@ -20,9 +20,9 @@ namespace Debugger.AddIn.Visualizers @@ -20,9 +20,9 @@ namespace Debugger.AddIn.Visualizers
return type.FullName == typeof(string).FullName;
}
public IVisualizerCommand CreateVisualizerCommand(string valueName, Func<Value> getValue)
public IVisualizerCommand CreateVisualizerCommand(Expression expression)
{
return new XmlVisualizerCommand(valueName, getValue);
return new XmlVisualizerCommand(expression);
}
}
@ -31,7 +31,8 @@ namespace Debugger.AddIn.Visualizers @@ -31,7 +31,8 @@ namespace Debugger.AddIn.Visualizers
/// </summary>
public class XmlVisualizerCommand : ExpressionVisualizerCommand
{
public XmlVisualizerCommand(string valueName, Func<Value> getValue) : base(valueName, getValue)
public XmlVisualizerCommand(Expression expression)
:base(expression)
{
}
@ -42,7 +43,11 @@ namespace Debugger.AddIn.Visualizers @@ -42,7 +43,11 @@ namespace Debugger.AddIn.Visualizers
public override void Execute()
{
var textVisualizerWindow = new TextVisualizerWindow(this.ValueName, this.GetValue().AsString(), ".xml");
if (this.Expression == null)
return;
var textVisualizerWindow = new TextVisualizerWindow(
this.Expression.PrettyPrint(), this.Expression.Evaluate(WindowsDebugger.CurrentProcess).AsString());
textVisualizerWindow.Mode = TextVisualizerMode.Xml;
textVisualizerWindow.ShowDialog();
}
}

16
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/IListValuesProvider.cs

@ -0,0 +1,16 @@ @@ -0,0 +1,16 @@
// 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
{
/// <summary>
/// Can provide individial items for a lazy collection, as well as total count of items.
/// </summary>
public interface IListValuesProvider<T>
{
int GetCount();
T GetItemAt(int index);
}
}

16
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Common/VirtualizingCollection.cs

@ -8,23 +8,21 @@ using System.Collections.Generic; @@ -8,23 +8,21 @@ using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers
{
/// <summary>
/// IList&lt;T&gt; with data vitualization - the indexer is lazy, uses lamda function to obtain values when needed.
/// IList&lt;T&gt; with data vitualization - the indexer is lazy, uses IListValuesProvider to obtain values when needed.
/// </summary>
public class VirtualizingCollection<T> : IList<T>, IList
{
int count;
Func<int, T> getItem;
Dictionary<int, T> itemCache = new Dictionary<int, T>();
private IListValuesProvider<T> valueProvider;
private Dictionary<int, T> itemCache = new Dictionary<int, T>();
public VirtualizingCollection(int count, Func<int, T> getItem)
public VirtualizingCollection(IListValuesProvider<T> valueProvider)
{
this.count = count;
this.getItem = getItem;
this.valueProvider = valueProvider;
}
public int Count
{
get { return count; }
get { return this.valueProvider.GetCount(); }
}
public T this[int index]
@ -34,7 +32,7 @@ namespace Debugger.AddIn.Visualizers @@ -34,7 +32,7 @@ namespace Debugger.AddIn.Visualizers
T cachedItem;
if (!itemCache.TryGetValue(index, out cachedItem))
{
cachedItem = getItem(index);
cachedItem = this.valueProvider.GetItemAt(index);
this.itemCache[index] = cachedItem;
}
return cachedItem;

4
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/Layout/TreeModel/ContentPropertyNode.cs

@ -6,7 +6,6 @@ using System.ComponentModel; @@ -6,7 +6,6 @@ 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
{
@ -78,7 +77,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -78,7 +77,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
if ((this.Property != null) && (this.Property.ObjectGraphProperty != null)) {
var memberInfo = (IDebugMemberInfo)this.Property.ObjectGraphProperty.MemberInfo;
if (memberInfo != null) {
var image = new ResourceServiceImage(ExpressionNode.GetImageForMember(memberInfo));
string imageName;
var image = ExpressionNode.GetImageForMember(memberInfo, out imageName);
this.MemberIcon = image.ImageSource;
}
}

3
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml

@ -27,6 +27,9 @@ @@ -27,6 +27,9 @@
<Border Margin="3" Padding="3">
<DockPanel>
<TextBlock VerticalAlignment="Center">Expression:</TextBlock>
<TextBox Name="txtExpression" VerticalAlignment="Center" Width="100"></TextBox>
<Button Name="btnInspect" Click="btnInspect_Click">Inspect</Button>
<ComboBox Name="cmbColumns" Style="{StaticResource styleColumnsComboBox}" Width="74" Height="20" HorizontalAlignment="Right">
<ComboBox.ItemTemplate>
<DataTemplate>

193
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/GridVisualizerWindow.xaml.cs

@ -2,16 +2,26 @@ @@ -2,16 +2,26 @@
// 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
{
@ -20,93 +30,160 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer @@ -20,93 +30,160 @@ namespace Debugger.AddIn.Visualizers.GridVisualizer
/// </summary>
public partial class GridVisualizerWindow : Window
{
Func<Value> getValue;
WindowsDebugger debuggerService;
GridViewColumnHider columnHider;
public GridVisualizerWindow(string valueName, Func<Value> getValue)
public GridVisualizerWindow()
{
InitializeComponent();
this.Title = valueName;
this.getValue = getValue;
this.debuggerService = DebuggerService.CurrentDebugger as WindowsDebugger;
if (debuggerService == null)
throw new ApplicationException("Only windows debugger is currently supported");
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;
/// <summary> When Window is visible, returns reference to the Window. Otherwise returns null. </summary>
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;
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 {
// Not IList or IEnumerable<T> - can't be displayed in GridVisualizer
return;
}
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);
}
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<VirtualizingCollection<string>>(
rowCount,
(rowIndex) => new VirtualizingCollection<string>(
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;
}
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);
} 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<T> - can't be displayed in GridVisualizer
return;
}
)
);
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) {
IList<MemberInfo> 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) {
MessageService.ShowMessage(e.Message);
}
}
void InitializeColumns(GridView gridView, MemberInfo[] members)
ListValuesProvider CreateListValuesProvider(ICSharpCode.NRefactory.Ast.Expression targetExpression, DebugType listItemType)
{
var listValuesProvider = new ListValuesProvider(targetExpression, listItemType);
var virtCollection = new VirtualizingCollection<ObjectValue>(listValuesProvider);
this.listView.ItemsSource = virtCollection;
return listValuesProvider;
}
void InitializeColumns(GridView gridView, IList<MemberInfo> itemTypeMembers)
{
gridView.Columns.Clear();
AddIndexColumn(gridView);
AddMembersColumns(gridView, itemTypeMembers);
}
// Index column
void AddIndexColumn(GridView gridView)
{
var indexColumn = new GridViewHideableColumn();
indexColumn.CanBeHidden = false;
indexColumn.Width = 36;
indexColumn.Header = string.Empty;
indexColumn.DisplayMemberBinding = new Binding("[" + members.Length + "]");
indexColumn.DisplayMemberBinding = new Binding("Index");
gridView.Columns.Add(indexColumn);
}
// Member columns
for (int i = 0; i < members.Length; i++) {
void AddMembersColumns(GridView gridView, IList<MemberInfo> itemTypeMembers)
{
foreach (var member in itemTypeMembers) {
var memberColumn = new GridViewHideableColumn();
memberColumn.CanBeHidden = true;
memberColumn.Header = members[i].Name;
memberColumn.IsVisibleDefault = ((IDebugMemberInfo)members[i]).IsPublic;
memberColumn.DisplayMemberBinding = new Binding("[" + i + "]");
memberColumn.Header = member.Name;
// "{Binding Path=[Name].Value}"
memberColumn.DisplayMemberBinding = new Binding("[" + member.Name + "].Value");
gridView.Columns.Add(memberColumn);
}
}

85
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ObjectValue.cs

@ -0,0 +1,85 @@ @@ -0,0 +1,85 @@
// 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
{
/// <summary>
/// Item of a collection in the debugee, with lazy evaluated properties.
/// </summary>
public class ObjectValue
{
/// <summary> Index of this item in the collection. </summary>
public int Index { get; private set; }
// PermanentReference for one row.
public Value PermanentReference { get; private set; }
private Dictionary<string, ObjectProperty> properties = new Dictionary<string, ObjectProperty>();
/// <summary> Used to quickly find MemberInfo by member name - DebugType.GetMember(name) uses a loop to search members </summary>
private Dictionary<string, MemberInfo> memberForNameMap;
internal ObjectValue(int index, Dictionary<string, MemberInfo> memberFromNameMap)
{
this.Index = index;
this.memberForNameMap = memberFromNameMap;
}
/// <summary>
/// Returns property with given name.
/// </summary>
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<string, MemberInfo> 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;
}
}
}

50
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/EnumerableValuesProvider.cs

@ -0,0 +1,50 @@ @@ -0,0 +1,50 @@
// 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
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s for debugee objects implementing IEnumerable.
/// </summary>
/*public class EnumerableValuesProvider : GridValuesProvider
{
public EnumerableValuesProvider(Expression targetObject, DebugType iEnumerableType, DebugType itemType)
:base(targetObject, iEnumerableType, itemType)
{
this.itemsSource = enumerateItems();
}
private IEnumerable<ObjectValue> itemsSource;
public IEnumerable<ObjectValue> ItemsSource
{
get { return this.itemsSource; }
}
private IEnumerable<ObjectValue> 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);
}
}
}*/
}

42
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/GridValuesProvider.cs

@ -0,0 +1,42 @@ @@ -0,0 +1,42 @@
// 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
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s to be displayed in Grid visualizer.
/// Descandants implement getting values for IList and IEnumerable.
/// </summary>
public class GridValuesProvider
{
/// <summary> Used to quickly find MemberInfo by member name - DebugType.GetMember(name) uses a loop to search members </summary>
protected Dictionary<string, MemberInfo> 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);
}
/// <summary>
/// Gets members that will be displayed as columns.
/// </summary>
public IList<MemberInfo> GetItemTypeMembers()
{
var publicPropetiesAndFields = itemType.GetFieldsAndNonIndexedProperties(BindingFlags.Public | BindingFlags.Instance);
return publicPropetiesAndFields;
}
}
}

59
src/AddIns/Debugger/Debugger.AddIn/Visualizers/GridVisualizer/ValueProviders/ListValuesProvider.cs

@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
// 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
{
/// <summary>
/// Provides <see cref="ObjectValue"/>s for debugee objects implementing IList.
/// </summary>
public class ListValuesProvider : GridValuesProvider, IListValuesProvider<ObjectValue>
{
int? listCount = null;
/// <summary>
/// After evaluating how many items to clear debugger Expression cache,
/// so that the cache does not keep too many PermanentReferences.
/// </summary>
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;
}
/// <summary>When this reaches ClearCacheThreshold, the debugger Expression cache is cleared.</summary>
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);
}
}
}

12
src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerMode.cs

@ -0,0 +1,12 @@ @@ -0,0 +1,12 @@
// 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
}

48
src/AddIns/Debugger/Debugger.AddIn/Visualizers/TextVisualizer/TextVisualizerWindow.xaml.cs

@ -1,9 +1,17 @@ @@ -1,9 +1,17 @@
// 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 ICSharpCode.AvalonEdit.Highlighting;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
namespace Debugger.AddIn.Visualizers.TextVisualizer
{
@ -12,14 +20,42 @@ namespace Debugger.AddIn.Visualizers.TextVisualizer @@ -12,14 +20,42 @@ namespace Debugger.AddIn.Visualizers.TextVisualizer
/// </summary>
public partial class TextVisualizerWindow : Window
{
public TextVisualizerWindow(string title, string text, string highlighting = null)
public TextVisualizerWindow()
{
InitializeComponent();
Mode = TextVisualizerMode.PlainText;
textEditor.IsReadOnly = true;
}
public TextVisualizerWindow(string title, string text)
{
InitializeComponent();
Title = title;
this.textEditor.Text = text;
if (highlighting != null)
this.textEditor.SyntaxHighlighting = HighlightingManager.Instance.GetDefinitionByExtension(highlighting);
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;
}
}
}
void CheckBox_CheckedChanged(object sender, RoutedEventArgs e)

13
src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs

@ -33,17 +33,6 @@ namespace Debugger.AddIn.Visualizers.Utils @@ -33,17 +33,6 @@ 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<T> constructor not found");
return (Value)ctor.Invoke(new object[] { iEnumerableValue });
}
/// <summary>
/// Gets underlying address of object in the debuggee.
/// </summary>
@ -131,7 +120,7 @@ namespace Debugger.AddIn.Visualizers.Utils @@ -131,7 +120,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("Object does not implement System.Collections.ICollection");
throw new GetValueException(targetObject, targetObject.PrettyPrint() + " 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;
}

12
src/AddIns/Debugger/Debugger.Core/Debugger.Core.csproj

@ -143,6 +143,8 @@ @@ -143,6 +143,8 @@
<Compile Include="Mono.Cecil\Mono.Cecil\MethodCallingConvention.cs" />
<Compile Include="Mono.Cecil\Mono.Cecil\ReflectionException.cs" />
<Compile Include="NDebugger.cs" />
<Compile Include="NRefactory\Ast\ExpressionExtensionMethods.cs" />
<Compile Include="NRefactory\Visitors\ExpressionEvaluator.cs" />
<Compile Include="Options.cs" />
<Compile Include="PausedReason.cs" />
<Compile Include="PauseSession.cs" />
@ -195,7 +197,17 @@ @@ -195,7 +197,17 @@
<Folder Include="Mono.Cecil\Mono.Cecil.Binary" />
<Folder Include="Mono.Cecil\Mono.Cecil.Metadata" />
<Folder Include="Mono.Cecil\Mono.Cecil.Signatures" />
<Folder Include="NRefactory" />
<Folder Include="NRefactory\Ast" />
<Folder Include="NRefactory\Visitors" />
<Folder Include="Tests" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\..\..\Libraries\NRefactory\Project\NRefactory.csproj">
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name>
<Private>False</Private>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildBinPath)\Microsoft.CSHARP.Targets" />
</Project>

14
src/AddIns/Debugger/Debugger.Core/Eval.cs

@ -273,24 +273,24 @@ namespace Debugger @@ -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

34
src/AddIns/Debugger/Debugger.Core/GetValueException.cs

@ -2,21 +2,55 @@ @@ -2,21 +2,55 @@
// 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;
/// <summary> Expression that has caused this exception to occur </summary>
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;
}
}
}

4
src/AddIns/Debugger/Debugger.Core/ManagedCallback.cs

@ -246,14 +246,14 @@ namespace Debugger @@ -246,14 +246,14 @@ namespace Debugger
public void EvalException(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval corEval)
{
EnterCallback(PausedReason.EvalComplete, "EvalException (" + process.ActiveEvals[corEval].Description + ")", pThread);
EnterCallback(PausedReason.EvalComplete, "EvalException", pThread);
HandleEvalComplete(pAppDomain, pThread, corEval, true);
}
public void EvalComplete(ICorDebugAppDomain pAppDomain, ICorDebugThread pThread, ICorDebugEval corEval)
{
EnterCallback(PausedReason.EvalComplete, "EvalComplete (" + process.ActiveEvals[corEval].Description + ")", pThread);
EnterCallback(PausedReason.EvalComplete, "EvalComplete", pThread);
HandleEvalComplete(pAppDomain, pThread, corEval, false);
}

18
src/AddIns/Debugger/Debugger.Core/MetaData/DebugMethodInfo.cs

@ -637,7 +637,7 @@ namespace Debugger.MetaData @@ -637,7 +637,7 @@ namespace Debugger.MetaData
{
List<DebugLocalVariableInfo> vars = new List<DebugLocalVariableInfo>();
foreach (ISymUnmanagedVariable symVar in symScope.GetLocals()) {
uint address = (uint)symVar.GetAddressField1();
ISymUnmanagedVariable symVarCopy = symVar;
int start;
SignatureReader sigReader = new SignatureReader(symVar.GetSignature());
LocalVarSig.LocalVariable locVarSig = sigReader.ReadLocalVariable(sigReader.Blob, 0, out start);
@ -652,7 +652,7 @@ namespace Debugger.MetaData @@ -652,7 +652,7 @@ namespace Debugger.MetaData
(int)symScope.GetStartOffset(),
(int)symScope.GetEndOffset(),
delegate(StackFrame context) {
return context.GetLocalVariableValue(address);
return GetLocalVariableValue(context, symVarCopy);
},
locVarType
);
@ -666,7 +666,7 @@ namespace Debugger.MetaData @@ -666,7 +666,7 @@ namespace Debugger.MetaData
(int)symScope.GetEndOffset(),
locVarType,
delegate(StackFrame context) {
return context.GetLocalVariableValue(address);
return GetLocalVariableValue(context, symVarCopy);
}
);
vars.Add(locVar);
@ -678,6 +678,18 @@ namespace Debugger.MetaData @@ -678,6 +678,18 @@ 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);
}
/// <inheritdoc/>
public override string ToString()
{

1
src/AddIns/Debugger/Debugger.Core/MetaData/DebugType.cs

@ -9,6 +9,7 @@ using System.Text; @@ -9,6 +9,7 @@ using System.Text;
using Debugger.Interop.CorDebug;
using Debugger.Interop.MetaData;
using ICSharpCode.NRefactory.Ast;
using Mono.Cecil.Signatures;
namespace Debugger.MetaData

0
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionExtensionMethods.cs → src/AddIns/Debugger/Debugger.Core/NRefactory/Ast/ExpressionExtensionMethods.cs

18
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluator.cs → src/AddIns/Debugger/Debugger.Core/NRefactory/Visitors/ExpressionEvaluator.cs

@ -15,8 +15,8 @@ namespace ICSharpCode.NRefactory.Visitors @@ -15,8 +15,8 @@ namespace ICSharpCode.NRefactory.Visitors
{
public class EvaluateException: GetValueException
{
public EvaluateException(INode code, string msg):base(msg) {}
public EvaluateException(INode code, string msgFmt, params string[] msgArgs):base(string.Format(msgFmt, msgArgs)) {}
public EvaluateException(INode code, string msg):base(code, msg) {}
public EvaluateException(INode code, string msgFmt, params string[] msgArgs):base(code, string.Format(msgFmt, msgArgs)) {}
}
class TypedValue
@ -163,7 +163,13 @@ namespace ICSharpCode.NRefactory.Visitors @@ -163,7 +163,13 @@ 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();
@ -171,8 +177,11 @@ namespace ICSharpCode.NRefactory.Visitors @@ -171,8 +177,11 @@ 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 EvaluateException(expression, "Language feature not implemented: " + e.Message);
throw new GetValueException(expression, "Language feature not implemented: " + e.Message);
} finally {
watch.Stop();
context.Process.TraceMessage("Evaluated: {0} in {1} ms total", expression.PrettyPrint(), watch.ElapsedMilliseconds);
@ -181,6 +190,9 @@ namespace ICSharpCode.NRefactory.Visitors @@ -181,6 +190,9 @@ 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;
}

17
src/AddIns/Debugger/Debugger.Core/Process.cs

@ -7,6 +7,8 @@ using System.Runtime.InteropServices; @@ -7,6 +7,8 @@ using System.Runtime.InteropServices;
using Debugger.Interop.CorDebug;
using Debugger.Interop.CorSym;
using ICSharpCode.NRefactory.Ast;
using ICSharpCode.NRefactory.Visitors;
namespace Debugger
{
@ -249,6 +251,7 @@ namespace Debugger @@ -249,6 +251,7 @@ namespace Debugger
internal bool TerminateCommandIssued = false;
internal Queue<Breakpoint> BreakpointHitEventQueue = new Queue<Breakpoint>();
internal Dictionary<INode, TypedValue> ExpressionsCache = new Dictionary<INode, TypedValue>();
#region Events
@ -327,6 +330,7 @@ namespace Debugger @@ -327,6 +330,7 @@ namespace Debugger
if (action == DebuggeeStateAction.Clear) {
if (debuggeeState == null) throw new DebuggerException("Debugee state already cleared");
debuggeeState = null;
this.ExpressionsCache.Clear();
}
}
@ -553,6 +557,19 @@ namespace Debugger @@ -553,6 +557,19 @@ namespace Debugger
// This is done once ExitProcess callback is received
}
/// <summary>
/// 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.
/// </summary>
public void ClearExpressionCache()
{
if (this.ExpressionsCache != null ){
this.ExpressionsCache.Clear();
}
}
void SelectSomeThread()
{
if (this.SelectedThread != null && !this.SelectedThread.IsInValidState) {

10
src/AddIns/Debugger/Debugger.Core/StackFrame.cs

@ -380,16 +380,6 @@ namespace Debugger @@ -380,16 +380,6 @@ 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;
}
}
/// <summary> Get instance of 'this'. It works well with delegates and enumerators. </summary>
[Debugger.Tests.Ignore]
public Value GetLocalVariableThis()

1
src/AddIns/Debugger/Debugger.Core/Value.cs

@ -613,7 +613,6 @@ namespace Debugger @@ -613,7 +613,6 @@ namespace Debugger
/// <summary> Invoke the ToString() method </summary>
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");

4
src/AddIns/Debugger/Debugger.Tests/Debugger.Tests.csproj

@ -77,10 +77,6 @@ @@ -77,10 +77,6 @@
<Project>{3A9AE6AA-BC07-4A2F-972C-581E3AE2F195}</Project>
<Name>NRefactory</Name>
</ProjectReference>
<ProjectReference Include="..\Debugger.AddIn\Debugger.AddIn.csproj">
<Project>{EC06F96A-AEEC-49D6-B03D-AB87C6EB674C}</Project>
<Name>Debugger.AddIn</Name>
</ProjectReference>
<ProjectReference Include="..\Debugger.Core\Debugger.Core.csproj">
<Project>{1D18D788-F7EE-4585-A23B-34DC8EC63CB8}</Project>
<Name>Debugger.Core</Name>

2
src/Main/Base/Project/Src/Bookmarks/BookmarkConverter.cs

@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -152,7 +152,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
b.Append('|');
b.Append(node.ImageName);
b.Append('|');
b.Append(node.Name);
b.Append(node.FullName);
b.Append('|');
b.Append(node.Text);
}

12
src/Main/Base/Project/Src/Services/Debugger/Tooltips/ITreeNode.cs

@ -10,12 +10,14 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -10,12 +10,14 @@ namespace ICSharpCode.SharpDevelop.Debugging
/// <summary>
/// Node that can be bound to <see cref="DebuggerTooltipControl" />.
/// </summary>
public interface ITreeNode
public interface ITreeNode : IComparable<ITreeNode>
{
string ImageName { get; }
string Name { get; }
string FullName { get; }
string ImageName { get; }
string Text { get; }
bool CanSetText { get; }
@ -24,7 +26,9 @@ namespace ICSharpCode.SharpDevelop.Debugging @@ -24,7 +26,9 @@ namespace ICSharpCode.SharpDevelop.Debugging
ImageSource ImageSource { get; }
Func<IEnumerable<ITreeNode>> GetChildren { get; }
IEnumerable<ITreeNode> ChildNodes { get; }
bool HasChildNodes { get; }
IEnumerable<IVisualizerCommand> VisualizerCommands { get; }

4
src/Main/Base/Project/Src/Services/Debugger/Tooltips/PinBookmark.cs

@ -77,7 +77,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -77,7 +77,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
throw new ArgumentNullException("Node is null");
foreach (var currentNode in mark.Nodes) {
if (node.Name == currentNode.Name)
if (node.FullName == currentNode.FullName)
return true;
}
@ -92,7 +92,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks @@ -92,7 +92,7 @@ namespace ICSharpCode.SharpDevelop.Bookmarks
throw new ArgumentNullException("Node is null");
foreach (var currentNode in mark.Nodes) {
if (node.Name == currentNode.Name) {
if (node.FullName == currentNode.FullName) {
mark.Nodes.Remove(currentNode);
return;
}

Loading…
Cancel
Save