summaryrefslogtreecommitdiff
path: root/plugins/structuralsearch/structuralsearch-java/src/com/intellij/structuralsearch/impl/matcher/iterators/HierarchyNodeIterator.java
blob: 324528435cb6d8c4a8b53a9fcfc6790c8f8e65bd (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
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;
  }
}