blob: 13d5afdd1e9f7cda4b409476cd7a75839d3414be [file] [log] [blame]
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;
}
}