mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-86019 [python]: show error when class pattern uses non-class type
GitOrigin-RevId: 1e0d0926155459d3112bf921967a822073f327f8
This commit is contained in:
committed by
intellij-monorepo-bot
parent
9beeab25eb
commit
f2b7fcd315
@@ -1373,6 +1373,7 @@ INSP.patterns.pattern.can.be.simplified=Pattern can be simplified
|
||||
INSP.patterns.class.does.not.support.pattern.matching.with.positional.arguments=Class {0} does not support pattern matching with positional arguments
|
||||
INSP.patterns.too.many.positional.patterns.expected=Too many positional patterns, expected {0}
|
||||
INSP.patterns.attribute.already.specified.as.positional.pattern.at.position=Attribute ''{0}'' is already specified as positional pattern at position {1}
|
||||
INSP.patterns.not.a.class=Class pattern requires a class, but ''{0}'' can be ''{1}''
|
||||
QFIX.simplify.as.pattern=Simplify 'as' pattern
|
||||
QFIX.NAME.remove.element=Remove element
|
||||
QFIX.remove.pattern=Remove pattern
|
||||
|
||||
@@ -15,10 +15,7 @@ import com.jetbrains.python.psi.*
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache
|
||||
import com.jetbrains.python.psi.impl.PyClassPatternImpl
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils
|
||||
import com.jetbrains.python.psi.types.PyClassType
|
||||
import com.jetbrains.python.psi.types.PyTupleType
|
||||
import com.jetbrains.python.psi.types.PyTypeChecker
|
||||
import com.jetbrains.python.psi.types.TypeEvalContext
|
||||
import com.jetbrains.python.psi.types.*
|
||||
|
||||
class PyPatternInspection : PyInspection() {
|
||||
override fun buildVisitor(holder: ProblemsHolder, isOnTheFly: Boolean, session: LocalInspectionToolSession): PsiElementVisitor {
|
||||
@@ -49,7 +46,20 @@ private class PyPatternInspectionVisitor(holder: ProblemsHolder, context: TypeEv
|
||||
|
||||
|
||||
override fun visitPyClassPattern(node: PyClassPattern) {
|
||||
val classType = myTypeEvalContext.getType(node.classNameReference) as? PyClassType ?: return
|
||||
val type = myTypeEvalContext.getType(node.classNameReference)
|
||||
val types = PyTypeUtil.toStream(type).toList()
|
||||
if (types.isNotEmpty() && types.none { PyTypeChecker.isUnknown(it, myTypeEvalContext) }) {
|
||||
val invalidTypes = types.filter { it !is PyClassType || !it.isDefinition }
|
||||
if (invalidTypes.isNotEmpty()) {
|
||||
val invalidTypesUnion = PyUnionType.union(invalidTypes)
|
||||
val invalidTypeName = PythonDocumentationProvider.getTypeName(invalidTypesUnion, myTypeEvalContext)
|
||||
holder.problem(node.classNameReference,
|
||||
PyPsiBundle.message("INSP.patterns.not.a.class", node.classNameReference.text, invalidTypeName)).register()
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val classType = type as? PyClassType ?: return
|
||||
val pyClass = classType.pyClass
|
||||
if (pyClass.name in PyClassPattern.SPECIAL_BUILTINS) return
|
||||
|
||||
|
||||
@@ -323,6 +323,70 @@ def f(c):
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-86019
|
||||
public void testFunctionPattern() {
|
||||
doTestByText("""
|
||||
def f():
|
||||
pass
|
||||
|
||||
match 1:
|
||||
case <warning descr="Class pattern requires a class, but 'f' can be '() -> None'">f</warning>():
|
||||
pass
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-86019
|
||||
public void testInstancePattern() {
|
||||
doTestByText("""
|
||||
x = 1
|
||||
match 1:
|
||||
case <warning descr="Class pattern requires a class, but 'x' can be 'int'">x</warning>():
|
||||
pass
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-86019
|
||||
public void testUnionOfClassesPattern() {
|
||||
doTestByText("""
|
||||
class A: pass
|
||||
class B: pass
|
||||
|
||||
def g(cond):
|
||||
if cond:
|
||||
c = A
|
||||
else:
|
||||
c = B
|
||||
match 1:
|
||||
case c():
|
||||
pass
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-86019
|
||||
public void testUnionOfClassAndFunctionPattern() {
|
||||
doTestByText("""
|
||||
class A: pass
|
||||
def f(): pass
|
||||
|
||||
def g(cond):
|
||||
c = A if cond else f
|
||||
match 1:
|
||||
case <warning descr="Class pattern requires a class, but 'c' can be '() -> None'">c</warning>():
|
||||
pass
|
||||
""");
|
||||
}
|
||||
|
||||
// PY-86019
|
||||
public void testAnyPattern() {
|
||||
doTestByText("""
|
||||
from typing import Any
|
||||
def g(c: Any):
|
||||
match 1:
|
||||
case c():
|
||||
pass
|
||||
""");
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
Reference in New Issue
Block a user