blob: 324528435cb6d8c4a8b53a9fcfc6790c8f8e65bd [file] [log] [blame]
package com.intellij.structuralsearch.impl.matcher.iterators;
import com.intellij.dupLocator.iterators.NodeIterator;
import com.intellij.psi.*;
import com.intellij.psi.impl.PsiClassImplUtil;
import com.intellij.structuralsearch.impl.matcher.MatchUtils;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
/**
* Passes the hierarchy
*/
public class HierarchyNodeIterator extends NodeIterator {
private int index;
private ArrayList<PsiElement> remaining;
private boolean objectTaken;
private boolean firstElementTaken;
private final boolean acceptClasses;
private final boolean acceptInterfaces;
private final boolean acceptFirstElement;
private void build(PsiElement current, Set<PsiElement> visited) {
if (current!=null) {
final String str = current instanceof PsiClass ? ((PsiClass)current).getName():current.getText();
if (MatchUtils.compareWithNoDifferenceToPackage(str,"Object")) {
if(objectTaken) return;
objectTaken = true;
}
PsiElement element = MatchUtils.getReferencedElement(current);
if (element instanceof PsiClass) {
if (visited.contains(element)) return;
final PsiClass clazz = (PsiClass)element;
if (acceptInterfaces || !clazz.isInterface() ) visited.add(element);
if (!firstElementTaken && acceptFirstElement || firstElementTaken) remaining.add(clazz);
firstElementTaken = true;
if (clazz instanceof PsiAnonymousClass) {
build(((PsiAnonymousClass)clazz).getBaseClassReference(),visited);
return;
}
if (acceptClasses) {
processClasses(clazz, visited);
if (!objectTaken) {
build(PsiClassImplUtil.getSuperClass(clazz), visited);
}
}
if (acceptInterfaces) {
final PsiReferenceList implementsList = clazz.getImplementsList();
if (implementsList != null) {
final PsiElement[] implementsListElements = implementsList.getReferenceElements();
for (PsiElement anImplementsList : implementsListElements) {
build(anImplementsList,visited);
}
}
if (!acceptClasses) processClasses(clazz, visited);
}
} else {
remaining.add(current);
}
}
}
private void processClasses(final PsiClass clazz, final Set<PsiElement> visited) {
final PsiReferenceList clazzExtendsList = clazz.getExtendsList();
final PsiElement[] extendsList = (clazzExtendsList != null)?clazzExtendsList.getReferenceElements():null;
if (extendsList != null) {
for (PsiElement anExtendsList : extendsList) {
build(anExtendsList,visited);
}
}
}
public HierarchyNodeIterator(PsiElement reference, boolean acceptClasses, boolean acceptInterfaces) {
this(reference, acceptClasses, acceptInterfaces, true);
}
public HierarchyNodeIterator(PsiElement reference, boolean acceptClasses, boolean acceptInterfaces, boolean acceptFirstElement) {
remaining = new ArrayList<PsiElement>();
this.acceptClasses = acceptClasses;
this.acceptInterfaces = acceptInterfaces;
this.acceptFirstElement = acceptFirstElement;
if (reference instanceof PsiIdentifier) {
reference = reference.getParent();
}
build(reference,new HashSet<PsiElement>());
}
public boolean hasNext() {
return index < remaining.size();
}
public PsiElement current() {
return remaining.get(index);
}
public void advance() {
if (index!=remaining.size()) {
++index;
}
}
public void rewind() {
if (index > 0) {
--index;
}
}
public void reset() {
index = 0;
}
}