Show instance attributes in structure view (PY-3371)

This commit is contained in:
Andrey Vlasovskikh
2011-05-27 19:31:51 +04:00
parent a0e2c0aa54
commit b849f3989b
4 changed files with 120 additions and 40 deletions
@@ -17,9 +17,7 @@ import com.jetbrains.python.psi.impl.PyBuiltinCache;
import org.jetbrains.annotations.Nullable;
import javax.swing.*;
import java.util.Arrays;
import java.util.LinkedHashSet;
import java.util.Set;
import java.util.*;
import static com.intellij.openapi.util.text.StringUtil.join;
import static com.intellij.openapi.util.text.StringUtil.notNullize;
@@ -75,7 +73,8 @@ public class PyStructureViewElement implements StructureViewTreeElement {
myElement.acceptChildren(new PyElementVisitor() {
@Override
public void visitElement(PsiElement element) {
if (isWorthyClassItem(element)) {
if (element instanceof PyClass || element instanceof PyFunction ||
(!(myElement instanceof PyClass) && isWorthyItem(element))) {
childrenElements.add((PyElement)element);
}
else {
@@ -83,47 +82,68 @@ public class PyStructureViewElement implements StructureViewTreeElement {
}
}
});
StructureViewTreeElement[] children = new StructureViewTreeElement[childrenElements.size()];
int i = 0;
final Collection<StructureViewTreeElement> children = new ArrayList<StructureViewTreeElement>();
for (PyElement element : childrenElements) {
// look at functions and predefined __names__
Visibility vis = Visibility.NORMAL;
final Visibility vis;
if (PsiTreeUtil.getParentOfType(element, PyFunction.class) != null) {
// whatever is defined inside a def, is hidden
vis = Visibility.INVISIBLE;
}
else {
String name = element.getName();
if (name != null && name.startsWith("__")) {
if (PyNames.UnderscoredAttributes.contains(name)) {
vis = Visibility.PREDEFINED;
}
else {
vis = Visibility.PRIVATE;
}
}
vis = getVisibilityByName(element.getName());
}
children[i] = new PyStructureViewElement(element, vis);
final PyStructureViewElement e = new PyStructureViewElement(element, vis);
children.add(e);
if (element instanceof PyClass && element.isValid()) {
PyClass the_exception = PyBuiltinCache.getInstance(element).getClass("Exception");
final PyClass cls = (PyClass)element;
for (PyClass anc : cls.iterateAncestorClasses()) {
if (anc == the_exception) {
((PyStructureViewElement)(children[i])).setIcon(Icons.EXCEPTION_CLASS_ICON);
e.setIcon(Icons.EXCEPTION_CLASS_ICON);
break;
}
}
}
i += 1;
}
return children;
final Collection<PyTargetExpression> attrs = new ArrayList<PyTargetExpression>();
if (myElement instanceof PyClass) {
final PyClass c = (PyClass)myElement;
final Comparator<PyTargetExpression> comparator = new Comparator<PyTargetExpression>() {
@Override
public int compare(PyTargetExpression e1, PyTargetExpression e2) {
final String n1 = e1.getName();
final String n2 = e2.getName();
return (n1 != null && n2 != null) ? n1.compareTo(n2) : 0;
}
};
final List<PyTargetExpression> instanceAttrs = c.getInstanceAttributes();
final List<PyTargetExpression> classAttrs = c.getClassAttributes();
Collections.sort(instanceAttrs, comparator);
Collections.sort(classAttrs, comparator);
attrs.addAll(classAttrs);
attrs.addAll(instanceAttrs);
}
for (PyTargetExpression e : attrs) {
if (e.isValid()) {
children.add(new PyStructureViewElement(e, getVisibilityByName(e.getName())));
}
}
return children.toArray(new StructureViewTreeElement[children.size()]);
}
static boolean isWorthyClassItem(PsiElement element) {
if (element instanceof PyClass) return true;
if (element instanceof PyFunction) return true;
private static Visibility getVisibilityByName(@Nullable String name) {
if (name != null && name.startsWith("__")) {
if (PyNames.UnderscoredAttributes.contains(name)) {
return Visibility.PREDEFINED;
}
else {
return Visibility.PRIVATE;
}
}
return Visibility.NORMAL;
}
private static boolean isWorthyItem(PsiElement element) {
if ((element instanceof PyTargetExpression) && ((PyTargetExpression)element).getQualifier() == null) {
PsiElement e = element.getParent();
if (e instanceof PyAssignmentStatement) {
@@ -142,8 +162,6 @@ public class PyStructureViewElement implements StructureViewTreeElement {
return false;
}
public ItemPresentation getPresentation() {
return new ItemPresentation() {
public String getPresentableText() {
@@ -0,0 +1,32 @@
class B(object):
c1 = 0
def f(self, x):
self.i1 = x
l1 = self.i1
self.i2 = l1
def __init__(self, x, y):
self.i2 = x
self.i3 = y
@classmethod
def g(cls, x):
cls.c2 = cls.c1
g1 = "foo"
class C(B):
c2 = -1
def __init__(self, x, y):
super(C, self).__init__(x, y)
self.i3 = -2
self.i4 = -3
def h(self):
self.i5 = self.i6
c3 = -4
g2 = "bar"
@@ -2,7 +2,7 @@ import lib1
class B1:
def f(self, x):
return x + self.y
return x
class B2(object):
@staticmethod
@@ -10,21 +10,51 @@ import static com.intellij.testFramework.PlatformTestUtil.assertTreeEqual;
* @author vlan
*/
public class PyStructureViewTest extends PyLightFixtureTestCase {
private static String TEST_DIRECTORY = "structureView/";
public void testBaseClassNames() {
myFixture.configureByFiles("structureView/baseClassNames.py",
"structureView/lib1.py");
myFixture.configureByFiles(TEST_DIRECTORY + "baseClassNames.py",
TEST_DIRECTORY + "lib1.py");
doTest("-baseClassNames.py\n" +
" -B1\n" +
" f(self, x)\n" +
" -B2(object)\n" +
" g(x)\n" +
" C(B1, B2)\n" +
" D1(C)\n" +
" D2(C)\n" +
" D3(lib1.C)\n");
}
public void testAttributes() { // PY-3371
myFixture.configureByFile(TEST_DIRECTORY + "attributes.py");
doTest("-attributes.py\n" +
" -B(object)\n" +
" f(self, x)\n" +
" __init__(self, x, y)\n" +
" g(cls, x)\n" +
" c1\n" +
" c2\n" +
" i1\n" +
" i2\n" +
" i3\n" +
" g1\n" +
" -C(B)\n" +
" __init__(self, x, y)\n" +
" h(self)\n" +
" c2\n" +
" c3\n" +
" i3\n" +
" i4\n" +
" i5\n" +
" g2\n");
}
private void doTest(final String expected) {
myFixture.testStructureView(new Consumer<StructureViewComponent>() {
@Override
public void consume(StructureViewComponent component) {
assertTreeEqual(component.getTree(), "-baseClassNames.py\n" +
" -B1\n" +
" f(self, x)\n" +
" -B2(object)\n" +
" g(x)\n" +
" C(B1, B2)\n" +
" D1(C)\n" +
" D2(C)\n" +
" D3(lib1.C)\n");
assertTreeEqual(component.getTree(), expected);
}
});
}