From 7d46075b5f31ce5ca91de8c4cdfec22b0d568c43 Mon Sep 17 00:00:00 2001 From: Daniil Kalinin Date: Thu, 23 Oct 2025 20:12:53 +0200 Subject: [PATCH] PY-84107 Fix Type Parameters mistakenly reported as unused in `PyUnusedLocalInspection` (cherry picked from commit 0593c2290aa1c84dde96673297374efef2b27fc3) GitOrigin-RevId: 56de9b7a6b305eb9e88dc2bf8281c93f788eae80 --- .../unusedLocal/PyUnusedLocalInspectionVisitor.java | 7 +++++++ .../newStyleTypeParameterInFuncNotMarkedAsUnused.py | 13 +++++++++++++ .../inspections/PyUnusedLocalInspectionTest.java | 5 +++++ 3 files changed, 25 insertions(+) create mode 100644 python/testData/inspections/PyUnusedLocalInspection/newStyleTypeParameterInFuncNotMarkedAsUnused.py 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 782ed05a3893..542a71cda9f3 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 @@ -257,6 +257,13 @@ public final class PyUnusedLocalInspectionVisitor extends PyInspectionVisitor { if (declOwner != null && declOwner != owner) { readsFromInstruction.addAll(ScopeUtil.getElementsOfAccessType(name, declOwner, ReadWriteInstruction.ACCESS.WRITE)); } + // Type params are not present in CFG + else if (owner instanceof PyTypeParameterListOwner typeParameterListOwner && + typeParameterListOwner.getTypeParameterList() != null) { + StreamEx.of(typeParameterListOwner.getTypeParameterList().getTypeParameters()) + .filter(typeParameter -> name.equals(typeParameter.getName())) + .forEach(readsFromInstruction::add); + } } ControlFlowUtil.iteratePrev(startInstruction, instructions, inst -> { final PsiElement instElement = inst.getElement(); diff --git a/python/testData/inspections/PyUnusedLocalInspection/newStyleTypeParameterInFuncNotMarkedAsUnused.py b/python/testData/inspections/PyUnusedLocalInspection/newStyleTypeParameterInFuncNotMarkedAsUnused.py new file mode 100644 index 000000000000..22df2b95dde5 --- /dev/null +++ b/python/testData/inspections/PyUnusedLocalInspection/newStyleTypeParameterInFuncNotMarkedAsUnused.py @@ -0,0 +1,13 @@ +from typing import Callable + +def wait_for_condition[T](fn: Callable[..., T]) -> T: + return fn() + +def foo[T, U](fn: Callable[..., T]) -> U: + return fn() + +def bar[T, U](fn: Callable[..., T]) -> T: + return fn() + +def baz[T, U](fn: Callable[..., int]) -> str: + return fn() \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java index 20a318d37d21..d2ab4bfa8d0f 100644 --- a/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/PyUnusedLocalInspectionTest.java @@ -247,6 +247,11 @@ def test(): doTest(); } + // PY-84107 + public void testNewStyleTypeParameterInFuncNotMarkedAsUnused() { + doTest(); + } + @NotNull @Override protected Class getInspectionClass() {