61 changed files with 1757 additions and 591 deletions
@ -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"); |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
||||
} |
@ -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(); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
||||
} |
@ -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; } |
||||
} |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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")); |
||||
} |
||||
} |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
||||
}*/ |
||||
} |
@ -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; |
||||
} |
||||
} |
||||
} |
@ -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); |
||||
} |
||||
} |
||||
} |
@ -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 |
||||
} |
Loading…
Reference in new issue