1 package annotator.find;
2 
3 import java.util.List;
4 
5 import annotations.el.LocalLocation;
6 import annotator.scanner.LocalVariableScanner;
7 
8 import com.sun.source.tree.MethodTree;
9 import com.sun.source.tree.Tree;
10 import com.sun.source.tree.VariableTree;
11 import com.sun.source.util.TreePath;
12 import com.sun.tools.javac.util.Pair;
13 
14 /**
15  * Criterion for being a specific local variable.
16  */
17 public class LocalVariableCriterion implements Criterion {
18 
19   private final String fullMethodName;
20   private final LocalLocation loc;
21 
LocalVariableCriterion(String methodName, LocalLocation loc)22   public LocalVariableCriterion(String methodName, LocalLocation loc) {
23     this.fullMethodName = methodName.substring(0, methodName.indexOf(")") + 1);
24     this.loc = loc;
25   }
26 
27   /** {@inheritDoc} */
28   @Override
isSatisfiedBy(TreePath path, Tree leaf)29   public boolean isSatisfiedBy(TreePath path, Tree leaf) {
30     assert path == null || path.getLeaf() == leaf;
31     return isSatisfiedBy(path);
32   }
33 
34   /** {@inheritDoc} */
35   @Override
isSatisfiedBy(TreePath path)36   public boolean isSatisfiedBy(TreePath path) {
37     if (path == null) {
38       return false;
39     }
40 
41     TreePath parentPath = path.getParentPath();
42     if (parentPath != null) {
43       Tree parent = parentPath.getLeaf();
44       if (parent != null) {
45         if ((parent instanceof VariableTree)
46             // Avoid matching formal parameters
47             && (! (parentPath.getParentPath().getLeaf() instanceof MethodTree))) {
48           VariableTree vtt = (VariableTree) parent;
49           String varName = vtt.getName().toString();
50 
51           if (loc.varName!=null && loc.varName.equals(varName)) {
52             int varIndex = LocalVariableScanner.indexOfVarTree(path, vtt, varName);
53 
54             if (loc.varIndex==varIndex) {
55               // the location specifies a variable name and index and it matches the current variable
56               // -> hurray
57               return true;
58             }
59             return false;
60           }
61 
62           Pair<String, Pair<Integer, Integer>> key =
63                   Pair.of(fullMethodName, Pair.of(loc.index, loc.scopeStart));
64           String potentialVarName =
65                   LocalVariableScanner.getFromMethodNameIndexMap(key);
66           if (potentialVarName != null) {
67             if (varName.equals(potentialVarName)) {
68               // now use methodNameCounter to ensure that if this is the
69               // i'th variable of this name, its offset is the i'th offset
70               // of all variables with this name
71               List<Integer> allOffsetsWithThisName =
72                       LocalVariableScanner.getFromMethodNameCounter(fullMethodName, potentialVarName);
73 //                methodNameCounter.get(fullMethodName).get(potentialVarName);
74               Integer thisVariablesOffset =
75                       allOffsetsWithThisName.indexOf(loc.scopeStart);
76 
77               // now you need to make sure that this is the
78               // thisVariablesOffset'th variable tree in the entire source
79               int i = LocalVariableScanner.indexOfVarTree(path, parent, potentialVarName);
80 
81               if (i == thisVariablesOffset) {
82                 return true;
83               }
84             }
85           }
86         } else {
87           // If present leaf does not yet satisfy the local variable
88           // criterion, note that it actually is the correct local variable
89           // if any of its parents satisfy this local variable criterion
90           // (and going all the way up past the top-level tree is taken
91           // care of by the check for null above.
92           //
93           // For example, if you have the tree for "Integer"
94           // for the local variable "List<Integer> foo;"
95           // the parent of the current leaf will satisfy the local variable
96           // criterion directly.  The fact that you will never return true
97           // for something that is not the correct local variable comes
98           // from the fact that you can't contain one local variable
99           // within another.  For example, you can't have
100           // List<Integer bar> foo;
101           // Thus, no local variable tree can contain another local
102           // variable tree.
103           // Another general example:
104           // List<Integer> foo = ...;
105           // If the tree for ... contains one local variable, there is no fear
106           // of a conflict with "List<Integer>", because "List<Integer> foo"
107           // is a subtree of "List<Integer> foo = ...;", so the two
108           // (possibly) conflicting local variable trees are both subtrees
109           // of the same tree, and neither is an ancestor of the other.
110           return this.isSatisfiedBy(parentPath);
111           // To do: should stop this once it gets to method? or some other top level?
112         }
113       }
114     }
115     return false;
116   }
117 
118 
119   @Override
getKind()120   public Kind getKind() {
121     return Kind.LOCAL_VARIABLE;
122   }
123 
124   @Override
toString()125   public String toString() {
126     return "LocalVariableCriterion: in: " + fullMethodName + " loc: " + loc;
127   }
128 }
129