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