diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index fa0cc1b32d22..93dab333a159 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -141,6 +141,8 @@ QFIX.NAME.rename.argument=Rename argument QFIX.NAME.wrap.in.exception=Wrap with Exception call +QFIX.NAME.make.list=Replace tuple with list + # Intentions: INTN INTN.Family.convert.import.unqualify=Convert 'import module' to 'from module import' INTN.Family.convert.import.qualify=Convert 'from module import' to 'import module' diff --git a/python/src/com/jetbrains/python/inspections/PyTupleItemAssignmentInspection.java b/python/src/com/jetbrains/python/inspections/PyTupleItemAssignmentInspection.java index 3416b5076ca4..79613f023770 100644 --- a/python/src/com/jetbrains/python/inspections/PyTupleItemAssignmentInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyTupleItemAssignmentInspection.java @@ -20,6 +20,7 @@ import com.intellij.codeInspection.ProblemsHolder; import com.intellij.psi.PsiElement; import com.intellij.psi.PsiElementVisitor; import com.jetbrains.python.PyBundle; +import com.jetbrains.python.inspections.quickfix.PyReplaceTupleWithListQuickFix; import com.jetbrains.python.psi.PyAssignmentStatement; import com.jetbrains.python.psi.PyExpression; import com.jetbrains.python.psi.PyReferenceExpression; @@ -64,7 +65,7 @@ public class PyTupleItemAssignmentInspection extends PyInspection { PyExpression expression = (PyExpression)element; PyType type = myTypeEvalContext.getType(expression); if (type instanceof PyTupleType) { - registerProblem(node, PyBundle.message("INSP.tuples.never.assign.items")); + registerProblem(node, PyBundle.message("INSP.tuples.never.assign.items"), new PyReplaceTupleWithListQuickFix()); } } } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyReplaceTupleWithListQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyReplaceTupleWithListQuickFix.java new file mode 100644 index 000000000000..ecb22c18ef14 --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyReplaceTupleWithListQuickFix.java @@ -0,0 +1,68 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.inspections.quickfix; + +import com.intellij.codeInspection.LocalQuickFix; +import com.intellij.codeInspection.ProblemDescriptor; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.psi.*; +import com.jetbrains.python.psi.resolve.PyResolveContext; +import org.jetbrains.annotations.NotNull; + +public class PyReplaceTupleWithListQuickFix implements LocalQuickFix { + @NotNull + @Override + public String getName() { + return PyBundle.message("QFIX.NAME.make.list"); + } + + @NotNull + @Override + public String getFamilyName() { + return getName(); + } + + @Override + public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { + PsiElement element = descriptor.getPsiElement(); + assert element instanceof PyAssignmentStatement; + PyExpression[] targets = ((PyAssignmentStatement)element).getTargets(); + if (targets.length == 1 && targets[0] instanceof PySubscriptionExpression) { + PySubscriptionExpression subscriptionExpression = (PySubscriptionExpression)targets[0]; + if (subscriptionExpression.getOperand() instanceof PyReferenceExpression) { + PyReferenceExpression referenceExpression = (PyReferenceExpression)subscriptionExpression.getOperand(); + element = referenceExpression.followAssignmentsChain(PyResolveContext.defaultContext()).getElement(); + if (element instanceof PyParenthesizedExpression) { + final PyExpression expression = ((PyParenthesizedExpression)element).getContainedExpression(); + replaceWithListLiteral(element, (PyTupleExpression)expression); + } + else if (element instanceof PyTupleExpression) { + replaceWithListLiteral(element, (PyTupleExpression)element); + } + } + } + } + + private static void replaceWithListLiteral(PsiElement element, PyTupleExpression expression) { + final String expressionText = expression.getElements().length == 0 ? "" :expression.getText(); + final PyExpression literal = PyElementGenerator.getInstance(element.getProject()). + createExpressionFromText(LanguageLevel.forElement(element), + "[" + expressionText + "]"); + element.replace(literal); + } +} diff --git a/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/empty.py b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/empty.py new file mode 100644 index 000000000000..fdb02322d363 --- /dev/null +++ b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/empty.py @@ -0,0 +1,2 @@ +a = () +a[0] = 3 \ No newline at end of file diff --git a/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/empty_after.py b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/empty_after.py new file mode 100644 index 000000000000..bb7e190fe5fa --- /dev/null +++ b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/empty_after.py @@ -0,0 +1,2 @@ +a = [] +a[0] = 3 \ No newline at end of file diff --git a/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/parenthesized.py b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/parenthesized.py new file mode 100644 index 000000000000..35c7f439f844 --- /dev/null +++ b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/parenthesized.py @@ -0,0 +1,2 @@ +a = ("11",) +a[0] = 3 \ No newline at end of file diff --git a/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/parenthesized_after.py b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/parenthesized_after.py new file mode 100644 index 000000000000..7e86b06cd032 --- /dev/null +++ b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/parenthesized_after.py @@ -0,0 +1,2 @@ +a = ["11", ] +a[0] = 3 \ No newline at end of file diff --git a/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/tupleExpression.py b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/tupleExpression.py new file mode 100644 index 000000000000..02325e4ebeb4 --- /dev/null +++ b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/tupleExpression.py @@ -0,0 +1,2 @@ +a = "11", +a[0] = 3 \ No newline at end of file diff --git a/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/tupleExpression_after.py b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/tupleExpression_after.py new file mode 100644 index 000000000000..7e86b06cd032 --- /dev/null +++ b/python/testData/quickFixes/PyReplaceTupleWithListQuickFixTest/tupleExpression_after.py @@ -0,0 +1,2 @@ +a = ["11", ] +a[0] = 3 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyReplaceTupleWithListQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/PyReplaceTupleWithListQuickFixTest.java new file mode 100644 index 000000000000..3a911f29c5df --- /dev/null +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyReplaceTupleWithListQuickFixTest.java @@ -0,0 +1,38 @@ +/* + * Copyright 2000-2013 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ +package com.jetbrains.python.quickFixes; + +import com.intellij.testFramework.TestDataPath; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.PyQuickFixTestCase; +import com.jetbrains.python.inspections.PyTupleItemAssignmentInspection; + +@TestDataPath("$CONTENT_ROOT/../testData/quickFixes/PyReplaceTupleWithListQuickFixTest/") +public class PyReplaceTupleWithListQuickFixTest extends PyQuickFixTestCase { + + public void testParenthesized() { + doQuickFixTest(PyTupleItemAssignmentInspection.class, PyBundle.message("QFIX.NAME.make.list")); + } + + public void testEmpty() { + doQuickFixTest(PyTupleItemAssignmentInspection.class, PyBundle.message("QFIX.NAME.make.list")); + } + + public void testTupleExpression() { + doQuickFixTest(PyTupleItemAssignmentInspection.class, PyBundle.message("QFIX.NAME.make.list")); + } + +}