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