Home | History | Annotate | Download | only in find
      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 
     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
     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
     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
    120   public Kind getKind() {
    121     return Kind.LOCAL_VARIABLE;
    122   }
    123 
    124   @Override
    125   public String toString() {
    126     return "LocalVariableCriterion: in: " + fullMethodName + " loc: " + loc;
    127   }
    128 }
    129