mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
Support abc.abstractstaticmethod and abc.abstractclassmethod (PY-14896)
Modifier inference for functions decorated with these decorators was fixed. Usages of these decorators are highlighted as deprecated.
This commit is contained in:
@@ -22,15 +22,12 @@ import com.intellij.lang.ASTNode;
|
||||
import com.intellij.psi.PsiElement;
|
||||
import com.intellij.psi.PsiElementVisitor;
|
||||
import com.intellij.psi.util.PsiTreeUtil;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator;
|
||||
import org.jetbrains.annotations.Nls;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Arrays;
|
||||
|
||||
/**
|
||||
* @author yole
|
||||
*/
|
||||
@@ -87,23 +84,34 @@ public class PyDeprecationInspection extends PyInspection {
|
||||
|
||||
final PyDecoratorList decoratorList = node.getDecoratorList();
|
||||
if (!LanguageLevel.forElement(node).isPython2() && decoratorList != null) {
|
||||
Arrays
|
||||
.stream(decoratorList.getDecorators())
|
||||
.filter(
|
||||
decorator -> PyKnownDecoratorUtil.asKnownDecorators(decorator, myTypeEvalContext).contains(KnownDecorator.ABC_ABSTRACTPROPERTY)
|
||||
)
|
||||
.forEach(
|
||||
decorator -> {
|
||||
final QualifiedName abcAbsPropertyQName = KnownDecorator.ABC_ABSTRACTPROPERTY.getQualifiedName();
|
||||
final QualifiedName propertyQName = KnownDecorator.PROPERTY.getQualifiedName();
|
||||
final QualifiedName abcAbsMethodQName = KnownDecorator.ABC_ABSTRACTMETHOD.getQualifiedName();
|
||||
for (PyDecorator decorator : decoratorList.getDecorators()) {
|
||||
for (KnownDecorator knownDecorator : PyKnownDecoratorUtil.asKnownDecorators(decorator, myTypeEvalContext)) {
|
||||
final KnownDecorator deprecated;
|
||||
final KnownDecorator builtin;
|
||||
|
||||
final String message = "'" + abcAbsPropertyQName + "' is deprecated since Python 3.3. " +
|
||||
"Use '" + propertyQName + "' with '" + abcAbsMethodQName + "' instead.";
|
||||
|
||||
registerProblem(decorator, message, ProblemHighlightType.LIKE_DEPRECATED);
|
||||
if (knownDecorator == KnownDecorator.ABC_ABSTRACTPROPERTY) {
|
||||
deprecated = KnownDecorator.ABC_ABSTRACTPROPERTY;
|
||||
builtin = KnownDecorator.PROPERTY;
|
||||
}
|
||||
);
|
||||
else if (knownDecorator == KnownDecorator.ABC_ABSTRACTCLASSMETHOD) {
|
||||
deprecated = KnownDecorator.ABC_ABSTRACTCLASSMETHOD;
|
||||
builtin = KnownDecorator.CLASSMETHOD;
|
||||
}
|
||||
else if (knownDecorator == KnownDecorator.ABC_ABSTRACTSTATICMETHOD) {
|
||||
deprecated = KnownDecorator.ABC_ABSTRACTSTATICMETHOD;
|
||||
builtin = KnownDecorator.STATICMETHOD;
|
||||
}
|
||||
else {
|
||||
continue;
|
||||
}
|
||||
|
||||
final KnownDecorator abcAbsMethod = KnownDecorator.ABC_ABSTRACTMETHOD;
|
||||
final String message = "'" + deprecated.getQualifiedName() + "' is deprecated since Python 3.3. " +
|
||||
"Use '" + builtin.getQualifiedName() + "' with '" + abcAbsMethod.getQualifiedName() + "' instead.";
|
||||
|
||||
registerProblem(decorator, message, ProblemHighlightType.LIKE_DEPRECATED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -673,6 +673,12 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
|
||||
if (PyNames.CLASS_GETITEM.equals(funcName) && level.isAtLeast(LanguageLevel.PYTHON37)) {
|
||||
return CLASSMETHOD;
|
||||
}
|
||||
|
||||
final TypeEvalContext context = TypeEvalContext.codeInsightFallback(getProject());
|
||||
for (PyKnownDecoratorUtil.KnownDecorator knownDecorator : PyKnownDecoratorUtil.getKnownDecorators(this, context)) {
|
||||
if (knownDecorator == PyKnownDecoratorUtil.KnownDecorator.ABC_ABSTRACTCLASSMETHOD) return CLASSMETHOD;
|
||||
if (knownDecorator == PyKnownDecoratorUtil.KnownDecorator.ABC_ABSTRACTSTATICMETHOD) return STATICMETHOD;
|
||||
}
|
||||
}
|
||||
|
||||
final PyFunctionStub stub = getStub();
|
||||
|
||||
@@ -9,4 +9,16 @@ def abstractmethod(foo):
|
||||
|
||||
|
||||
def abstractproperty(foo):
|
||||
pass
|
||||
|
||||
|
||||
# Important:
|
||||
# classes below are not presented in Python 2
|
||||
# they were added just for PyDeprecationTest#testAbcDeprecatedAbstracts
|
||||
# to not create separate test case for them
|
||||
class abstractstaticmethod(staticmethod):
|
||||
pass
|
||||
|
||||
|
||||
class abstractclassmethod(classmethod):
|
||||
pass
|
||||
+10
@@ -31,4 +31,14 @@ import abc as foo
|
||||
class D(metaclass=abc.ABCMeta):
|
||||
<warning descr="'abc.abstractproperty' is deprecated since Python 3.3. Use 'property' with 'abc.abstractmethod' instead.">@foo.abstractproperty</warning>
|
||||
def prop(self):
|
||||
pass
|
||||
|
||||
|
||||
class A:
|
||||
<warning descr="'abc.abstractclassmethod' is deprecated since Python 3.3. Use 'classmethod' with 'abc.abstractmethod' instead.">@abc.abstractclassmethod</warning>
|
||||
def foo(cls):
|
||||
pass
|
||||
|
||||
<warning descr="'abc.abstractstaticmethod' is deprecated since Python 3.3. Use 'staticmethod' with 'abc.abstractmethod' instead.">@abc.abstractstaticmethod</warning>
|
||||
def bar():
|
||||
pass
|
||||
+11
@@ -0,0 +1,11 @@
|
||||
import abc
|
||||
|
||||
|
||||
class A:
|
||||
@abc.abstractclassmethod
|
||||
def foo(cls):
|
||||
pass
|
||||
|
||||
@abc.abstractstaticmethod
|
||||
def bar():
|
||||
pass
|
||||
@@ -78,12 +78,12 @@ public class PyDeprecationTest extends PyTestCase {
|
||||
myFixture.checkHighlighting(true, false, false);
|
||||
}
|
||||
|
||||
public void testAbsAbstractProperty() {
|
||||
public void testAbcDeprecatedAbstracts() {
|
||||
runWithLanguageLevel(
|
||||
LanguageLevel.PYTHON34,
|
||||
() -> {
|
||||
myFixture.enableInspections(PyDeprecationInspection.class);
|
||||
myFixture.configureByFile("deprecation/abcAbstractProperty.py");
|
||||
myFixture.configureByFile("deprecation/abcDeprecatedAbstracts.py");
|
||||
myFixture.checkHighlighting(true, false, false);
|
||||
}
|
||||
);
|
||||
|
||||
@@ -58,6 +58,11 @@ public class PythonInspectionsTest extends PyTestCase {
|
||||
doHighlightingTest(PyMethodParametersInspection.class, LanguageLevel.PYTHON37);
|
||||
}
|
||||
|
||||
// PY-14896
|
||||
public void testPyMethodParametersInspectionAbstractClassAndStaticMethods() {
|
||||
doHighlightingTest(PyMethodParametersInspection.class, LanguageLevel.PYTHON34);
|
||||
}
|
||||
|
||||
public void testPyNestedDecoratorsInspection() {
|
||||
LocalInspectionTool inspection = new PyNestedDecoratorsInspection();
|
||||
doTest(getTestName(false), inspection);
|
||||
|
||||
Reference in New Issue
Block a user