diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index 05250175717c..448a53da9856 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -1400,35 +1400,24 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla if (PyNames.TYPES_INSTANCE_TYPE.equals(getQualifiedName())) { return Collections.emptyList(); } - final PyClassStub stub = getStub(); final List result = new ArrayList<>(); // In some cases stub may not provide all information, so we use stubs only if AST access id disabled if (!context.maySwitchToAST(this)) { - fillSuperClassesNoSwitchToAst(context, stub, result); + fillSuperClassesNoSwitchToAst(context, getStub(), result); } else { fillSuperClassesSwitchingToAst(context, result); } - final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(this); PyPsiUtils.assertValid(this); - if (result.isEmpty() && isValid() && !builtinCache.isBuiltin(this)) { - final PyClass implicitSuper; - if (LanguageLevel.forElement(this).isOlderThan(LanguageLevel.PYTHON30) && getMetaClassQName() == null) { - implicitSuper = as(resolveTopLevelMember(QualifiedName.fromDottedString(PyNames.TYPES_INSTANCE_TYPE), - fromFoothold(this)), PyClass.class); - } - else { - implicitSuper = builtinCache.getClass(PyNames.OBJECT); - } - if (implicitSuper != null) { - final PyType type = context.getType(implicitSuper); - if (type instanceof PyClassLikeType) { - result.add((PyClassLikeType)type); - } - } + if (result.isEmpty()) { + return Optional + .ofNullable(getImplicitSuper(context)) + .map(Collections::singletonList) + .orElse(Collections.emptyList()); } + return result; } @@ -1475,6 +1464,29 @@ public class PyClassImpl extends PyBaseElementImpl implements PyCla } } + @Nullable + private PyClassLikeType getImplicitSuper(@NotNull TypeEvalContext context) { + final PyBuiltinCache builtinCache = PyBuiltinCache.getInstance(this); + final PyClassType objectType = builtinCache.getObjectType(); + + if (objectType != null && this == objectType.getPyClass()) { + return null; + } + + if (LanguageLevel.forElement(this).isOlderThan(LanguageLevel.PYTHON30) && getMetaClassQName() == null) { + final QualifiedName typesInstanceTypeQName = QualifiedName.fromDottedString(PyNames.TYPES_INSTANCE_TYPE); + final PsiElement typesInstanceType = resolveTopLevelMember(typesInstanceTypeQName, fromFoothold(this)); + + return Optional + .ofNullable(as(typesInstanceType, PyClass.class)) + .map(context::getType) + .map(type -> as(type, PyClassLikeType.class)) + .orElse(null); + } + + return objectType; + } + @NotNull @Override public List getAncestorTypes(@NotNull TypeEvalContext context) { diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection3K/callTypeGetAttributeAndSetAttrInInheritor.py b/python/testData/inspections/PyUnresolvedReferencesInspection3K/callTypeGetAttributeAndSetAttrInInheritor.py new file mode 100644 index 000000000000..4b9858fac7ce --- /dev/null +++ b/python/testData/inspections/PyUnresolvedReferencesInspection3K/callTypeGetAttributeAndSetAttrInInheritor.py @@ -0,0 +1,6 @@ +class ConfigMeta(type): + def __getattribute__(self, item): + return super().__getattribute__(item) + + def __setattr__(self, key, value): + super().__setattr__(key, value) \ No newline at end of file diff --git a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java index 034911607a39..5862048b9968 100644 --- a/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java +++ b/python/testSrc/com/jetbrains/python/inspections/Py3UnresolvedReferencesInspectionTest.java @@ -205,4 +205,9 @@ public class Py3UnresolvedReferencesInspectionTest extends PyTestCase { public void testTypingGenericDunderGetItem() { doTest(); } + + // PY-22899, PY-22937 + public void testCallTypeGetAttributeAndSetAttrInInheritor() { + doTest(); + } }