refactor to avoid SOE and fail to stop problems ever (IDEA-140324)

This commit is contained in:
Gregory Shrago
2015-05-16 00:46:56 +03:00
committed by nik
parent b337efce90
commit a88099d232
2 changed files with 76 additions and 67 deletions
@@ -29,6 +29,7 @@ import com.intellij.psi.*;
import com.intellij.psi.search.GlobalSearchScope;
import com.intellij.psi.search.PsiFileSystemItemProcessor;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.PathUtil;
import com.intellij.util.Processor;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.annotations.Nullable;
@@ -181,4 +182,51 @@ public class DefaultNavBarExtension extends AbstractNavBarModelExtension {
}
});
}
@Nullable
@Override
public PsiElement getParent(PsiElement psiElement) {
PsiFile containingFile = psiElement.getContainingFile();
if (containingFile != null) {
PsiDirectory containingDirectory = containingFile.getContainingDirectory();
if (containingDirectory != null) {
return containingDirectory;
}
}
else if (psiElement instanceof PsiDirectory) {
PsiDirectory psiDirectory = (PsiDirectory)psiElement;
Project project = psiElement.getProject();
PsiDirectory parentDirectory = psiDirectory.getParentDirectory();
if (parentDirectory == null) {
VirtualFile jar = PathUtil.getLocalFile(psiDirectory.getVirtualFile());
if (ProjectRootManager.getInstance(project).getFileIndex().isInContent(jar)) {
parentDirectory = PsiManager.getInstance(project).findDirectory(jar.getParent());
}
}
return parentDirectory;
}
else if (psiElement instanceof PsiFileSystemItem) {
VirtualFile virtualFile = ((PsiFileSystemItem)psiElement).getVirtualFile();
if (virtualFile == null) return null;
PsiManager psiManager = psiElement.getManager();
PsiElement resultElement;
if (virtualFile.isDirectory()) {
resultElement = psiManager.findDirectory(virtualFile);
}
else {
resultElement = psiManager.findFile(virtualFile);
}
if (resultElement == null) return null;
VirtualFile parentVFile = virtualFile.getParent();
if (parentVFile != null) {
PsiDirectory parentDirectory = psiManager.findDirectory(parentVFile);
if (parentDirectory != null) {
return parentDirectory;
}
}
}
return null;
}
}
@@ -33,9 +33,9 @@ import com.intellij.openapi.util.Computable;
import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.psi.*;
import com.intellij.psi.util.PsiUtilCore;
import com.intellij.util.CommonProcessors;
import com.intellij.util.ObjectUtils;
import com.intellij.util.PathUtil;
import com.intellij.util.Processor;
import com.intellij.util.containers.ContainerUtil;
import org.jetbrains.annotations.NotNull;
@@ -174,7 +174,7 @@ public class NavBarModel {
}
});
setModel(updatedModel);
setModel(ContainerUtil.reverse(updatedModel));
}
void revalidate() {
@@ -215,81 +215,42 @@ public class NavBarModel {
}
}
private void traverseToRoot(@NotNull PsiElement psiElement, Set<VirtualFile> roots, List<Object> model) {
if (!psiElement.isValid()) return;
final PsiFile containingFile = psiElement.getContainingFile();
if (containingFile != null && containingFile.getVirtualFile() == null) return; //non physical elements
psiElement = getOriginalElement(psiElement);
PsiElement resultElement = psiElement;
private static void traverseToRoot(@NotNull PsiElement psiElement, Set<VirtualFile> roots, List<Object> model) {
if (!isValid(psiElement)) return;
resultElement = normalize(resultElement);
if (resultElement == null) return;
NavBarModelExtension[] extensions = Extensions.getExtensions(NavBarModelExtension.EP_NAME);
boolean foundByExtension = false;
for (final NavBarModelExtension modelExtension : Extensions.getExtensions(NavBarModelExtension.EP_NAME)) {
final PsiElement parent = modelExtension.getParent(resultElement);
if (parent != null) {
if (parent != resultElement) { // HACK is to return same element to stop traversing
traverseToRoot(parent, roots, model);
}
foundByExtension = true;
break;
}
}
for (PsiElement e = normalize(getOriginalElement(psiElement)), next = null;
e != null; e = normalize(getOriginalElement(next)), next = null) {
// check if we're running circles due to getParent()->normalize/adjust()
if (model.contains(e)) break;
if (!foundByExtension) {
if (containingFile != null) {
final PsiDirectory containingDirectory = containingFile.getContainingDirectory();
if (containingDirectory != null) {
traverseToRoot(containingDirectory, roots, model);
}
}
else if (psiElement instanceof PsiDirectory) {
final PsiDirectory psiDirectory = (PsiDirectory)psiElement;
model.add(e);
if (!roots.contains(psiDirectory.getVirtualFile())) {
PsiDirectory parentDirectory = psiDirectory.getParentDirectory();
// check if a root is reached
VirtualFile vFile = PsiUtilCore.getVirtualFile(e);
if (roots.contains(vFile)) break;
if (parentDirectory == null) {
VirtualFile jar = PathUtil.getLocalFile(psiDirectory.getVirtualFile());
if (ProjectRootManager.getInstance(myProject).getFileIndex().isInContent(jar)) {
parentDirectory = PsiManager.getInstance(myProject).findDirectory(jar.getParent());
}
}
if (parentDirectory != null) {
traverseToRoot(parentDirectory, roots, model);
}
}
}
else if (psiElement instanceof PsiFileSystemItem) {
final VirtualFile virtualFile = ((PsiFileSystemItem)psiElement).getVirtualFile();
if (virtualFile == null) return;
final PsiManager psiManager = PsiManager.getInstance(myProject);
if (virtualFile.isDirectory()) {
resultElement = psiManager.findDirectory(virtualFile);
}
else {
resultElement = psiManager.findFile(virtualFile);
}
if (resultElement == null) return;
final VirtualFile parentVFile = virtualFile.getParent();
if (parentVFile != null && !roots.contains(parentVFile)) {
final PsiDirectory parentDirectory = psiManager.findDirectory(parentVFile);
if (parentDirectory != null) {
traverseToRoot(parentDirectory, roots, model);
}
for (NavBarModelExtension ext : extensions) {
PsiElement parent = ext.getParent(e);
if (parent != null && parent != e) {
//noinspection AssignmentToForLoopParameter
next = parent;
break;
}
}
}
model.add(resultElement);
}
private static PsiElement getOriginalElement(PsiElement psiElement) {
final PsiElement originalElement = psiElement.getOriginalElement();
return !(psiElement instanceof PsiCompiledElement) && originalElement instanceof PsiCompiledElement ? psiElement : originalElement;
@Nullable
private static PsiElement getOriginalElement(@Nullable PsiElement e) {
if (e == null || !e.isValid()) return null;
PsiFile containingFile = e.getContainingFile();
if (containingFile != null && containingFile.getVirtualFile() == null) return null;
PsiElement orig = e.getOriginalElement();
return !(e instanceof PsiCompiledElement) && orig instanceof PsiCompiledElement ? e : orig;
}