1 package annotator.scanner; 2 3 import com.sun.source.tree.BlockTree; 4 import com.sun.source.tree.ClassTree; 5 import com.sun.source.tree.StatementTree; 6 import com.sun.source.tree.Tree; 7 import com.sun.source.util.TreePath; 8 import com.sun.source.util.TreePathScanner; 9 10 /** 11 * LocalClassScanner determines the index of a tree for a local 12 * class. If the index is i, it is the ith local class with the class name in 13 * the file. Thus, if i = 2, it will have a name of the form 14 * OuterClass$2InnerClass. 15 */ 16 public class LocalClassScanner extends TreePathScanner<Void, Integer> { 17 18 /** 19 * Given a local class, computes and returns its 1-based index in the given 20 * tree representing a local class. 21 * 22 * @param path the source path ending in the local class 23 * @param localClass the local class to search for 24 * @return the index of the local class in the source code 25 */ 26 public static int indexOfClassTree(TreePath path, ClassTree localClass) { 27 // Move up to the CLASS tree enclosing this CLASS tree and start the tree 28 // traversal from there. This prevents us from counting local classes that 29 // are in a different part of the tree and therefore aren't included in the 30 // index number. 31 int classesFound = 0; 32 boolean localClassFound = false; 33 while (path.getParentPath() != null && classesFound < 1) { 34 if (path.getLeaf() == localClass) { 35 localClassFound = true; 36 } 37 path = path.getParentPath(); 38 if (localClassFound && path.getLeaf().getKind() == Tree.Kind.CLASS) { 39 classesFound++; 40 } 41 } 42 LocalClassScanner lcs = new LocalClassScanner(localClass); 43 lcs.scan(path, 0); 44 if (lcs.found) { 45 return lcs.index; 46 } else { 47 return -1; 48 } 49 } 50 51 private int index; 52 private boolean found; 53 private ClassTree localClass; 54 55 /** 56 * Creates a new LocalClassScanner that searches for the index of the given 57 * tree, representing a local class. 58 * 59 * @param localClass the local class to search for 60 */ 61 private LocalClassScanner(ClassTree localClass) { 62 this.index = 1; 63 this.found = false; 64 this.localClass = localClass; 65 } 66 67 // The level parameter keeps us from traversing too low in the tree and 68 // counting classes that aren't included in the index number. 69 70 @Override 71 public Void visitBlock(BlockTree node, Integer level) { 72 if (level < 1) { 73 // Visit blocks since a local class can only be in a block. Then visit each 74 // statement of the block to see if any are the correct local class. 75 for (StatementTree statement : node.getStatements()) { 76 if (!found && statement.getKind() == Tree.Kind.CLASS) { 77 ClassTree c = (ClassTree) statement; 78 if (localClass == statement) { 79 found = true; 80 } else if (c.getSimpleName().equals(localClass.getSimpleName())) { 81 index++; 82 } 83 } 84 } 85 super.visitBlock(node, level + 1); 86 } 87 return null; 88 } 89 } 90