diff --git a/python/src/META-INF/python-plugin-common.xml b/python/src/META-INF/python-plugin-common.xml index c7881fc32334..de51c0f60606 100644 --- a/python/src/META-INF/python-plugin-common.xml +++ b/python/src/META-INF/python-plugin-common.xml @@ -115,6 +115,12 @@ ConvertFormatOperatorToMethodIntention + + com.jetbrains.python.codeInsight.intentions.PyFlipComparisonIntention + Python + PyFlipComparisonIntention + + diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 8fcfdaef7065..e7669faadfef 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -98,6 +98,10 @@ INTN.replace.plus.with.format.operator=Replace + with string formatting operator INTN.format.operator.to.method=Convert format operator usage to str.format method call INTN.replace.with.method=Replace with str.format method call +INTN.flip.comparison=Flip comparison +INTN.flip.$0=Flip ''{0}'' +INTN.flip.$0.to.$1=Flip ''{0}'' to ''{1}'' + # Conflict checker CONFLICT.name.$0.obscured=Name ''{0}'' obscured by local definitions CONFLICT.name.$0.obscured.cannot.convert=Name ''{0}'' obscured. Cannot convert. diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyFlipComparisonIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyFlipComparisonIntention.java new file mode 100644 index 000000000000..91b9fca4db74 --- /dev/null +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyFlipComparisonIntention.java @@ -0,0 +1,80 @@ +package com.jetbrains.python.codeInsight.intentions; + +import com.intellij.codeInsight.intention.impl.BaseIntentionAction; +import com.intellij.openapi.editor.Editor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiFile; +import com.intellij.psi.util.PsiTreeUtil; +import com.intellij.util.IncorrectOperationException; +import com.intellij.util.containers.HashMap; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.PyTokenTypes; +import com.jetbrains.python.PythonLanguage; +import com.jetbrains.python.psi.PyBinaryExpression; +import com.jetbrains.python.psi.PyElementGenerator; +import com.jetbrains.python.psi.PyElementType; +import org.jetbrains.annotations.NotNull; + +import java.util.Map; + +/** + * Created by IntelliJ IDEA. + * Author: Alexey.Ivanov + * Date: 26.03.2010 + * Time: 22:01:27 + */ +public class PyFlipComparisonIntention extends BaseIntentionAction { + private static final Map FLIPPED_OPERATORS = new HashMap(7); + + static { + FLIPPED_OPERATORS.put(PyTokenTypes.EQEQ, "=="); + FLIPPED_OPERATORS.put(PyTokenTypes.NE, "!="); + FLIPPED_OPERATORS.put(PyTokenTypes.NE_OLD, "<>"); + FLIPPED_OPERATORS.put(PyTokenTypes.GE, "<="); + FLIPPED_OPERATORS.put(PyTokenTypes.LE, ">="); + FLIPPED_OPERATORS.put(PyTokenTypes.GT, "<"); + FLIPPED_OPERATORS.put(PyTokenTypes.LT, ">"); + } + + @NotNull + public String getFamilyName() { + return PyBundle.message("INTN.flip.comparison"); + } + + public boolean isAvailable(@NotNull Project project, Editor editor, PsiFile file) { + PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); + PyBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(element, PyBinaryExpression.class, false); + while (binaryExpression != null) { + PyElementType operator = binaryExpression.getOperator(); + if (FLIPPED_OPERATORS.containsKey(operator)) { + String operatorText = binaryExpression.getPsiOperator().getText(); + String flippedOperatorText = FLIPPED_OPERATORS.get(operator); + if (flippedOperatorText.equals(operatorText)) { + setText(PyBundle.message("INTN.flip.$0", operatorText)); + } + else { + setText(PyBundle.message("INTN.flip.$0.to.$1", operatorText, flippedOperatorText)); + } + return true; + } + binaryExpression = PsiTreeUtil.getParentOfType(binaryExpression, PyBinaryExpression.class); + } + return false; + } + + public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { + PsiElement element = file.findElementAt(editor.getCaretModel().getOffset()); + PyBinaryExpression binaryExpression = PsiTreeUtil.getParentOfType(element, PyBinaryExpression.class, false); + while (binaryExpression != null) { + if (FLIPPED_OPERATORS.containsKey(binaryExpression.getOperator())) { + PyElementGenerator elementGenerator = PythonLanguage.getInstance().getElementGenerator(); + binaryExpression.replace(elementGenerator.createBinaryExpression(project, FLIPPED_OPERATORS.get(binaryExpression.getOperator()), + binaryExpression.getRightExpression(), + binaryExpression.getLeftExpression())); + return; + } + binaryExpression = PsiTreeUtil.getParentOfType(binaryExpression, PyBinaryExpression.class); + } + } +} diff --git a/python/testData/intentions/afterFlipComparison.py b/python/testData/intentions/afterFlipComparison.py new file mode 100644 index 000000000000..db88524a2d60 --- /dev/null +++ b/python/testData/intentions/afterFlipComparison.py @@ -0,0 +1,2 @@ +if 3 < (a + 2) and b < 4: + a = a and b \ No newline at end of file diff --git a/python/testData/intentions/beforeFlipComparison.py b/python/testData/intentions/beforeFlipComparison.py new file mode 100644 index 000000000000..145ecd7a4c22 --- /dev/null +++ b/python/testData/intentions/beforeFlipComparison.py @@ -0,0 +1,2 @@ +if (a + 2) > 3 and b < 4: + a = a and b \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/PyIntentionTest.java index 96acb1071fc1..3e05a100f841 100644 --- a/python/testSrc/com/jetbrains/python/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/PyIntentionTest.java @@ -101,4 +101,8 @@ public class PyIntentionTest extends PyLightFixtureTestCase { public void testConvertFormatOperatorToMethod() throws Exception { doTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON30); } + + public void testFlipComparison() throws Exception { + doTest(PyBundle.message("INTN.flip.$0.to.$1", ">", "<")); + } }