Home | History | Annotate | Download | only in scanner
      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