• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    */
indexOfLambdaExpressionTree(TreePath origpath, Tree tree)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    */
LambdaScanner(Tree tree)49   private LambdaScanner(Tree tree) {
50     this.index = -1;
51     this.done = false;
52     this.tree = tree;
53   }
54 
55   @Override
visitLambdaExpression(LambdaExpressionTree node, Void p)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    */
addLambdaExpressionToMethod(String methodName, Integer offset)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
getMethodLambdaExpressionIndex(String methodName, Integer offset)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