diff --git a/python/python-psi-impl/resources/messages/PyPsiBundle.properties b/python/python-psi-impl/resources/messages/PyPsiBundle.properties index a60c48492c8a..558d920217d0 100644 --- a/python/python-psi-impl/resources/messages/PyPsiBundle.properties +++ b/python/python-psi-impl/resources/messages/PyPsiBundle.properties @@ -374,6 +374,7 @@ QFIX.NAME.add.field.to.class=Add field to class QFIX.add.field.to.class=Add field ''{0}'' to class {1} QFIX.add.field.to.class.popup.content.added.init=Added a __init__ to class {0}
to accommodate new field {1} QFIX.NAME.remove.parameter=Remove parameter +QFIX.NAME.remove.type.parameter=Remove type parameter QFIX.NAME.rename.parameter=Rename parameter QFIX.rename.parameter=Rename to ''{0}'' QFIX.NAME.remove.statement=Remove statement diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/quickfix/PyRemoveTypeParameterQuickFix.kt b/python/python-psi-impl/src/com/jetbrains/python/inspections/quickfix/PyRemoveTypeParameterQuickFix.kt new file mode 100644 index 000000000000..1badc467e2ab --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/quickfix/PyRemoveTypeParameterQuickFix.kt @@ -0,0 +1,49 @@ +package com.jetbrains.python.inspections.quickfix + +import com.intellij.modcommand.ModPsiUpdater +import com.intellij.modcommand.PsiUpdateModCommandQuickFix +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.PyPsiBundle +import com.jetbrains.python.PyTokenTypes +import com.jetbrains.python.psi.PyElement +import com.jetbrains.python.psi.PyTypeParameter +import com.jetbrains.python.psi.PyTypeParameterList + +/** + * Removes a single type parameter from a type parameter list. + * If the list becomes empty, removes the brackets as well. + */ +class PyRemoveTypeParameterQuickFix : PsiUpdateModCommandQuickFix() { + override fun getFamilyName(): String = PyPsiBundle.message("QFIX.NAME.remove.type.parameter") + + override fun applyFix(project: Project, element: PsiElement, updater: ModPsiUpdater) { + val typeParameter = PsiTreeUtil.getParentOfType(element, PyTypeParameter::class.java, false) ?: return + val list = PsiTreeUtil.getParentOfType(typeParameter, PyTypeParameterList::class.java, false) ?: return + + var prev: PsiElement? = typeParameter.prevSibling + var next: PsiElement? = typeParameter.nextSibling + + if (prev is PsiWhiteSpace) prev = prev.prevSibling + if (next is PsiWhiteSpace) next = next.nextSibling + + if (prev != null && prev.node.elementType == PyTokenTypes.COMMA) { + prev.delete() + val afterComma = typeParameter.prevSibling + if (afterComma is PsiWhiteSpace) afterComma.delete() + } + else if (next != null && next.node.elementType == PyTokenTypes.COMMA) { + val ws = next.nextSibling + next.delete() + if (ws is PsiWhiteSpace) ws.delete() + } + + typeParameter.delete() + + if (list.typeParameters.isEmpty()) { + (list as PyElement).delete() + } + } +} diff --git a/python/python-psi-impl/src/com/jetbrains/python/inspections/unusedLocal/PyUnusedLocalInspectionVisitor.java b/python/python-psi-impl/src/com/jetbrains/python/inspections/unusedLocal/PyUnusedLocalInspectionVisitor.java index 542a71cda9f3..370ff0173931 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/inspections/unusedLocal/PyUnusedLocalInspectionVisitor.java +++ b/python/python-psi-impl/src/com/jetbrains/python/inspections/unusedLocal/PyUnusedLocalInspectionVisitor.java @@ -362,7 +362,7 @@ public final class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { final PsiElement name = typeParameter.getNameIdentifier(); registerWarning(name != null ? name : element, PyPsiBundle.message("INSP.unused.locals.type.parameter.isnot.used", typeParameter.getName()), - new PyRemoveStatementQuickFix()); + new PyRemoveTypeParameterQuickFix()); } else { // Local variable or parameter diff --git a/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInFunction.py b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInFunction.py new file mode 100644 index 000000000000..eeab21762d95 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInFunction.py @@ -0,0 +1,4 @@ +from typing import Callable + +def foo[T, U](fn: Callable[..., T]) -> T: + return fn() diff --git a/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInFunction_after.py b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInFunction_after.py new file mode 100644 index 000000000000..fa57b53569be --- /dev/null +++ b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInFunction_after.py @@ -0,0 +1,4 @@ +from typing import Callable + +def foo[T](fn: Callable[..., T]) -> T: + return fn() diff --git a/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInTypeAlias.py b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInTypeAlias.py new file mode 100644 index 000000000000..91899a8a6bef --- /dev/null +++ b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInTypeAlias.py @@ -0,0 +1,3 @@ +from typing import Callable + +type Alias[T, U] = Callable[..., T] diff --git a/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInTypeAlias_after.py b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInTypeAlias_after.py new file mode 100644 index 000000000000..2ff4f0f682c0 --- /dev/null +++ b/python/testData/quickFixes/PyRemoveUnusedLocalQuickFixTest/removeUnusedTypeParameterInTypeAlias_after.py @@ -0,0 +1,3 @@ +from typing import Callable + +type Alias[T] = Callable[..., T] diff --git a/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveUnusedLocalQuickFixTest.java b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveUnusedLocalQuickFixTest.java index 0a7c255f4e67..903f8eb36da0 100644 --- a/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveUnusedLocalQuickFixTest.java +++ b/python/testSrc/com/jetbrains/python/quickFixes/PyRemoveUnusedLocalQuickFixTest.java @@ -103,4 +103,16 @@ public class PyRemoveUnusedLocalQuickFixTest extends PyQuickFixTestCase { public void testComprehensionIterator() { doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("INSP.unused.locals.replace.with.wildcard")); } + + // PY-85080 + public void testRemoveUnusedTypeParameterInFunction() { + runWithLanguageLevel(LanguageLevel.PYTHON312, + () -> doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.type.parameter"))); + } + + // PY-85080 + public void testRemoveUnusedTypeParameterInTypeAlias() { + runWithLanguageLevel(LanguageLevel.PYTHON312, + () -> doQuickFixTest(PyUnusedLocalInspection.class, PyPsiBundle.message("QFIX.NAME.remove.type.parameter"))); + } }