diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs index edf0a95862..667323c4c2 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Graph/ObjectGraph/ObjectGraphBuilder.cs @@ -4,13 +4,13 @@ using System; using System.Collections.Generic; using System.Reflection; - using Debugger.AddIn.Visualizers.Common; using Debugger.AddIn.Visualizers.Utils; using Debugger.MetaData; using ICSharpCode.NRefactory; using ICSharpCode.NRefactory.Ast; using ICSharpCode.NRefactory.Visitors; +using ICSharpCode.SharpDevelop.Dom; using ICSharpCode.SharpDevelop.Services; namespace Debugger.AddIn.Visualizers.Graph @@ -150,7 +150,7 @@ namespace Debugger.AddIn.Visualizers.Graph DebugType listItemType; if (thisNode.PermanentReference.Type.ResolveIListImplementation(out iListType, out listItemType)) { - // it is a collection + // it is an IList loadNodeCollectionContent(contentRoot, thisNode.Expression, iListType); } else @@ -236,7 +236,7 @@ namespace Debugger.AddIn.Visualizers.Graph } // ObjectGraphProperty needs an expression - // to use expanded / nonexpanded (and to evaluate?) + // to know whether it is expanded, and to evaluate Expression propExpression = expression.AppendMemberReference((IDebugMemberInfo)memberProp); // Value, IsAtomic are lazy evaluated propertyList.Add(new ObjectGraphProperty @@ -259,13 +259,12 @@ namespace Debugger.AddIn.Visualizers.Graph foreach(ObjectGraphProperty complexProperty in thisNode.Properties) { 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 && we dont know yet if it's null */expandedNodes.IsExpanded(complexProperty.Expression)) + // We are only evaluating expanded nodes here. + // We have to do this to know the "shape" of the graph. + // We do not evaluate atomic and non-expanded properties, those will be lazy evaluated when drawn. + if (expandedNodes.IsExpanded(complexProperty.Expression)) { // if expanded, evaluate this property - // complexProperty.Evaluate(); // consider Value memberValue = complexProperty.Expression.Evaluate(this.debuggerService.DebuggedProcess); if (memberValue.IsNull) { @@ -302,8 +301,12 @@ namespace Debugger.AddIn.Visualizers.Graph /// New empty object node representing the value. private ObjectGraphNode createNewNode(Value permanentReference, Expression expression) { + if (permanentReference == null) throw new ArgumentNullException("permanentReference"); + ObjectGraphNode newNode = new ObjectGraphNode(); - newNode.TypeName = permanentReference.Type.Name; + if (permanentReference.Type != null) { + newNode.TypeName = permanentReference.Type.FormatNameCSharp(); + } newNode.HashCode = permanentReference.InvokeDefaultGetHashCode(); resultGraph.AddNode(newNode); @@ -366,7 +369,6 @@ namespace Debugger.AddIn.Visualizers.Graph DebugType typeOfValue = expr.Evaluate(debuggerService.DebuggedProcess).Type; if (typeOfValue.IsArray) { - // arrays will be supported of course in the final version throw new DebuggerVisualizerException("Arrays are not supported yet"); } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs index 165f739a48..148d63802a 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Visualizers/Utils/DebuggerHelpers.cs @@ -1,6 +1,7 @@ // 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.Linq; using Debugger.Interop.CorDebug; using System; using System.Collections.Generic; @@ -8,6 +9,7 @@ using System.Reflection; using Debugger; using Debugger.MetaData; using ICSharpCode.NRefactory.Ast; +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Services; namespace Debugger.AddIn.Visualizers.Utils @@ -84,10 +86,6 @@ namespace Debugger.AddIn.Visualizers.Utils 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 Value defaultHashCode = Eval.InvokeMethod(DebuggerHelpers.hashCodeMethod, null, new Value[]{value}); //MethodInfo method = value.Type.GetMember("GetHashCode", BindingFlags.Method | BindingFlags.IncludeSuperType) as MethodInfo; @@ -95,6 +93,19 @@ namespace Debugger.AddIn.Visualizers.Utils return (int)defaultHashCode.PrimitiveValue; } + /// + /// Formats System.Type to the C# format, that is generic parameters in angle brackets. + /// + public static string FormatNameCSharp(this Type type) + { + string typeName = type.Name.CutoffEnd("`"); // get rid of the `n in generic type names + if (type.IsGenericType) { + return typeName + "<" + string.Join(", ", type.GetGenericArguments().Select(a => FormatNameCSharp(a))) + ">"; + } else { + return typeName; + } + } + public static Value EvalPermanentReference(this Expression expr) { return expr.Evaluate(WindowsDebugger.CurrentProcess).GetPermanentReference(); diff --git a/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs b/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs index d1d1964238..7355567520 100644 --- a/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs +++ b/src/Main/Base/Project/Src/Editor/CodeCompletion/CodeCompletionItemProvider.cs @@ -284,7 +284,7 @@ namespace ICSharpCode.SharpDevelop.Editor.CodeCompletion } // Special case for Attributes if (insertedText.EndsWith("Attribute") && IsInAttributeContext(editor, context.StartOffset)) { - insertedText = insertedText.RemoveEnd("Attribute"); + insertedText = insertedText.RemoveFromEnd("Attribute"); } } else if (this.Entity is IMethod) { addUsing = !IsKnownName(nameResult); diff --git a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/AbstractProjectBrowserTreeNode.cs b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/AbstractProjectBrowserTreeNode.cs index 75ab003073..979319eaac 100644 --- a/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/AbstractProjectBrowserTreeNode.cs +++ b/src/Main/Base/Project/Src/Gui/Pads/ProjectBrowser/TreeNodes/AbstractProjectBrowserTreeNode.cs @@ -178,7 +178,7 @@ namespace ICSharpCode.SharpDevelop.Project return this; } - string currentPath = relativePath.Trim('/', '\\').RemoveStart(targets[0]).Trim('/', '\\'); + string currentPath = relativePath.Trim('/', '\\').RemoveFromStart(targets[0]).Trim('/', '\\'); //LoggingService.Debug("entering depth loop..."); //LoggingService.DebugFormatted(@"\- looking for '{0}'", relativePath); //LoggingService.DebugFormatted(@"\- starting at '{0}'", targetNode != null ? targetNode.Text : "null"); diff --git a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs index ef7ec8814a..1726e6efee 100644 --- a/src/Main/Base/Project/Src/Util/ExtensionMethods.cs +++ b/src/Main/Base/Project/Src/Util/ExtensionMethods.cs @@ -325,7 +325,7 @@ namespace ICSharpCode.SharpDevelop /// Removes from the start of this string. /// Throws ArgumentException if this string does not start with . /// - public static string RemoveStart(this string s, string stringToRemove) + public static string RemoveFromStart(this string s, string stringToRemove) { if (s == null) return null; @@ -337,13 +337,12 @@ namespace ICSharpCode.SharpDevelop } /// - /// Removes from the end of this string. - /// Throws ArgumentException if this string does not end with . + /// Removes from the end of this string. + /// Throws ArgumentException if this string does not end with . /// - public static string RemoveEnd(this string s, string stringToRemove) + public static string RemoveFromEnd(this string s, string stringToRemove) { - if (s == null) - return null; + if (s == null) return null; if (string.IsNullOrEmpty(stringToRemove)) return s; if (!s.EndsWith(stringToRemove)) @@ -351,6 +350,21 @@ namespace ICSharpCode.SharpDevelop return s.Substring(0, s.Length - stringToRemove.Length); } + /// + /// Trims the string from the first occurence of to the end, including . + /// If the string does not contain , just returns the original string. + /// + public static string CutoffEnd(this string s, string cutoffStart) + { + if (s == null) return null; + int pos = s.IndexOf(cutoffStart); + if (pos != -1) { + return s.Substring(0, pos); + } else { + return s; + } + } + /// /// Takes at most first characters from string. /// String can be null.