diff --git a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java index 78d919d4b251..7a2125c2d43b 100644 --- a/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java +++ b/python/src/com/jetbrains/python/codeInsight/intentions/PyStringConcatenationToFormatIntention.java @@ -84,7 +84,8 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction List res = new ArrayList(); if (expression.getLeftExpression() instanceof PyBinaryExpression) { res.addAll(getSimpleExpressions((PyBinaryExpression) expression.getLeftExpression())); - } else { + } + else { res.add(expression.getLeftExpression()); } if (expression.getRightExpression() instanceof PyBinaryExpression) { @@ -108,10 +109,8 @@ public class PyStringConcatenationToFormatIntention extends BaseIntentionAction } public void invoke(@NotNull Project project, Editor editor, PsiFile file) throws IncorrectOperationException { - PsiElement element = PsiTreeUtil.getParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class, false); - while (element != null && element.getParent() instanceof PyBinaryExpression) { - element = element.getParent(); - } + PsiElement element = PsiTreeUtil.getTopmostParentOfType(file.findElementAt(editor.getCaretModel().getOffset()), PyBinaryExpression.class); + if (element == null) return; final LanguageLevel languageLevel = LanguageLevel.forElement(element); final boolean useFormatMethod = languageLevel.isAtLeast(LanguageLevel.PYTHON27); diff --git a/python/testData/intentions/beforeStringConcatToFormat1.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/augmentAssignment.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormat1.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/augmentAssignment.py diff --git a/python/testData/intentions/afterStringConcatToFormat1.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/augmentAssignment_after.py similarity index 100% rename from python/testData/intentions/afterStringConcatToFormat1.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/augmentAssignment_after.py diff --git a/python/testData/intentions/beforeStringConcatToFormat5.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/emptyStrings.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormat5.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/emptyStrings.py diff --git a/python/testData/intentions/beforeStringConcatToFormatEscaping.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escaping.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormatEscaping.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escaping.py diff --git a/python/testData/intentions/beforeStringConcatToFormatEscapingPy3.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escapingPy3.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormatEscapingPy3.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escapingPy3.py diff --git a/python/testData/intentions/afterStringConcatToFormatEscapingPy3.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escapingPy3_after.py similarity index 100% rename from python/testData/intentions/afterStringConcatToFormatEscapingPy3.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escapingPy3_after.py diff --git a/python/testData/intentions/afterStringConcatToFormatEscaping.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escaping_after.py similarity index 100% rename from python/testData/intentions/afterStringConcatToFormatEscaping.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/escaping_after.py diff --git a/python/testData/intentions/beforeStringConcatToFormat2.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/negative.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormat2.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/negative.py diff --git a/python/testData/intentions/beforeStringConcatToFormatPy3.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/py3.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormatPy3.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/py3.py diff --git a/python/testData/intentions/afterStringConcatToFormatPy3.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/py3_after.py similarity index 100% rename from python/testData/intentions/afterStringConcatToFormatPy3.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/py3_after.py diff --git a/python/testData/intentions/beforeStringConcatToFormat.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/simple.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormat.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/simple.py diff --git a/python/testData/intentions/afterStringConcatToFormat.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/simple_after.py similarity index 100% rename from python/testData/intentions/afterStringConcatToFormat.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/simple_after.py diff --git a/python/testData/intentions/beforeStringConcatToFormat3.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/twoStrings.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormat3.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/twoStrings.py diff --git a/python/testData/intentions/afterStringConcatToFormat3.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/twoStrings_after.py similarity index 100% rename from python/testData/intentions/afterStringConcatToFormat3.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/twoStrings_after.py diff --git a/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeSecondString.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeSecondString.py new file mode 100644 index 000000000000..d2302ef7f3de --- /dev/null +++ b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeSecondString.py @@ -0,0 +1 @@ +'x' + u'привет' \ No newline at end of file diff --git a/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeSecondString_after.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeSecondString_after.py new file mode 100644 index 000000000000..157e545fe041 --- /dev/null +++ b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeSecondString_after.py @@ -0,0 +1 @@ +u'xпривет' \ No newline at end of file diff --git a/python/testData/intentions/beforeUnicodeStringConcatToFormat.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeString.py similarity index 100% rename from python/testData/intentions/beforeUnicodeStringConcatToFormat.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeString.py diff --git a/python/testData/intentions/afterUnicodeStringConcatToFormat.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeString_after.py similarity index 100% rename from python/testData/intentions/afterUnicodeStringConcatToFormat.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unicodeString_after.py diff --git a/python/testData/intentions/beforeStringConcatToFormat4.py b/python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unknownType.py similarity index 100% rename from python/testData/intentions/beforeStringConcatToFormat4.py rename to python/testData/intentions/PyStringConcatenationToFormatIntentionTest/unknownType.py diff --git a/python/testSrc/com/jetbrains/python/intentions/PyConvertFormatOperatorToMethodIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyConvertFormatOperatorToMethodIntentionTest.java index b477f5eadb26..b9a820a98919 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyConvertFormatOperatorToMethodIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyConvertFormatOperatorToMethodIntentionTest.java @@ -9,18 +9,18 @@ import com.jetbrains.python.psi.LanguageLevel; public class PyConvertFormatOperatorToMethodIntentionTest extends PyIntentionTestCase { public void testSimple() { - doIntentionTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); + doTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); } public void testMulti() { - doIntentionTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); + doTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); } public void testEscaped() { - doIntentionTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); + doTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); } public void testUnicode() { - doIntentionTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); + doTest(PyBundle.message("INTN.replace.with.method"), LanguageLevel.PYTHON26); } } \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/intentions/PyConvertMethodToPropertyIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyConvertMethodToPropertyIntentionTest.java index 2b87c424878f..d8e452e69c2a 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyConvertMethodToPropertyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyConvertMethodToPropertyIntentionTest.java @@ -8,7 +8,7 @@ import com.jetbrains.python.PyBundle; public class PyConvertMethodToPropertyIntentionTest extends PyIntentionTestCase { public void testParamList() throws Exception { - doNegateIntentionTest(PyBundle.message("INTN.convert.method.to.property")); + doNegativeTest(PyBundle.message("INTN.convert.method.to.property")); } public void testSimple() throws Exception { @@ -16,11 +16,11 @@ public class PyConvertMethodToPropertyIntentionTest extends PyIntentionTestCase } public void testProperty() throws Exception { - doNegateIntentionTest(PyBundle.message("INTN.convert.method.to.property")); + doNegativeTest(PyBundle.message("INTN.convert.method.to.property")); } public void testEmptyReturn() throws Exception { - doNegateIntentionTest(PyBundle.message("INTN.convert.method.to.property")); + doNegativeTest(PyBundle.message("INTN.convert.method.to.property")); } public void testYield() throws Exception { @@ -28,7 +28,7 @@ public class PyConvertMethodToPropertyIntentionTest extends PyIntentionTestCase } public void testNoReturn() throws Exception { - doNegateIntentionTest(PyBundle.message("INTN.convert.method.to.property")); + doNegativeTest(PyBundle.message("INTN.convert.method.to.property")); } } \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java index 5758804645a1..395db7ef1d31 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTest.java @@ -128,38 +128,6 @@ public class PyIntentionTest extends PyTestCase { doTest(PyBundle.message("INTN.negate.$0.to.$1", ">", "<=")); } - public void testStringConcatToFormat() { - doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); - } - - public void testStringConcatToFormat1() { //PY-5226 - doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); - } - - public void testStringConcatToFormat2() { //PY-6505 - runWithLanguageLevel(LanguageLevel.PYTHON25, new Runnable() { - @Override - public void run() { - doNegativeTest(PyBundle.message("INTN.replace.plus.with.format.operator")); - } - }); - } - - public void testStringConcatToFormat3() { //PY-6505 - doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); - } - - public void testStringConcatToFormat4() { //PY-7969 - doNegativeTest(PyBundle.message("INTN.replace.plus.with.format.operator")); - } - - public void testStringConcatToFormat5() { //PY-7968 - doNegativeTest(PyBundle.message("INTN.replace.plus.with.format.operator")); - } - - public void testStringConcatToFormatPy3() { //PY-4706 - doTest(PyBundle.message("INTN.replace.plus.with.str.format"), LanguageLevel.PYTHON33); - } public void testFlipComparison() { doTest(PyBundle.message("INTN.flip.$0.to.$1", ">", "<")); @@ -390,20 +358,6 @@ public class PyIntentionTest extends PyTestCase { doTest(PyBundle.message("INTN.yield.from"), LanguageLevel.PYTHON33); } - public void testUnicodeStringConcatToFormat() { //PY-7463 - doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); - } - - // PY-8366 - public void testStringConcatToFormatEscapingPy3() { - doTest(PyBundle.message("INTN.replace.plus.with.str.format"), LanguageLevel.PYTHON33); - } - - // PY-8588 - public void testStringConcatToFormatEscaping() { - doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); - } - public void testConvertStaticMethodToFunction() { doTest(PyBundle.message("INTN.convert.static.method.to.function")); } diff --git a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTestCase.java b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTestCase.java index c1cd0d78f706..4db528694b14 100644 --- a/python/testSrc/com/jetbrains/python/intentions/PyIntentionTestCase.java +++ b/python/testSrc/com/jetbrains/python/intentions/PyIntentionTestCase.java @@ -17,7 +17,7 @@ public abstract class PyIntentionTestCase extends PyTestCase { return PythonTestUtil.getTestDataPath() + "/intentions/" + getClass().getSimpleName(); } - protected void doIntentionTest(String hint, LanguageLevel languageLevel) { + protected void doTest(String hint, LanguageLevel languageLevel) { PythonLanguageLevelPusher.setForcedLanguageLevel(myFixture.getProject(), languageLevel); try { doIntentionTest(hint); @@ -36,7 +36,7 @@ public abstract class PyIntentionTestCase extends PyTestCase { myFixture.checkResultByFile(testFileName + "_after.py", true); } - protected void doNegateIntentionTest(final String hint) { + protected void doNegativeTest(final String hint) { final String testFileName = getTestName(true); myFixture.configureByFile(testFileName + ".py"); final IntentionAction intentionAction = myFixture.getAvailableIntention(hint); diff --git a/python/testSrc/com/jetbrains/python/intentions/PyStringConcatenationToFormatIntentionTest.java b/python/testSrc/com/jetbrains/python/intentions/PyStringConcatenationToFormatIntentionTest.java new file mode 100644 index 000000000000..b5c69a23ad07 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/intentions/PyStringConcatenationToFormatIntentionTest.java @@ -0,0 +1,61 @@ +package com.jetbrains.python.intentions; + +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.LanguageLevel; + +/** + * User : ktisha + */ +public class PyStringConcatenationToFormatIntentionTest extends PyIntentionTestCase { + + public void testSimple() { + doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); + } + + public void testAugmentAssignment() { //PY-5226 + doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); + } + + public void testNegative() { //PY-6505 + runWithLanguageLevel(LanguageLevel.PYTHON25, new Runnable() { + @Override + public void run() { + doNegativeTest(PyBundle.message("INTN.replace.plus.with.format.operator")); + } + }); + } + + public void testTwoStrings() { //PY-6505 + doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); + } + + public void testUnknownType() { //PY-7969 + doNegativeTest(PyBundle.message("INTN.replace.plus.with.format.operator")); + } + + public void testEmptyStrings() { //PY-7968 + doNegativeTest(PyBundle.message("INTN.replace.plus.with.format.operator")); + } + + public void testUnicodeString() { //PY-7463 + doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); + } + + public void testUnicodeSecondString() { //PY-7463 + doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); + } + + // PY-8366 + public void testEscapingPy3() { + doTest(PyBundle.message("INTN.replace.plus.with.str.format"), LanguageLevel.PYTHON33); + } + + // PY-8588 + public void testEscaping() { + doTest(PyBundle.message("INTN.replace.plus.with.format.operator"), LanguageLevel.PYTHON25); + } + + public void testPy3() { //PY-4706 + doTest(PyBundle.message("INTN.replace.plus.with.str.format"), LanguageLevel.PYTHON33); + } +} \ No newline at end of file