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 */ 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 */ 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 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 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