Fixed false positive attribute assignment warning for classes that inherit '__slots__', but don't define their own slots (PY-10158)

This commit is contained in:
Andrey Vlasovskikh
2013-09-19 22:04:28 +04:00
parent df135fc4fb
commit bc2140236b
5 changed files with 24 additions and 10 deletions
@@ -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<String> 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<String> getSlots();
List<String> getOwnSlots();
@Nullable
String getDocStringValue();
@@ -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<String> slots = pyClass.getSlots();
final String attrName = node.getReferencedName();
if (slots != null && !slots.contains(attrName) && !slots.contains(PyNames.DICT)) {
@@ -246,20 +246,25 @@ public class PyClassImpl extends PyPresentableElementImpl<PyClassStub> implement
@Override
public List<String> getSlots() {
List<String> slots = getOwnSlots();
if (slots != null) {
return slots;
final Set<String> result = new LinkedHashSet<String>();
boolean found = false;
final List<String> 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<String> ancestorSlots = cls.getOwnSlots();
if (ancestorSlots != null) {
found = true;
result.addAll(ancestorSlots);
}
}
return null;
return found ? new ArrayList<String>(result) : null;
}
@Nullable
@Override
public List<String> getOwnSlots() {
final PyClassStub stub = getStub();
if (stub != null) {
@@ -49,7 +49,7 @@ public class PyClassElementType extends PyStubElementType<PyClassStub, PyClass>
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());
}
@@ -8,7 +8,7 @@ class C(B):
pass
c = C()
c.<warning descr="'C' object has no attribute 'bar'">bar</warning> = 1
c.bar = 1
def test_slots_with_dict():
class C(object):