mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Warn incorrect usages of @overload and @final (PEP 591) (PY-34945)
GitOrigin-RevId: fd9c3acc6b67d9ac1c46512573df3e936c683e29
This commit is contained in:
committed by
intellij-monorepo-bot
parent
c61d1c4e84
commit
b5fe834814
@@ -10,6 +10,7 @@ import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.TYPING_FINAL
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.TYPING_FINAL_EXT
|
||||
import com.jetbrains.python.psi.search.PySuperMethodsSearch
|
||||
import com.jetbrains.python.psi.types.PyClassType
|
||||
import com.jetbrains.python.pyi.PyiUtil
|
||||
|
||||
class PyFinalInspection : PyInspection() {
|
||||
|
||||
@@ -28,6 +29,21 @@ class PyFinalInspection : PyInspection() {
|
||||
registerProblem(it, "'${cls.name}' is marked as '@final' and should not be subclassed")
|
||||
}
|
||||
}
|
||||
|
||||
if (PyiUtil.isInsideStub(node)) {
|
||||
val visitedNames = mutableSetOf<String?>()
|
||||
|
||||
node.visitMethods(
|
||||
{ m ->
|
||||
if (!visitedNames.add(m.name) && isFinal(m)) {
|
||||
registerProblem(m.nameIdentifier, "'@final' should be placed on the first overload")
|
||||
}
|
||||
true
|
||||
},
|
||||
false,
|
||||
myTypeEvalContext
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitPyFunction(node: PyFunction) {
|
||||
@@ -40,6 +56,10 @@ class PyFinalInspection : PyInspection() {
|
||||
?.let {
|
||||
registerProblem(node.nameIdentifier, "'${(it as PyFunction).qualifiedName}' is marked as '@final' and should not be overridden")
|
||||
}
|
||||
|
||||
if (!PyiUtil.isInsideStub(node) && isFinal(node) && PyiUtil.isOverload(node, myTypeEvalContext)) {
|
||||
registerProblem(node.nameIdentifier, "'@final' should be placed on the implementation")
|
||||
}
|
||||
}
|
||||
else if (isFinal(node)) {
|
||||
registerProblem(node.nameIdentifier, "Non-method function could not be marked as '@final'")
|
||||
|
||||
@@ -0,0 +1,18 @@
|
||||
from typing import overload
|
||||
from typing_extensions import final
|
||||
|
||||
class A:
|
||||
@final
|
||||
@overload
|
||||
def foo(self, a: int) -> int: ...
|
||||
|
||||
@overload
|
||||
def foo(self, a: str) -> str: ...
|
||||
|
||||
class B:
|
||||
@overload
|
||||
def foo(self, a: int) -> int: ...
|
||||
|
||||
@final
|
||||
@overload
|
||||
def <warning descr="'@final' should be placed on the first overload">foo</warning>(self, a: str) -> str: ...
|
||||
@@ -1,6 +1,7 @@
|
||||
// Copyright 2000-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
|
||||
package com.jetbrains.python.inspections;
|
||||
|
||||
import com.intellij.psi.PsiFile;
|
||||
import com.jetbrains.python.fixtures.PyInspectionTestCase;
|
||||
import com.jetbrains.python.psi.LanguageLevel;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
@@ -84,6 +85,44 @@ public class PyFinalInspectionTest extends PyInspectionTestCase {
|
||||
);
|
||||
}
|
||||
|
||||
// PY-34945
|
||||
public void testOverloadedFinalMethod() {
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON35,
|
||||
() -> doTestByText("from typing import overload\n" +
|
||||
"from typing_extensions import final\n" +
|
||||
"\n" +
|
||||
"class A:\n" +
|
||||
" @overload\n" +
|
||||
" def foo(self, a: int) -> int: ...\n" +
|
||||
"\n" +
|
||||
" @overload\n" +
|
||||
" def foo(self, a: str) -> str: ...\n" +
|
||||
"\n" +
|
||||
" @final\n" +
|
||||
" def foo(self, a):\n" +
|
||||
" pass\n" +
|
||||
"\n" +
|
||||
"class B:\n" +
|
||||
" @final\n" +
|
||||
" @overload\n" +
|
||||
" def <warning descr=\"'@final' should be placed on the implementation\">foo</warning>(self, a: int) -> int: ...\n" +
|
||||
"\n" +
|
||||
" @overload\n" +
|
||||
" def foo(self, a: str) -> str: ...\n" +
|
||||
"\n" +
|
||||
" def foo(self, a):\n" +
|
||||
" pass\n")
|
||||
);
|
||||
}
|
||||
|
||||
// PY-34945
|
||||
public void testOverloadedFinalMethodInStub() {
|
||||
final PsiFile currentFile = myFixture.configureByFile(getTestFilePath() + "i");
|
||||
configureInspection();
|
||||
assertSdkRootsNotParsed(currentFile);
|
||||
}
|
||||
|
||||
@NotNull
|
||||
@Override
|
||||
protected Class<? extends PyInspection> getInspectionClass() {
|
||||
|
||||
Reference in New Issue
Block a user