• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 package annotator.scanner;
2 
3 import com.sun.source.tree.ClassTree;
4 import com.sun.source.tree.NewClassTree;
5 import com.sun.source.tree.Tree;
6 import com.sun.source.util.TreePath;
7 import com.sun.source.util.TreePathScanner;
8 
9 /**
10  * AnonymousClassScanner determine the index of a tree for an anonymous
11  * class.  If the index is i, it is the ith anonymous class in the file.
12  * Thus, if i = 2, it will have a name of the form NamedClass$2.
13  */
14 public class AnonymousClassScanner extends TreePathScanner<Void, Integer> {
15 
16   /**
17    * Given an anonymous class, computes and returns its 1-based index in the given tree representing
18    * an anonymous class.
19    *
20    * @param path the source path ending in the anonymous class
21    * @param anonclass the anonymous class to search for
22    * @return the index of the anonymous class in the source code
23    */
indexOfClassTree(TreePath path, Tree anonclass)24   public static int indexOfClassTree(TreePath path, Tree anonclass) {
25     // Move up to the CLASS tree enclosing this CLASS tree and start the tree
26     // traversal from there. This prevents us from counting anonymous classes
27     // that are in a different part of the tree and therefore aren't included
28     // in the index number.
29     int classesFound = 0;
30     boolean anonclassFound = false;
31     while (path.getParentPath() != null && classesFound < 1) {
32       if (path.getLeaf() == anonclass) {
33         anonclassFound = true;
34       }
35       path = path.getParentPath();
36       if (anonclassFound && CommonScanner.hasClassKind(path.getLeaf())) {
37         classesFound++;
38       }
39     }
40     AnonymousClassScanner lvts = new AnonymousClassScanner(anonclass);
41     lvts.scan(path, 0);
42     if (lvts.found) {
43       return lvts.index;
44     } else {
45       return -1;
46     }
47   }
48 
49   private int index;
50   // top-level class doesn't count, so first index will be -1
51   private boolean found;
52   private Tree anonclass;
53 
54   /**
55    * Creates a new AnonymousClassScanner that searches for the index of the given
56    * tree, representing an anonymous class.
57    *
58    * @param tree the anonymous class to search for
59    */
AnonymousClassScanner(Tree anonclass)60   private AnonymousClassScanner(Tree anonclass) {
61     this.index = 1;             // start counting at 1
62     this.found = false;
63     this.anonclass = anonclass;
64   }
65 
66   // Slightly tricky counting:  if the target item is a CLASS, only count
67   // CLASSes.  If it is a NEW_CLASS, only count NEW_CLASSes
68   // The level parameter keeps us from traversing too low in the tree and
69   // counting classes that aren't included in the index number.
70 
71   @Override
visitClass(ClassTree node, Integer level)72   public Void visitClass(ClassTree node, Integer level) {
73     if (level < 2) {
74       if (!found && CommonScanner.hasClassKind(anonclass)) {
75         if (anonclass == node) {
76           found = true;
77         } else if (node.getSimpleName().toString().trim().isEmpty()) {
78           // don't count classes with given names in source
79           index++;
80         }
81       }
82       super.visitClass(node, level + 1);
83     }
84     return null;
85   }
86 
87   @Override
visitNewClass(NewClassTree node, Integer level)88   public Void visitNewClass(NewClassTree node, Integer level) {
89     // if (level < 2) {
90       if (!found && anonclass.getKind() == Tree.Kind.NEW_CLASS) {
91         if (anonclass == node) {
92           found = true;
93         } else if (node.getClassBody() != null) {
94           // Need to make sure you actually are creating anonymous inner class,
95           // not just object creation.
96           index++;
97         } else {
98           return null;
99         }
100       }
101       super.visitNewClass(node, level + 1);
102     // }
103     return null;
104   }
105 }
106