diff --git a/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs index 40db94eda9..30ea878d5c 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/NRefactory/ExpressionEvaluationVisitor.cs @@ -29,6 +29,7 @@ using ICSharpCode.NRefactory.CSharp.Resolver; using ICSharpCode.NRefactory.Semantics; using ICSharpCode.NRefactory.TypeSystem; using ICSharpCode.NRefactory.Utils; +using ICSharpCode.SharpDevelop; using ICSharpCode.SharpDevelop.Services; namespace Debugger.AddIn @@ -239,7 +240,7 @@ namespace Debugger.AddIn var val = resolver.ResolveUnaryOperator(operatorType, operand); if (val.IsCompileTimeConstant) return Convert(val); - throw new InvalidOperationException(); + throw new GetValueException("Operator {0} is not supported for {1}!", operatorType, new CSharpAmbience().ConvertType(operand.Type)); } Value VisitBinaryOperator(OperatorResolveResult result, BinaryOperatorType operatorType, bool checkForOverflow = false) @@ -256,14 +257,41 @@ namespace Debugger.AddIn var val = resolver.ResolveBinaryOperator(operatorType, lhsRR, rhsRR); if (val.IsCompileTimeConstant) return Convert(val); - if (operatorType == BinaryOperatorType.Add && - (lhsRR.Type.IsKnownType(KnownTypeCode.String) || rhsRR.Type.IsKnownType(KnownTypeCode.String))) { - var method = debuggerTypeSystem.FindType(KnownTypeCode.String) - .GetMethods(m => m.Name == "Concat" && m.Parameters.Count == 2) - .Single(m => m.Parameters.All(p => p.Type.IsKnownType(KnownTypeCode.Object))); - return InvokeMethod(null, method, lhs, rhs); + switch (operatorType) { + case BinaryOperatorType.Equality: + case BinaryOperatorType.InEquality: + bool equality = (operatorType == BinaryOperatorType.Equality); + if (lhsRR.Type.IsKnownType(KnownTypeCode.String) && rhsRR.Type.IsKnownType(KnownTypeCode.String)) { + if (lhs.IsNull || rhs.IsNull) { + bool bothNull = lhs.IsNull && rhs.IsNull; + return Eval.CreateValue(evalThread, equality ? bothNull : !bothNull); + } else { + bool equal = (string)lhs.PrimitiveValue == (string)rhs.PrimitiveValue; + return Eval.CreateValue(evalThread, equality ? equal : !equal); + } + } + if (lhsRR.Type.IsReferenceType != false && rhsRR.Type.IsReferenceType != false) { + // Reference comparison + if (lhs.IsNull || rhs.IsNull) { + bool bothNull = lhs.IsNull && rhs.IsNull; + return Eval.CreateValue(evalThread, equality ? bothNull : !bothNull); + } else { + bool equal = lhs.Address == rhs.Address; + return Eval.CreateValue(evalThread, equality ? equal : !equal); + } + } + goto default; + case BinaryOperatorType.Add: + if (lhsRR.Type.IsKnownType(KnownTypeCode.String) || rhsRR.Type.IsKnownType(KnownTypeCode.String)) { + var method = debuggerTypeSystem.FindType(KnownTypeCode.String) + .GetMethods(m => m.Name == "Concat" && m.Parameters.Count == 2) + .Single(m => m.Parameters.All(p => p.Type.IsKnownType(KnownTypeCode.Object))); + return InvokeMethod(null, method, lhs, rhs); + } + goto default; + default: + throw new GetValueException("Operator {0} is not supported for {1} and {2}!", operatorType, new CSharpAmbience().ConvertType(lhsRR.Type), new CSharpAmbience().ConvertType(rhsRR.Type)); } - throw new InvalidOperationException(); } Value VisitConditionalOperator(OperatorResolveResult result, BinaryOperatorType bitwiseOperatorType) @@ -357,7 +385,7 @@ namespace Debugger.AddIn return val; if (result.Conversion.IsNullLiteralConversion) return val; - throw new NotImplementedException(string.Format("conversion '{0}' not implemented!", result.Conversion)); + throw new GetValueException("conversion '{0}' not implemented!", result.Conversion); } Value Visit(LocalResolveResult result) @@ -455,12 +483,21 @@ namespace Debugger.AddIn public class ResolveResultPrettyPrinter { - public ResolveResultPrettyPrinter() + ResolveResultPrettyPrinter() { - } - public string Print(ResolveResult result) + public static string Print(ResolveResult result) + { + try { + return new ResolveResultPrettyPrinter().PrintInternal(result); + } catch (NotImplementedException ex) { + SD.Log.Warn(ex); + return ""; + } + } + + string PrintInternal(ResolveResult result) { if (result == null) return ""; @@ -486,7 +523,7 @@ namespace Debugger.AddIn string Visit(MemberResolveResult result) { - string text = Print(result.TargetResult); + string text = PrintInternal(result.TargetResult); if (!string.IsNullOrWhiteSpace(text)) text += "."; return text + result.Member.Name; @@ -553,7 +590,7 @@ namespace Debugger.AddIn { StringBuilder sb = new StringBuilder(); - sb.Append(Print(result.TargetResult)); + sb.Append(PrintInternal(result.TargetResult)); sb.Append('.'); sb.Append(result.Member.Name); diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs index 41b39d6533..1510a5efc7 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/AutoCompleteTextBox.cs @@ -20,6 +20,7 @@ using System; using System.Text; using System.Windows; using System.Windows.Controls; +using System.Windows.Controls.Primitives; using System.Windows.Input; using System.Windows.Media; using System.Windows.Threading; @@ -102,6 +103,7 @@ namespace Debugger.AddIn.Pads.Controls this.editor.TextArea.TextEntered += editor_TextArea_TextEntered; this.Content = this.editor.TextArea; + this.messageView = new ToolTip { PlacementTarget = this, Placement = PlacementMode.Bottom, StaysOpen = true }; HorizontalContentAlignment = HorizontalAlignment.Stretch; VerticalContentAlignment = VerticalAlignment.Stretch; @@ -119,22 +121,38 @@ namespace Debugger.AddIn.Pads.Controls } } + ToolTip messageView; + void editor_TextArea_TextEntered(object sender, TextCompositionEventArgs e) { - if (e.Text != ".") return; - DebuggerCompletionContext context = null; - StackFrame frame = WindowsDebugger.CurrentStackFrame; - if (frame == null) { - if (DebugContext != null) { - context = DebugContext; + if (e.Text == ".") { + DebuggerCompletionContext context = null; + StackFrame frame = WindowsDebugger.CurrentStackFrame; + if (frame == null) { + if (DebugContext != null) { + context = DebugContext; + } + } else { + context = new DebuggerCompletionContext(frame); } + if (context == null) return; + var binding = DebuggerDotCompletion.PrepareDotCompletion(editor.Text.Substring(0, editor.CaretOffset), context); + if (binding == null) return; + binding.HandleKeyPressed(editorAdapter, '.'); } else { - context = new DebuggerCompletionContext(frame); + // TODO : implement automated error checking CSharpParser.ParseExpression does not report useful error messages. +// Error[] errors; +// if (!DebuggerDotCompletion.CheckSyntax(Text, out errors)) { +// StringBuilder output = new StringBuilder(); +// foreach (var error in errors) { +// output.AppendLine(error.Message + " at " + error.Region.Begin); +// } +// messageView.Content = output.ToString(); +// messageView.IsOpen = true; +// } else { +// messageView.IsOpen = false; +// } } - if (context == null) return; - var binding = DebuggerDotCompletion.PrepareDotCompletion(editor.Text.Substring(0, editor.CaretOffset), context); - if (binding == null) return; - binding.HandleKeyPressed(editorAdapter, '.'); } public void FocusEditor() diff --git a/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs b/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs index 9ab75a4063..7ef10201d3 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Pads/DebuggerDotCompletion.cs @@ -33,11 +33,12 @@ namespace Debugger.AddIn.Pads.Controls { static class DebuggerDotCompletion { - public static bool CheckSyntax(string expression) + public static bool CheckSyntax(string expression, out Error[] errors) { var p = new CSharpParser(); p.ParseExpression(expression); - return !p.Errors.Any(); + errors = p.Errors.ToArray(); + return !errors.Any(); } public static ICodeCompletionBinding PrepareDotCompletion(string expressionToComplete, DebuggerCompletionContext context) diff --git a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs index 0e486fe9f6..a9df381344 100644 --- a/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs +++ b/src/AddIns/Debugger/Debugger.AddIn/Service/WindowsDebugger.cs @@ -629,12 +629,7 @@ namespace ICSharpCode.SharpDevelop.Services if (resolveResult == null) return; if (resolveResult is LocalResolveResult || resolveResult is MemberResolveResult) { - string text = string.Empty; - try { - text = new ResolveResultPrettyPrinter().Print(resolveResult); - } catch (NotImplementedException ex) { - SD.Log.Warn(ex); - } + string text = ResolveResultPrettyPrinter.Print(resolveResult); Func getValue = delegate { ExpressionEvaluationVisitor eval = new ExpressionEvaluationVisitor(CurrentStackFrame, EvalThread, CurrentStackFrame.AppDomain.Compilation); return eval.Convert(resolveResult);