From dccf197fb0314e709623446e492f8852902c87fc Mon Sep 17 00:00:00 2001 From: mkonicek Date: Wed, 8 Dec 2010 16:15:10 +0100 Subject: [PATCH] Editor context actions - Fix: "Check for (not) null" is only offered if the type of the assigned expression is reference type. Now the actions is offered pretty much only in the situations where it makes sense. --- .../ContextActions/CheckAssignmentCache.cs | 16 ++++++++++++--- .../Src/ContextActions/CheckMemberNotNull.cs | 20 +++++++++---------- .../ContextActions/EditorContext.cs | 17 +++++++++++++--- 3 files changed, 37 insertions(+), 16 deletions(-) diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckAssignmentCache.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckAssignmentCache.cs index 66b7deafc0..4bc1618be7 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckAssignmentCache.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckAssignmentCache.cs @@ -17,16 +17,19 @@ namespace SharpRefactoring.ContextActions { public void Initialize(EditorContext context) { + this.context = context; this.VariableName = GetVariableName(context); this.CodeGenerator = GetCodeGenerator(context); this.Element = GetElement(context); this.ElementRegion = (Element == null) ? DomRegion.Empty : DomRegion.FromLocation(Element.StartLocation, Element.EndLocation); } + EditorContext context; + public bool IsActionAvailable { get { - return !string.IsNullOrEmpty(this.VariableName) && (this.CodeGenerator != null); + return !string.IsNullOrEmpty(this.VariableName) && (this.CodeGenerator != null) && (this.context.CurrentLine.Text.Contains(";")); } } @@ -76,7 +79,7 @@ namespace SharpRefactoring.ContextActions var identifier = assignment.Left as IdentifierExpression; if (identifier == null) return null; - if (!ExpressionCanBeNull(assignment.Right)) + if ((!ExpressionCanBeNull(assignment.Right)) || ExpressionIsValueType(assignment.Right)) // don't offer action where it makes no sense return null; return identifier.Identifier; @@ -89,12 +92,19 @@ namespace SharpRefactoring.ContextActions if (declaration.Variables.Count != 1) return null; VariableDeclaration varDecl = declaration.Variables[0]; - if (!ExpressionCanBeNull(varDecl.Initializer)) + if (!ExpressionCanBeNull(varDecl.Initializer) || ExpressionIsValueType(varDecl.Initializer)) // don't offer action where it makes no sense return null; return varDecl.Name; } + bool ExpressionIsValueType(Expression expr) + { + ResolveResult rr = this.context.ResolveExpression(expr); + if (rr == null) return false; // when cannot resolve the assignment right, still offer the action + return (rr.ResolvedType != null && rr.ResolvedType.IsReferenceType == false); + } + bool ExpressionCanBeNull(Expression expr) { if (expr == null) return false; diff --git a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckMemberNotNull.cs b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckMemberNotNull.cs index 7143353d93..a14d2d0014 100644 --- a/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckMemberNotNull.cs +++ b/src/AddIns/Misc/SharpRefactoring/Project/Src/ContextActions/CheckMemberNotNull.cs @@ -46,6 +46,16 @@ namespace SharpRefactoring.ContextActions //this.targetExpr is IdentifierExpression; // "don't offer the action for just a.b, only for a.b.c" } + public override void Execute(EditorContext context) + { + var conditionExpr = BuildCondition(this.targetExpr); + if (conditionExpr == null) + return; + var ifExpr = new IfElseStatement(conditionExpr, new BlockStatement()); + + context.Editor.InsertCodeBefore(this.currentExpr, ifExpr); + } + /// /// Gets "a.b" from "a.b.c" /// @@ -57,16 +67,6 @@ namespace SharpRefactoring.ContextActions return null; } - public override void Execute(EditorContext context) - { - var conditionExpr = BuildCondition(this.targetExpr); - if (conditionExpr == null) - return; - var ifExpr = new IfElseStatement(conditionExpr, new BlockStatement()); - - context.Editor.InsertCodeBefore(this.currentExpr, ifExpr); - } - /// /// Turns "(a.b as T).d.e" into "(a != null) && (a.b is T) && ((a.b as T).d != null)" /// diff --git a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs index e5287d8a87..639d676b99 100644 --- a/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs +++ b/src/Main/Base/Project/Src/Services/RefactoringService/ContextActions/EditorContext.cs @@ -104,6 +104,12 @@ namespace ICSharpCode.SharpDevelop.Refactoring // DebugLog(); } + public ResolveResult ResolveExpression(Expression expression) + { + ExpressionResult expr = GetExpressionAt(this.Editor, expression.EndLocation.Line, expression.EndLocation.Column); + return ResolveExpression(expr, this.Editor, expression.EndLocation.Line, expression.EndLocation.Column); + } + /// /// Do not call from your Context actions - used by SharpDevelop. /// Sets contents of editor context to null to prevent memory leaks. Used in case users implementing IContextActionProvider @@ -236,10 +242,15 @@ namespace ICSharpCode.SharpDevelop.Refactoring ExpressionResult GetExpressionAtCaret(ITextEditor editor) { - ExpressionResult expr = ParserService.FindFullExpression(CaretLine, CaretColumn, editor.Document, editor.FileName); + return GetExpressionAt(editor, this.CaretLine, this.CaretColumn); + } + + ExpressionResult GetExpressionAt(ITextEditor editor, int caretLine, int caretColumn) + { + ExpressionResult expr = ParserService.FindFullExpression(caretLine, caretColumn, editor.Document, editor.FileName); // if no expression, look one character back (works better with method calls - Foo()(*caret*)) - if (string.IsNullOrWhiteSpace(expr.Expression) && CaretColumn > 1) - expr = ParserService.FindFullExpression(CaretLine, CaretColumn - 1, editor.Document, editor.FileName); + if (string.IsNullOrWhiteSpace(expr.Expression) && caretColumn > 1) + expr = ParserService.FindFullExpression(caretLine, caretColumn - 1, editor.Document, editor.FileName); return expr; }