Home | History | Annotate | Download | only in find
      1 package annotator.find;
      2 
      3 import java.util.LinkedHashMap;
      4 import java.util.Map;
      5 
      6 import annotations.el.BoundLocation;
      7 import annotations.el.InnerTypeLocation;
      8 import annotations.el.LocalLocation;
      9 import annotations.el.RelativeLocation;
     10 import annotations.el.TypeIndexLocation;
     11 import annotations.io.ASTPath;
     12 import annotations.io.DebugWriter;
     13 import annotator.Main;
     14 
     15 import com.sun.source.tree.Tree;
     16 import com.sun.source.util.TreePath;
     17 
     18 /**
     19  * Represents a set of Criterion objects for locating a program element in
     20  * a source tree.
     21  * <p>
     22  *
     23  * This class also contains static factory methods for creating a {@code
     24  * Criterion}.
     25  */
     26 public final class Criteria {
     27   public static DebugWriter dbug = new DebugWriter();
     28 
     29   /** The set of criterion objects, indexed by kind. */
     30   private final Map<Criterion.Kind, Criterion> criteria;
     31 
     32   /**
     33    * Creates a new {@code Criteria} without any {@code Criterion}.
     34    */
     35   public Criteria() {
     36     this.criteria = new LinkedHashMap<Criterion.Kind, Criterion>();
     37   }
     38 
     39   /**
     40    * Add a {@code Criterion} to this {@code Criteria}.
     41    *
     42    * @param c the criterion to add
     43    */
     44   public void add(Criterion c) {
     45     criteria.put(c.getKind(), c);
     46   }
     47 
     48   /**
     49    * Determines whether or not the program element at the leaf of the
     50    * specified path is satisfied by these criteria.
     51    *
     52    * @param path the tree path to check against
     53    * @param leaf the tree at the leaf of the path; only relevant when the path
     54    *        is null, in which case the leaf is a CompilationUnitTree
     55    * @return true if all of these criteria are satisfied by the given path,
     56    * false otherwise
     57    */
     58   public boolean isSatisfiedBy(TreePath path, Tree leaf) {
     59     assert path == null || path.getLeaf() == leaf;
     60     for (Criterion c : criteria.values()) {
     61       if (! c.isSatisfiedBy(path, leaf)) {
     62         dbug.debug("UNsatisfied criterion:%n    %s%n    %s%n",
     63             c, Main.pathToString(path));
     64         return false;
     65       } else {
     66         dbug.debug("satisfied criterion:%n    %s%n    %s%n",
     67             c, Main.pathToString(path));
     68       }
     69     }
     70     return true;
     71   }
     72 
     73   /**
     74    * Determines whether or not the program element at the leaf of the
     75    * specified path is satisfied by these criteria.
     76    *
     77    * @param path the tree path to check against
     78    * @return true if all of these criteria are satisfied by the given path,
     79    * false otherwise
     80    */
     81   public boolean isSatisfiedBy(TreePath path) {
     82     for (Criterion c : criteria.values()) {
     83       if (! c.isSatisfiedBy(path)) {
     84         dbug.debug("UNsatisfied criterion: %s%n", c);
     85         return false;
     86       } else {
     87         dbug.debug("satisfied criterion: %s%n", c);
     88       }
     89     }
     90     return true;
     91   }
     92 
     93   /**
     94    * Determines whether this is the criteria on a receiver.
     95    *
     96    * @return true iff this is the criteria on a receiver
     97    */
     98   public boolean isOnReceiver() {
     99     for (Criterion c : criteria.values()) {
    100       if (c.getKind() == Criterion.Kind.RECEIVER) {
    101         return true;
    102       }
    103     }
    104 
    105     return false;
    106   }
    107 
    108   /**
    109    * Determines whether this is the criteria on a package.
    110    *
    111    * @return true iff this is the criteria on a package
    112    */
    113   public boolean isOnPackage() {
    114     for (Criterion c : criteria.values()) {
    115       if (c.getKind() == Criterion.Kind.PACKAGE) {
    116         return true;
    117       }
    118     }
    119 
    120     return false;
    121   }
    122 
    123   /**
    124    * Determines whether this is the criteria on a return type.
    125    *
    126    * @return true iff this is the criteria on a return type
    127    */
    128   public boolean isOnReturnType() {
    129     for (Criterion c : criteria.values()) {
    130       if (c.getKind() == Criterion.Kind.RETURN_TYPE) {
    131         return true;
    132       }
    133     }
    134 
    135     return false;
    136   }
    137 
    138   /**
    139    * Determines whether this is the criteria on a local variable.
    140    *
    141    * @return true iff this is the criteria on a local variable
    142    */
    143   public boolean isOnLocalVariable() {
    144     for (Criterion c : criteria.values()) {
    145       if (c.getKind() == Criterion.Kind.LOCAL_VARIABLE) {
    146         return true;
    147       }
    148     }
    149 
    150     return false;
    151   }
    152 
    153   /**
    154    * Determines whether this is the criteria on the RHS of an occurrence
    155    * of 'instanceof'.
    156    */
    157   public boolean isOnInstanceof() {
    158     for (Criterion c : criteria.values()) {
    159       if (c.getKind() == Criterion.Kind.INSTANCE_OF) {
    160         return true;
    161       }
    162     }
    163     return false;
    164   }
    165 
    166   /**
    167    * Determines whether this is the criteria on an object initializer.
    168    */
    169   public boolean isOnNew() {
    170     for (Criterion c : criteria.values()) {
    171       if (c.getKind() == Criterion.Kind.NEW) {
    172         return true;
    173       }
    174     }
    175     return false;
    176   }
    177 
    178   /**
    179    * Determines whether this is the criteria on a class {@code extends} bound.
    180    */
    181   public boolean isOnTypeDeclarationExtendsClause() {
    182     for (Criterion c : criteria.values()) {
    183       if (c.getKind() == Criterion.Kind.EXTIMPLS_LOCATION) {
    184         return ((ExtImplsLocationCriterion) c).getIndex() == -1;
    185       }
    186     }
    187     return false;
    188   }
    189 
    190   /**
    191    * Returns true if this Criteria is on the given method.
    192    */
    193   public boolean isOnMethod(String methodname) {
    194     for (Criterion c : criteria.values()) {
    195       if (c.getKind() == Criterion.Kind.IN_METHOD) {
    196         if (((InMethodCriterion) c).name.equals(methodname)) {
    197           return true;
    198         }
    199       }
    200     }
    201     return false;
    202   }
    203 
    204   /**
    205    * Returns true if this Criteria is on the given method.
    206    */
    207   public boolean isOnFieldDeclaration() {
    208     for (Criterion c : criteria.values()) {
    209       if (c.getKind() == Criterion.Kind.FIELD
    210           && ((FieldCriterion) c).isDeclaration) {
    211         return true;
    212       }
    213     }
    214     return false;
    215   }
    216 
    217   /**
    218    * Gives the AST path specified in the criteria, if any.
    219    *
    220    * @return AST path from {@link ASTPathCriterion}, or null if none present
    221    */
    222   public ASTPath getASTPath() {
    223     for (Criterion c : criteria.values()) {
    224       if (c.getKind() == Criterion.Kind.AST_PATH) {
    225         return ((ASTPathCriterion) c).astPath;
    226       }
    227     }
    228 
    229     return null;
    230   }
    231 
    232   /**
    233    * Returns the name of the class specified in the Criteria, if any.
    234    *
    235    * @return class name from {@link InClassCriterion}, or null if none present
    236    */
    237   public String getClassName() {
    238     for (Criterion c : criteria.values()) {
    239       if (c.getKind() == Criterion.Kind.IN_CLASS) {
    240         return ((InClassCriterion) c).className;
    241       }
    242     }
    243 
    244     return null;
    245   }
    246 
    247   /**
    248    * Returns the name of the method specified in the Criteria, if any.
    249    *
    250    * @return method name from {@link InMethodCriterion}, or null if none present
    251    */
    252   public String getMethodName() {
    253     for (Criterion c : criteria.values()) {
    254       if (c.getKind() == Criterion.Kind.IN_METHOD) {
    255         return ((InMethodCriterion) c).name;
    256       }
    257     }
    258 
    259     return null;
    260   }
    261 
    262   /**
    263    * Returns the name of the member field specified in the Criteria, if any.
    264    *
    265    * @return field name from {@link FieldCriterion}, or null if none present
    266    */
    267   public String getFieldName() {
    268     for (Criterion c : criteria.values()) {
    269       if (c.getKind() == Criterion.Kind.FIELD) {
    270         return ((FieldCriterion) c).varName;
    271       }
    272     }
    273 
    274     return null;
    275   }
    276 
    277   /**
    278    * @return a GenericArrayLocationCriterion if this has one, else null
    279    */
    280   public GenericArrayLocationCriterion getGenericArrayLocation() {
    281     for (Criterion c : criteria.values()) {
    282       if (c.getKind() == Criterion.Kind.GENERIC_ARRAY_LOCATION) {
    283         return (GenericArrayLocationCriterion) c;
    284       }
    285     }
    286     return null;
    287   }
    288 
    289   /**
    290    * @return a RelativeCriterion if this has one, else null
    291    */
    292   public RelativeLocation getCastRelativeLocation() {
    293     RelativeLocation result = null;
    294     for (Criterion c : criteria.values()) {
    295       if (c.getKind() == Criterion.Kind.CAST) {
    296         result = ((CastCriterion) c).getLocation();
    297       }
    298     }
    299     return result;
    300   }
    301 
    302   // Returns the last one. Should really return the outermost one.
    303   // However, there should not be more than one unless all are equivalent.
    304   /**
    305    * @return an InClassCriterion if this has one, else null
    306    */
    307   public InClassCriterion getInClass() {
    308     InClassCriterion result = null;
    309     for (Criterion c : criteria.values()) {
    310       if (c.getKind() == Criterion.Kind.IN_CLASS) {
    311         result = (InClassCriterion) c;
    312       }
    313     }
    314     return result;
    315   }
    316 
    317   /**
    318    * @return true if this is on the zeroth bound of a type
    319    */
    320   // Used when determining whether an annotation is on an implicit upper
    321   // bound (the "extends Object" that is customarily omitted).
    322   public boolean onBoundZero() {
    323     for (Criterion c : criteria.values()) {
    324       switch (c.getKind()) {
    325       case CLASS_BOUND:
    326         if (((ClassBoundCriterion) c).boundLoc.boundIndex != 0) { break; }
    327         return true;
    328       case METHOD_BOUND:
    329         if (((MethodBoundCriterion) c).boundLoc.boundIndex != 0) { break; }
    330         return true;
    331       case AST_PATH:
    332         ASTPath astPath = ((ASTPathCriterion) c).astPath;
    333         if (!astPath.isEmpty()) {
    334           ASTPath.ASTEntry entry = astPath.get(-1);
    335           if (entry.childSelectorIs(ASTPath.BOUND)
    336               && entry.getArgument() == 0) {
    337             return true;
    338           }
    339         }
    340         break;
    341       default:
    342         break;
    343       }
    344     }
    345     return false;
    346   }
    347 
    348   /**
    349    * {@inheritDoc}
    350    */
    351   @Override
    352   public String toString() {
    353     return criteria.toString();
    354   }
    355 
    356 
    357   ///////////////////////////////////////////////////////////////////////////
    358   /// Factory methods
    359   ///
    360 
    361   /**
    362    * Creates an "is" criterion: that a program element has the specified
    363    * kind and name.
    364    *
    365    * @param kind the program element's kind
    366    * @param name the program element's name
    367    * @return an "is" criterion
    368    */
    369   public final static Criterion is(Tree.Kind kind, String name) {
    370     return new IsCriterion(kind, name);
    371   }
    372 
    373   /**
    374    * Creates an "enclosed by" criterion: that a program element is enclosed
    375    * by the specified kind of program element.
    376    *
    377    * @param kind the kind of enclosing program element
    378    * @return an "enclosed by" criterion
    379    */
    380   public final static Criterion enclosedBy(Tree.Kind kind) {
    381     return new EnclosedByCriterion(kind);
    382   }
    383 
    384   /**
    385    * Creates an "in package" criterion: that a program element is enclosed
    386    * by the specified package.
    387    *
    388    * @param name the name of the enclosing package
    389    * @return an "in package" criterion
    390    */
    391   public final static Criterion inPackage(String name) {
    392     return new InPackageCriterion(name);
    393   }
    394 
    395   /**
    396    * Creates an "in class" criterion: that a program element is enclosed
    397    * by the specified class.
    398    *
    399    * @param name the name of the enclosing class
    400    * @param exact whether to match only in the class itself, not in its inner classes
    401    * @return an "in class" criterion
    402    */
    403   public final static Criterion inClass(String name, boolean exact) {
    404     return new InClassCriterion(name, /*exactmatch=*/ true);
    405   }
    406 
    407   /**
    408    * Creates an "in method" criterion: that a program element is enclosed
    409    * by the specified method.
    410    *
    411    * @param name the name of the enclosing method
    412    * @return an "in method" criterion
    413    */
    414   public final static Criterion inMethod(String name) {
    415     return new InMethodCriterion(name);
    416   }
    417 
    418   /**
    419    * Creates a "not in method" criterion: that a program element is not
    420    * enclosed by any method.
    421    *
    422    * @return a "not in method" criterion
    423    */
    424   public final static Criterion notInMethod() {
    425     return new NotInMethodCriterion();
    426   }
    427 
    428   public final static Criterion packageDecl(String packageName) {
    429     return new PackageCriterion(packageName);
    430   }
    431 
    432   public final static Criterion atLocation() {
    433     return new GenericArrayLocationCriterion();
    434   }
    435 
    436   public final static Criterion atLocation(InnerTypeLocation loc) {
    437     return new GenericArrayLocationCriterion(loc);
    438   }
    439 
    440   @Deprecated
    441   public final static Criterion field(String varName) {
    442     return new FieldCriterion(varName);
    443   }
    444 
    445   public final static Criterion field(String varName, boolean isOnDeclaration) {
    446     return new FieldCriterion(varName, isOnDeclaration);
    447   }
    448 
    449   public final static Criterion inStaticInit(int blockID) {
    450     return new InInitBlockCriterion(blockID, true);
    451   }
    452 
    453   public final static Criterion inInstanceInit(int blockID) {
    454     return new InInitBlockCriterion(blockID, false);
    455   }
    456 
    457   public final static Criterion inFieldInit(String varName) {
    458     return new InFieldInitCriterion(varName);
    459   }
    460 
    461   public final static Criterion receiver(String methodName) {
    462     return new ReceiverCriterion(methodName);
    463   }
    464 
    465   public final static Criterion returnType(String className, String methodName) {
    466     return new ReturnTypeCriterion(className, methodName);
    467   }
    468 
    469   public final static Criterion isSigMethod(String methodName) {
    470     return new IsSigMethodCriterion(methodName);
    471   }
    472 
    473 
    474   public final static Criterion param(String methodName, Integer pos) {
    475     return new ParamCriterion(methodName, pos);
    476   }
    477 //
    478 //  public final static Criterion param(String methodName, Integer pos, InnerTypeLocation loc) {
    479 //    return new ParamCriterion(methodName, pos, loc);
    480 //  }
    481 
    482 
    483   public final static Criterion local(String methodName, LocalLocation loc) {
    484     return new LocalVariableCriterion(methodName, loc);
    485   }
    486 
    487   public final static Criterion cast(String methodName, RelativeLocation loc) {
    488     return new CastCriterion(methodName, loc);
    489   }
    490 
    491   public final static Criterion newObject(String methodName, RelativeLocation loc) {
    492     return new NewCriterion(methodName, loc);
    493   }
    494 
    495   public final static Criterion instanceOf(String methodName, RelativeLocation loc) {
    496     return new InstanceOfCriterion(methodName, loc);
    497   }
    498 
    499   public static Criterion memberReference(String methodName, RelativeLocation loc) {
    500     return new MemberReferenceCriterion(methodName, loc);
    501   }
    502 
    503   public static Criterion methodCall(String methodName, RelativeLocation loc) {
    504     return new CallCriterion(methodName, loc);
    505   }
    506 
    507   public final static Criterion typeArgument(String methodName, RelativeLocation loc) {
    508     return new TypeArgumentCriterion(methodName, loc);
    509   }
    510 
    511   public final static Criterion lambda(String methodName, RelativeLocation loc) {
    512     return new LambdaCriterion(methodName, loc);
    513   }
    514 
    515   public final static Criterion atBoundLocation(BoundLocation loc) {
    516     return new BoundLocationCriterion(loc);
    517   }
    518 
    519   public final static Criterion atExtImplsLocation(String className, TypeIndexLocation loc) {
    520     return new ExtImplsLocationCriterion(className, loc);
    521   }
    522 
    523   public final static Criterion methodBound(String methodName, BoundLocation boundLoc) {
    524     return new MethodBoundCriterion(methodName, boundLoc);
    525   }
    526 
    527   public final static Criterion classBound(String className, BoundLocation boundLoc) {
    528     return new ClassBoundCriterion(className, boundLoc);
    529   }
    530 
    531   public final static Criterion astPath(ASTPath astPath) {
    532     return new ASTPathCriterion(astPath);
    533   }
    534 }
    535