1package annotator.scanner; 2 3import java.util.ArrayList; 4import java.util.HashMap; 5import java.util.List; 6import java.util.Map; 7 8import com.sun.source.tree.LambdaExpressionTree; 9import com.sun.source.tree.Tree; 10import 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 */ 19public 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