Support for @DynamicAttrs annotation in the docstring of a class (PY-4600)

This commit is contained in:
Andrey Vlasovskikh
2013-01-28 22:05:33 +04:00
parent 8e4270e44a
commit fb578301b5
3 changed files with 55 additions and 6 deletions
@@ -658,14 +658,9 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
if (hasUnresolvedAncestors(cls)) {
return true;
}
if (cls.getDecoratorList() != null) {
if (isDecoratedAsDynamic(cls, true)) {
return true;
}
for (PyClass base : cls.iterateAncestorClasses()) {
if (base.getDecoratorList() != null) {
return true;
}
}
}
if (qtype instanceof CythonBuiltinType ||
(qtype instanceof CythonType && reference instanceof PyOperatorReference)) {
@@ -680,6 +675,29 @@ public class PyUnresolvedReferencesInspection extends PyInspection {
return false;
}
private static boolean isDecoratedAsDynamic(@NotNull PyClass cls, boolean inherited) {
if (inherited) {
if (isDecoratedAsDynamic(cls, false)) {
return true;
}
for (PyClass base : cls.iterateAncestorClasses()) {
if (base != null && isDecoratedAsDynamic(base, false)) {
return true;
}
}
}
else {
if (cls.getDecoratorList() != null) {
return true;
}
final String docString = cls.getDocStringValue();
if (docString != null && docString.indexOf("@DynamicAttrs") != -1) {
return true;
}
}
return false;
}
private static boolean hasUnresolvedAncestors(PyClass cls) {
for (PyClassRef classRef : cls.iterateAncestors()) {
if (classRef.getPyClass() == null && classRef.getType() == null) {
@@ -0,0 +1,26 @@
class B(object):
def foo(self):
pass
class C(object):
"""
@DynamicAttrs
"""
def bar(self):
pass
class D(C):
def baz(self):
pass
b = B()
b.foo(), b.<warning descr="Unresolved attribute reference 'spam' for class 'B'">spam</warning>()
c = C()
c.bar(), c.spam()
d = D()
d.bar(), d.baz(), d.spam(), d.eggs()
@@ -237,6 +237,11 @@ public class PyUnresolvedReferencesInspectionTest extends PyTestCase {
doTest();
}
// PY-4600
public void testDynamicAttrsAnnotation() {
doTest();
}
private void doTest() {
myFixture.configureByFile(TEST_DIRECTORY + getTestName(true) + ".py");
myFixture.enableInspections(PyUnresolvedReferencesInspection.class);