mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-27 10:03:11 +07:00
PY-46623 Refactor PyKnownDecorator and related classes to be extendable
PyKnownDecorator is now a class instead of an enum, allowing extension to create new instances GitOrigin-RevId: 846617f68e559f7f77af15a999f837391ac3090e
This commit is contained in:
committed by
intellij-monorepo-bot
parent
3df8d77318
commit
bf6e4735b6
@@ -1,13 +0,0 @@
|
||||
// Copyright 2000-2021 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.psi;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
|
||||
public interface PyKnownDecoratorProvider {
|
||||
ExtensionPointName<PyKnownDecoratorProvider> EP_NAME = ExtensionPointName.create("Pythonid.knownDecoratorProvider");
|
||||
|
||||
@Nullable
|
||||
String toKnownDecorator(String decoratorName);
|
||||
}
|
||||
@@ -539,6 +539,7 @@
|
||||
<inspectionExtension implementation="com.jetbrains.python.pyi.PyiInspectionExtension"/>
|
||||
<inspectionExtension implementation="com.jetbrains.python.codeInsight.typing.PyTypingInspectionExtension"/>
|
||||
<customPackageIdentifier implementation="com.jetbrains.python.pyi.PyiCustomPackageIdentifier"/>
|
||||
<knownDecoratorProvider implementation="com.jetbrains.python.psi.PyStdKnownDecoratorProvider"/>
|
||||
|
||||
<!-- IPython -->
|
||||
<pyReferenceResolveProvider implementation="com.jetbrains.python.psi.resolve.PyIPythonBuiltinReferenceResolveProvider"/>
|
||||
|
||||
@@ -12,7 +12,7 @@ import com.jetbrains.python.codeInsight.PyDataclassParameters.Type
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil
|
||||
import com.jetbrains.python.psi.*
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator
|
||||
import com.jetbrains.python.psi.PyKnownDecorator
|
||||
import com.jetbrains.python.psi.impl.PyCallExpressionHelper
|
||||
import com.jetbrains.python.psi.impl.PyEvaluator
|
||||
import com.jetbrains.python.psi.impl.StubAwareComputation
|
||||
@@ -120,17 +120,17 @@ object PyDataclassNames {
|
||||
* determine what settings dataclass has.
|
||||
*/
|
||||
private val DECORATOR_AND_TYPE_AND_PARAMETERS = listOf(
|
||||
Triple(KnownDecorator.DATACLASSES_DATACLASS, PyDataclassParameters.PredefinedType.STD, PyDataclassNames.Dataclasses.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTR_S, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTR_ATTRS, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTR_ATTRIBUTES, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTR_DATACLASS, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTR_DEFINE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTR_MUTABLE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTR_FROZEN, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTRS_DEFINE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTRS_MUTABLE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(KnownDecorator.ATTRS_FROZEN, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.DATACLASSES_DATACLASS, PyDataclassParameters.PredefinedType.STD, PyDataclassNames.Dataclasses.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTR_S, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTR_ATTRS, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTR_ATTRIBUTES, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTR_DATACLASS, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTR_DEFINE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTR_MUTABLE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTR_FROZEN, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTRS_DEFINE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTRS_MUTABLE, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
Triple(PyKnownDecorator.ATTRS_FROZEN, PyDataclassParameters.PredefinedType.ATTRS, PyDataclassNames.Attrs.DECORATOR_PARAMETERS),
|
||||
)
|
||||
|
||||
fun parseStdDataclassParameters(cls: PyClass, context: TypeEvalContext): PyDataclassParameters? {
|
||||
@@ -521,7 +521,7 @@ private fun resolveDataclassParameters(
|
||||
PyDataclassParameters.PredefinedType.ATTRS -> {
|
||||
// TODO remove this hack, make it a proper field
|
||||
val extraArguments = mutableMapOf<String, PyExpression>()
|
||||
if (type.asPredefinedType == PyDataclassParameters.PredefinedType.ATTRS && stub.decoratorName() == KnownDecorator.ATTR_DATACLASS.qualifiedName) {
|
||||
if (type.asPredefinedType == PyDataclassParameters.PredefinedType.ATTRS && stub.decoratorName() == PyKnownDecorator.ATTR_DATACLASS.qualifiedName) {
|
||||
extraArguments["auto_attribs"] =
|
||||
PyElementGenerator.getInstance(pyClass.project).createExpressionFromText(LanguageLevel.forElement(pyClass), PyNames.TRUE)
|
||||
}
|
||||
|
||||
+2
-1
@@ -5,6 +5,7 @@ import com.intellij.psi.PsiElement
|
||||
import com.intellij.psi.util.QualifiedName
|
||||
import com.intellij.util.containers.ContainerUtil
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil
|
||||
import com.jetbrains.python.psi.PyKnownDecorator
|
||||
import com.jetbrains.python.psi.PyCallable
|
||||
import com.jetbrains.python.psi.PyFunction
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil
|
||||
@@ -35,7 +36,7 @@ class PyFunctoolsWrapsDecoratedFunctionTypeProvider : PyTypeProviderBase() {
|
||||
private fun resolveWrapped(function: PyFunction, context: TypeEvalContext): List<PsiElement> {
|
||||
val decorator = function.decoratorList?.decorators?.find {
|
||||
val qName = it.qualifiedName
|
||||
qName != null && PyKnownDecoratorUtil.asKnownDecorators(qName).contains(PyKnownDecoratorUtil.KnownDecorator.FUNCTOOLS_WRAPS)
|
||||
qName != null && PyKnownDecoratorUtil.asKnownDecorators(qName).contains(PyKnownDecorator.FUNCTOOLS_WRAPS)
|
||||
} ?: return emptyList()
|
||||
return StubAwareComputation.on(decorator)
|
||||
.withCustomStub { it.getCustomStub(PyFunctoolsWrapsDecoratorStub::class.java) }
|
||||
|
||||
+2
-2
@@ -11,7 +11,7 @@ import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil;
|
||||
import com.jetbrains.python.psi.*;
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator;
|
||||
import com.jetbrains.python.psi.PyKnownDecorator;
|
||||
import com.jetbrains.python.psi.impl.PyBuiltinCache;
|
||||
import com.jetbrains.python.psi.impl.PyTypeProvider;
|
||||
import com.jetbrains.python.psi.impl.stubs.PyEnumAttributeStubType;
|
||||
@@ -301,7 +301,7 @@ public final class PyStdlibTypeProvider extends PyTypeProviderBase {
|
||||
}
|
||||
|
||||
private static boolean isEnumMember(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
||||
return PyKnownDecoratorUtil.getKnownDecorators(decoratable, context).contains(KnownDecorator.ENUM_MEMBER);
|
||||
return PyKnownDecoratorUtil.getKnownDecorators(decoratable, context).contains(PyKnownDecorator.ENUM_MEMBER);
|
||||
}
|
||||
|
||||
private static @Nullable PyType getEnumAutoConstructorType(@NotNull PsiElement target,
|
||||
|
||||
+3
-3
@@ -50,8 +50,8 @@ import java.util.regex.Pattern;
|
||||
import java.util.stream.Stream;
|
||||
|
||||
import static com.intellij.openapi.util.RecursionManager.doPreventingRecursion;
|
||||
import static com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.TYPING_FINAL;
|
||||
import static com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.TYPING_FINAL_EXT;
|
||||
import static com.jetbrains.python.psi.PyKnownDecorator.TYPING_FINAL;
|
||||
import static com.jetbrains.python.psi.PyKnownDecorator.TYPING_FINAL_EXT;
|
||||
import static com.jetbrains.python.psi.PyUtil.as;
|
||||
|
||||
public final class PyTypingTypeProvider extends PyTypeProviderWithCustomContext<PyTypingTypeProvider.Context> {
|
||||
@@ -187,7 +187,7 @@ public static final String CONTEXT_MANAGER = "contextlib.AbstractContextManager"
|
||||
* some synthetic values.
|
||||
*/
|
||||
public static final ImmutableSet<String> OPAQUE_NAMES = ImmutableSet.<String>builder()
|
||||
.add(PyKnownDecoratorUtil.KnownDecorator.TYPING_OVERLOAD.name())
|
||||
.add(PyKnownDecorator.TYPING_OVERLOAD.getQualifiedName().toString())
|
||||
.add(ANY)
|
||||
.add(TYPE_VAR)
|
||||
.add(TYPE_VAR_EXT)
|
||||
|
||||
+3
-2
@@ -5,6 +5,7 @@ import com.intellij.codeInspection.LocalInspectionToolSession
|
||||
import com.intellij.codeInspection.ProblemsHolder
|
||||
import com.intellij.psi.PsiElementVisitor
|
||||
import com.jetbrains.python.PyPsiBundle
|
||||
import com.jetbrains.python.psi.PyKnownDecorator
|
||||
import com.jetbrains.python.psi.PyFunction
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil
|
||||
import com.jetbrains.python.psi.search.PySuperMethodsSearch
|
||||
@@ -23,8 +24,8 @@ class PyOverridesInspection : PyInspection() {
|
||||
super.visitPyFunction(node)
|
||||
|
||||
if (!PyKnownDecoratorUtil.getKnownDecorators(node, myTypeEvalContext)
|
||||
.any { it == PyKnownDecoratorUtil.KnownDecorator.TYPING_OVERRIDE ||
|
||||
it == PyKnownDecoratorUtil.KnownDecorator.TYPING_EXTENSIONS_OVERRIDE }) {
|
||||
.any { it == PyKnownDecorator.TYPING_OVERRIDE ||
|
||||
it == PyKnownDecorator.TYPING_EXTENSIONS_OVERRIDE }) {
|
||||
return
|
||||
}
|
||||
|
||||
|
||||
@@ -12,7 +12,7 @@ import com.jetbrains.python.codeInsight.typing.PyTypingTypeProvider
|
||||
import com.jetbrains.python.codeInsight.typing.inspectProtocolSubclass
|
||||
import com.jetbrains.python.codeInsight.typing.isProtocol
|
||||
import com.jetbrains.python.psi.*
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.*
|
||||
import com.jetbrains.python.psi.PyKnownDecorator.*
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext
|
||||
import com.jetbrains.python.psi.resolve.PyResolveUtil
|
||||
import com.jetbrains.python.psi.resolve.RatedResolveResult
|
||||
|
||||
@@ -0,0 +1,182 @@
|
||||
package com.jetbrains.python.psi;
|
||||
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
|
||||
// TODO provide more information about these decorators: attributes (e.g. lru_cache(f).cache_info), side-effects etc.
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
public class PyKnownDecorator {
|
||||
private final QualifiedName myQualifiedName;
|
||||
private final boolean myIsProperty;
|
||||
private final boolean myIsMutableProperty;
|
||||
private final boolean myIsGeneratorBasedCoroutine;
|
||||
private final boolean myIsAbstract;
|
||||
private final boolean myIsClassMethod;
|
||||
private final boolean myIsStaticMethod;
|
||||
|
||||
public PyKnownDecorator(@NotNull String qualifiedName) {
|
||||
myQualifiedName = QualifiedName.fromDottedString(qualifiedName);
|
||||
myIsProperty = false;
|
||||
myIsMutableProperty = false;
|
||||
myIsGeneratorBasedCoroutine = false;
|
||||
myIsAbstract = false;
|
||||
myIsClassMethod = false;
|
||||
myIsStaticMethod = false;
|
||||
}
|
||||
|
||||
private PyKnownDecorator(@NotNull String qualifiedName, boolean isProperty, boolean isMutableProperty, boolean isGeneratorBasedCoroutine, boolean isAbstract,
|
||||
boolean isClassMethod,
|
||||
boolean isStaticMethod) {
|
||||
myQualifiedName = QualifiedName.fromDottedString(qualifiedName);
|
||||
myIsProperty = isProperty;
|
||||
myIsMutableProperty = isMutableProperty;
|
||||
myIsGeneratorBasedCoroutine = isGeneratorBasedCoroutine;
|
||||
myIsAbstract = isAbstract;
|
||||
myIsClassMethod = isClassMethod;
|
||||
myIsStaticMethod = isStaticMethod;
|
||||
}
|
||||
|
||||
public static class Builder {
|
||||
private boolean isProperty = false;
|
||||
private boolean isMutableProperty = false;
|
||||
private boolean isGeneratorBasedCoroutine = false;
|
||||
private boolean isAbstract = false;
|
||||
private boolean isClassMethod = false;
|
||||
private boolean isStaticMethod = false;
|
||||
private final String qualifiedName;
|
||||
|
||||
public Builder(String name) {
|
||||
qualifiedName = name;
|
||||
}
|
||||
|
||||
public @NotNull Builder setProperty() {
|
||||
isProperty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder setMutableProperty() {
|
||||
isMutableProperty = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder setGeneratorBasedCoroutine() {
|
||||
isGeneratorBasedCoroutine = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder setAbstract() {
|
||||
isAbstract = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder setClassMethod() {
|
||||
isClassMethod = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull Builder setStaticMethod() {
|
||||
isStaticMethod = true;
|
||||
return this;
|
||||
}
|
||||
|
||||
public @NotNull PyKnownDecorator build() {
|
||||
return new PyKnownDecorator(qualifiedName, isProperty, isMutableProperty, isGeneratorBasedCoroutine, isAbstract, isClassMethod, isStaticMethod);
|
||||
}
|
||||
}
|
||||
|
||||
public @NotNull QualifiedName getQualifiedName() {
|
||||
return myQualifiedName;
|
||||
}
|
||||
|
||||
public @NotNull String getShortName() {
|
||||
//noinspection ConstantConditions
|
||||
return myQualifiedName.getLastComponent();
|
||||
}
|
||||
|
||||
public final static PyKnownDecorator STATICMETHOD = new PyKnownDecorator.Builder(PyNames.STATICMETHOD).setStaticMethod().build();
|
||||
public final static PyKnownDecorator CLASSMETHOD = new PyKnownDecorator.Builder(PyNames.CLASSMETHOD).setClassMethod().build();
|
||||
public final static PyKnownDecorator PROPERTY = new PyKnownDecorator.Builder(PyNames.PROPERTY).setProperty().build();
|
||||
|
||||
public final static PyKnownDecorator FUNCTOOLS_LRU_CACHE = new PyKnownDecorator("functools.lru_cache");
|
||||
public final static PyKnownDecorator FUNCTOOLS_WRAPS = new PyKnownDecorator("functools.wraps");
|
||||
public final static PyKnownDecorator FUNCTOOLS_TOTAL_ORDERING = new PyKnownDecorator("functools.total_ordering");
|
||||
public final static PyKnownDecorator FUNCTOOLS_SINGLEDISPATCH = new PyKnownDecorator("functools.singledispatch");
|
||||
public final static PyKnownDecorator FUNCTOOLS_CACHED_PROPERTY = new PyKnownDecorator.Builder("functools.cached_property").setProperty().setMutableProperty().build();
|
||||
|
||||
public final static PyKnownDecorator ABC_ABSTRACTMETHOD = new PyKnownDecorator.Builder("abc.abstractmethod").setAbstract().build();
|
||||
public final static PyKnownDecorator ABC_ABSTRACTCLASSMETHOD = new PyKnownDecorator.Builder("abc.abstractclassmethod").setAbstract().setClassMethod().build();
|
||||
public final static PyKnownDecorator ABC_ABSTRACTSTATICMETHOD = new PyKnownDecorator.Builder("abc.abstractstaticmethod").setAbstract().setStaticMethod().build();
|
||||
public final static PyKnownDecorator ABC_ABSTRACTPROPERTY = new PyKnownDecorator.Builder("abc.abstractproperty").setAbstract().setProperty().build();
|
||||
|
||||
public final static PyKnownDecorator ASYNCIO_TASKS_COROUTINE = new PyKnownDecorator.Builder("asyncio.tasks.coroutine").setGeneratorBasedCoroutine().build();
|
||||
public final static PyKnownDecorator ASYNCIO_COROUTINES_COROUTINE = new PyKnownDecorator.Builder("asyncio.coroutines.coroutine").setGeneratorBasedCoroutine().build();
|
||||
public final static PyKnownDecorator TYPES_COROUTINE = new PyKnownDecorator.Builder("types.coroutine").setGeneratorBasedCoroutine().build();
|
||||
|
||||
public final static PyKnownDecorator UNITTEST_SKIP = new PyKnownDecorator("unittest.case.skip");
|
||||
public final static PyKnownDecorator UNITTEST_SKIP_IF = new PyKnownDecorator("unittest.case.skipIf");
|
||||
public final static PyKnownDecorator UNITTEST_SKIP_UNLESS = new PyKnownDecorator("unittest.case.skipUnless");
|
||||
public final static PyKnownDecorator UNITTEST_EXPECTED_FAILURE = new PyKnownDecorator("unittest.case.expectedFailure");
|
||||
public final static PyKnownDecorator UNITTEST_MOCK_PATCH = new PyKnownDecorator("unittest.mock.patch");
|
||||
|
||||
public final static PyKnownDecorator TYPING_OVERLOAD = new PyKnownDecorator("typing." + PyNames.OVERLOAD);
|
||||
public final static PyKnownDecorator TYPING_OVERRIDE = new PyKnownDecorator("typing." + PyNames.OVERRIDE);
|
||||
public final static PyKnownDecorator TYPING_EXTENSIONS_OVERRIDE = new PyKnownDecorator("typing_extensions." + PyNames.OVERRIDE);
|
||||
public final static PyKnownDecorator TYPING_RUNTIME = new PyKnownDecorator("typing.runtime");
|
||||
public final static PyKnownDecorator TYPING_RUNTIME_EXT = new PyKnownDecorator("typing_extensions.runtime");
|
||||
public final static PyKnownDecorator TYPING_RUNTIME_CHECKABLE = new PyKnownDecorator("typing.runtime_checkable");
|
||||
public final static PyKnownDecorator TYPING_RUNTIME_CHECKABLE_EXT = new PyKnownDecorator("typing_extensions.runtime_checkable");
|
||||
public final static PyKnownDecorator TYPING_FINAL = new PyKnownDecorator("typing.final");
|
||||
public final static PyKnownDecorator TYPING_FINAL_EXT = new PyKnownDecorator("typing_extensions.final");
|
||||
public final static PyKnownDecorator TYPING_DEPRECATED = new PyKnownDecorator("typing_extensions.deprecated");
|
||||
|
||||
public final static PyKnownDecorator WARNING_DEPRECATED = new PyKnownDecorator("warnings.deprecated");
|
||||
|
||||
public final static PyKnownDecorator REPRLIB_RECURSIVE_REPR = new PyKnownDecorator("reprlib.recursive_repr");
|
||||
|
||||
public final static PyKnownDecorator PYRAMID_DECORATOR_REIFY = new PyKnownDecorator.Builder("pyramid.decorator.reify").setProperty().build();
|
||||
public final static PyKnownDecorator KOMBU_UTILS_CACHED_PROPERTY = new PyKnownDecorator.Builder("kombu.utils.cached_property").setProperty().setMutableProperty().build();
|
||||
|
||||
public final static PyKnownDecorator DATACLASSES_DATACLASS = new PyKnownDecorator("dataclasses.dataclass");
|
||||
public final static PyKnownDecorator ATTR_S = new PyKnownDecorator("attr.s");
|
||||
public final static PyKnownDecorator ATTR_ATTRS = new PyKnownDecorator("attr.attrs");
|
||||
public final static PyKnownDecorator ATTR_ATTRIBUTES = new PyKnownDecorator("attr.attributes");
|
||||
public final static PyKnownDecorator ATTR_DATACLASS = new PyKnownDecorator("attr.dataclass");
|
||||
public final static PyKnownDecorator ATTR_DEFINE = new PyKnownDecorator("attr.define");
|
||||
public final static PyKnownDecorator ATTR_MUTABLE = new PyKnownDecorator("attr.mutable");
|
||||
public final static PyKnownDecorator ATTR_FROZEN = new PyKnownDecorator("attr.frozen");
|
||||
public final static PyKnownDecorator ATTRS_DEFINE = new PyKnownDecorator("attrs.define");
|
||||
public final static PyKnownDecorator ATTRS_MUTABLE = new PyKnownDecorator("attrs.mutable");
|
||||
public final static PyKnownDecorator ATTRS_FROZEN = new PyKnownDecorator("attrs.frozen");
|
||||
|
||||
public final static PyKnownDecorator PYTEST_FIXTURES_FIXTURE = new PyKnownDecorator("_pytest.fixtures.fixture");
|
||||
public final static PyKnownDecorator ENUM_MEMBER = new PyKnownDecorator(PyNames.TYPE_ENUM_MEMBER);
|
||||
public final static PyKnownDecorator ENUM_NONMEMBER = new PyKnownDecorator(PyNames.TYPE_ENUM_NONMEMBER);
|
||||
|
||||
/**
|
||||
* Mutable properties support __set__ and __delete__
|
||||
*/
|
||||
public boolean isMutableProperty() {
|
||||
return myIsMutableProperty;
|
||||
}
|
||||
|
||||
public boolean isProperty() {
|
||||
return myIsProperty;
|
||||
}
|
||||
|
||||
public boolean isGeneratorBasedCoroutine() {
|
||||
return myIsGeneratorBasedCoroutine;
|
||||
}
|
||||
|
||||
public boolean isAbstract() {
|
||||
return myIsAbstract;
|
||||
}
|
||||
|
||||
public boolean isClassMethod() {
|
||||
return myIsClassMethod;
|
||||
}
|
||||
|
||||
public boolean isStaticMethod() {
|
||||
return myIsStaticMethod;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,26 @@
|
||||
// Copyright 2000-2021 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.psi;
|
||||
|
||||
import com.intellij.openapi.extensions.ExtensionPointName;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.Collection;
|
||||
import java.util.Collections;
|
||||
|
||||
|
||||
public interface PyKnownDecoratorProvider {
|
||||
ExtensionPointName<PyKnownDecoratorProvider> EP_NAME = ExtensionPointName.create("Pythonid.knownDecoratorProvider");
|
||||
|
||||
default @NotNull Collection<PyKnownDecorator> getKnownDecorators() {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
|
||||
/**
|
||||
* @deprecated Use {@link #getKnownDecorators()} instead to provide a new {@link PyKnownDecorator} using {@link PyKnownDecorator.Builder}
|
||||
*/
|
||||
@Deprecated(forRemoval = true)
|
||||
@Nullable default String toKnownDecorator(String decoratorName) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
@@ -6,7 +6,6 @@ import com.intellij.psi.PsiFile;
|
||||
import com.intellij.psi.util.QualifiedName;
|
||||
import com.intellij.util.containers.ContainerUtil;
|
||||
import com.jetbrains.python.FunctionParameter;
|
||||
import com.jetbrains.python.PyNames;
|
||||
import com.jetbrains.python.codeInsight.controlflow.ScopeOwner;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveContext;
|
||||
import com.jetbrains.python.psi.resolve.PyResolveUtil;
|
||||
@@ -15,10 +14,12 @@ import com.jetbrains.python.pyi.PyiFile;
|
||||
import one.util.streamex.StreamEx;
|
||||
import org.jetbrains.annotations.ApiStatus;
|
||||
import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
|
||||
import java.util.*;
|
||||
import java.util.stream.Collectors;
|
||||
|
||||
import static com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator.*;
|
||||
import static com.jetbrains.python.psi.PyKnownDecorator.*;
|
||||
|
||||
/**
|
||||
* Contains list of well-behaved decorators from Pythons standard library, that don't change
|
||||
@@ -31,120 +32,15 @@ public final class PyKnownDecoratorUtil {
|
||||
private PyKnownDecoratorUtil() {
|
||||
}
|
||||
|
||||
// TODO provide more information about these decorators: attributes (e.g. lru_cache(f).cache_info), side-effects etc.
|
||||
@SuppressWarnings("SpellCheckingInspection")
|
||||
public enum KnownDecorator {
|
||||
|
||||
STATICMETHOD(PyNames.STATICMETHOD),
|
||||
CLASSMETHOD(PyNames.CLASSMETHOD),
|
||||
PROPERTY(PyNames.PROPERTY),
|
||||
|
||||
FUNCTOOLS_LRU_CACHE("functools.lru_cache"),
|
||||
FUNCTOOLS_WRAPS("functools.wraps"),
|
||||
FUNCTOOLS_TOTAL_ORDERING("functools.total_ordering"),
|
||||
FUNCTOOLS_SINGLEDISPATCH("functools.singledispatch"),
|
||||
FUNCTOOLS_CACHED_PROPERTY("functools.cached_property"),
|
||||
|
||||
ABC_ABSTRACTMETHOD("abc.abstractmethod"),
|
||||
ABC_ABSTRACTCLASSMETHOD("abc.abstractclassmethod"),
|
||||
ABC_ABSTRACTSTATICMETHOD("abc.abstractstaticmethod"),
|
||||
ABC_ABSTRACTPROPERTY("abc.abstractproperty"),
|
||||
|
||||
//ATEXIT_REGISTER("atexit.register", true),
|
||||
//ATEXIT_UNREGISTER("atexit.unregister", false),
|
||||
|
||||
ASYNCIO_TASKS_COROUTINE("asyncio.tasks.coroutine"),
|
||||
ASYNCIO_COROUTINES_COROUTINE("asyncio.coroutines.coroutine"),
|
||||
TYPES_COROUTINE("types.coroutine"),
|
||||
|
||||
UNITTEST_SKIP("unittest.case.skip"),
|
||||
UNITTEST_SKIP_IF("unittest.case.skipIf"),
|
||||
UNITTEST_SKIP_UNLESS("unittest.case.skipUnless"),
|
||||
UNITTEST_EXPECTED_FAILURE("unittest.case.expectedFailure"),
|
||||
UNITTEST_MOCK_PATCH("unittest.mock.patch"),
|
||||
|
||||
TYPING_OVERLOAD("typing." + PyNames.OVERLOAD),
|
||||
TYPING_OVERRIDE("typing." + PyNames.OVERRIDE),
|
||||
TYPING_EXTENSIONS_OVERRIDE("typing_extensions." + PyNames.OVERRIDE),
|
||||
TYPING_RUNTIME("typing.runtime"),
|
||||
TYPING_RUNTIME_EXT("typing_extensions.runtime"),
|
||||
TYPING_RUNTIME_CHECKABLE("typing.runtime_checkable"),
|
||||
TYPING_RUNTIME_CHECKABLE_EXT("typing_extensions.runtime_checkable"),
|
||||
TYPING_FINAL("typing.final"),
|
||||
TYPING_FINAL_EXT("typing_extensions.final"),
|
||||
TYPING_DEPRECATED("typing_extensions.deprecated"),
|
||||
|
||||
WARNING_DEPRECATED("warnings.deprecated"),
|
||||
|
||||
REPRLIB_RECURSIVE_REPR("reprlib.recursive_repr"),
|
||||
|
||||
PYRAMID_DECORATOR_REIFY("pyramid.decorator.reify"),
|
||||
DJANGO_UTILS_FUNCTIONAL_CACHED_PROPERTY("django.utils.functional.cached_property"),
|
||||
KOMBU_UTILS_CACHED_PROPERTY("kombu.utils.cached_property"),
|
||||
|
||||
DATACLASSES_DATACLASS("dataclasses.dataclass"),
|
||||
ATTR_S("attr.s"),
|
||||
ATTR_ATTRS("attr.attrs"),
|
||||
ATTR_ATTRIBUTES("attr.attributes"),
|
||||
ATTR_DATACLASS("attr.dataclass"),
|
||||
ATTR_DEFINE("attr.define"),
|
||||
ATTR_MUTABLE("attr.mutable"),
|
||||
ATTR_FROZEN("attr.frozen"),
|
||||
ATTRS_DEFINE("attrs.define"),
|
||||
ATTRS_MUTABLE("attrs.mutable"),
|
||||
ATTRS_FROZEN("attrs.frozen"),
|
||||
|
||||
PYTEST_FIXTURES_FIXTURE("_pytest.fixtures.fixture"),
|
||||
ENUM_MEMBER(PyNames.TYPE_ENUM_MEMBER),
|
||||
ENUM_NONMEMBER(PyNames.TYPE_ENUM_NONMEMBER);
|
||||
|
||||
private final QualifiedName myQualifiedName;
|
||||
|
||||
KnownDecorator(@NotNull String qualifiedName) {
|
||||
myQualifiedName = QualifiedName.fromDottedString(qualifiedName);
|
||||
}
|
||||
|
||||
public @NotNull QualifiedName getQualifiedName() {
|
||||
return myQualifiedName;
|
||||
}
|
||||
|
||||
public @NotNull String getShortName() {
|
||||
//noinspection ConstantConditions
|
||||
return myQualifiedName.getLastComponent();
|
||||
}
|
||||
}
|
||||
|
||||
private static final Set<KnownDecorator> ABSTRACT_DECORATORS = EnumSet.of(ABC_ABSTRACTMETHOD,
|
||||
ABC_ABSTRACTPROPERTY,
|
||||
ABC_ABSTRACTSTATICMETHOD,
|
||||
ABC_ABSTRACTCLASSMETHOD);
|
||||
|
||||
private static final Set<KnownDecorator> PROPERTY_DECORATORS = EnumSet.of(PROPERTY,
|
||||
ABC_ABSTRACTPROPERTY,
|
||||
PYRAMID_DECORATOR_REIFY,
|
||||
FUNCTOOLS_CACHED_PROPERTY,
|
||||
DJANGO_UTILS_FUNCTIONAL_CACHED_PROPERTY,
|
||||
KOMBU_UTILS_CACHED_PROPERTY);
|
||||
|
||||
private static final Set<KnownDecorator> GENERATOR_BASED_COROUTINE_DECORATORS = EnumSet.of(ASYNCIO_TASKS_COROUTINE,
|
||||
ASYNCIO_COROUTINES_COROUTINE,
|
||||
TYPES_COROUTINE);
|
||||
|
||||
private static final Map<QualifiedName, KnownDecorator> BY_QUALIFIED_NAME =
|
||||
StreamEx.of(values()).toMap(KnownDecorator::getQualifiedName, x -> x);
|
||||
|
||||
private static final Map<String, List<KnownDecorator>> BY_SHORT_NAME =
|
||||
StreamEx.of(values()).groupingBy(KnownDecorator::getShortName);
|
||||
|
||||
/**
|
||||
* Map decorators of element to {@link PyKnownDecoratorUtil.KnownDecorator}.
|
||||
* Map decorators of element to {@link PyKnownDecorator}.
|
||||
*
|
||||
* @param element decoratable element to check
|
||||
* @param context type evaluation context. If it doesn't allow switch to AST, decorators will be compared by the text of the last component
|
||||
* of theirs qualified names.
|
||||
* @return list of known decorators in declaration order with duplicates (with any)
|
||||
*/
|
||||
public static @NotNull List<KnownDecorator> getKnownDecorators(@NotNull PyDecoratable element, @NotNull TypeEvalContext context) {
|
||||
public static @NotNull List<PyKnownDecorator> getKnownDecorators(@NotNull PyDecoratable element, @NotNull TypeEvalContext context) {
|
||||
final PyDecoratorList decoratorList = element.getDecoratorList();
|
||||
if (decoratorList == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -155,7 +51,7 @@ public final class PyKnownDecoratorUtil {
|
||||
.toImmutableList();
|
||||
}
|
||||
|
||||
public static @NotNull List<KnownDecorator> asKnownDecorators(@NotNull PyDecorator decorator, @NotNull TypeEvalContext context) {
|
||||
public static @NotNull List<PyKnownDecorator> asKnownDecorators(@NotNull PyDecorator decorator, @NotNull TypeEvalContext context) {
|
||||
final QualifiedName qualifiedName = decorator.getQualifiedName();
|
||||
if (qualifiedName == null) {
|
||||
return Collections.emptyList();
|
||||
@@ -175,7 +71,7 @@ public final class PyKnownDecoratorUtil {
|
||||
.map(PyQualifiedNameOwner::getQualifiedName)
|
||||
.nonNull()
|
||||
.map(QualifiedName::fromDottedString)
|
||||
.map(BY_QUALIFIED_NAME::get)
|
||||
.map(PyKnownDecoratorUtil::findByQualifiedName)
|
||||
.nonNull()
|
||||
.toImmutableList();
|
||||
}
|
||||
@@ -185,10 +81,14 @@ public final class PyKnownDecoratorUtil {
|
||||
}
|
||||
|
||||
@ApiStatus.Internal
|
||||
public static @NotNull List<KnownDecorator> asKnownDecorators(@NotNull QualifiedName qualifiedName) {
|
||||
public static @NotNull List<PyKnownDecorator> asKnownDecorators(@NotNull QualifiedName qualifiedName) {
|
||||
// The method might have been called during building of PSI stub indexes. Thus, we can't leave this file's boundaries.
|
||||
// TODO Use proper local resolve to imported names here
|
||||
return Collections.unmodifiableList(BY_SHORT_NAME.getOrDefault(qualifiedName.getLastComponent(), Collections.emptyList()));
|
||||
String lastComponent = qualifiedName.getLastComponent();
|
||||
if (lastComponent == null) {
|
||||
return Collections.emptyList();
|
||||
}
|
||||
return findByShortName(lastComponent);
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -197,7 +97,7 @@ public final class PyKnownDecoratorUtil {
|
||||
* @param element decoratable element to check
|
||||
* @param context type evaluation context. If it doesn't allow switch to AST, decorators will be compared by the text of the last component
|
||||
* of theirs qualified names.
|
||||
* @see PyKnownDecoratorUtil.KnownDecorator
|
||||
* @see PyKnownDecorator
|
||||
*/
|
||||
public static boolean hasUnknownDecorator(@NotNull PyDecoratable element, @NotNull TypeEvalContext context) {
|
||||
return !allDecoratorsAreKnown(element, getKnownDecorators(element, context));
|
||||
@@ -209,18 +109,14 @@ public final class PyKnownDecoratorUtil {
|
||||
* @param element Python function to check
|
||||
* @param context type evaluation context. If it doesn't allow switch to AST, decorators will be compared by the text of the last component
|
||||
* of theirs qualified names.
|
||||
* @see PyKnownDecoratorUtil.KnownDecorator
|
||||
* @see PyKnownDecorator
|
||||
*/
|
||||
public static boolean hasAbstractDecorator(@NotNull PyDecoratable element, @NotNull TypeEvalContext context) {
|
||||
return ContainerUtil.exists(getKnownDecorators(element, context), ABSTRACT_DECORATORS::contains);
|
||||
}
|
||||
|
||||
public static boolean isPropertyDecorator(@NotNull PyDecorator decorator, @NotNull TypeEvalContext context) {
|
||||
return ContainerUtil.exists(asKnownDecorators(decorator, context), PROPERTY_DECORATORS::contains);
|
||||
return ContainerUtil.exists(getKnownDecorators(element, context), knownDecorator -> knownDecorator.isAbstract());
|
||||
}
|
||||
|
||||
public static boolean hasGeneratorBasedCoroutineDecorator(@NotNull PyFunction function, @NotNull TypeEvalContext context) {
|
||||
return ContainerUtil.exists(getKnownDecorators(function, context), GENERATOR_BASED_COROUTINE_DECORATORS::contains);
|
||||
return ContainerUtil.exists(getKnownDecorators(function, context), knownDecorator -> knownDecorator.isGeneratorBasedCoroutine());
|
||||
}
|
||||
|
||||
public static boolean isResolvedToGeneratorBasedCoroutine(@NotNull PyCallExpression receiver,
|
||||
@@ -237,12 +133,12 @@ public final class PyKnownDecoratorUtil {
|
||||
}
|
||||
|
||||
public static boolean hasUnknownOrChangingSignatureDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
||||
final List<KnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
final List<PyKnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
return !allDecoratorsAreKnown(decoratable, decorators) || decorators.contains(UNITTEST_MOCK_PATCH);
|
||||
}
|
||||
|
||||
public static boolean hasUnknownOrChangingReturnTypeDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
||||
final List<KnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
final List<PyKnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
|
||||
if (!allDecoratorsAreKnown(decoratable, decorators)) {
|
||||
return true;
|
||||
@@ -252,12 +148,12 @@ public final class PyKnownDecoratorUtil {
|
||||
}
|
||||
|
||||
public static boolean hasChangingReturnTypeDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
||||
final List<KnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
final List<PyKnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
return ContainerUtil.exists(decorators, d -> d == UNITTEST_MOCK_PATCH);
|
||||
}
|
||||
|
||||
public static boolean hasUnknownOrUpdatingAttributesDecorator(@NotNull PyDecoratable decoratable, @NotNull TypeEvalContext context) {
|
||||
final List<KnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
final List<PyKnownDecorator> decorators = getKnownDecorators(decoratable, context);
|
||||
|
||||
if (!allDecoratorsAreKnown(decoratable, decorators)) {
|
||||
return true;
|
||||
@@ -271,11 +167,37 @@ public final class PyKnownDecoratorUtil {
|
||||
);
|
||||
}
|
||||
|
||||
private static boolean allDecoratorsAreKnown(@NotNull PyDecoratable element, @NotNull List<KnownDecorator> decorators) {
|
||||
private static boolean allDecoratorsAreKnown(@NotNull PyDecoratable element, @NotNull List<PyKnownDecorator> decorators) {
|
||||
final PyDecoratorList decoratorList = element.getDecoratorList();
|
||||
return decoratorList == null
|
||||
? decorators.isEmpty()
|
||||
: decoratorList.getDecorators().length == StreamEx.of(decorators).groupingBy(KnownDecorator::getShortName).size();
|
||||
: decoratorList.getDecorators().length == StreamEx.of(decorators).groupingBy(PyKnownDecorator::getShortName).size();
|
||||
}
|
||||
|
||||
private static List<PyKnownDecorator> findByShortName(@NotNull String shortName) {
|
||||
return PyKnownDecoratorProvider.EP_NAME.getExtensionList().stream()
|
||||
.flatMap(knownDecoratorProvider -> {
|
||||
Collection<PyKnownDecorator> decorators = knownDecoratorProvider.getKnownDecorators();
|
||||
if (!decorators.isEmpty()) {
|
||||
return decorators.stream();
|
||||
}
|
||||
// Fallback to the old implementation that will be removed in the future release
|
||||
String knownDecorator = knownDecoratorProvider.toKnownDecorator(shortName);
|
||||
if (knownDecorator != null && !knownDecorator.isEmpty() && !knownDecorator.equals(shortName)) {
|
||||
return StreamEx.of(findByShortName(knownDecorator));
|
||||
}
|
||||
return StreamEx.empty();
|
||||
})
|
||||
.filter(knownDecorator -> knownDecorator.getShortName().equals(shortName))
|
||||
.toList();
|
||||
}
|
||||
|
||||
private static @Nullable PyKnownDecorator findByQualifiedName(@NotNull QualifiedName qualifiedName) {
|
||||
return PyKnownDecoratorProvider.EP_NAME.getExtensionList().stream()
|
||||
.flatMap(knownDecoratorProvider -> knownDecoratorProvider.getKnownDecorators().stream())
|
||||
.filter(knownDecorator -> knownDecorator.getQualifiedName().equals(qualifiedName))
|
||||
.findFirst()
|
||||
.orElse(null);
|
||||
}
|
||||
|
||||
public enum FunctoolsWrapsParameters implements FunctionParameter {
|
||||
|
||||
@@ -0,0 +1,56 @@
|
||||
package com.jetbrains.python.psi
|
||||
|
||||
class PyStdKnownDecoratorProvider : PyKnownDecoratorProvider {
|
||||
override fun getKnownDecorators(): Collection<PyKnownDecorator> {
|
||||
return listOf(
|
||||
PyKnownDecorator.STATICMETHOD,
|
||||
PyKnownDecorator.CLASSMETHOD,
|
||||
PyKnownDecorator.PROPERTY,
|
||||
PyKnownDecorator.FUNCTOOLS_LRU_CACHE,
|
||||
PyKnownDecorator.FUNCTOOLS_WRAPS,
|
||||
PyKnownDecorator.FUNCTOOLS_TOTAL_ORDERING,
|
||||
PyKnownDecorator.FUNCTOOLS_SINGLEDISPATCH,
|
||||
PyKnownDecorator.FUNCTOOLS_CACHED_PROPERTY,
|
||||
PyKnownDecorator.ABC_ABSTRACTMETHOD,
|
||||
PyKnownDecorator.ABC_ABSTRACTCLASSMETHOD,
|
||||
PyKnownDecorator.ABC_ABSTRACTSTATICMETHOD,
|
||||
PyKnownDecorator.ABC_ABSTRACTPROPERTY,
|
||||
PyKnownDecorator.ASYNCIO_TASKS_COROUTINE,
|
||||
PyKnownDecorator.ASYNCIO_COROUTINES_COROUTINE,
|
||||
PyKnownDecorator.TYPES_COROUTINE,
|
||||
PyKnownDecorator.UNITTEST_SKIP,
|
||||
PyKnownDecorator.UNITTEST_SKIP_IF,
|
||||
PyKnownDecorator.UNITTEST_SKIP_UNLESS,
|
||||
PyKnownDecorator.UNITTEST_EXPECTED_FAILURE,
|
||||
PyKnownDecorator.UNITTEST_MOCK_PATCH,
|
||||
PyKnownDecorator.TYPING_OVERLOAD,
|
||||
PyKnownDecorator.TYPING_OVERRIDE,
|
||||
PyKnownDecorator.TYPING_EXTENSIONS_OVERRIDE,
|
||||
PyKnownDecorator.TYPING_RUNTIME,
|
||||
PyKnownDecorator.TYPING_RUNTIME_EXT,
|
||||
PyKnownDecorator.TYPING_RUNTIME_CHECKABLE,
|
||||
PyKnownDecorator.TYPING_RUNTIME_CHECKABLE_EXT,
|
||||
PyKnownDecorator.TYPING_FINAL,
|
||||
PyKnownDecorator.TYPING_FINAL_EXT,
|
||||
PyKnownDecorator.TYPING_DEPRECATED,
|
||||
PyKnownDecorator.WARNING_DEPRECATED,
|
||||
PyKnownDecorator.REPRLIB_RECURSIVE_REPR,
|
||||
PyKnownDecorator.PYRAMID_DECORATOR_REIFY,
|
||||
PyKnownDecorator.KOMBU_UTILS_CACHED_PROPERTY,
|
||||
PyKnownDecorator.DATACLASSES_DATACLASS,
|
||||
PyKnownDecorator.ATTR_S,
|
||||
PyKnownDecorator.ATTR_ATTRS,
|
||||
PyKnownDecorator.ATTR_ATTRIBUTES,
|
||||
PyKnownDecorator.ATTR_DATACLASS,
|
||||
PyKnownDecorator.ATTR_DEFINE,
|
||||
PyKnownDecorator.ATTR_MUTABLE,
|
||||
PyKnownDecorator.ATTR_FROZEN,
|
||||
PyKnownDecorator.ATTRS_DEFINE,
|
||||
PyKnownDecorator.ATTRS_MUTABLE,
|
||||
PyKnownDecorator.ATTRS_FROZEN,
|
||||
PyKnownDecorator.PYTEST_FIXTURES_FIXTURE,
|
||||
PyKnownDecorator.ENUM_MEMBER,
|
||||
PyKnownDecorator.ENUM_NONMEMBER
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -674,24 +674,25 @@ public class PyClassImpl extends PyBaseElementImpl<PyClassStub> implements PyCla
|
||||
final PyDecoratorList decoratorList = method.getDecoratorList();
|
||||
if (decoratorList != null) {
|
||||
for (PyDecorator deco : decoratorList.getDecorators()) {
|
||||
final QualifiedName qname = deco.getQualifiedName();
|
||||
if (qname != null) {
|
||||
String decoName = qname.toString();
|
||||
for (PyKnownDecoratorProvider provider : PyKnownDecoratorProvider.EP_NAME.getExtensionList()) {
|
||||
final String knownName = provider.toKnownDecorator(decoName);
|
||||
if (knownName != null) {
|
||||
decoName = knownName;
|
||||
}
|
||||
}
|
||||
if (PyNames.CACHED_PROPERTY.equals(decoName)) {
|
||||
TypeEvalContext context = TypeEvalContext.codeInsightFallback(getProject());
|
||||
List<PyKnownDecorator> knownDecorators = PyKnownDecoratorUtil.asKnownDecorators(deco, context);
|
||||
for (PyKnownDecorator knownDecorator : knownDecorators) {
|
||||
if (knownDecorator.isMutableProperty()) {
|
||||
getter = new Maybe<>(method);
|
||||
setter = new Maybe<>(method);
|
||||
deleter = new Maybe<>(method);
|
||||
break;
|
||||
}
|
||||
if (PyNames.PROPERTY.equals(decoName) ||
|
||||
PyKnownDecoratorUtil.isPropertyDecorator(deco, TypeEvalContext.codeInsightFallback(getProject())) ||
|
||||
qname.matches(decoratorName, PyNames.GETTER)) {
|
||||
|
||||
if (knownDecorator.isProperty()) {
|
||||
getter = new Maybe<>(method);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
final QualifiedName qname = deco.getQualifiedName();
|
||||
if (qname != null) {
|
||||
if (qname.matches(decoratorName, PyNames.GETTER)) {
|
||||
getter = new Maybe<>(method);
|
||||
}
|
||||
else if (qname.matches(decoratorName, PyNames.SETTER)) {
|
||||
|
||||
@@ -546,12 +546,14 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
|
||||
*/
|
||||
@Override
|
||||
public @Nullable Modifier getModifier() {
|
||||
final String deconame = getClassOrStaticMethodDecorator();
|
||||
if (PyNames.CLASSMETHOD.equals(deconame)) {
|
||||
return CLASSMETHOD;
|
||||
}
|
||||
else if (PyNames.STATICMETHOD.equals(deconame)) {
|
||||
return STATICMETHOD;
|
||||
final PyKnownDecorator decorator = getClassOrStaticMethodDecorator();
|
||||
if (decorator != null) {
|
||||
if (decorator.isClassMethod()) {
|
||||
return CLASSMETHOD;
|
||||
}
|
||||
else if (decorator.isStaticMethod()) {
|
||||
return STATICMETHOD;
|
||||
}
|
||||
}
|
||||
|
||||
final String funcName = getName();
|
||||
@@ -574,12 +576,6 @@ 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();
|
||||
@@ -709,21 +705,17 @@ public class PyFunctionImpl extends PyBaseElementImpl<PyFunctionStub> implements
|
||||
*
|
||||
* @return name of the built-in decorator, or null (even if there are non-built-in decorators).
|
||||
*/
|
||||
private @Nullable String getClassOrStaticMethodDecorator() {
|
||||
private @Nullable PyKnownDecorator getClassOrStaticMethodDecorator() {
|
||||
PyDecoratorList decolist = getDecoratorList();
|
||||
if (decolist != null) {
|
||||
PyDecorator[] decos = decolist.getDecorators();
|
||||
if (decos.length > 0) {
|
||||
for (int i = decos.length - 1; i >= 0; i -= 1) {
|
||||
PyDecorator deco = decos[i];
|
||||
String deconame = deco.getName();
|
||||
if (PyNames.CLASSMETHOD.equals(deconame) || PyNames.STATICMETHOD.equals(deconame)) {
|
||||
return deconame;
|
||||
}
|
||||
for (PyKnownDecoratorProvider provider : PyKnownDecoratorProvider.EP_NAME.getIterable()) {
|
||||
String name = provider.toKnownDecorator(deconame);
|
||||
if (name != null) {
|
||||
return name;
|
||||
List<PyKnownDecorator> knownDecorators = PyKnownDecoratorUtil.asKnownDecorators(deco, TypeEvalContext.codeInsightFallback(getProject()));
|
||||
for (PyKnownDecorator decorator : knownDecorators) {
|
||||
if (decorator.isClassMethod() || decorator.isStaticMethod()) {
|
||||
return decorator;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+3
-3
@@ -5,9 +5,9 @@ import com.intellij.psi.stubs.StubOutputStream
|
||||
import com.intellij.psi.util.QualifiedName
|
||||
import com.jetbrains.python.PyNames
|
||||
import com.jetbrains.python.codeInsight.dataflow.scope.ScopeUtil
|
||||
import com.jetbrains.python.psi.PyKnownDecorator
|
||||
import com.jetbrains.python.psi.PyCallExpression
|
||||
import com.jetbrains.python.psi.PyClass
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil.KnownDecorator
|
||||
import com.jetbrains.python.psi.PyReferenceExpression
|
||||
import com.jetbrains.python.psi.PyTargetExpression
|
||||
import com.jetbrains.python.psi.impl.PyPsiUtils
|
||||
@@ -29,8 +29,8 @@ class PyEnumAttributeStubType : CustomTargetExpressionStubType<PyEnumAttributeSt
|
||||
|
||||
val argument = callExpr.arguments.singleOrNull() ?: return null
|
||||
val isMember = when (calleeFqn) {
|
||||
KnownDecorator.ENUM_MEMBER.qualifiedName -> true
|
||||
KnownDecorator.ENUM_NONMEMBER.qualifiedName -> false
|
||||
PyKnownDecorator.ENUM_MEMBER.qualifiedName -> true
|
||||
PyKnownDecorator.ENUM_NONMEMBER.qualifiedName -> false
|
||||
else -> return null
|
||||
}
|
||||
return PyEnumAttributeStubImpl(PyLiteralKind.fromExpression(argument), isMember)
|
||||
|
||||
+2
-1
@@ -2,6 +2,7 @@ package com.jetbrains.python.psi.stubs
|
||||
|
||||
import com.intellij.psi.stubs.StubInputStream
|
||||
import com.intellij.psi.stubs.StubOutputStream
|
||||
import com.jetbrains.python.psi.PyKnownDecorator
|
||||
import com.jetbrains.python.psi.PyDecorator
|
||||
import com.jetbrains.python.psi.PyKnownDecoratorUtil
|
||||
import com.jetbrains.python.psi.PyReferenceExpression
|
||||
@@ -33,7 +34,7 @@ class PyFunctoolsWrapsDecoratorStub(val wrapped: String) : PyCustomDecoratorStub
|
||||
companion object {
|
||||
fun create(psi: PyDecorator): PyFunctoolsWrapsDecoratorStub? {
|
||||
val qName = psi.qualifiedName ?: return null
|
||||
if (!PyKnownDecoratorUtil.asKnownDecorators(qName).contains(PyKnownDecoratorUtil.KnownDecorator.FUNCTOOLS_WRAPS)) return null
|
||||
if (!PyKnownDecoratorUtil.asKnownDecorators(qName).contains(PyKnownDecorator.FUNCTOOLS_WRAPS)) return null
|
||||
val wrappedExpr = psi.argumentList?.getValueExpressionForParam(PyKnownDecoratorUtil.FunctoolsWrapsParameters.WRAPPED) as? PyReferenceExpression
|
||||
val wrappedExprQName = wrappedExpr?.asQualifiedName() ?: return null
|
||||
return PyFunctoolsWrapsDecoratorStub(wrappedExprQName.toString())
|
||||
|
||||
@@ -112,7 +112,7 @@ public final class PyiUtil {
|
||||
}
|
||||
|
||||
public static boolean isOverload(@NotNull PsiElement element, @NotNull TypeEvalContext context) {
|
||||
final PyKnownDecoratorUtil.KnownDecorator overload = PyKnownDecoratorUtil.KnownDecorator.TYPING_OVERLOAD;
|
||||
final PyKnownDecorator overload = PyKnownDecorator.TYPING_OVERLOAD;
|
||||
|
||||
return element instanceof PyFunction &&
|
||||
PyKnownDecoratorUtil.getKnownDecorators((PyFunction)element, context).contains(overload);
|
||||
|
||||
Reference in New Issue
Block a user