diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index b24c6f8690..a68aabeea4 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -710,18 +710,23 @@ namespace ICSharpCode.SharpDevelop.Services { if (!(IsDebugging && CurrentProcess.IsPaused)) return; - if (e.ResolveResult == null) + var resolveResult = e.ResolveResult; + if (resolveResult == null) return; - if (e.ResolveResult is LocalResolveResult || e.ResolveResult is MemberResolveResult || e.ResolveResult is InvocationResolveResult) { + if (resolveResult is LocalResolveResult || resolveResult is MemberResolveResult || resolveResult is InvocationResolveResult) { + string text = string.Empty; try { + text = new ResolveResultPrettyPrinter().Print(resolveResult); + } catch (NotImplementedException) { + } + Func getValue = delegate { ExpressionEvaluationVisitor eval = new ExpressionEvaluationVisitor(CurrentStackFrame, EvalThread, CurrentStackFrame.AppDomain.Compilation); - Value result = eval.Convert(e.ResolveResult); - string text = new ResolveResultPrettyPrinter().Print(e.ResolveResult); - e.SetToolTip(new DebuggerTooltipControl(ValueNode.GetTooltipFor(text, result))); - } catch (GetValueException ex) { - e.SetToolTip(ex.Message); + return eval.Convert(resolveResult); + }; + try { + var rootNode = new ValueNode(ClassBrowserIconService.LocalVariable, text, getValue); + e.SetToolTip(new DebuggerTooltipControl(rootNode)); } catch (InvalidOperationException) { - return; } } } diff --git a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs index fa07d1704b..f2702d97c3 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs @@ -72,7 +72,7 @@ namespace Debugger.AddIn.TreeModel cachedValue = this.getValue().GetPermanentReference(WindowsDebugger.EvalThread); cachedValueProcess = cachedValue.Process; cachedValueDebuggeeState = cachedValue.Process.DebuggeeState; - LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms (result cached for future use)", this.Name, watch.ElapsedMilliseconds); + LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms (result cached)", this.Name, watch.ElapsedMilliseconds); } return cachedValue; } @@ -92,9 +92,8 @@ namespace Debugger.AddIn.TreeModel } } - /// - /// Get the value of the node and update the UI text fields. - /// + /// Get the value of the node and update the UI text fields. + /// This should be only called once so the Value is not cached. void GetValueAndUpdateUI() { try { @@ -175,7 +174,6 @@ namespace Debugger.AddIn.TreeModel this.Type = string.Empty; this.GetChildren = null; #warning this.VisualizerCommands = null; - return; } } @@ -242,13 +240,6 @@ namespace Debugger.AddIn.TreeModel return WindowsDebugger.CurrentStackFrame; } - public static TreeNode GetTooltipFor(string text, Value value) - { - if (value == null) - throw new ArgumentNullException("value"); - return new ValueNode(ClassBrowserIconService.LocalVariable, text, () => value); - } - public static IEnumerable GetLocalVariables() { var stackFrame = GetCurrentStackFrame(); @@ -361,15 +352,13 @@ namespace Debugger.AddIn.TreeModel } } + /// 'getValue' really should return cached value, because we do Eval to create indices. static IEnumerable GetIListChildren(Func getValue) { - Value list; IProperty itemProp; int count = 0; try { - // TODO: We want new list on reeval - // We need the list to survive generation of index via Eval - list = getValue().GetPermanentReference(WindowsDebugger.EvalThread); + Value list = getValue(); IType iListType = list.Type.GetAllBaseTypeDefinitions().Where(t => t.FullName == typeof(IList).FullName).FirstOrDefault(); itemProp = iListType.GetProperties(p => p.Name == "Item").Single(); // Do not get string representation since it can be printed in hex @@ -380,7 +369,7 @@ namespace Debugger.AddIn.TreeModel if (count == 0) { return new [] { new TreeNode("(empty)", null) }; } else { - return Enumerable.Range(0, count).Select(i => new ValueNode(ClassBrowserIconService.Field, "[" + i + "]", () => list.GetPropertyValue(WindowsDebugger.EvalThread, itemProp, Eval.CreateValue(WindowsDebugger.EvalThread, i)))); + return Enumerable.Range(0, count).Select(i => new ValueNode(ClassBrowserIconService.Field, "[" + i + "]", () => getValue().GetPropertyValue(WindowsDebugger.EvalThread, itemProp, Eval.CreateValue(WindowsDebugger.EvalThread, i)))); } } diff --git a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs index 4e361195e1..4ac7787046 100644 --- a/src/AddIns/Debugger/Debugger.Core/StackFrame.cs +++ b/src/AddIns/Debugger/Debugger.Core/StackFrame.cs @@ -371,7 +371,9 @@ namespace Debugger public Value GetLocalVariableValue(string name) { var loc = GetLocalVariables(this.IP).Where(v => v.Name == name).FirstOrDefault(); - return loc != null ? loc.GetValue(this) : null; + if (loc == null) + throw new GetValueException("Local variable \"{0}\" not found", name); + return loc.GetValue(this); } /// Gets value indicating whether this method should be stepped over according to current options