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