• 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.Tree;
9 import com.sun.source.tree.VariableTree;
10 import com.sun.source.util.TreePath;
11 import com.sun.tools.javac.util.Pair;
12 
13 /** LocalVariableScanner stores information about the names and offsets of
14  * local variables inside a method, and can also be used to scan the source
15  * tree and determine the index of a local variable with a given name, so that
16  * the i^th index corresponds to the i^th declaration of a local variable with
17  * that name, using 0-based indexing.
18  */
19 public class LocalVariableScanner extends CommonScanner {
20   /**
21    * Computes the index i of the given tree along the given tree path
22    * such that it is the i^th declaration of the local variable with the given
23    * var name, using 0-based indexing.
24    *
25    * @param origpath the source path that ends in varTree
26    * @param varTree the variable tree that declares the local variable
27    * @param varName the name of the local variable
28    * @return the index of the variable tree with respect to the given
29    *  local variable name
30    */
indexOfVarTree(TreePath origpath, Tree varTree, String varName)31   public static int indexOfVarTree(TreePath origpath, Tree varTree, String varName) {
32     TreePath path = findCountingContext(origpath);
33     if (path == null) {
34       return -1;
35     }
36 
37     LocalVariableScanner lvts = new LocalVariableScanner(varTree, varName);
38 
39     try {
40       lvts.scan(path, null);
41     } catch (Throwable e) {
42       System.out.println("LocalVariableScanner: can't locate: " + varTree);
43       return -2; // Don't return -1, which is above return code
44     }
45     return lvts.index;
46   }
47 
48   /*
49    * For efficiency, we might want to have methods like the following, specialized for the
50    * three different cases.
51    */
52   /*
53   public static int indexOfVarTreeInStaticInit(TreePath path, Tree tree, String varName) {
54     // only start searching from within this method
55       path = findEnclosingStaticInit(path);
56       if (path == null) {
57         return -1;
58       }
59 
60       LocalVariableScanner lvts = new LocalVariableScanner(tree, varName);
61       lvts.scan(path, null);
62       return lvts.index;
63   }
64   */
65 
66   private int index = -1;
67   private boolean done = false;
68   private final Tree varTree;
69   private final String varName;
70 
LocalVariableScanner(Tree varTree, String varName)71   private LocalVariableScanner(Tree varTree, String varName) {
72     this.index = -1;
73     this.done = false;
74     this.varTree = varTree;
75     this.varName = varName;
76   }
77 
78   @Override
visitVariable(VariableTree node, Void p)79   public Void visitVariable(VariableTree node, Void p) {
80     // increment index only if you have not already reached the right node, and
81     // if this node declares the same local variable you are searching for
82     if (varName.equals(node.getName().toString())) {
83       if (!done) {
84         index++;
85       }
86       if (varTree == node) {
87         done = true;
88       }
89     }
90     return p;
91   }
92 
93   // TODO: refactor class keys to avoid so many uses of generics
94 
95   // mapping from (method-name, variable-index, start-offset)
96   // to variable name
97   private static Map<Pair<String, Pair<Integer,Integer>>, String>
98     methodNameIndexMap = new HashMap<Pair<String, Pair<Integer,Integer>>, String>();
99 
100   // map from method to map from variable name to
101   // a list of start offsets
102   private static Map<String, Map<String, List<Integer>>>
103     methodNameCounter = new HashMap<String, Map<String,List<Integer>>>();
104 
105   /**
106    * Adds the given variable specified as a pair of method name and
107    *  (index, start-offset) under the given name to the list of all local
108    *  variables.
109    *
110    * @param varInfo a pair of the method and a pair describing the local
111    *  variable index and start offset of the local variable
112    * @param name the name of the local variable
113    */
addToMethodNameIndexMap(Pair<String, Pair<Integer,Integer>> varInfo, String name)114   public static void addToMethodNameIndexMap(Pair<String, Pair<Integer,Integer>> varInfo, String name) {
115     methodNameIndexMap.put(varInfo, name);
116   }
117 
118   /**
119    * Gets the name of the local variable in the given method, and at the
120    *  the given index and offset.
121    *
122    * @param varInfo a pair of the method name and a pair of the local variable's
123    *  index and start offset
124    * @return the name of the local variable at the specified location
125    */
getFromMethodNameIndexMap(Pair<String, Pair<Integer, Integer>> varInfo)126   public static String getFromMethodNameIndexMap(Pair<String, Pair<Integer, Integer>> varInfo) {
127     return methodNameIndexMap.get(varInfo);
128   }
129 
130   /**
131    * Adds to the given method the fact that the local variable with the given
132    *  name is declared at the given start offset.
133    *
134    * @param methodName the method containing the local variable
135    * @param varName the name of the local variable
136    * @param offset the start offset of the local variable
137    */
addToMethodNameCounter(String methodName, String varName, Integer offset)138   public static void addToMethodNameCounter(String methodName, String varName,
139         Integer offset) {
140     Map<String, List<Integer>> nameOffsetCounter = methodNameCounter.get(methodName);
141     if (nameOffsetCounter == null) {
142       nameOffsetCounter = new HashMap<String, List<Integer>>();
143       methodNameCounter.put(methodName, nameOffsetCounter);
144     }
145 
146     List<  Integer> listOfOffsets = nameOffsetCounter.get(varName);
147     if (listOfOffsets == null) {
148       listOfOffsets = new ArrayList<  Integer>();
149       nameOffsetCounter.put(varName, listOfOffsets);
150     }
151 
152     listOfOffsets.add(offset);
153   }
154 
155   /**
156    * Returns a list of all start bytecode offsets of variable declarations with
157    * the given variable name in the given method.
158    *
159    * @param methodName the name of the method
160    * @param varName the name of the local variable
161    * @return a list of start offsets for live ranges of all local variables
162    * with the given name in the given method
163    */
getFromMethodNameCounter(String methodName, String varName)164   public static List<Integer> getFromMethodNameCounter(String methodName, String varName) {
165     return methodNameCounter.get(methodName).get(varName);
166   }
167 }
168