PY-76832 Add missing inspection reports for Self type support

Remove `generics_self_usage.py` from the ignored tests as it passes now

GitOrigin-RevId: 0761d2c161ca00768be967b65639d806dfa4bac4
This commit is contained in:
Daniil Kalinin
2025-11-28 12:42:06 +00:00
committed by intellij-monorepo-bot
parent 99ad4dd3f9
commit 2efa7df328
4 changed files with 61 additions and 6 deletions
@@ -1239,6 +1239,8 @@ INSP.type.hints.typeIs.has.zero.parameters=User-defined TypeGuard or TypeIs func
INSP.type.hints.typeIs.does.not.match=Return type of TypeIs ''{0}'' is not consistent with the type of the first parameter ''{1}''
INSP.type.hints.self.use.in.staticmethod=Cannot use 'Self' in staticmethod
INSP.type.hints.self.use.outside.class=Cannot use 'Self' outside class
INSP.type.hints.self.cannot.use.self.in.this.context=Cannot use 'Self' in this context
INSP.type.hints.self.cannot.use.self.in.metaclass=Type 'Self' cannot be used in a metaclass
INSP.type.hints.self.use.for.self.parameter.with.self.annotation=Cannot use 'Self' if 'self' parameter is not 'Self' annotated
INSP.type.hints.self.use.for.cls.parameter.with.self.annotation=Cannot use 'Self' if 'cls' parameter is not 'Self' annotated
INSP.type.hints.type.var.tuple.must.always.be.unpacked=TypeVarTuple must always be unpacked
@@ -201,6 +201,7 @@ class PyTypeHintsInspection : PyInspection() {
if (type is PyTypeParameterType && type.scopeOwner == null && !isInsideTypeParameterDefault(node)) {
registerProblem(node, PyPsiBundle.message("INSP.type.hints.unbound.type.variable"))
}
checkSelfType(node)
}
if (!insideTypeHint) {
@@ -231,6 +232,27 @@ class PyTypeHintsInspection : PyInspection() {
}
}
private fun checkSelfType(node: PyReferenceExpression) {
if (resolvesToAnyOfQualifiedNames(node, PyTypingTypeProvider.SELF, PyTypingTypeProvider.SELF_EXT)) {
val selfType = Ref.deref(PyTypingTypeProvider.getType(node, myTypeEvalContext)) as? PySelfType
if (selfType == null) { // we don't infer Self type outside a class
registerProblem(node, PyPsiBundle.message("INSP.type.hints.self.use.outside.class"))
return
}
else {
val argList = PsiTreeUtil.getParentOfType(node, PyArgumentList::class.java)
if (argList != null && argList.parent is PyClass) {
registerProblem(node, PyPsiBundle.message("INSP.type.hints.self.cannot.use.self.in.this.context"))
return
}
if (selfType.scopeClassType.getAncestorTypes(myTypeEvalContext)
.contains(PyBuiltinCache.getInstance(node).typeType?.toClass())) {
registerProblem(node, PyPsiBundle.message("INSP.type.hints.self.cannot.use.self.in.metaclass"))
}
}
}
}
private fun isGenericTypeArgument(node: PyReferenceExpression): Boolean {
var element: PyElement = node
var parentElement = element.parent
@@ -326,11 +348,6 @@ class PyTypeHintsInspection : PyInspection() {
}
}
val classParent = PsiTreeUtil.getParentOfType(node, PyClass::class.java)
if (classParent == null) {
registerProblemForSelves(PyPsiBundle.message("INSP.type.hints.self.use.outside.class"))
}
val functionParent = PsiTreeUtil.getParentOfType(node, PyFunction::class.java)
if (functionParent != null) {
if (PyAstFunction.Modifier.STATICMETHOD == functionParent.modifier && PyNames.NEW != functionParent.name) {
-1
View File
@@ -26,7 +26,6 @@ generics_base_class.py
generics_paramspec_components.py
generics_paramspec_semantics.py
generics_self_attributes.py
generics_self_usage.py
generics_syntax_infer_variance.py
generics_typevartuple_basic.py
generics_typevartuple_overloads.py
@@ -3156,6 +3156,43 @@ public class PyTypeHintsInspectionTest extends PyInspectionTestCase {
doMultiFileTest();
}
// PY-76832
public void testTypeSelfAsTypeArg() {
doTestByText("""
from typing import TypeAlias, Self
TupleSelf: TypeAlias = tuple[<warning descr="Cannot use 'Self' outside class">Self</warning>] # E
class A[T]: ...
a = A[<warning descr="Cannot use 'Self' outside class">Self</warning>]() # E
class B:
def __init__(self):
self.l: List[Self] = [] # OK
""");
}
// PY-76832
public void testTypeSelfInBaseClassTypeArgs() {
doTestByText("""
from typing import Self
class Bar[T]: ...
class Baz(Bar[<warning descr="Cannot use 'Self' in this context">Self</warning>]): ... # E
""");
}
// PY-76832
public void testTypeSelfInMetaclass() {
doTestByText("""
from typing import Self, Any
class MyMetaclass(type):
def __new__(cls, *args: Any) -> <warning descr="Type 'Self' cannot be used in a metaclass">Self</warning>: # E
...
def __mul__(cls, count: int) -> list[<warning descr="Type 'Self' cannot be used in a metaclass">Self</warning>]: # E
...
""");
}
// PY-84289
public void testExponentialAnalysisTimeWhenMapLookupKeyEqualsVariableName() {