Browse Source

reimplement tooltips for simple expressions

newNRvisualizers
Siegfried Pammer 13 years ago
parent
commit
c9bea6a597
  1. 5
      src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj
  2. 143
      src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs
  3. 32
      src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs
  4. 5
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/DebuggerTooltipControl.xaml.cs
  5. 24
      src/AddIns/Debugger/Debugger.AddIn/Tooltips/VisualizerPicker.cs
  6. 14
      src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs

5
src/AddIns/Debugger/Debugger.AddIn/Debugger.AddIn.csproj

@ -144,6 +144,8 @@
<DependentUpon>EditBreakpointScriptWindow.xaml</DependentUpon> <DependentUpon>EditBreakpointScriptWindow.xaml</DependentUpon>
<SubType>Code</SubType> <SubType>Code</SubType>
</Compile> </Compile>
<Compile Include="Tooltips\DebuggerTooltipControl.xaml.cs" />
<Compile Include="Tooltips\VisualizerPicker.cs" />
<Compile Include="TreeModel\SharpTreeNodeAdapter.cs" /> <Compile Include="TreeModel\SharpTreeNodeAdapter.cs" />
<Compile Include="TreeModel\TreeNode.cs" /> <Compile Include="TreeModel\TreeNode.cs" />
<EmbeddedResource Include="Service\DebuggeeExceptionForm.resx"> <EmbeddedResource Include="Service\DebuggeeExceptionForm.resx">
@ -221,9 +223,12 @@
</ProjectReference> </ProjectReference>
</ItemGroup> </ItemGroup>
<ItemGroup> <ItemGroup>
<Folder Include="Tooltips" />
<Page Include="Options\DebuggingOptionsPanel.xaml" /> <Page Include="Options\DebuggingOptionsPanel.xaml" />
<Page Include="Pads\Common\CommonResources.xaml" /> <Page Include="Pads\Common\CommonResources.xaml" />
<Page Include="Service\EditBreakpointScriptWindow.xaml" /> <Page Include="Service\EditBreakpointScriptWindow.xaml" />
<Page Include="Tooltips\DebuggerTooltipControl.xaml" />
<Page Include="Tooltips\VisualizerPicker.xaml" />
<ProjectReference Include="..\..\..\Main\ICSharpCode.Core.WinForms\ICSharpCode.Core.WinForms.csproj"> <ProjectReference Include="..\..\..\Main\ICSharpCode.Core.WinForms\ICSharpCode.Core.WinForms.csproj">
<Project>{857CA1A3-FC88-4BE0-AB6A-D1EE772AB288}</Project> <Project>{857CA1A3-FC88-4BE0-AB6A-D1EE772AB288}</Project>
<Name>ICSharpCode.Core.WinForms</Name> <Name>ICSharpCode.Core.WinForms</Name>

143
src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs

@ -59,8 +59,11 @@ namespace Debugger.AddIn
StackFrame context; StackFrame context;
ICompilation debuggerTypeSystem; ICompilation debuggerTypeSystem;
Thread evalThread; Thread evalThread;
bool allowMethodInvoke;
bool allowSetValue;
public ExpressionEvaluationVisitor(StackFrame context, Thread evalThread, ICompilation debuggerTypeSystem) public ExpressionEvaluationVisitor(StackFrame context, Thread evalThread, ICompilation debuggerTypeSystem,
bool allowMethodInvoke = false, bool allowSetValue = false)
{ {
if (evalThread == null) if (evalThread == null)
throw new ArgumentNullException("evalThread"); throw new ArgumentNullException("evalThread");
@ -71,6 +74,8 @@ namespace Debugger.AddIn
this.context = context; this.context = context;
this.debuggerTypeSystem = debuggerTypeSystem; this.debuggerTypeSystem = debuggerTypeSystem;
this.evalThread = evalThread; this.evalThread = evalThread;
this.allowMethodInvoke = allowMethodInvoke;
this.allowSetValue = allowSetValue;
} }
public Value Convert(ResolveResult result) public Value Convert(ResolveResult result)
@ -121,6 +126,8 @@ namespace Debugger.AddIn
{ {
switch (result.OperatorType) { switch (result.OperatorType) {
case ExpressionType.Assign: case ExpressionType.Assign:
if (!allowSetValue)
throw new InvalidOperationException("Setting values is not allowed in the current context!");
Debug.Assert(result.Operands.Count == 2); Debug.Assert(result.Operands.Count == 2);
return VisitAssignment((dynamic)result.Operands[0], (dynamic)result.Operands[1]); return VisitAssignment((dynamic)result.Operands[0], (dynamic)result.Operands[1]);
case ExpressionType.Add: case ExpressionType.Add:
@ -300,7 +307,7 @@ namespace Debugger.AddIn
Value Visit(ArrayAccessResolveResult result) Value Visit(ArrayAccessResolveResult result)
{ {
var val = Convert(result.Array); var val = Convert(result.Array).GetPermanentReference(evalThread);
return val.GetArrayElement(result.Indexes.Select(rr => (int)Convert(rr).PrimitiveValue).ToArray()); return val.GetArrayElement(result.Indexes.Select(rr => (int)Convert(rr).PrimitiveValue).ToArray());
} }
@ -321,10 +328,9 @@ namespace Debugger.AddIn
return Eval.CreateValue(evalThread, convVal); return Eval.CreateValue(evalThread, convVal);
} else if (result.Conversion.IsUserDefined) } else if (result.Conversion.IsUserDefined)
return InvokeMethod(null, result.Conversion.Method, val); return InvokeMethod(null, result.Conversion.Method, val);
else if (result.Conversion.IsReferenceConversion && result.Conversion.IsImplicit) { else if (result.Conversion.IsReferenceConversion && result.Conversion.IsImplicit)
return val; return val;
} else throw new NotImplementedException();
throw new NotImplementedException();
} }
Value Visit(LocalResolveResult result) Value Visit(LocalResolveResult result)
@ -351,13 +357,15 @@ namespace Debugger.AddIn
throw new GetValueException("Indexer does not have a getter."); throw new GetValueException("Indexer does not have a getter.");
usedMethod = prop.Getter; usedMethod = prop.Getter;
} else if (importedMember is IMethod) { } else if (importedMember is IMethod) {
if (!allowMethodInvoke)
throw new InvalidOperationException("Method invocation not allowed in the current context!");
usedMethod = (IMethod)importedMember; usedMethod = (IMethod)importedMember;
} else } else
throw new GetValueException("Invoked member must be a method or property"); throw new GetValueException("Invoked member must be a method or property");
Value target = null; Value target = null;
if (!usedMethod.IsStatic) if (!usedMethod.IsStatic)
target = Convert(result.TargetResult); target = Convert(result.TargetResult).GetPermanentReference(evalThread);
return InvokeMethod(target, usedMethod, result.Arguments.Select(rr => Convert(rr)).ToArray()); return InvokeMethod(target, usedMethod, result.Arguments.Select(rr => Convert(rr).GetPermanentReference(evalThread)).ToArray());
} }
Value Visit(NamespaceResolveResult result) Value Visit(NamespaceResolveResult result)
@ -416,4 +424,125 @@ namespace Debugger.AddIn
} }
} }
public class ResolveResultPrettyPrinter
{
public ResolveResultPrettyPrinter()
{
}
public string Print(ResolveResult result)
{
if (result == null)
return "";
if (result.IsError)
return "{Error}";
return Visit((dynamic)result);
}
string Visit(ResolveResult result)
{
return "Not supported: " + result.GetType().Name;
}
// string Visit(ValueResolveResult result)
// {
// throw new NotImplementedException();
// }
string Visit(ThisResolveResult result)
{
return "this";
}
string Visit(MemberResolveResult result)
{
return Print(result.TargetResult) + "." + result.Member.Name;
}
string Visit(OperatorResolveResult result)
{
throw new NotImplementedException();
}
string Visit(TypeIsResolveResult result)
{
throw new NotImplementedException();
}
string Visit(TypeOfResolveResult result)
{
throw new NotImplementedException();
}
string Visit(TypeResolveResult result)
{
throw new NotImplementedException();
}
string Visit(UnknownMemberResolveResult result)
{
return result.MemberName;
}
string Visit(UnknownIdentifierResolveResult result)
{
return result.Identifier;
}
string Visit(ArrayAccessResolveResult result)
{
throw new NotImplementedException();
}
string Visit(ArrayCreateResolveResult result)
{
throw new NotImplementedException();
}
string Visit(ConversionResolveResult result)
{
throw new NotImplementedException();
}
string Visit(LocalResolveResult result)
{
if (result.IsParameter)
return result.Variable.Name;
return result.Variable.Name;
}
string Visit(AmbiguousMemberResolveResult result)
{
throw new NotImplementedException();
}
string Visit(InvocationResolveResult result)
{
StringBuilder sb = new StringBuilder();
sb.Append(Print(result.TargetResult));
sb.Append('.');
sb.Append(result.Member.Name);
sb.Append(result.Member is IProperty ? "[" : "(");
bool first = true;
foreach (var p in result.Member.Parameters) {
if (first) first = false;
else sb.Append(", ");
sb.Append(p.Name);
}
sb.Append(result.Member is IProperty ? "]" : ")");
return sb.ToString();
}
string Visit(NamespaceResolveResult result)
{
return "namespace " + result.NamespaceName;
}
}
} }

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

@ -13,6 +13,7 @@ using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using Debugger; using Debugger;
using Debugger.AddIn; using Debugger.AddIn;
using Debugger.AddIn.Tooltips;
using Debugger.AddIn.TreeModel; using Debugger.AddIn.TreeModel;
using Debugger.Interop.CorPublish; using Debugger.Interop.CorPublish;
using Debugger.MetaData; using Debugger.MetaData;
@ -20,6 +21,7 @@ using ICSharpCode.Core;
using ICSharpCode.Core.WinForms; using ICSharpCode.Core.WinForms;
using ICSharpCode.NRefactory; using ICSharpCode.NRefactory;
using ICSharpCode.NRefactory.CSharp; using ICSharpCode.NRefactory.CSharp;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.SharpDevelop.Bookmarks; using ICSharpCode.SharpDevelop.Bookmarks;
using ICSharpCode.SharpDevelop.Debugging; using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Editor; using ICSharpCode.SharpDevelop.Editor;
@ -613,11 +615,11 @@ namespace ICSharpCode.SharpDevelop.Services
WorkbenchSingleton.MainWindow.Activate(); WorkbenchSingleton.MainWindow.Activate();
// if (debuggedProcess.IsSelectedFrameForced()) { // if (debuggedProcess.IsSelectedFrameForced()) {
if (CurrentThread != null && CurrentStackFrame.HasSymbols) { if (CurrentThread != null && CurrentStackFrame.HasSymbols) {
JumpToSourceCode(); JumpToSourceCode();
} else { } else {
#warning JumpToDecompiledCode(CurrentStackFrame); #warning JumpToDecompiledCode(CurrentStackFrame);
} }
// } else { // } else {
// var frame = debuggedProcess.SelectedThread.MostRecentStackFrame; // var frame = debuggedProcess.SelectedThread.MostRecentStackFrame;
// // other pause reasons // // other pause reasons
@ -686,7 +688,7 @@ namespace ICSharpCode.SharpDevelop.Services
} }
} }
*/ */
StopAttachedProcessDialogResult ShowStopAttachedProcessDialog() StopAttachedProcessDialogResult ShowStopAttachedProcessDialog()
{ {
@ -708,7 +710,23 @@ namespace ICSharpCode.SharpDevelop.Services
public void HandleToolTipRequest(ToolTipRequestEventArgs e) public void HandleToolTipRequest(ToolTipRequestEventArgs e)
{ {
// throw new NotImplementedException(); if (e.ResolveResult == null)
return;
if (e.ResolveResult is LocalResolveResult || e.ResolveResult is MemberResolveResult || e.ResolveResult is InvocationResolveResult) {
Value result;
string text;
try {
ExpressionEvaluationVisitor eval = new ExpressionEvaluationVisitor(CurrentStackFrame, EvalThread, CurrentStackFrame.AppDomain.Compilation);
result = eval.Convert(e.ResolveResult);
text = new ResolveResultPrettyPrinter().Print(e.ResolveResult);
} catch (GetValueException ex) {
text = ex.Message;
result = null;
} catch (InvalidOperationException) {
return;
}
e.SetToolTip(new DebuggerTooltipControl(ValueNode.GetTooltipFor(text, result)));
}
} }
} }
} }

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

@ -36,6 +36,11 @@ namespace Debugger.AddIn.Tooltips
this.Placement = PlacementMode.Absolute; this.Placement = PlacementMode.Absolute;
} }
public DebuggerTooltipControl(params TreeNode[] treeNodes)
: this((IEnumerable<TreeNode>)treeNodes)
{
}
private void Expand_Click(object sender, RoutedEventArgs e) private void Expand_Click(object sender, RoutedEventArgs e)
{ {
var clickedButton = (ToggleButton)e.OriginalSource; var clickedButton = (ToggleButton)e.OriginalSource;

24
src/AddIns/Debugger/Debugger.AddIn/Tooltips/VisualizerPicker.cs

@ -26,23 +26,23 @@ namespace Debugger.AddIn.Tooltips
if (this.SelectedItem == null) { if (this.SelectedItem == null) {
return; return;
} }
var clickedCommand = this.SelectedItem as IVisualizerCommand; // var clickedCommand = this.SelectedItem as IVisualizerCommand;
if (clickedCommand == null) { // if (clickedCommand == null) {
throw new InvalidOperationException( // throw new InvalidOperationException(
string.Format("{0} clicked, only instances of {1} must be present in {2}.", // string.Format("{0} clicked, only instances of {1} must be present in {2}.",
this.SelectedItem.GetType().ToString(), typeof(IVisualizerCommand).Name, typeof(VisualizerPicker).Name)); // this.SelectedItem.GetType().ToString(), typeof(IVisualizerCommand).Name, typeof(VisualizerPicker).Name));
} // }
clickedCommand.Execute(); // clickedCommand.Execute();
// Make no item selected, so that multiple selections of the same item always execute the command. // Make no item selected, so that multiple selections of the same item always execute the command.
// This triggers VisualizerPicker_SelectionChanged again, which returns immediately. // This triggers VisualizerPicker_SelectionChanged again, which returns immediately.
this.SelectedIndex = -1; this.SelectedIndex = -1;
} }
public new IEnumerable<IVisualizerCommand> ItemsSource // public new IEnumerable<IVisualizerCommand> ItemsSource
{ // {
get { return (IEnumerable<IVisualizerCommand>)base.ItemsSource; } // get { return (IEnumerable<IVisualizerCommand>)base.ItemsSource; }
set { base.ItemsSource = value; } // set { base.ItemsSource = value; }
} // }
} }
} }

14
src/AddIns/Debugger/Debugger.AddIn/TreeModel/ValueNode.cs

@ -14,6 +14,7 @@ using System.Text;
using System.Windows.Forms; using System.Windows.Forms;
using Debugger.MetaData; using Debugger.MetaData;
using ICSharpCode.Core; using ICSharpCode.Core;
using ICSharpCode.NRefactory.Semantics;
using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.TypeSystem;
using ICSharpCode.SharpDevelop.Debugging; using ICSharpCode.SharpDevelop.Debugging;
using ICSharpCode.SharpDevelop.Gui.Pads; using ICSharpCode.SharpDevelop.Gui.Pads;
@ -169,20 +170,20 @@ namespace Debugger.AddIn.TreeModel
this.Type = val.Type.Name; this.Type = val.Type.Name;
if (!val.IsNull) { if (!val.IsNull) {
#warning this.VisualizerCommands = VisualizerDescriptors.GetAllDescriptors() #warning this.VisualizerCommands = VisualizerDescriptors.GetAllDescriptors()
// .Where(descriptor => descriptor.IsVisualizerAvailable(val.Type)) // .Where(descriptor => descriptor.IsVisualizerAvailable(val.Type))
// .Select(descriptor => descriptor.CreateVisualizerCommand(this.Name, this.GetValue)) // .Select(descriptor => descriptor.CreateVisualizerCommand(this.Name, this.GetValue))
// .ToList(); // .ToList();
} }
LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms", this.Name, watch.ElapsedMilliseconds); LoggingService.InfoFormatted("Evaluated node '{0}' in {1} ms", this.Name, watch.ElapsedMilliseconds);
} catch (GetValueException e) { } catch (GetValueException e) {
error = e; error = e;
this.Value = e.Message; this.Value = e.Message;
this.Type = string.Empty; this.Type = string.Empty;
this.GetChildren = null; this.GetChildren = null;
#warning this.VisualizerCommands = null; #warning this.VisualizerCommands = null;
return; return;
} }
} }
@ -276,6 +277,11 @@ namespace Debugger.AddIn.TreeModel
return WindowsDebugger.CurrentStackFrame; return WindowsDebugger.CurrentStackFrame;
} }
public static TreeNode GetTooltipFor(string text, Value value)
{
return new ValueNode("Icons.16x16.Local", text, () => value);
}
public static IEnumerable<TreeNode> GetLocalVariables() public static IEnumerable<TreeNode> GetLocalVariables()
{ {
var stackFrame = GetCurrentStackFrame(); var stackFrame = GetCurrentStackFrame();
@ -306,7 +312,7 @@ namespace Debugger.AddIn.TreeModel
}); });
} }
} }
*/ */
} }
} }

Loading…
Cancel
Save