diff --git a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java index 80ac706fa490..c24871db9f6d 100644 --- a/python/psi-api/src/com/jetbrains/python/psi/PyClass.java +++ b/python/psi-api/src/com/jetbrains/python/psi/PyClass.java @@ -181,6 +181,12 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine boolean isSubclass(@NotNull String superClassQName); + /** + * Returns the aggregated list of names defined in __slots__ attributes of the class and its ancestors. + */ + @Nullable + List getSlots(); + /** * Returns the list of names in the class' __slots__ attribute, or null if the class * does not define such an attribute. @@ -188,7 +194,7 @@ public interface PyClass extends PsiNameIdentifierOwner, PyStatement, NameDefine * @return the list of names or null. */ @Nullable - List getSlots(); + List getOwnSlots(); @Nullable String getDocStringValue(); diff --git a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java index 4f7c75af671d..a3c9ba7d5127 100644 --- a/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java +++ b/python/src/com/jetbrains/python/inspections/PyUnresolvedReferencesInspection.java @@ -128,6 +128,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection { if (type instanceof PyClassType) { final PyClass pyClass = ((PyClassType)type).getPyClass(); if (pyClass.isNewStyleClass()) { + if (pyClass.getOwnSlots() == null) { + return; + } final List slots = pyClass.getSlots(); final String attrName = node.getReferencedName(); if (slots != null && !slots.contains(attrName) && !slots.contains(PyNames.DICT)) { diff --git a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java index a8e506f39301..89ea4d51e1d2 100644 --- a/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java +++ b/python/src/com/jetbrains/python/psi/impl/PyClassImpl.java @@ -246,20 +246,25 @@ public class PyClassImpl extends PyPresentableElementImpl implement @Override public List getSlots() { - List slots = getOwnSlots(); - if (slots != null) { - return slots; + final Set result = new LinkedHashSet(); + boolean found = false; + final List ownSlots = getOwnSlots(); + if (ownSlots != null) { + found = true; + result.addAll(ownSlots); } for (PyClass cls : getAncestorClasses()) { - slots = ((PyClassImpl)cls).getOwnSlots(); - if (slots != null) { - return slots; + final List ancestorSlots = cls.getOwnSlots(); + if (ancestorSlots != null) { + found = true; + result.addAll(ancestorSlots); } } - return null; + return found ? new ArrayList(result) : null; } @Nullable + @Override public List getOwnSlots() { final PyClassStub stub = getStub(); if (stub != null) { diff --git a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java index 5b584b2d2822..e0d93eb86f5f 100644 --- a/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java +++ b/python/src/com/jetbrains/python/psi/impl/stubs/PyClassElementType.java @@ -49,7 +49,7 @@ public class PyClassElementType extends PyStubElementType final PyStringLiteralExpression docStringExpression = psi.getDocStringExpression(); return new PyClassStubImpl(psi.getName(), parentStub, superClasses.toArray(new PyQualifiedName[superClasses.size()]), - ((PyClassImpl)psi).getOwnSlots(), + psi.getOwnSlots(), PyPsiUtils.strValue(docStringExpression), getStubElementType()); } diff --git a/python/testData/inspections/PyUnresolvedReferencesInspection/slots.py b/python/testData/inspections/PyUnresolvedReferencesInspection/slots.py index 6929ebccd548..793903c2338b 100644 --- a/python/testData/inspections/PyUnresolvedReferencesInspection/slots.py +++ b/python/testData/inspections/PyUnresolvedReferencesInspection/slots.py @@ -8,7 +8,7 @@ class C(B): pass c = C() -c.bar = 1 +c.bar = 1 def test_slots_with_dict(): class C(object):