Browse Source

- Refactored ObjectGraphNode - using tree-structured content (like in Debugger.AddIn.TreeModel) instead of flat list of properties.

- Refactored ObjectGraphBuilder.

git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@4361 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61
shortcuts
Martin Koníček 17 years ago
parent
commit
65afc732e5
  1. 16
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj
  2. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Common/DebuggerVisualizerException.cs
  3. 27
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Common/IEvaluate.cs
  4. 31
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Common/ObjectPropertyComparer.cs
  5. 1
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedEdge.cs
  6. 6
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs
  7. 16
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs
  8. 4
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs
  9. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs
  10. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs
  11. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/NamedEdge.cs
  12. 8
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs
  13. 143
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs
  14. 59
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphNode.cs
  15. 2
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphProperty.cs
  16. 102
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs
  17. 19
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/AbstractNode.cs
  18. 44
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/NestedNode.cs
  19. 22
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/NestedNodeType.cs
  20. 53
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/PropertyNode.cs
  21. 30
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Utils/AtomicType.cs
  22. 59
      src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Utils/DebuggerHelpers.cs

16
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Debugger.AddIn.csproj

@ -121,7 +121,16 @@ @@ -121,7 +121,16 @@
<Compile Include="Src\Service\DebuggerEventForm.Designer.cs">
<DependentUpon>DebuggerEventForm.cs</DependentUpon>
</Compile>
<Compile Include="Src\Visualizers\Common\DebuggerVisualizerException.cs" />
<Compile Include="Src\Visualizers\Common\IEvaluate.cs" />
<Compile Include="Src\Visualizers\Common\ObjectPropertyComparer.cs" />
<Compile Include="Src\Visualizers\Controls\DragScrollViewer.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\NamedEdge.cs" />
<Compile Include="Src\Visualizers\Graph\TreeModel\AbstractNode.cs" />
<Compile Include="Src\Visualizers\Graph\TreeModel\NestedNode.cs" />
<Compile Include="Src\Visualizers\Graph\TreeModel\NestedNodeType.cs" />
<Compile Include="Src\Visualizers\Graph\TreeModel\PropertyNode.cs" />
<Compile Include="Src\Visualizers\Utils\AtomicType.cs" />
<Compile Include="Src\Visualizers\Utils\TypeResolver.cs" />
<EmbeddedResource Include="Src\Service\DebuggeeExceptionForm.resx">
<DependentUpon>DebuggeeExceptionForm.cs</DependentUpon>
@ -167,7 +176,6 @@ @@ -167,7 +176,6 @@
<Compile Include="Src\TreeModel\ChildNodesOfObject.cs" />
<Compile Include="Src\TreeModel\StackFrameNode.cs" />
<Compile Include="Src\TreeModel\Utils.cs" />
<Compile Include="Src\Visualizers\Graph\DebuggerVisualizerException.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\CanvasLocationAdapter.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\GraphDrawer.cs" />
<Compile Include="Src\Visualizers\Graph\Drawing\NodeControl.xaml.cs">
@ -195,11 +203,9 @@ @@ -195,11 +203,9 @@
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNode.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeLR.cs" />
<Compile Include="Src\Visualizers\Graph\Layout\Tree\TreeNodeTB.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\NamedEdge.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectEdge.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectGraph.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectGraphBuilder.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectNode.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectGraphNode.cs" />
<Compile Include="Src\Visualizers\Graph\ObjectGraph\ObjectGraphProperty.cs" />
<Compile Include="Src\Visualizers\Graph\ShowObjectGraphVisualizerCommand.cs" />
<Compile Include="Src\Visualizers\GridVisualizer\GridVisualizerWindow.xaml.cs">
@ -309,9 +315,11 @@ @@ -309,9 +315,11 @@
<Folder Include="Src\Visualizers\Graph\Layout" />
<Folder Include="Src\Visualizers\Graph\Layout\Tree" />
<Folder Include="Src\Visualizers\Graph\Graphviz" />
<Folder Include="Src\Visualizers\Graph\TreeModel" />
<Folder Include="Src\Visualizers\Graph\ObjectGraph" />
<Folder Include="Src\Visualizers\GridVisualizer\ValueProviders" />
<Folder Include="Src\Visualizers\Controls" />
<Folder Include="Src\Visualizers\Common" />
<Folder Include="Src\Visualizers\Utils" />
<Folder Include="Src\Visualizers\GridVisualizer" />
<Folder Include="Src\Visualizers\PresentationBindings" />

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/DebuggerVisualizerException.cs → src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Common/DebuggerVisualizerException.cs

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
// </file>
using System;
namespace Debugger.AddIn.Visualizers.Graph
namespace Debugger.AddIn.Visualizers
{
/// <summary>
/// Description of DebuggerVisualizerException.

27
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Common/IEvaluate.cs

@ -0,0 +1,27 @@ @@ -0,0 +1,27 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
namespace Debugger.AddIn.Visualizers
{
/// <summary>
/// Object that has its state partially uninitialized,
/// and can initialize its state fully on demand.
/// </summary>
public interface IEvaluate
{
/// <summary>
/// On-demand evaluation of internal state.
/// </summary>
void Evaluate();
/// <summary>
/// Is this object fully evaluated?
/// </summary>
bool IsEvaluated { get; }
}
}

31
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Common/ObjectPropertyComparer.cs

@ -0,0 +1,31 @@ @@ -0,0 +1,31 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers.Common
{
/// <summary>
/// Provides sort ordering on ObjectProperties.
/// </summary>
class ObjectPropertyComparer : IComparer<ObjectProperty>
{
public int Compare(ObjectProperty prop1, ObjectProperty prop2)
{
// order by IsAtomic, Name
int comparedAtomic = prop2.IsAtomic.CompareTo(prop1.IsAtomic);
if (comparedAtomic != 0)
{
return comparedAtomic;
}
else
{
return prop1.Name.CompareTo(prop2.Name);
}
}
}
}

1
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedEdge.cs

@ -4,6 +4,7 @@ @@ -4,6 +4,7 @@
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using Debugger.AddIn.Visualizers.Utils;
using System;
using System.Collections.Generic;
using System.Windows;

6
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/PositionedNode.cs

@ -16,11 +16,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -16,11 +16,11 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public class PositionedNode
{
private ObjectNode objectNode;
private ObjectGraphNode objectNode;
/// <summary>
/// Underlying ObjectNode.
/// </summary>
public ObjectNode ObjectNode
public ObjectGraphNode ObjectNode
{
get { return objectNode; }
}
@ -51,7 +51,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -51,7 +51,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// Creates new PositionedNode.
/// </summary>
/// <param name="objectNode">Underlying ObjectNode.</param>
public PositionedNode(ObjectNode objectNode)
public PositionedNode(ObjectGraphNode objectNode)
{
this.objectNode = objectNode;

16
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeLayouter.cs

@ -24,8 +24,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -24,8 +24,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
PositionedGraph resultGraph = null;
Dictionary<ObjectNode, TreeNode> treeNodeFor = new Dictionary<ObjectNode, TreeNode>();
Dictionary<ObjectNode, object> seenNodes = new Dictionary<ObjectNode, object>();
Dictionary<ObjectGraphNode, TreeNode> treeNodeFor = new Dictionary<ObjectGraphNode, TreeNode>();
Dictionary<ObjectGraphNode, object> seenNodes = new Dictionary<ObjectGraphNode, object>();
public TreeLayouter()
{
@ -41,8 +41,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -41,8 +41,8 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
layoutDirection = direction;
resultGraph = new PositionedGraph();
treeNodeFor = new Dictionary<ObjectNode, TreeNode>();
seenNodes = new Dictionary<ObjectNode, object>();
treeNodeFor = new Dictionary<ObjectGraphNode, TreeNode>();
seenNodes = new Dictionary<ObjectGraphNode, object>();
TreeNode tree = buildTreeRecursive(objectGraph.Root, expandedNodes);
calculateNodePosRecursive(tree, 0, 0);
@ -53,7 +53,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -53,7 +53,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
return resultGraph;
}
private TreeNode buildTreeRecursive(ObjectNode objectGraphNode, ExpandedNodes expandedNodes)
private TreeNode buildTreeRecursive(ObjectGraphNode objectGraphNode, ExpandedNodes expandedNodes)
{
seenNodes.Add(objectGraphNode, null);
@ -64,11 +64,13 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -64,11 +64,13 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
treeNodeFor[objectGraphNode] = newTreeNode;
double subtreeSize = 0;
foreach (ObjectGraphProperty property in objectGraphNode.Properties)
foreach (AbstractNode absNode in objectGraphNode.Content.Childs)
{
ObjectGraphProperty property = ((PropertyNode)absNode).Property;
if (property.TargetNode != null)
{
ObjectNode neighbor = property.TargetNode;
ObjectGraphNode neighbor = property.TargetNode;
TreeNode targetTreeNode = null;
bool newEdgeIsTreeEdge = false;
if (seenNodes.ContainsKey(neighbor))

4
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNode.cs

@ -19,7 +19,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -19,7 +19,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public abstract class TreeNode : PositionedNode
{
public static TreeNode Create(LayoutDirection direction, ObjectNode objectNode)
public static TreeNode Create(LayoutDirection direction, ObjectGraphNode objectNode)
{
switch (direction) {
case LayoutDirection.TopBottom: return new TreeNodeTB(objectNode);
@ -31,7 +31,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -31,7 +31,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
public double HorizontalMargin { get; set; }
public double VerticalMargin { get; set; }
protected TreeNode(ObjectNode objectNode) : base(objectNode)
protected TreeNode(ObjectGraphNode objectNode) : base(objectNode)
{
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeLR.cs

@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public class TreeNodeLR: TreeNode
{
public TreeNodeLR(ObjectNode objectNode) : base(objectNode)
public TreeNodeLR(ObjectGraphNode objectNode) : base(objectNode)
{
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/Layout/Tree/TreeNodeTB.cs

@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout @@ -14,7 +14,7 @@ namespace Debugger.AddIn.Visualizers.Graph.Layout
/// </summary>
public class TreeNodeTB : TreeNode
{
public TreeNodeTB(ObjectNode objectNode) : base(objectNode)
public TreeNodeTB(ObjectGraphNode objectNode) : base(objectNode)
{
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/NamedEdge.cs

@ -6,7 +6,7 @@ @@ -6,7 +6,7 @@
// </file>
using System;
namespace Debugger.AddIn.Visualizers.Graph
namespace Debugger.AddIn.Visualizers
{
/// <summary>
/// Named edge connecting 2 objects of same type.

8
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraph.cs

@ -18,22 +18,22 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -18,22 +18,22 @@ namespace Debugger.AddIn.Visualizers.Graph
/// <summary>
/// Root of the graph.
/// </summary>
public ObjectNode Root { get; internal set; }
public ObjectGraphNode Root { get; internal set; }
/// <summary>
/// Adds node to the graph.
/// </summary>
/// <param name="node">node to be added</param>
internal void AddNode(ObjectNode node)
internal void AddNode(ObjectGraphNode node)
{
_nodes.Add(node);
}
private List<ObjectNode> _nodes = new List<ObjectNode>();
private List<ObjectGraphNode> _nodes = new List<ObjectGraphNode>();
/// <summary>
/// All nodes in the graph.
/// </summary>
public IEnumerable<ObjectNode> Nodes
public IEnumerable<ObjectGraphNode> Nodes
{
get { return _nodes; }
}

143
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs

@ -50,20 +50,15 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -50,20 +50,15 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
public ObjectGraph ResultGraph { get { return this.resultGraph; } }
/// <summary>
/// System.Runtime.CompilerServices.GetHashCode method, for obtaining non-overriden hash codes from debuggee.
/// </summary>
private MethodInfo hashCodeMethod;
/// <summary>
/// Given hash code, lookup already existing node(s) with this hash code.
/// </summary>
private Lookup<int, ObjectNode> objectNodesForHashCode = new Lookup<int, ObjectNode>();
private Lookup<int, ObjectGraphNode> objectNodesForHashCode = new Lookup<int, ObjectGraphNode>();
/// <summary>
/// Binding flags for getting member expressions.
/// </summary>
private readonly Debugger.MetaData.BindingFlags _bindingFlags =
private readonly Debugger.MetaData.BindingFlags memberBindingFlags =
BindingFlags.Public | BindingFlags.Instance | BindingFlags.Field | BindingFlags.GetProperty;
/// <summary>
@ -73,9 +68,6 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -73,9 +68,6 @@ namespace Debugger.AddIn.Visualizers.Graph
public ObjectGraphBuilder(WindowsDebugger debuggerService)
{
this.debuggerService = debuggerService;
DebugType typeRuntimeHelpers = DebugType.Create(debuggerService.DebuggedProcess, null, "System.Runtime.CompilerServices.RuntimeHelpers");
this.hashCodeMethod = typeRuntimeHelpers.GetMember("GetHashCode", BindingFlags.Public | BindingFlags.Static | BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo;
}
/// <summary>
@ -97,19 +89,19 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -97,19 +89,19 @@ namespace Debugger.AddIn.Visualizers.Graph
{
//resultGraph.Root = buildGraphRecursive(debuggerService.GetValueFromName(expression).GetPermanentReference(), expandedNodes);
resultGraph.Root = createNewNode(debuggerService.GetValueFromName(expression).GetPermanentReference());
loadNodeProperties(resultGraph.Root);
loadChildrenRecursive(resultGraph.Root, expandedNodes);
loadContent(resultGraph.Root);
loadNeighborsRecursive(resultGraph.Root, expandedNodes);
}
return resultGraph;
}
public ObjectNode ObtainNodeForExpression(Expression expr, out bool createdNewNode)
public ObjectGraphNode ObtainNodeForExpression(Expression expr, out bool createdNewNode)
{
return ObtainNodeForValue(getPermanentReference(expr), out createdNewNode);
return ObtainNodeForValue(expr.GetPermanentReference(), out createdNewNode);
}
public ObjectNode ObtainNodeForExpression(Expression expr)
public ObjectGraphNode ObtainNodeForExpression(Expression expr)
{
bool createdNewNode; // ignore (caller is not interested, otherwise he would use the other overload)
return ObtainNodeForExpression(expr, out createdNewNode);
@ -120,62 +112,67 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -120,62 +112,67 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="value">Value for which to obtain the node/</param>
/// <param name="createdNew">True if new node was created, false if existing node was returned.</param>
public ObjectNode ObtainNodeForValue(Value value, out bool createdNew)
public ObjectGraphNode ObtainNodeForValue(Value value, out bool createdNew)
{
createdNew = false;
ObjectNode nodeForValue = getExistingNodeForValue(value);
ObjectGraphNode nodeForValue = getExistingNodeForValue(value);
if (nodeForValue == null)
{
// if no node for memberValue exists, create it
nodeForValue = createNewNode(value);
loadNodeProperties(nodeForValue);
loadContent(nodeForValue);
createdNew = true;
}
return nodeForValue;
}
/// <summary>
/// Fills node contents by adding properties.
/// Fills node Content property tree.
/// </summary>
/// <param name="thisNode"></param>
private void loadNodeProperties(ObjectNode thisNode)
private void loadContent(ObjectGraphNode thisNode)
{
NestedNode contentRoot = new NestedNode(NestedNodeType.ThisNode);
thisNode.Content = contentRoot;
// take all properties for this value (type = value's real type)
foreach(Expression memberExpr in thisNode.PermanentReference.Expression.AppendObjectMembers(thisNode.PermanentReference.Type, _bindingFlags))
foreach(Expression memberExpr in thisNode.PermanentReference.Expression.AppendObjectMembers(thisNode.PermanentReference.Type, this.memberBindingFlags))
{
checkIsOfSupportedType(memberExpr);
string memberName = memberExpr.CodeTail;
if (isOfAtomicType(memberExpr))
if (memberExpr.IsOfAtomicType())
{
// atomic members are added to the list of node's "properties"
string memberValueAsString = memberExpr.Evaluate(debuggerService.DebuggedProcess).AsString;
thisNode.AddAtomicProperty(memberName, memberValueAsString, memberExpr);
// properties are now lazy-evaluated
// string memberValueAsString = memberExpr.Evaluate(debuggerService.DebuggedProcess).InvokeToString();
AddAtomicPropertyChild(contentRoot, memberName, memberExpr);
}
else
{
// for object members, complex properties are added
ObjectNode targetNode = null;
bool memberIsNull = isNull(memberExpr);
thisNode.AddComplexProperty(memberName, "", memberExpr, targetNode, memberIsNull);
ObjectGraphNode targetNode = null;
bool memberIsNull = memberExpr.IsNull();
AddComplexPropertyChild(contentRoot, memberName, memberExpr, targetNode, memberIsNull);
}
}
}
/// <summary>
/// Creates child nodes of this node for each complex property and connects them to property.TargetNode.
/// For each complex property of this node, create s neighbor graph node if needed and connects the neighbor to ObjectProperty.TargetNode.
/// </summary>
/// <param name="thisNode"></param>
/// <param name="expandedNodes"></param>
private void loadChildrenRecursive(ObjectNode thisNode, ExpandedNodes expandedNodes)
private void loadNeighborsRecursive(ObjectGraphNode thisNode, ExpandedNodes expandedNodes)
{
foreach(ObjectGraphProperty complexProperty in thisNode.ComplexProperties)
{
Expression memberExpr = complexProperty.Expression;
ObjectNode targetNode = null;
ObjectGraphNode targetNode = null;
// we are only evaluating expanded nodes here
// (we have to do this to know the "shape" of the graph)
// property laziness makes sense, as we are not evaluating atomic and non-expanded properties out of user's view
if (!complexProperty.IsNull && expandedNodes.IsExpanded(memberExpr.Code))
{
Value memberValue = getPermanentReference(memberExpr);
Value memberValue = memberExpr.GetPermanentReference();
bool createdNew;
// get existing node (loop) or create new
@ -183,7 +180,7 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -183,7 +180,7 @@ namespace Debugger.AddIn.Visualizers.Graph
if (createdNew)
{
// if member node is new, recursively build its subtree
loadChildrenRecursive(targetNode, expandedNodes);
loadNeighborsRecursive(targetNode, expandedNodes);
}
}
else
@ -199,10 +196,10 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -199,10 +196,10 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="permanentReference">Value, has to be valid.</param>
/// <returns>New empty object node representing the value.</returns>
private ObjectNode createNewNode(Value permanentReference)
private ObjectGraphNode createNewNode(Value permanentReference)
{
ObjectNode newNode = new ObjectNode();
newNode.HashCode = invokeGetHashCode(permanentReference);
ObjectGraphNode newNode = new ObjectGraphNode();
newNode.HashCode = permanentReference.InvokeDefaultGetHashCode();
resultGraph.AddNode(newNode);
// remember this node's hashcode for quick lookup
@ -220,11 +217,11 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -220,11 +217,11 @@ namespace Debugger.AddIn.Visualizers.Graph
/// </summary>
/// <param name="value">Valid value representing an instance.</param>
/// <returns></returns>
private ObjectNode getExistingNodeForValue(Value value)
private ObjectGraphNode getExistingNodeForValue(Value value)
{
int objectHashCode = invokeGetHashCode(value);
int objectHashCode = value.InvokeDefaultGetHashCode();
// are there any nodes with the same hash code?
LookupValueCollection<ObjectNode> nodesWithSameHashCode = objectNodesForHashCode[objectHashCode];
LookupValueCollection<ObjectGraphNode> nodesWithSameHashCode = objectNodesForHashCode[objectHashCode];
if (nodesWithSameHashCode == null)
{
return null;
@ -234,28 +231,30 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -234,28 +231,30 @@ namespace Debugger.AddIn.Visualizers.Graph
// if there is a node with same hash code, check if it has also the same address
// (hash codes are not uniqe - http://stackoverflow.com/questions/750947/-net-unique-object-identifier)
ulong objectAddress = value.GetObjectAddress();
ObjectNode nodeWithSameAddress = nodesWithSameHashCode.Find(
ObjectGraphNode nodeWithSameAddress = nodesWithSameHashCode.Find(
node => { return node.PermanentReference.GetObjectAddress() == objectAddress; } );
return nodeWithSameAddress;
}
}
/// <summary>
/// Invokes GetHashCode on given value.
/// Adds primitive property.
/// </summary>
/// <param name="value">Valid value.</param>
/// <returns>Hash code of the object in the debugee.</returns>
private int invokeGetHashCode(Value value)
public void AddAtomicPropertyChild(NestedNode node, string name, Expression expression)
{
// David: I had hard time finding out how to invoke static method
// value.InvokeMethod is nice for instance methods.
// what about MethodInfo.Invoke() ?
// also, there could be an overload that takes 1 parameter instead of array
string defaultHashCode = Eval.InvokeMethod(this.hashCodeMethod, null, new Value[]{value}).AsString;
//MethodInfo method = value.Type.GetMember("GetHashCode", BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo;
//string hashCode = value.InvokeMethod(method, null).AsString;
return int.Parse(defaultHashCode);
// add child with no value (will be lazy-evaluated later)
node.AddChild(new PropertyNode(new ObjectGraphProperty
{ Name = name, Value = "", Expression = expression, IsAtomic = true, TargetNode = null }));
}
/// <summary>
/// Adds complex property.
/// </summary>
public void AddComplexPropertyChild(NestedNode node, string name, Expression expression, ObjectGraphNode targetNode, bool isNull)
{
// add child with no value (will be lazy-evaluated later)
node.AddChild(new PropertyNode(new ObjectGraphProperty
{ Name = name, Value = "", Expression = expression, IsAtomic = false, TargetNode = targetNode, IsNull = isNull }));
}
/// <summary>
@ -271,41 +270,5 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -271,41 +270,5 @@ namespace Debugger.AddIn.Visualizers.Graph
throw new DebuggerVisualizerException("Arrays are not supported yet");
}
}
/// <summary>
/// Checks whether given expression's type is atomic.
/// </summary>
/// <param name="expr">Expression.</param>
/// <returns>True if expression's type is atomic, False otherwise.</returns>
private bool isOfAtomicType(Expression expr)
{
DebugType typeOfValue = expr.Evaluate(debuggerService.DebuggedProcess).Type;
return !(typeOfValue.IsClass || typeOfValue.IsValueType);
//return (!typeOfValue.IsClass) || typeOfValue.IsString;
}
#region Expression helpers
private Value getPermanentReference(Expression expr)
{
return expr.Evaluate(debuggerService.DebuggedProcess).GetPermanentReference();
}
private bool isNull(Expression expr)
{
return expr.Evaluate(debuggerService.DebuggedProcess).IsNull;
}
private DebugType getType(Expression expr)
{
return expr.Evaluate(debuggerService.DebuggedProcess).Type;
}
private ulong getObjectAddress(Expression expr)
{
return expr.Evaluate(debuggerService.DebuggedProcess).GetObjectAddress();
}
#endregion
}
}

59
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphNode.cs

@ -0,0 +1,59 @@ @@ -0,0 +1,59 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
using Debugger.Expressions;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Node in the <see cref="ObjectGraph" />.
/// </summary>
public class ObjectGraphNode
{
/// <summary>
/// Permanent reference to the value in the the debugee this node represents.
/// </summary>
internal Debugger.Value PermanentReference { get; set; } // needed for graph building and matching, since hashCodes are not unique
/// <summary>
/// Hash code in the debuggee of the DebuggerValue this node represents.
/// </summary>
internal int HashCode { get; set; }
/// <summary>
/// Expression used to obtain this node.
/// </summary>
public Expressions.Expression Expression { get { return this.PermanentReference.Expression; } }
/// <summary>
/// Property tree of this node.
/// </summary>
public NestedNode Content
{
get; set;
}
// TODO just for ObjectGraphBuilder, remove
/// <summary>
/// Only complex properties filtered out of <see cref="Properties"/>
/// </summary>
public IEnumerable<ObjectGraphProperty> ComplexProperties
{
get
{
if (this.Content == null)
throw new InvalidOperationException("Cannot enumerate properties, Content is null");
foreach (var child in this.Content.Childs)
{
if (child is PropertyNode && !(((PropertyNode)child).Property.IsAtomic))
yield return ((PropertyNode)child).Property;
}
}
}
}
}

2
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectGraphProperty.cs

@ -18,6 +18,6 @@ namespace Debugger.AddIn.Visualizers.Graph @@ -18,6 +18,6 @@ namespace Debugger.AddIn.Visualizers.Graph
/// <summary>
/// Node that this property points to. Can be null. Always null if <see cref="IsAtomic"/> is true.
/// </summary>
public ObjectNode TargetNode { get; set; }
public ObjectGraphNode TargetNode { get; set; }
}
}

102
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectNode.cs

@ -1,102 +0,0 @@ @@ -1,102 +0,0 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
using Debugger.Expressions;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Node in the <see cref="ObjectGraph" />.
/// </summary>
public class ObjectNode
{
/// <summary>
/// Permanent reference to the value in the the debugee this node represents.
/// </summary>
internal Debugger.Value PermanentReference { get; set; } // needed for graph building and matching, since hashCodes are not unique
/// <summary>
/// Hash code in the debuggee of the DebuggerValue this node represents.
/// </summary>
internal int HashCode { get; set; }
/// <summary>
/// Expression used to obtain this node.
/// </summary>
public Expressions.Expression Expression { get { return this.PermanentReference.Expression; } }
class PropertyComparer : IComparer<ObjectGraphProperty>
{
public int Compare(ObjectGraphProperty prop1, ObjectGraphProperty prop2)
{
// order by IsAtomic, Name
int comparedAtomic = prop2.IsAtomic.CompareTo(prop1.IsAtomic);
if (comparedAtomic != 0)
{
return comparedAtomic;
}
else
{
return prop1.Name.CompareTo(prop2.Name);
}
}
}
private static PropertyComparer propertySortComparer = new PropertyComparer();
private bool sorted = false;
private List<ObjectGraphProperty> properties = new List<ObjectGraphProperty>();
/// <summary>
/// Properties (either atomic or complex) of the object this node represents.
/// </summary>
public List<ObjectGraphProperty> Properties
{
get
{
if (!sorted)
{
properties.Sort(propertySortComparer);
sorted = true;
}
return properties;
}
}
/// <summary>
/// Only complex properties filtered out of <see cref="Properties"/>
/// </summary>
public IEnumerable<ObjectGraphProperty> ComplexProperties
{
get
{
foreach (var property in Properties)
{
if (!property.IsAtomic)
yield return property;
}
}
}
/// <summary>
/// Adds primitive property.
/// </summary>
internal void AddAtomicProperty(string name, string value, Expression expression)
{
properties.Add(new ObjectGraphProperty
{ Name = name, Value = value, Expression = expression, IsAtomic = true, TargetNode = null });
}
/// <summary>
/// Adds complex property.
/// </summary>
internal void AddComplexProperty(string name, string value, Expression expression, ObjectNode targetNode, bool isNull)
{
properties.Add(new ObjectGraphProperty
{ Name = name, Value = value, Expression = expression, IsAtomic = false, TargetNode = targetNode, IsNull = isNull });
}
}
}

19
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/ObjectGraph/ObjectEdge.cs → src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/AbstractNode.cs

@ -5,15 +5,18 @@ @@ -5,15 +5,18 @@
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
using System.Text;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Named edge in the <see cref="ObjectGraph" />.
/// </summary>
/*public class ObjectEdge : NamedEdge<ObjectNode>
{
}*/
/// <summary>
/// Description of AbstractNode.
/// </summary>
public class AbstractNode
{
public AbstractNode()
{
}
}
}

44
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/NestedNode.cs

@ -0,0 +1,44 @@ @@ -0,0 +1,44 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
using System.Collections.Generic;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Description of NestedNode.
/// </summary>
public class NestedNode : AbstractNode
{
private List<AbstractNode> childs = new List<AbstractNode>();
private NestedNodeType nodeType;
public NestedNodeType NodeType
{
get { return nodeType; }
}
public IEnumerable<AbstractNode> Childs
{
get
{
foreach (var child in childs)
yield return child;
}
}
public void AddChild(AbstractNode child)
{
this.childs.Add(child);
}
public NestedNode(NestedNodeType nodeType)
{
this.nodeType = nodeType;
}
}
}

22
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/NestedNodeType.cs

@ -0,0 +1,22 @@ @@ -0,0 +1,22 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using System;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Description of NestedNodeType.
/// </summary>
public enum NestedNodeType
{
ThisNode,
BaseClassNode,
NonPublicInstanceMembersNode,
StaticMembersNode,
NonPublicStaticMembersNode
}
}

53
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Graph/TreeModel/PropertyNode.cs

@ -0,0 +1,53 @@ @@ -0,0 +1,53 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using ICSharpCode.SharpDevelop.Services;
using System;
namespace Debugger.AddIn.Visualizers.Graph
{
/// <summary>
/// Node containing ObjectGraphProperty, with lazy evaluation.
/// </summary>
public class PropertyNode : AbstractNode, IEvaluate
{
public PropertyNode(ObjectGraphProperty objectGraphProperty)
{
if (objectGraphProperty == null)
throw new ArgumentNullException("objectGraphProperty");
this.property = objectGraphProperty;
}
private ObjectGraphProperty property;
public ObjectGraphProperty Property
{
get { return this.property; }
}
#region IEvaluate members
bool evaluateCalled = false;
public bool IsEvaluated
{
get { return this.evaluateCalled; }
}
public void Evaluate()
{
if (this.Property.Expression == null)
{
throw new DebuggerVisualizerException("Cannot evaluate property with missing Expression");
}
this.Property.Value =
this.Property.Expression.Evaluate(WindowsDebugger.CurrentProcess).InvokeToString();
this.evaluateCalled = true;
}
#endregion
}
}

30
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Utils/AtomicType.cs

@ -0,0 +1,30 @@ @@ -0,0 +1,30 @@
// <file>
// <copyright see="prj:///doc/copyright.txt"/>
// <license see="prj:///doc/license.txt"/>
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using Debugger.MetaData;
using System;
using Debugger.Expressions;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.Utils
{
/// <summary>
/// Atomic type is a type that "cannot be expanded".
/// </summary>
public static class AtomicType
{
/// <summary>
/// Checks whether given expression's type is atomic.
/// </summary>
/// <param name="expr">Expression.</param>
/// <returns>True if expression's type is atomic, False otherwise.</returns>
public static bool IsOfAtomicType(this Expression expr)
{
DebugType typeOfValue = expr.Evaluate(WindowsDebugger.CurrentProcess).Type;
return !(typeOfValue.IsClass || typeOfValue.IsValueType /* = struct in C# */);
}
}
}

59
src/AddIns/Misc/Debugger/Debugger.AddIn/Project/Src/Visualizers/Utils/DebuggerHelpers.cs

@ -4,8 +4,11 @@ @@ -4,8 +4,11 @@
// <owner name="Martin Koníček" email="martin.konicek@gmail.com"/>
// <version>$Revision$</version>
// </file>
using Debugger.Expressions;
using System;
using Debugger.MetaData;
using Debugger.Wrappers.CorDebug;
using ICSharpCode.SharpDevelop.Services;
namespace Debugger.AddIn.Visualizers.Utils
{
@ -19,5 +22,61 @@ namespace Debugger.AddIn.Visualizers.Utils @@ -19,5 +22,61 @@ namespace Debugger.AddIn.Visualizers.Utils
ICorDebugReferenceValue refVal = val.CorValue.CastTo<ICorDebugReferenceValue>();
return refVal.Value;
}
/// <summary>
/// Evaluates expression and gets underlying address of object in the debuggee.
/// </summary>
public static ulong GetObjectAddress(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).GetObjectAddress();
}
/// <summary>
/// System.Runtime.CompilerServices.GetHashCode method, for obtaining non-overriden hash codes from debuggee.
/// </summary>
private static MethodInfo hashCodeMethod;
/// <summary>
/// Invokes RuntimeHelpers.GetHashCode on given value, that is a default hashCode ignoring user overrides.
/// </summary>
/// <param name="value">Valid value.</param>
/// <returns>Hash code of the object in the debugee.</returns>
public static int InvokeDefaultGetHashCode(this Value value)
{
if (DebuggerHelpers.hashCodeMethod == null)
{
DebugType typeRuntimeHelpers = DebugType.Create(WindowsDebugger.CurrentProcess, null, "System.Runtime.CompilerServices.RuntimeHelpers");
DebuggerHelpers.hashCodeMethod = typeRuntimeHelpers.GetMember("GetHashCode", BindingFlags.Public | BindingFlags.Static | BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo;
if (DebuggerHelpers.hashCodeMethod == null)
{
throw new DebuggerException("Cannot obtain method System.Runtime.CompilerServices.RuntimeHelpers.GetHashCode");
}
}
// David: I had hard time finding out how to invoke static method.
// value.InvokeMethod is nice for instance methods.
// what about MethodInfo.Invoke() ?
// also, there could be an overload that takes 1 parameter instead of array
string defaultHashCode = Eval.InvokeMethod(DebuggerHelpers.hashCodeMethod, null, new Value[]{value}).AsString;
//MethodInfo method = value.Type.GetMember("GetHashCode", BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo;
//string hashCode = value.InvokeMethod(method, null).AsString;
return int.Parse(defaultHashCode);
}
public static Value GetPermanentReference(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).GetPermanentReference();
}
public static bool IsNull(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).IsNull;
}
public static DebugType GetType(this Expression expr)
{
return expr.Evaluate(WindowsDebugger.CurrentProcess).Type;
}
}
}

Loading…
Cancel
Save