| package annotator.scanner; |
| |
| import com.sun.source.tree.ClassTree; |
| import com.sun.source.tree.NewClassTree; |
| import com.sun.source.tree.Tree; |
| import com.sun.source.util.TreePath; |
| import com.sun.source.util.TreePathScanner; |
| |
| /** |
| * AnonymousClassScanner determine the index of a tree for an anonymous |
| * class. If the index is i, it is the ith anonymous class in the file. |
| * Thus, if i = 2, it will have a name of the form NamedClass$2. |
| */ |
| public class AnonymousClassScanner extends TreePathScanner<Void, Integer> { |
| |
| /** |
| * Given an anonymous class, computes and returns its 1-based index in the given tree representing |
| * an anonymous class. |
| * |
| * @param path the source path ending in the anonymous class |
| * @param anonclass the anonymous class to search for |
| * @return the index of the anonymous class in the source code |
| */ |
| public static int indexOfClassTree(TreePath path, Tree anonclass) { |
| // Move up to the CLASS tree enclosing this CLASS tree and start the tree |
| // traversal from there. This prevents us from counting anonymous classes |
| // that are in a different part of the tree and therefore aren't included |
| // in the index number. |
| int classesFound = 0; |
| boolean anonclassFound = false; |
| while (path.getParentPath() != null && classesFound < 1) { |
| if (path.getLeaf() == anonclass) { |
| anonclassFound = true; |
| } |
| path = path.getParentPath(); |
| if (anonclassFound && CommonScanner.hasClassKind(path.getLeaf())) { |
| classesFound++; |
| } |
| } |
| AnonymousClassScanner lvts = new AnonymousClassScanner(anonclass); |
| lvts.scan(path, 0); |
| if (lvts.found) { |
| return lvts.index; |
| } else { |
| return -1; |
| } |
| } |
| |
| private int index; |
| // top-level class doesn't count, so first index will be -1 |
| private boolean found; |
| private Tree anonclass; |
| |
| /** |
| * Creates a new AnonymousClassScanner that searches for the index of the given |
| * tree, representing an anonymous class. |
| * |
| * @param tree the anonymous class to search for |
| */ |
| private AnonymousClassScanner(Tree anonclass) { |
| this.index = 1; // start counting at 1 |
| this.found = false; |
| this.anonclass = anonclass; |
| } |
| |
| // Slightly tricky counting: if the target item is a CLASS, only count |
| // CLASSes. If it is a NEW_CLASS, only count NEW_CLASSes |
| // The level parameter keeps us from traversing too low in the tree and |
| // counting classes that aren't included in the index number. |
| |
| @Override |
| public Void visitClass(ClassTree node, Integer level) { |
| if (level < 2) { |
| if (!found && CommonScanner.hasClassKind(anonclass)) { |
| if (anonclass == node) { |
| found = true; |
| } else if (node.getSimpleName().toString().trim().isEmpty()) { |
| // don't count classes with given names in source |
| index++; |
| } |
| } |
| super.visitClass(node, level + 1); |
| } |
| return null; |
| } |
| |
| @Override |
| public Void visitNewClass(NewClassTree node, Integer level) { |
| // if (level < 2) { |
| if (!found && anonclass.getKind() == Tree.Kind.NEW_CLASS) { |
| if (anonclass == node) { |
| found = true; |
| } else if (node.getClassBody() != null) { |
| // Need to make sure you actually are creating anonymous inner class, |
| // not just object creation. |
| index++; |
| } else { |
| return null; |
| } |
| } |
| super.visitNewClass(node, level + 1); |
| // } |
| return null; |
| } |
| } |