• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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    */
Criteria()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    */
add(Criterion c)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    */
isSatisfiedBy(TreePath path, Tree leaf)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    */
isSatisfiedBy(TreePath path)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    */
isOnReceiver()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    */
isOnPackage()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    */
isOnReturnType()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    */
isOnLocalVariable()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    */
isOnInstanceof()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    */
isOnNew()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    */
isOnTypeDeclarationExtendsClause()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    */
isOnMethod(String methodname)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    */
isOnFieldDeclaration()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    */
getASTPath()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    */
getClassName()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    */
getMethodName()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    */
getFieldName()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    */
getGenericArrayLocation()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    */
getCastRelativeLocation()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    */
getInClass()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).
onBoundZero()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
toString()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    */
is(Tree.Kind kind, String name)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    */
enclosedBy(Tree.Kind kind)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    */
inPackage(String name)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    */
inClass(String name, boolean exact)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    */
inMethod(String name)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    */
notInMethod()424   public final static Criterion notInMethod() {
425     return new NotInMethodCriterion();
426   }
427 
packageDecl(String packageName)428   public final static Criterion packageDecl(String packageName) {
429     return new PackageCriterion(packageName);
430   }
431 
atLocation()432   public final static Criterion atLocation() {
433     return new GenericArrayLocationCriterion();
434   }
435 
atLocation(InnerTypeLocation loc)436   public final static Criterion atLocation(InnerTypeLocation loc) {
437     return new GenericArrayLocationCriterion(loc);
438   }
439 
440   @Deprecated
field(String varName)441   public final static Criterion field(String varName) {
442     return new FieldCriterion(varName);
443   }
444 
field(String varName, boolean isOnDeclaration)445   public final static Criterion field(String varName, boolean isOnDeclaration) {
446     return new FieldCriterion(varName, isOnDeclaration);
447   }
448 
inStaticInit(int blockID)449   public final static Criterion inStaticInit(int blockID) {
450     return new InInitBlockCriterion(blockID, true);
451   }
452 
inInstanceInit(int blockID)453   public final static Criterion inInstanceInit(int blockID) {
454     return new InInitBlockCriterion(blockID, false);
455   }
456 
inFieldInit(String varName)457   public final static Criterion inFieldInit(String varName) {
458     return new InFieldInitCriterion(varName);
459   }
460 
receiver(String methodName)461   public final static Criterion receiver(String methodName) {
462     return new ReceiverCriterion(methodName);
463   }
464 
returnType(String className, String methodName)465   public final static Criterion returnType(String className, String methodName) {
466     return new ReturnTypeCriterion(className, methodName);
467   }
468 
isSigMethod(String methodName)469   public final static Criterion isSigMethod(String methodName) {
470     return new IsSigMethodCriterion(methodName);
471   }
472 
473 
param(String methodName, Integer pos)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 
local(String methodName, LocalLocation loc)483   public final static Criterion local(String methodName, LocalLocation loc) {
484     return new LocalVariableCriterion(methodName, loc);
485   }
486 
cast(String methodName, RelativeLocation loc)487   public final static Criterion cast(String methodName, RelativeLocation loc) {
488     return new CastCriterion(methodName, loc);
489   }
490 
newObject(String methodName, RelativeLocation loc)491   public final static Criterion newObject(String methodName, RelativeLocation loc) {
492     return new NewCriterion(methodName, loc);
493   }
494 
instanceOf(String methodName, RelativeLocation loc)495   public final static Criterion instanceOf(String methodName, RelativeLocation loc) {
496     return new InstanceOfCriterion(methodName, loc);
497   }
498 
memberReference(String methodName, RelativeLocation loc)499   public static Criterion memberReference(String methodName, RelativeLocation loc) {
500     return new MemberReferenceCriterion(methodName, loc);
501   }
502 
methodCall(String methodName, RelativeLocation loc)503   public static Criterion methodCall(String methodName, RelativeLocation loc) {
504     return new CallCriterion(methodName, loc);
505   }
506 
typeArgument(String methodName, RelativeLocation loc)507   public final static Criterion typeArgument(String methodName, RelativeLocation loc) {
508     return new TypeArgumentCriterion(methodName, loc);
509   }
510 
lambda(String methodName, RelativeLocation loc)511   public final static Criterion lambda(String methodName, RelativeLocation loc) {
512     return new LambdaCriterion(methodName, loc);
513   }
514 
atBoundLocation(BoundLocation loc)515   public final static Criterion atBoundLocation(BoundLocation loc) {
516     return new BoundLocationCriterion(loc);
517   }
518 
atExtImplsLocation(String className, TypeIndexLocation loc)519   public final static Criterion atExtImplsLocation(String className, TypeIndexLocation loc) {
520     return new ExtImplsLocationCriterion(className, loc);
521   }
522 
methodBound(String methodName, BoundLocation boundLoc)523   public final static Criterion methodBound(String methodName, BoundLocation boundLoc) {
524     return new MethodBoundCriterion(methodName, boundLoc);
525   }
526 
classBound(String className, BoundLocation boundLoc)527   public final static Criterion classBound(String className, BoundLocation boundLoc) {
528     return new ClassBoundCriterion(className, boundLoc);
529   }
530 
astPath(ASTPath astPath)531   public final static Criterion astPath(ASTPath astPath) {
532     return new ASTPathCriterion(astPath);
533   }
534 }
535