EA-83566 PyStructureViewElement considers that underlying PSI element can be invalid
authorMikhail Golubev <mikhail.golubev@jetbrains.com>
Mon, 14 Nov 2016 12:45:22 +0000 (15:45 +0300)
committerMikhail Golubev <mikhail.golubev@jetbrains.com>
Wed, 16 Nov 2016 12:39:57 +0000 (15:39 +0300)
python/src/com/jetbrains/python/structureView/PyStructureViewElement.java
python/testSrc/com/jetbrains/python/PyStructureViewTest.java

index 9962f6ee00e3c597d143bf6b33d980cd452eda5c..fa283359c4a93d82dd5f286ceb3136d74dad21cb 100644 (file)
@@ -68,9 +68,10 @@ public class PyStructureViewElement implements StructureViewTreeElement {
     return new PyStructureViewElement(element, visibility, inherited, field);
   }
 
     return new PyStructureViewElement(element, visibility, inherited, field);
   }
 
+  @Nullable
   @Override
   public PyElement getValue() {
   @Override
   public PyElement getValue() {
-    return myElement;
+    return myElement.isValid() ? myElement : null;
   }
 
   public boolean isInherited() {
   }
 
   public boolean isInherited() {
@@ -83,17 +84,20 @@ public class PyStructureViewElement implements StructureViewTreeElement {
 
   @Override
   public void navigate(boolean requestFocus) {
 
   @Override
   public void navigate(boolean requestFocus) {
-    myElement.navigate(requestFocus);
+    final PyElement element = getValue();
+    if (element != null) {
+      myElement.navigate(requestFocus);
+    }
   }
 
   @Override
   public boolean canNavigate() {
   }
 
   @Override
   public boolean canNavigate() {
-    return myElement.canNavigate();
+    return myElement.isValid() && myElement.canNavigate();
   }
 
   @Override
   public boolean canNavigateToSource() {
   }
 
   @Override
   public boolean canNavigateToSource() {
-    return myElement.canNavigateToSource();
+    return myElement.isValid() && myElement.canNavigateToSource();
   }
 
   public void setIcon(Icon icon) {
   }
 
   public void setIcon(Icon icon) {
@@ -120,13 +124,18 @@ public class PyStructureViewElement implements StructureViewTreeElement {
 
   @NotNull
   public StructureViewTreeElement[] getChildren() {
 
   @NotNull
   public StructureViewTreeElement[] getChildren() {
+    final PyElement element = getValue();
+    if (element == null) {
+      return EMPTY_ARRAY;
+    }
+
     final Collection<StructureViewTreeElement> children = new ArrayList<>();
     final Collection<StructureViewTreeElement> children = new ArrayList<>();
-    for (PyElement e : getElementChildren(myElement)) {
+    for (PyElement e : getElementChildren(element)) {
       children.add(createChild(e, getElementVisibility(e), false, elementIsField(e)));
     }
       children.add(createChild(e, getElementVisibility(e), false, elementIsField(e)));
     }
-    PyPsiUtils.assertValid(myElement);
-    if (myElement instanceof PyClass) {
-      for (PyClass c : ((PyClass)myElement).getAncestorClasses(null)) {
+    PyPsiUtils.assertValid(element);
+    if (element instanceof PyClass) {
+      for (PyClass c : ((PyClass)element).getAncestorClasses(null)) {
         for (PyElement e: getElementChildren(c)) {
           final StructureViewTreeElement inherited = createChild(e, getElementVisibility(e), true, elementIsField(e));
           if (!children.contains(inherited)) {
         for (PyElement e: getElementChildren(c)) {
           final StructureViewTreeElement inherited = createChild(e, getElementVisibility(e), true, elementIsField(e));
           if (!children.contains(inherited)) {
@@ -231,13 +240,15 @@ public class PyStructureViewElement implements StructureViewTreeElement {
   @NotNull
   @Override
   public ItemPresentation getPresentation() {
   @NotNull
   @Override
   public ItemPresentation getPresentation() {
-    final ItemPresentation presentation = myElement.getPresentation();
+    final PyElement element = getValue();
+    final ItemPresentation presentation = element != null ? element.getPresentation() : null;
+
     return new ColoredItemPresentation() {
       @Nullable
       @Override
       public String getPresentableText() {
     return new ColoredItemPresentation() {
       @Nullable
       @Override
       public String getPresentableText() {
-        if (myElement instanceof PyFile) {
-          return myElement.getName();
+        if (element instanceof PyFile) {
+          return element.getName();
         }
         return presentation != null ? presentation.getPresentableText() : PyNames.UNNAMED_ELEMENT;
       }
         }
         return presentation != null ? presentation.getPresentableText() : PyNames.UNNAMED_ELEMENT;
       }
@@ -260,7 +271,11 @@ public class PyStructureViewElement implements StructureViewTreeElement {
       @Nullable
       @Override
       public Icon getIcon(boolean open) {
       @Nullable
       @Override
       public Icon getIcon(boolean open) {
-        Icon normal_icon = myElement.getIcon(0);
+        if (element == null) {
+          return null;
+        }
+
+        Icon normal_icon = element.getIcon(0);
         if (myIcon != null) normal_icon = myIcon; // override normal
         if (myVisibility == Visibility.NORMAL) {
           return normal_icon;
         if (myIcon != null) normal_icon = myIcon; // override normal
         if (myVisibility == Visibility.NORMAL) {
           return normal_icon;
index d30bba454b52aebdee0a5031742acc8c277e240f..30ec32af1548709e5f06802aea626ae23a762eb1 100644 (file)
  */
 package com.jetbrains.python;
 
  */
 package com.jetbrains.python;
 
-import com.intellij.ide.structureView.newStructureView.StructureViewComponent;
-import com.intellij.util.Consumer;
+import com.intellij.navigation.ItemPresentation;
+import com.intellij.openapi.command.WriteCommandAction;
 import com.jetbrains.python.fixtures.PyTestCase;
 import com.jetbrains.python.fixtures.PyTestCase;
+import com.jetbrains.python.psi.PyFunction;
+import com.jetbrains.python.structureView.PyStructureViewElement;
+
+import javax.swing.*;
 
 import static com.intellij.testFramework.PlatformTestUtil.assertTreeEqual;
 
 
 import static com.intellij.testFramework.PlatformTestUtil.assertTreeEqual;
 
@@ -96,6 +100,21 @@ public class PyStructureViewTest extends PyTestCase {
            true);
   }
 
            true);
   }
 
+  // EA-83566
+  public void testInvalidatedElement() {
+    myFixture.configureByText("a.py",
+                              "def f():\n" +
+                              "    pass");
+    final PyFunction function = myFixture.findElementByText("f", PyFunction.class);
+    final PyStructureViewElement node = new PyStructureViewElement(function);
+    WriteCommandAction.runWriteCommandAction(myFixture.getProject(), function::delete);
+    assertNull(node.getValue());
+    final ItemPresentation presentation = node.getPresentation();
+    assertNotNull(presentation);
+    final Icon icon = presentation.getIcon(false);
+    assertNull(icon);
+  }
+
   private void doTest(final String expected, final boolean inherited) {
     myFixture.testStructureView(component -> {
       component.setActionActive("SHOW_INHERITED", !inherited);
   private void doTest(final String expected, final boolean inherited) {
     myFixture.testStructureView(component -> {
       component.setActionActive("SHOW_INHERITED", !inherited);