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.MethodInvocationTree;
      9 import com.sun.source.tree.Tree;
     10 import com.sun.source.util.TreePath;
     11 
     12 public class MethodCallScanner extends CommonScanner {
     13 
     14   /**
     15    * Computes the index of the given method invocation amongst all
     16    * method invocation trees inside its method, using 0-based indexing.
     17    *
     18    * @param origpath the path ending in the given method invocation tree
     19    * @param tree the method invocation tree to search for
     20    * @return the index of the given method invocation tree
     21    */
     22   public static int indexOfMethodCallTree(TreePath origpath, Tree tree) {
     23     TreePath path = findCountingContext(origpath);
     24     if (path == null) {
     25       return -1;
     26     }
     27 
     28     MethodCallScanner mcs = new MethodCallScanner(tree);
     29     mcs.scan(path, null);
     30     return mcs.index;
     31   }
     32 
     33   private int index;
     34   private boolean done;
     35   private final Tree tree;
     36 
     37   /**
     38    * Creates an InstanceOfScanner that will scan the source tree for the
     39    *  given node representing the method invocation to find.
     40    * @param tree the given method invocation to search for
     41    */
     42   private MethodCallScanner(Tree tree) {
     43     this.index = -1;
     44     this.done = false;
     45     this.tree = tree;
     46   }
     47 
     48   @Override
     49   public Void visitMethodInvocation(MethodInvocationTree node, Void p) {
     50     if (!done) {
     51       index++;
     52     }
     53     if (tree == node) {
     54       done = true;
     55     }
     56     return super.visitMethodInvocation(node, p);
     57   }
     58 
     59   // Map from name of a method to a list of bytecode offsets of all
     60   // method invocations in that method.
     61   private static Map<String, List<Integer>> methodNameToMethodCallOffsets =
     62       new HashMap<String, List<Integer>>();
     63 
     64   /**
     65    * Adds a lambda expression bytecode offset to the current list of
     66    * offsets for methodName.  This method must be called with
     67    * monotonically increasing offsets for any one method.
     68    *
     69    * @param methodName the name of the method
     70    * @param offset the offset to add
     71    */
     72   public static void addMethodCallToMethod(String methodName, Integer offset) {
     73     List<Integer> offsetList =
     74         methodNameToMethodCallOffsets.get(methodName);
     75     if (offsetList == null) {
     76       offsetList = new ArrayList<Integer>();
     77       methodNameToMethodCallOffsets.put(methodName, offsetList);
     78     }
     79     offsetList.add(offset);
     80   }
     81 
     82   /**
     83    * Returns the index of the given offset within the list of offsets
     84    * for the given method, using 0-based indexing, or returns a negative
     85    * number if the offset is not one of the offsets in the context.
     86    *
     87    * @param methodName the name of the method
     88    * @param offset the offset of the lambda expression
     89    * @return the index of the given offset, or a negative number
     90    *  if the offset does not exist inside the context
     91    */
     92   public static Integer
     93   getMethodCallIndex(String methodName, Integer offset) {
     94     List<Integer> offsetList =
     95         methodNameToMethodCallOffsets.get(methodName);
     96     if (offsetList == null) {
     97       return -1;
     98     }
     99 
    100     return offsetList.indexOf(offset);
    101   }
    102 }
    103