diff --git a/python/python-ast/src/com/jetbrains/python/ast/impl/PyDeprecationUtil.kt b/python/python-ast/src/com/jetbrains/python/ast/impl/PyDeprecationUtil.kt deleted file mode 100644 index ca15b04a16f9..000000000000 --- a/python/python-ast/src/com/jetbrains/python/ast/impl/PyDeprecationUtil.kt +++ /dev/null @@ -1,21 +0,0 @@ -package com.jetbrains.python.ast.impl - -import com.jetbrains.python.ast.PyAstDecoratable -import com.jetbrains.python.ast.PyAstStringLiteralExpression - -val deprecatedDecoratorContainers = arrayOf("typing_extensions.pyi", "warnings.pyi") - -fun extractDeprecationMessageFromDecorator(element: PyAstDecoratable): String? { - val deprecatedDecorator = element.decoratorList?.decorators?.firstOrNull { it.name == "deprecated" } ?: return null - val annotationClass = deprecatedDecorator.callee?.reference?.resolve() ?: return null - if (annotationClass.containingFile?.name !in deprecatedDecoratorContainers) { - return null - } - - if (deprecatedDecorator.arguments.isEmpty()) { - return null - } - - val argument = deprecatedDecorator.arguments[0] as? PyAstStringLiteralExpression ?: return null - return argument.stringValue -} \ No newline at end of file diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyClass.java index ee0f40c4edc6..ff3dd65199e2 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyClass.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyClass.java @@ -36,8 +36,6 @@ import org.jetbrains.annotations.Nullable; import java.util.List; import java.util.Map; -import static com.jetbrains.python.ast.impl.PyDeprecationUtilKt.extractDeprecationMessageFromDecorator; - /** * Represents a class declaration in source. */ @@ -369,12 +367,6 @@ public interface PyClass extends PyAstClass, PsiNameIdentifierOwner, PyCompoundS @Nullable PyClassLikeType getType(@NotNull TypeEvalContext context); - @Nullable - @Override - default String getDeprecationMessage() { - return extractDeprecationMessageFromDecorator(this); - } - @Override @Nullable default PyStringLiteralExpression getDocStringExpression() { diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyDeprecatable.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyDeprecatable.java index a05e4431c50e..e5bae8eac524 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyDeprecatable.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyDeprecatable.java @@ -5,5 +5,5 @@ import org.jetbrains.annotations.Nullable; public interface PyDeprecatable { @Nullable - String getDeprecationMessage(); + default String getDeprecationMessage() { return null; } } diff --git a/python/python-psi-api/src/com/jetbrains/python/psi/PyFunction.java b/python/python-psi-api/src/com/jetbrains/python/psi/PyFunction.java index c0699b996b99..e168159fab2c 100644 --- a/python/python-psi-api/src/com/jetbrains/python/psi/PyFunction.java +++ b/python/python-psi-api/src/com/jetbrains/python/psi/PyFunction.java @@ -14,10 +14,8 @@ import com.jetbrains.python.psi.types.TypeEvalContext; import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; -import java.util.Arrays; import java.util.List; -import static com.jetbrains.python.ast.impl.PyDeprecationUtilKt.extractDeprecationMessageFromDecorator; /** * Function declaration in source (the {@code def} and everything within). @@ -72,27 +70,6 @@ public interface PyFunction extends PyAstFunction, StubBasedPsiElement statements) { for (PyAstStatement statement : statements) { if (statement instanceof PyAstExpressionStatement expressionStatement) { diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 82b30ba27d4e..64e9a7a11341 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -56,6 +56,7 @@ import java.util.*; import static com.intellij.openapi.util.text.StringUtil.join; import static com.intellij.openapi.util.text.StringUtil.notNullize; import static com.jetbrains.python.psi.PyUtil.as; +import static com.jetbrains.python.psi.impl.PyDeprecationUtilKt.extractDeprecationMessageFromDecorator; public class PyClassImpl extends PyBaseElementImpl implements PyClass { @@ -1311,7 +1312,7 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla if (stub != null) { return stub.getDeprecationMessage(); } - return PyClass.super.getDeprecationMessage(); + return extractDeprecationMessageFromDecorator(this); } @Nullable diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDeprecationUtil.kt b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDeprecationUtil.kt new file mode 100644 index 000000000000..f08caaa97400 --- /dev/null +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyDeprecationUtil.kt @@ -0,0 +1,25 @@ +package com.jetbrains.python.psi.impl + +import com.jetbrains.python.ast.PyAstDecoratable +import com.jetbrains.python.ast.PyAstStringLiteralExpression +import com.jetbrains.python.psi.PyFromImportStatement +import com.jetbrains.python.psi.PyReferenceExpression +import com.jetbrains.python.psi.resolve.PyResolveUtil + +val deprecationDecorators = arrayOf("typing_extensions.deprecated", "warnings.deprecated") + +fun extractDeprecationMessageFromDecorator(element: PyAstDecoratable): String? { + val deprecatedDecorator = element.decoratorList?.decorators?.firstOrNull { it.name == "deprecated" } ?: return null + if (deprecatedDecorator.arguments.isEmpty()) { + return null + } + val decoratorCall = deprecatedDecorator.callee as? PyReferenceExpression ?: return null + if (decoratorCall.asQualifiedName()?.toString() !in deprecationDecorators) { + if (!PyResolveUtil.resolveLocally(decoratorCall).mapNotNull { it.parent as? PyFromImportStatement }. + flatMap { it.fullyQualifiedObjectNames }.any { it in deprecationDecorators }) { + return null + } + } + + return (deprecatedDecorator.arguments[0] as? PyAstStringLiteralExpression)?.stringValue +} \ No newline at end of file diff --git a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java index 746a79c0e3b9..3d75aa718aee 100644 --- a/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java +++ b/python/python-psi-impl/src/com/jetbrains/python/psi/impl/PyFunctionImpl.java @@ -46,6 +46,7 @@ import static com.jetbrains.python.ast.PyAstFunction.Modifier.CLASSMETHOD; import static com.jetbrains.python.ast.PyAstFunction.Modifier.STATICMETHOD; import static com.jetbrains.python.psi.PyUtil.as; import static com.jetbrains.python.psi.impl.PyCallExpressionHelper.interpretAsModifierWrappingCall; +import static com.jetbrains.python.psi.impl.PyDeprecationUtilKt.extractDeprecationMessageFromDecorator; public class PyFunctionImpl extends PyBaseElementImpl implements PyFunction { @@ -349,7 +350,17 @@ public class PyFunctionImpl extends PyBaseElementImpl implements if (stub != null) { return stub.getDeprecationMessage(); } - return PyFunction.super.getDeprecationMessage(); + return extractDeprecationMessage(); + } + + @Nullable + public String extractDeprecationMessage() { + String deprecationMessageFromDecorator = extractDeprecationMessageFromDecorator(this); + if (deprecationMessageFromDecorator != null) { + return deprecationMessageFromDecorator; + } + PyStatementList statementList = getStatementList(); + return PyFunction.extractDeprecationMessage(Arrays.asList(statementList.getStatements())); } @Override diff --git a/python/testData/deprecation/fqnDeprecation.py b/python/testData/deprecation/fqnDeprecation.py new file mode 100644 index 000000000000..8997806b6204 --- /dev/null +++ b/python/testData/deprecation/fqnDeprecation.py @@ -0,0 +1,8 @@ +import warnings + +@warnings.deprecated("deprecated") +class MyClass: + pass + + +var = MyClass() diff --git a/python/testSrc/com/jetbrains/python/PyDeprecationTest.java b/python/testSrc/com/jetbrains/python/PyDeprecationTest.java index 699a1cfd05e5..9430c79c132b 100644 --- a/python/testSrc/com/jetbrains/python/PyDeprecationTest.java +++ b/python/testSrc/com/jetbrains/python/PyDeprecationTest.java @@ -90,6 +90,12 @@ public class PyDeprecationTest extends PyTestCase { myFixture.checkHighlighting(true, false, false); } + public void testFqnDecorator() { + myFixture.enableInspections(PyDeprecationInspection.class); + myFixture.configureByFile("deprecation/fqnDeprecation.py"); + myFixture.checkHighlighting(true, false, false); + } + public void testDeprecatedMethod() { myFixture.enableInspections(PyDeprecationInspection.class); myFixture.configureByFile("deprecation/deprecatedMethod.py");