Home | History | Annotate | Download | only in scanner
      1 package annotator.scanner;
      2 
      3 import java.util.ArrayList;
      4 import java.util.HashMap;
      5 import java.util.List;
      6 import java.util.Map;
      7 
      8 import com.sun.source.tree.LambdaExpressionTree;
      9 import com.sun.source.tree.Tree;
     10 import com.sun.source.util.TreePath;
     11 
     12 /**
     13  * LambdaScanner stores information about the names and offsets of
     14  * lambda expressions inside a method, and can also be used to scan the
     15  * source tree and determine the index of a given instanceof check,
     16  * where the i^th index corresponds to the i^th instanceof check, using
     17  * 0-based indexing.
     18  */
     19 public class LambdaScanner extends CommonScanner {
     20 
     21   /**
     22    * Computes the index of the given lambda expression tree amongst all
     23    * lambda expression trees inside its method, using 0-based indexing.
     24    *
     25    * @param origpath the path ending in the given lambda expression tree
     26    * @param tree the lambda expression tree to search for
     27    * @return the index of the given lambda expression tree
     28    */
     29   public static int indexOfLambdaExpressionTree(TreePath origpath, Tree tree) {
     30     TreePath path = findCountingContext(origpath);
     31     if (path == null) {
     32       return -1;
     33     }
     34 
     35     LambdaScanner ls = new LambdaScanner(tree);
     36     ls.scan(path, null);
     37     return ls.index;
     38   }
     39 
     40   private int index;
     41   private boolean done;
     42   private final Tree tree;
     43 
     44   /**
     45    * Creates an InstanceOfScanner that will scan the source tree for the
     46    *  given node representing the lambda expression to find.
     47    * @param tree the given lambda expression to search for
     48    */
     49   private LambdaScanner(Tree tree) {
     50     this.index = -1;
     51     this.done = false;
     52     this.tree = tree;
     53   }
     54 
     55   @Override
     56   public Void visitLambdaExpression(LambdaExpressionTree node, Void p) {
     57     if (!done) {
     58       index++;
     59     }
     60     if (tree == node) {
     61       done = true;
     62     }
     63     return super.visitLambdaExpression(node, p);
     64   }
     65 
     66   // Map from name of a method to a list of bytecode offsets of all
     67   // lambda expressions in that method.
     68   private static Map<String, List<Integer>> methodNameToLambdaExpressionOffsets =
     69       new HashMap<String, List<Integer>>();
     70 
     71   /**
     72    * Adds a lambda expression bytecode offset to the current list of
     73    * offsets for methodName.  This method must be called with
     74    * monotonically increasing offsets for any one method.
     75    *
     76    * @param methodName the name of the method
     77    * @param offset the offset to add
     78    */
     79   public static void addLambdaExpressionToMethod(String methodName, Integer offset) {
     80     List<Integer> offsetList =
     81         methodNameToLambdaExpressionOffsets.get(methodName);
     82     if (offsetList == null) {
     83       offsetList = new ArrayList<Integer>();
     84       methodNameToLambdaExpressionOffsets.put(methodName, offsetList);
     85     }
     86     offsetList.add(offset);
     87   }
     88 
     89   /**
     90    * Returns the index of the given offset within the list of offsets
     91    * for the given method, using 0-based indexing, or returns a negative
     92    * number if the offset is not one of the offsets in the context.
     93    *
     94    * @param methodName the name of the method
     95    * @param offset the offset of the lambda expression
     96    * @return the index of the given offset, or a negative number
     97    *  if the offset does not exist inside the context
     98    */
     99   public static Integer
    100   getMethodLambdaExpressionIndex(String methodName, Integer offset) {
    101     List<Integer> offsetList =
    102         methodNameToLambdaExpressionOffsets.get(methodName);
    103     if (offsetList == null) {
    104       return -1;
    105     }
    106 
    107     return offsetList.indexOf(offset);
    108   }
    109 }
    110