mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Warn about non-outer most Final (PEP 591) (PY-34945)
GitOrigin-RevId: 57be34d3f7d6574ade00be2cbef34228cdf3a882
This commit is contained in:
committed by
intellij-monorepo-bot
parent
67a0f2f9c0
commit
9709256ca6
@@ -5,8 +5,10 @@ import com.intellij.codeInspection.LocalInspectionToolSession
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.intellij.psi.impl.source.resolve.FileContextUtil
|
||||
import com.jetbrains.python.codeInsight.functionTypeComments.psi.PyParameterTypeList
|
||||
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider
|
||||
import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider.getFunctionTypeAnnotation
|
||||
import com.jetbrains.python.documentation.doctest.PyDocstringFile
|
||||
import com.jetbrains.python.psi.*
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.TYPING_FINAL
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.TYPING_FINAL_EXT
|
||||
@@ -93,6 +95,23 @@ class PyFinalInspection : PyInspection() {
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitPyReferenceExpression(node: PyReferenceExpression) {
|
||||
super.visitPyReferenceExpression(node)
|
||||
|
||||
checkFinalIsOuterMost(node)
|
||||
}
|
||||
|
||||
private fun checkFinalIsOuterMost(node: PyReferenceExpression) {
|
||||
if (isTopLevelInAnnotationOrTypeComment(node)) return
|
||||
(node.parent as? PySubscriptionExpression)?.let {
|
||||
if (it.operand == node && isTopLevelInAnnotationOrTypeComment(it)) return
|
||||
}
|
||||
|
||||
if (PyTypingTypeProvider.isInAnnotationOrTypeComment(node) && resolvesToFinal(node)) {
|
||||
registerProblem(node, "'Final' could only be used as the outermost type")
|
||||
}
|
||||
}
|
||||
|
||||
private fun isFinal(decoratable: PyDecoratable): Boolean {
|
||||
return PyKnownDecoratorUtil.getKnownDecorators(decoratable, myTypeEvalContext).any { it == TYPING_FINAL || it == TYPING_FINAL_EXT }
|
||||
}
|
||||
@@ -120,5 +139,12 @@ class PyFinalInspection : PyInspection() {
|
||||
val file = FileContextUtil.getContextFile(node) ?: return null
|
||||
return PyUtil.createExpressionFromFragment(typeComment, file)
|
||||
}
|
||||
|
||||
private fun isTopLevelInAnnotationOrTypeComment(node: PyExpression): Boolean {
|
||||
if (node.parent is PyAnnotation) return true
|
||||
if (node.parent is PyExpressionStatement && node.parent.parent is PyDocstringFile) return true
|
||||
if (node.parent is PyParameterTypeList) return true
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -142,6 +142,26 @@ public class PyFinalInspectionTest extends PyInspectionTestCase {
|
||||
);
|
||||
}
|
||||
|
||||
// PY-34945
|
||||
public void testOuterMostFinal() {
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON36,
|
||||
() -> doTestByText("from typing_extensions import Final\n" +
|
||||
"\n" +
|
||||
"a1: Final[int] = 10\n" +
|
||||
"b1: List[<warning descr=\"'Final' could only be used as the outermost type\">Final</warning>[int]] = []\n" +
|
||||
"\n" +
|
||||
"a2 = 10 # type: Final[int]\n" +
|
||||
"b2 = [] # type: List[<warning descr=\"'Final' could only be used as the outermost type\">Final</warning>[int]]\n" +
|
||||
"\n" +
|
||||
"a3: Final = 10\n" +
|
||||
"b3: List[<warning descr=\"'Final' could only be used as the outermost type\">Final</warning>] = []\n" +
|
||||
"\n" +
|
||||
"a4 = 10 # type: Final\n" +
|
||||
"b4 = [] # type: List[<warning descr=\"'Final' could only be used as the outermost type\">Final</warning>]")
|
||||
);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
Reference in New Issue
Block a user