diff --git a/python/src/com/jetbrains/python/PyBundle.properties b/python/src/com/jetbrains/python/PyBundle.properties index 5cd08be688f5..0d219d6d79ef 100644 --- a/python/src/com/jetbrains/python/PyBundle.properties +++ b/python/src/com/jetbrains/python/PyBundle.properties @@ -145,6 +145,8 @@ QFIX.NAME.change.signature=Change signature QFIX.NAME.remove.argument=Remove argument +QFIX.NAME.remove.parameter=Remove parameter + QFIX.NAME.rename.argument=Rename argument QFIX.NAME.wrap.in.exception=Wrap with Exception call diff --git a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java index 756ae140391f..968a723045f8 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java +++ b/python/src/com/jetbrains/python/inspections/PyUnusedLocalInspectionVisitor.java @@ -34,6 +34,8 @@ import com.jetbrains.python.codeInsight.controlflow.ScopeOwner; import com.jetbrains.python.codeInsight.dataflow.scope.Scope; import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil; import com.jetbrains.python.inspections.quickfix.AddFieldQuickFix; +import com.jetbrains.python.inspections.quickfix.PyRemoveParameterQuickFix; +import com.jetbrains.python.inspections.quickfix.PyRemoveStatementQuickFix; import com.jetbrains.python.psi.*; import com.jetbrains.python.psi.impl.PyAugAssignmentStatementNavigator; import com.jetbrains.python.psi.impl.PyBuiltinCache; @@ -246,14 +248,14 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { final PsiElement nameIdentifier = ((PyFunction)element).getNameIdentifier(); registerWarning(nameIdentifier == null ? element : nameIdentifier, PyBundle.message("INSP.unused.locals.local.function.isnot.used", - ((PyFunction)element).getName())); + ((PyFunction)element).getName()), new PyRemoveStatementQuickFix()); } else if (element instanceof PyClass) { // Local class final PyClass cls = (PyClass)element; final PsiElement name = cls.getNameIdentifier(); registerWarning(name != null ? name : element, - PyBundle.message("INSP.unused.locals.local.class.isnot.used", cls.getName())); + PyBundle.message("INSP.unused.locals.local.class.isnot.used", cls.getName()), new PyRemoveStatementQuickFix()); } else { // Local variable or parameter @@ -297,7 +299,7 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { } final LocalQuickFix[] fixes = mayBeField ? new LocalQuickFix[] { new AddFieldQuickFix(name, name, containingClass.getName()) } - : LocalQuickFix.EMPTY_ARRAY; + : new LocalQuickFix[] { new PyRemoveParameterQuickFix() }; registerWarning(element, PyBundle.message("INSP.unused.locals.parameter.isnot.used", name), fixes); } else { @@ -312,7 +314,7 @@ public class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { } } else { - registerWarning(element, PyBundle.message("INSP.unused.locals.local.variable.isnot.used", name)); + registerWarning(element, PyBundle.message("INSP.unused.locals.local.variable.isnot.used", name), new PyRemoveStatementQuickFix()); } } } diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java new file mode 100644 index 000000000000..84935b8fd561 --- /dev/null +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveParameterQuickFix.java @@ -0,0 +1,78 @@ +/* + * 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.module.Module; +import com.intellij.openapi.module.ModuleUtilCore; +import com.intellij.openapi.project.Project; +import com.intellij.psi.PsiElement; +import com.intellij.psi.PsiWhiteSpace; +import com.intellij.psi.util.PsiTreeUtil; +import com.jetbrains.python.PyBundle; +import com.jetbrains.python.PyTokenTypes; +import com.jetbrains.python.documentation.PyDocumentationSettings; +import com.jetbrains.python.editor.PythonDocCommentUtil; +import com.jetbrains.python.psi.*; +import org.jetbrains.annotations.NonNls; +import org.jetbrains.annotations.NotNull; + +public class PyRemoveParameterQuickFix implements LocalQuickFix { + + @NotNull + public String getName() { + return PyBundle.message("QFIX.NAME.remove.parameter"); + } + + @NonNls + @NotNull + public String getFamilyName() { + return getName(); + } + + public void applyFix(@NotNull final Project project, @NotNull final ProblemDescriptor descriptor) { + final PsiElement element = descriptor.getPsiElement(); + assert element instanceof PyParameter; + + final PyFunction pyFunction = PsiTreeUtil.getParentOfType(element, PyFunction.class); + final PsiElement nextSibling = PsiTreeUtil.skipSiblingsForward(element, PsiWhiteSpace.class); + final PsiElement prevSibling = PsiTreeUtil.skipSiblingsBackward(element, PsiWhiteSpace.class); + element.delete(); + if (nextSibling != null && nextSibling.getNode().getElementType().equals(PyTokenTypes.COMMA)) { + nextSibling.delete(); + return; + } + if (prevSibling != null && prevSibling.getNode().getElementType().equals(PyTokenTypes.COMMA)) { + prevSibling.delete(); + } + + if (pyFunction != null) { + final PyStringLiteralExpression expression = pyFunction.getDocStringExpression(); + final String paramName = ((PyParameter)element).getName(); + if (expression != null && paramName != null) { + final Module module = ModuleUtilCore.findModuleForPsiElement(pyFunction); + assert module != null; + PyDocumentationSettings documentationSettings = PyDocumentationSettings.getInstance(module); + String prefix = documentationSettings.isEpydocFormat(pyFunction.getContainingFile()) ? "@" : ":"; + final String replacement = PythonDocCommentUtil.removeParamFromDocstring(expression.getText(), prefix, paramName); + PyExpression str = + PyElementGenerator.getInstance(project).createDocstring(replacement).getExpression(); + expression.replace(str); + } + } + } +} diff --git a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveStatementQuickFix.java b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveStatementQuickFix.java index 0099a4e0b003..8e0fb40d3f7b 100644 --- a/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveStatementQuickFix.java +++ b/python/src/com/jetbrains/python/inspections/quickfix/PyRemoveStatementQuickFix.java @@ -18,7 +18,6 @@ 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.intellij.psi.util.PsiTreeUtil; import com.jetbrains.python.PyBundle; import com.jetbrains.python.psi.PyElementGenerator; @@ -41,8 +40,8 @@ public class PyRemoveStatementQuickFix implements LocalQuickFix { @Override public void applyFix(@NotNull Project project, @NotNull ProblemDescriptor descriptor) { - final PsiElement statement = descriptor.getPsiElement(); - if (statement instanceof PyStatement) { + final PyStatement statement = PsiTreeUtil.getParentOfType(descriptor.getPsiElement(), PyStatement.class, false); + if (statement != null) { final PyStatementList statementList = PsiTreeUtil.getParentOfType(statement, PyStatementList.class); if (statementList != null) { if (statementList.getStatements().length == 1) { diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring.py new file mode 100644 index 000000000000..3663937b4ec4 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring.py @@ -0,0 +1,11 @@ + +def foo(r): + """ + + :param r: + :return: + """ + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring_after.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring_after.py new file mode 100644 index 000000000000..df7e8c01c98f --- /dev/null +++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/docstring_after.py @@ -0,0 +1,10 @@ + +def foo(): + """ + + :return: + """ + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/kwParam.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/kwParam.py new file mode 100644 index 000000000000..152576382b61 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/kwParam.py @@ -0,0 +1,6 @@ + +def foo(r, **kwargs): + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/kwParam_after.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/kwParam_after.py new file mode 100644 index 000000000000..d30ca7d1a943 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/kwParam_after.py @@ -0,0 +1,6 @@ + +def foo(r): + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/param.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/param.py new file mode 100644 index 000000000000..1a8953fa9328 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/param.py @@ -0,0 +1,6 @@ + +def foo(r): + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveParameterQuickFixTest/param_after.py b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/param_after.py new file mode 100644 index 000000000000..78e168bd1256 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveParameterQuickFixTest/param_after.py @@ -0,0 +1,6 @@ + +def foo(): + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveStatementQuickFixTest/function.py b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/function.py new file mode 100644 index 000000000000..ad6bb75f9e1f --- /dev/null +++ b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/function.py @@ -0,0 +1,11 @@ + +def foo(r): + """ + + :param r: + :return: + """ + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveStatementQuickFixTest/function_after.py b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/function_after.py new file mode 100644 index 000000000000..cb72dcabb947 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/function_after.py @@ -0,0 +1,10 @@ + +def foo(r): + """ + + :param r: + :return: + """ + + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveStatementQuickFixTest/variable.py b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/variable.py new file mode 100644 index 000000000000..b8d7fc5ba7d8 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/variable.py @@ -0,0 +1,11 @@ + +def foo(r): + """ + + :param r: + :return: + """ + def a(): + pass + x = 1 + x = 2 \ No newline at end of file diff --git a/python/testData/quickFixes/PyRemoveStatementQuickFixTest/variable_after.py b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/variable_after.py new file mode 100644 index 000000000000..7267b432d301 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveStatementQuickFixTest/variable_after.py @@ -0,0 +1,11 @@ + +def foo(r): + """ + + :param r: + :return: + """ + def a(): + pass + + x = 2 \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveParameterQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveParameterQuickFixTest.java new file mode 100644 index 000000000000..32fc35d31e11 --- /dev/null +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveParameterQuickFixTest.java @@ -0,0 +1,37 @@ +/* + * 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.PyUnusedLocalInspection; + +@TestDataPath("$CONTENT_ROOT/../testData//quickFixes/PyRemoveParameterQuickFixTest/") +public class PyRemoveParameterQuickFixTest extends PyQuickFixTestCase { + + public void testParam() { + doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.parameter")); + } + + public void testKwParam() { + doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.parameter")); + } + + public void testDocstring() { + doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.parameter")); + } +} diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveStatementQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveStatementQuickFixTest.java index 846221f2f406..e1b981168212 100644 --- a/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveStatementQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveStatementQuickFixTest.java @@ -19,6 +19,7 @@ import com.intellij.testFramework.TestDataPath; import com.jetbrains.python.PyBundle; import com.jetbrains.python.PyQuickFixTestCase; import com.jetbrains.python.inspections.PyReturnFromInitInspection; +import com.jetbrains.python.inspections.PyUnusedLocalInspection; @TestDataPath("$CONTENT_ROOT/../testData//quickFixes/PyRemoveStatementQuickFixTest/") public class PyRemoveStatementQuickFixTest extends PyQuickFixTestCase { @@ -31,4 +32,12 @@ public class PyRemoveStatementQuickFixTest extends PyQuickFixTestCase { doQuickFixTest(PyReturnFromInitInspection.class, PyBundle.message("QFIX.NAME.remove.statement")); } + public void testFunction() { + doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.statement")); + } + + public void testVariable() { + doQuickFixTest(PyUnusedLocalInspection.class, PyBundle.message("QFIX.NAME.remove.statement")); + } + }