Iterator<PsiClass> () { //noinspection SSBasedInspection return new Iterator<>() { final IntArrayList indices = new IntArrayList(); final Stack<PsiClassType[]> superTypesStack = new Stack<>(); final Set<PsiClass> visited = new HashSet<>(); PsiClass current; boolean nextObtained; { if (includeSelf) { current = psiClass; nextObtained = true; } else { current = null; nextObtained = false; } pushSuper(psiClass); } @Override public boolean hasNext() { nextElement(); return current != null; } private void nextElement() { if (nextObtained) return; nextObtained = true; while (!superTypesStack.empty()) { assert !indices.isEmpty(); int i = indices.popInt(); PsiClassType[] superTypes = superTypesStack.peek(); while (i < superTypes.length) { PsiClass clazz = superTypes[i].resolve(); if (clazz != null && !visited.contains(clazz)) { current = clazz; visited.add(clazz); indices.push(i + 1); pushSuper(clazz); return; } i++; } superTypesStack.pop(); } current = null; } private void pushSuper(PsiClass clazz) { superTypesStack.push(clazz.getSuperTypes()); indices.push(0); } @Override @NotNull public PsiClass next() { nextElement(); nextObtained = false; if (current == null) throw new NoSuchElementException(); return current; } @Override public void remove() { throw new IllegalStateException("should not be called"); } }; }