From 925fb725331d482cb7cc56b6508929b248ff8963 Mon Sep 17 00:00:00 2001 From: peter Date: Tue, 15 Nov 2011 16:14:24 +0100 Subject: [PATCH] [Niels Harremoes @ hackergarten] invert if condition in groovy --- .../InvertIfIntention/after.groovy.template | 1 + .../InvertIfIntention/before.groovy.template | 2 + .../InvertIfIntention/description.html | 10 ++ plugins/groovy/src/META-INF/plugin.xml | 5 + .../GroovyIntentionsBundle.properties | 2 + .../intentions/control/InvertIfIntention.java | 100 +++++++++++++++ .../groovy/intentions/InvertIfTest.groovy | 115 ++++++++++++++++++ 7 files changed, 235 insertions(+) create mode 100644 plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/after.groovy.template create mode 100644 plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/before.groovy.template create mode 100644 plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/description.html create mode 100644 plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/InvertIfIntention.java create mode 100644 plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/InvertIfTest.groovy diff --git a/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/after.groovy.template b/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/after.groovy.template new file mode 100644 index 000000000000..19869450ea5d --- /dev/null +++ b/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/after.groovy.template @@ -0,0 +1 @@ +if (a) b = false \ No newline at end of file diff --git a/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/before.groovy.template b/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/before.groovy.template new file mode 100644 index 000000000000..1ef4948fc7da --- /dev/null +++ b/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/before.groovy.template @@ -0,0 +1,2 @@ +if (!a) { +} else b = false; \ No newline at end of file diff --git a/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/description.html b/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/description.html new file mode 100644 index 000000000000..3823b58a844c --- /dev/null +++ b/plugins/IntelliLang/src/intentionDescriptions/InvertIfIntention/description.html @@ -0,0 +1,10 @@ + + + +This intention replaces if statement with +another if statement using inverted condition inside. +
+The intention might be useful to e.g. simplify complex code using multiple nested if statements. +
+ + \ No newline at end of file diff --git a/plugins/groovy/src/META-INF/plugin.xml b/plugins/groovy/src/META-INF/plugin.xml index 62095d0baaa8..501149f02a4e 100644 --- a/plugins/groovy/src/META-INF/plugin.xml +++ b/plugins/groovy/src/META-INF/plugin.xml @@ -710,6 +710,11 @@ intention.category.groovy/intention.category.control.flow org.jetbrains.plugins.groovy.intentions.control.SplitIfIntention + + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle + intention.category.groovy/intention.category.control.flow + org.jetbrains.plugins.groovy.intentions.control.InvertIfIntention + org.jetbrains.plugins.groovy.intentions.GroovyIntentionsBundle intention.category.groovy/intention.category.control.flow diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties index bb841abb0c3d..17988f9cecce 100644 --- a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/GroovyIntentionsBundle.properties @@ -41,6 +41,8 @@ split.else.if.intention.name=Split else-if split.else.if.intention.family.name=Split Else If split.if.intention.name=Split into 2 if's split.if.intention.family.name=Split into 2 if's +invert.if.intention.name=Invert If Condition +invert.if.intention.family.name=Invert If Condition flip.conditional.intention.name=Flip ?: flip.conditional.intention.family.name=Flip Conditional conditional.to.elvis.intention.name=Convert Conditional to Elvis diff --git a/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/InvertIfIntention.java b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/InvertIfIntention.java new file mode 100644 index 000000000000..6b55e4d7938a --- /dev/null +++ b/plugins/groovy/src/org/jetbrains/plugins/groovy/intentions/control/InvertIfIntention.java @@ -0,0 +1,100 @@ +package org.jetbrains.plugins.groovy.intentions.control; + +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.util.IncorrectOperationException; +import org.jetbrains.annotations.NotNull; +import org.jetbrains.plugins.groovy.intentions.base.Intention; +import org.jetbrains.plugins.groovy.intentions.base.PsiElementPredicate; +import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrIfStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrParenthesizedExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrReferenceExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrUnaryExpression; +import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrCallExpression; + +/** + * @author Niels Harremoes + */ +public class InvertIfIntention extends Intention { + + @Override + protected void processIntention(@NotNull PsiElement element, Project project, Editor editor) throws IncorrectOperationException { + PsiElement parent = element.getParent(); + + if (!"if".equals(element.getText()) || !(parent instanceof GrIfStatement)) { + throw new IncorrectOperationException("Not invoked on an if"); + } + GrIfStatement parentIf = (GrIfStatement)parent; + GroovyPsiElementFactory groovyPsiElementFactory = GroovyPsiElementFactory.getInstance(project); + + GrStatement thenBranch = parentIf.getThenBranch(); + GrStatement elseBranch = parentIf.getElseBranch(); + + GrExpression condition = parentIf.getCondition(); + if (condition == null) { + throw new IncorrectOperationException("Invoked on an if with empty condition"); + } + + GrExpression negatedCondition = null; + if (condition instanceof GrUnaryExpression) { + GrUnaryExpression unaryCondition = (GrUnaryExpression)condition; + if ("!".equals(unaryCondition.getOperationToken().getText())) { + negatedCondition = stripParenthesis(unaryCondition.getOperand()); + } + } + + if (negatedCondition==null) { + // Now check whether this is a simple expression + condition = stripParenthesis(condition); + String negatedExpressionText; + if (condition instanceof GrCallExpression || condition instanceof GrReferenceExpression) { + negatedExpressionText = "!" + condition.getText(); + } else { + negatedExpressionText = "!(" + condition.getText() + ")"; + } + negatedCondition = groovyPsiElementFactory.createExpressionFromText(negatedExpressionText, parentIf); + } + + GrIfStatement newIf = (GrIfStatement)groovyPsiElementFactory.createStatementFromText( + "if (" + negatedCondition.getText() + ") " + + (elseBranch != null ? elseBranch.getText() : "{}") + " else " + + (thenBranch != null ? thenBranch.getText() : "{}"), parentIf.getContext() + ); + + parentIf.replace(newIf); + } + + private static GrExpression stripParenthesis(GrExpression operand) { + while (operand instanceof GrParenthesizedExpression) { + operand = ((GrParenthesizedExpression) operand).getOperand(); + } + return operand; + } + + @NotNull + @Override + protected PsiElementPredicate getElementPredicate() { + return new PsiElementPredicate() { + @Override + public boolean satisfiedBy(PsiElement element) { + + if (!"if".equals(element.getText())) { + return false; + } + PsiElement parent = element.getParent(); + if (!(parent instanceof GrIfStatement)) { + return false; + } + + if (((GrIfStatement)parent).getCondition() == null) { + return false; + } + return true; + } + }; + } +} diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/InvertIfTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/InvertIfTest.groovy new file mode 100644 index 000000000000..102faf3f5b33 --- /dev/null +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/intentions/InvertIfTest.groovy @@ -0,0 +1,115 @@ +package org.jetbrains.plugins.groovy.intentions + +/** + * @author Niels Harremoes + */ +class InvertIfTest extends GrIntentionTestCase { + + String intentionName = GroovyIntentionsBundle.message("invert.if.intention.name") + + public void testDoNotTriggerOnIncompleteIf() throws Exception { + doAntiTest ''' +if () { + succes +} else { + no_succes +} +''', intentionName + + } + + private void doTest(String before, String after) { + + doTextTest before, intentionName, after + } + + public void testSimpleCondition() throws Exception { + + doTest ''' +if (a) { + succes +} else { + no_succes +} +''', '''if (!a) { + no_succes +} else { + succes +} +''' + } + + public void testCallCondition() throws Exception { + + doTest ''' +if (func()) { + succes +} else { + no_succes +} +''', '''if (!func()) { + no_succes +} else { + succes +} +''' + } + + public void testComplexCondition() throws Exception { + doTest ''' +if (a && b) { + succes +} else { + no_succes +} +''', '''if (!(a && b)) { + no_succes +} else { + succes +} +''' + } + + public void testNegatedComplexCondition() throws Exception { + doTest ''' +if (!(a && b)) { + succes +} else { + no_succes +} +''', '''if (a && b) { + no_succes +} else { + succes +} +''' + } + + public void testNegatedSimpleCondition() throws Exception { + doTest ''' +if (!a) { + succes +} else { + no_succes +} +''', '''if (a) { + no_succes +} else { + succes +} +''' + } + + public void testNoElseBlock() throws Exception { + doTest ''' +if (a) { + succes +} +''', '''if (!a) { +} else { + succes +} +''' + } + +}