• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright 2014 Google LLC
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 package com.google.auto.common;
17 
18 import static com.google.common.base.Preconditions.checkNotNull;
19 import static com.google.common.base.Preconditions.checkState;
20 import static javax.lang.model.type.TypeKind.ARRAY;
21 import static javax.lang.model.type.TypeKind.DECLARED;
22 import static javax.lang.model.type.TypeKind.EXECUTABLE;
23 import static javax.lang.model.type.TypeKind.INTERSECTION;
24 import static javax.lang.model.type.TypeKind.TYPEVAR;
25 import static javax.lang.model.type.TypeKind.WILDCARD;
26 
27 import com.google.common.base.Equivalence;
28 import com.google.common.base.Optional;
29 import com.google.common.collect.ImmutableList;
30 import com.google.common.collect.ImmutableSet;
31 import java.util.HashSet;
32 import java.util.Iterator;
33 import java.util.List;
34 import java.util.Set;
35 import javax.lang.model.element.Element;
36 import javax.lang.model.element.ElementKind;
37 import javax.lang.model.element.ExecutableElement;
38 import javax.lang.model.element.Modifier;
39 import javax.lang.model.element.TypeElement;
40 import javax.lang.model.element.TypeParameterElement;
41 import javax.lang.model.element.VariableElement;
42 import javax.lang.model.type.ArrayType;
43 import javax.lang.model.type.DeclaredType;
44 import javax.lang.model.type.ErrorType;
45 import javax.lang.model.type.ExecutableType;
46 import javax.lang.model.type.IntersectionType;
47 import javax.lang.model.type.NoType;
48 import javax.lang.model.type.NullType;
49 import javax.lang.model.type.PrimitiveType;
50 import javax.lang.model.type.TypeKind;
51 import javax.lang.model.type.TypeMirror;
52 import javax.lang.model.type.TypeVariable;
53 import javax.lang.model.type.WildcardType;
54 import javax.lang.model.util.Elements;
55 import javax.lang.model.util.SimpleTypeVisitor8;
56 import javax.lang.model.util.Types;
57 import org.checkerframework.checker.nullness.qual.Nullable;
58 
59 /**
60  * Utilities related to {@link TypeMirror} instances.
61  *
62  * @author Gregory Kick
63  * @since 2.0
64  */
65 public final class MoreTypes {
66   private static final class TypeEquivalence extends Equivalence<TypeMirror> {
67     private static final TypeEquivalence INSTANCE = new TypeEquivalence();
68 
69     @Override
doEquivalent(TypeMirror a, TypeMirror b)70     protected boolean doEquivalent(TypeMirror a, TypeMirror b) {
71       return MoreTypes.equal(a, b, ImmutableSet.<ComparedElements>of());
72     }
73 
74     @Override
doHash(TypeMirror t)75     protected int doHash(TypeMirror t) {
76       return MoreTypes.hash(t, ImmutableSet.<Element>of());
77     }
78 
79     @Override
toString()80     public String toString() {
81       return "MoreTypes.equivalence()";
82     }
83   }
84 
85   /**
86    * Returns an {@link Equivalence} that can be used to compare types. The standard way to compare
87    * types is {@link javax.lang.model.util.Types#isSameType Types.isSameType}, but this alternative
88    * may be preferred in a number of cases:
89    *
90    * <ul>
91    * <li>If you don't have an instance of {@code Types}.
92    * <li>If you want a reliable {@code hashCode()} for the types, for example to construct a set
93    *     of types using {@link java.util.HashSet} with {@link Equivalence#wrap(Object)}.
94    * <li>If you want distinct type variables to be considered equal if they have the same names
95    *     and bounds.
96    * <li>If you want wildcard types to compare equal if they have the same bounds. {@code
97    *     Types.isSameType} never considers wildcards equal, even when comparing a type to itself.
98    * </ul>
99    */
equivalence()100   public static Equivalence<TypeMirror> equivalence() {
101     return TypeEquivalence.INSTANCE;
102   }
103 
104   // So EQUAL_VISITOR can be a singleton, we maintain visiting state, in particular which types
105   // have been seen already, in this object.
106   // The logic for handling recursive types like Comparable<T extends Comparable<T>> is very tricky.
107   // If we're not careful we'll end up with an infinite recursion. So we record the types that
108   // we've already seen during the recursion, and if we see the same pair of types again we just
109   // return true provisionally. But "the same pair of types" is itself poorly-defined. We can't
110   // just say that it is an equal pair of TypeMirrors, because of course if we knew how to
111   // determine that then we wouldn't need the complicated type visitor at all. On the other hand,
112   // we can't say that it is an identical pair of TypeMirrors either, because there's no
113   // guarantee that the TypeMirrors for the two Ts in Comparable<T extends Comparable<T>> will be
114   // represented by the same object, and indeed with the Eclipse compiler they aren't. We could
115   // compare the corresponding Elements, since equality is well-defined there, but that's not enough
116   // either, because the Element for Set<Object> is the same as the one for Set<String>. So we
117   // approximate by comparing the Elements and, if there are any type arguments, requiring them to
118   // be identical. This may not be foolproof either but it is sufficient for all the cases we've
119   // encountered so far.
120   private static final class EqualVisitorParam {
121     TypeMirror type;
122     Set<ComparedElements> visiting;
123   }
124 
125   private static class ComparedElements {
126     final Element a;
127     final ImmutableList<TypeMirror> aArguments;
128     final Element b;
129     final ImmutableList<TypeMirror> bArguments;
130 
ComparedElements( Element a, ImmutableList<TypeMirror> aArguments, Element b, ImmutableList<TypeMirror> bArguments)131     ComparedElements(
132         Element a,
133         ImmutableList<TypeMirror> aArguments,
134         Element b,
135         ImmutableList<TypeMirror> bArguments) {
136       this.a = a;
137       this.aArguments = aArguments;
138       this.b = b;
139       this.bArguments = bArguments;
140     }
141 
142     @Override
equals(@ullable Object o)143     public boolean equals(@Nullable Object o) {
144       if (!(o instanceof ComparedElements)) {
145         return false;
146       }
147       ComparedElements that = (ComparedElements) o;
148 
149       int nArguments = this.aArguments.size();
150       if (nArguments != that.aArguments.size()) {
151         return false;
152       }
153       // The arguments must be the same size, but we check anyway.
154       if (nArguments != this.bArguments.size() || nArguments != that.bArguments.size()) {
155         return false;
156       }
157 
158       if (!this.a.equals(that.a) || !this.b.equals(that.b)) {
159         return false;
160       }
161 
162       /*
163        * The purpose here is just to avoid the infinite recursion that we would otherwise have
164        * if Enum<E extends Enum<E>> is compared against itself, for example. If we are able to
165        * see that the inner Enum<E> is the same object as the outer one then we don't need a
166        * recursive call to compare the "a" Enum<E> against the "b" Enum<E>. The same-object check
167        * may not be completely justified, but it relies on the practical assumption that the
168        * compiler is not going to conjure up an infinite regress of objects to represent this
169        * recursive type. Other comparison methods like comparing their toString() are expensive
170        * and not warranted.
171        */
172       for (int i = 0; i < nArguments; i++) {
173         if (this.aArguments.get(i) != that.aArguments.get(i)) {
174           return false;
175         }
176         if (this.bArguments.get(i) != that.bArguments.get(i)) {
177           return false;
178         }
179       }
180 
181       return true;
182     }
183 
184     @Override
hashCode()185     public int hashCode() {
186       return a.hashCode() * 31 + b.hashCode();
187     }
188   }
189 
190   private static final class EqualVisitor extends SimpleTypeVisitor8<Boolean, EqualVisitorParam> {
191     private static final EqualVisitor INSTANCE = new EqualVisitor();
192 
193     @Override
defaultAction(TypeMirror a, EqualVisitorParam p)194     protected Boolean defaultAction(TypeMirror a, EqualVisitorParam p) {
195       return a.getKind().equals(p.type.getKind());
196     }
197 
198     @Override
visitArray(ArrayType a, EqualVisitorParam p)199     public Boolean visitArray(ArrayType a, EqualVisitorParam p) {
200       if (p.type.getKind().equals(ARRAY)) {
201         ArrayType b = (ArrayType) p.type;
202         return equal(a.getComponentType(), b.getComponentType(), p.visiting);
203       }
204       return false;
205     }
206 
207     @Override
visitDeclared(DeclaredType a, EqualVisitorParam p)208     public Boolean visitDeclared(DeclaredType a, EqualVisitorParam p) {
209       if (p.type.getKind().equals(DECLARED)) {
210         DeclaredType b = (DeclaredType) p.type;
211         Element aElement = a.asElement();
212         Element bElement = b.asElement();
213         Set<ComparedElements> newVisiting =
214             visitingSetPlus(
215                 p.visiting, aElement, a.getTypeArguments(), bElement, b.getTypeArguments());
216         if (newVisiting.equals(p.visiting)) {
217           // We're already visiting this pair of elements.
218           // This can happen for example with Enum in Enum<E extends Enum<E>>. Return a
219           // provisional true value since if the Elements are not in fact equal the original
220           // visitor of Enum will discover that. We have to check both Elements being compared
221           // though to avoid missing the fact that one of the types being compared
222           // differs at exactly this point.
223           return true;
224         }
225         return aElement.equals(bElement)
226             && equal(enclosingType(a), enclosingType(b), newVisiting)
227             && equalLists(a.getTypeArguments(), b.getTypeArguments(), newVisiting);
228       }
229       return false;
230     }
231 
232     @Override
233     @SuppressWarnings("TypeEquals")
visitError(ErrorType a, EqualVisitorParam p)234     public Boolean visitError(ErrorType a, EqualVisitorParam p) {
235       return a.equals(p.type);
236     }
237 
238     @Override
visitExecutable(ExecutableType a, EqualVisitorParam p)239     public Boolean visitExecutable(ExecutableType a, EqualVisitorParam p) {
240       if (p.type.getKind().equals(EXECUTABLE)) {
241         ExecutableType b = (ExecutableType) p.type;
242         return equalLists(a.getParameterTypes(), b.getParameterTypes(), p.visiting)
243             && equal(a.getReturnType(), b.getReturnType(), p.visiting)
244             && equalLists(a.getThrownTypes(), b.getThrownTypes(), p.visiting)
245             && equalLists(a.getTypeVariables(), b.getTypeVariables(), p.visiting);
246       }
247       return false;
248     }
249 
250     @Override
visitIntersection(IntersectionType a, EqualVisitorParam p)251     public Boolean visitIntersection(IntersectionType a, EqualVisitorParam p) {
252       if (p.type.getKind().equals(INTERSECTION)) {
253         IntersectionType b = (IntersectionType) p.type;
254         return equalLists(a.getBounds(), b.getBounds(), p.visiting);
255       }
256       return false;
257     }
258 
259     @Override
visitTypeVariable(TypeVariable a, EqualVisitorParam p)260     public Boolean visitTypeVariable(TypeVariable a, EqualVisitorParam p) {
261       if (p.type.getKind().equals(TYPEVAR)) {
262         TypeVariable b = (TypeVariable) p.type;
263         TypeParameterElement aElement = (TypeParameterElement) a.asElement();
264         TypeParameterElement bElement = (TypeParameterElement) b.asElement();
265         Set<ComparedElements> newVisiting = visitingSetPlus(p.visiting, aElement, bElement);
266         if (newVisiting.equals(p.visiting)) {
267           // We're already visiting this pair of elements.
268           // This can happen with our friend Eclipse when looking at <T extends Comparable<T>>.
269           // It incorrectly reports the upper bound of T as T itself.
270           return true;
271         }
272         // We use aElement.getBounds() instead of a.getUpperBound() to avoid having to deal with
273         // the different way intersection types (like <T extends Number & Comparable<T>>) are
274         // represented before and after Java 8. We do have an issue that this code may consider
275         // that <T extends Foo & Bar> is different from <T extends Bar & Foo>, but it's very
276         // hard to avoid that, and not likely to be much of a problem in practice.
277         return equalLists(aElement.getBounds(), bElement.getBounds(), newVisiting)
278             && equal(a.getLowerBound(), b.getLowerBound(), newVisiting)
279             && a.asElement().getSimpleName().equals(b.asElement().getSimpleName());
280       }
281       return false;
282     }
283 
284     @Override
visitWildcard(WildcardType a, EqualVisitorParam p)285     public Boolean visitWildcard(WildcardType a, EqualVisitorParam p) {
286       if (p.type.getKind().equals(WILDCARD)) {
287         WildcardType b = (WildcardType) p.type;
288         return equal(a.getExtendsBound(), b.getExtendsBound(), p.visiting)
289             && equal(a.getSuperBound(), b.getSuperBound(), p.visiting);
290       }
291       return false;
292     }
293 
294     @Override
visitUnknown(TypeMirror a, EqualVisitorParam p)295     public Boolean visitUnknown(TypeMirror a, EqualVisitorParam p) {
296       throw new UnsupportedOperationException();
297     }
298 
visitingSetPlus( Set<ComparedElements> visiting, Element a, Element b)299     private Set<ComparedElements> visitingSetPlus(
300         Set<ComparedElements> visiting, Element a, Element b) {
301       ImmutableList<TypeMirror> noArguments = ImmutableList.of();
302       return visitingSetPlus(visiting, a, noArguments, b, noArguments);
303     }
304 
visitingSetPlus( Set<ComparedElements> visiting, Element a, List<? extends TypeMirror> aArguments, Element b, List<? extends TypeMirror> bArguments)305     private Set<ComparedElements> visitingSetPlus(
306         Set<ComparedElements> visiting,
307         Element a,
308         List<? extends TypeMirror> aArguments,
309         Element b,
310         List<? extends TypeMirror> bArguments) {
311       ComparedElements comparedElements =
312           new ComparedElements(
313               a, ImmutableList.<TypeMirror>copyOf(aArguments),
314               b, ImmutableList.<TypeMirror>copyOf(bArguments));
315       Set<ComparedElements> newVisiting = new HashSet<ComparedElements>(visiting);
316       newVisiting.add(comparedElements);
317       return newVisiting;
318     }
319   }
320 
321   @SuppressWarnings("TypeEquals")
equal( @ullable TypeMirror a, @Nullable TypeMirror b, Set<ComparedElements> visiting)322   private static boolean equal(
323       @Nullable TypeMirror a, @Nullable TypeMirror b, Set<ComparedElements> visiting) {
324     if (a == b) {
325       return true;
326     }
327     if (a == null || b == null) {
328       return false;
329     }
330     // TypeMirror.equals is not guaranteed to return true for types that are equal, but we can
331     // assume that if it does return true then the types are equal. This check also avoids getting
332     // stuck in infinite recursion when Eclipse decrees that the upper bound of the second K in
333     // <K extends Comparable<K>> is a distinct but equal K.
334     // The javac implementation of ExecutableType, at least in some versions, does not take thrown
335     // exceptions into account in its equals implementation, so avoid this optimization for
336     // ExecutableType.
337     @SuppressWarnings("TypesEquals")
338     boolean equal = a.equals(b);
339     if (equal && a.getKind() != TypeKind.EXECUTABLE) {
340       return true;
341     }
342     EqualVisitorParam p = new EqualVisitorParam();
343     p.type = b;
344     p.visiting = visiting;
345     return a.accept(EqualVisitor.INSTANCE, p);
346   }
347 
348   /**
349    * Returns the type of the innermost enclosing instance, or null if there is none. This is the
350    * same as {@link DeclaredType#getEnclosingType()} except that it returns null rather than
351    * NoType for a static type. We need this because of
352    * <a href="https://bugs.eclipse.org/bugs/show_bug.cgi?id=508222">this bug</a> whereby
353    * the Eclipse compiler returns a value for static classes that is not NoType.
354    */
enclosingType(DeclaredType t)355   private static @Nullable TypeMirror enclosingType(DeclaredType t) {
356     TypeMirror enclosing = t.getEnclosingType();
357     if (enclosing.getKind().equals(TypeKind.NONE)
358         || t.asElement().getModifiers().contains(Modifier.STATIC)) {
359       return null;
360     }
361     return enclosing;
362   }
363 
equalLists( List<? extends TypeMirror> a, List<? extends TypeMirror> b, Set<ComparedElements> visiting)364   private static boolean equalLists(
365       List<? extends TypeMirror> a, List<? extends TypeMirror> b, Set<ComparedElements> visiting) {
366     int size = a.size();
367     if (size != b.size()) {
368       return false;
369     }
370     // Use iterators in case the Lists aren't RandomAccess
371     Iterator<? extends TypeMirror> aIterator = a.iterator();
372     Iterator<? extends TypeMirror> bIterator = b.iterator();
373     while (aIterator.hasNext()) {
374       // We checked that the lists have the same size, so we know that bIterator.hasNext() too.
375       TypeMirror nextMirrorA = aIterator.next();
376       TypeMirror nextMirrorB = bIterator.next();
377       if (!equal(nextMirrorA, nextMirrorB, visiting)) {
378         return false;
379       }
380     }
381     return true;
382   }
383 
384   private static final int HASH_SEED = 17;
385   private static final int HASH_MULTIPLIER = 31;
386 
387   private static final class HashVisitor extends SimpleTypeVisitor8<Integer, Set<Element>> {
388     private static final HashVisitor INSTANCE = new HashVisitor();
389 
hashKind(int seed, TypeMirror t)390     int hashKind(int seed, TypeMirror t) {
391       int result = seed * HASH_MULTIPLIER;
392       result += t.getKind().hashCode();
393       return result;
394     }
395 
396     @Override
defaultAction(TypeMirror e, Set<Element> visiting)397     protected Integer defaultAction(TypeMirror e, Set<Element> visiting) {
398       return hashKind(HASH_SEED, e);
399     }
400 
401     @Override
visitArray(ArrayType t, Set<Element> visiting)402     public Integer visitArray(ArrayType t, Set<Element> visiting) {
403       int result = hashKind(HASH_SEED, t);
404       result *= HASH_MULTIPLIER;
405       result += t.getComponentType().accept(this, visiting);
406       return result;
407     }
408 
409     @Override
visitDeclared(DeclaredType t, Set<Element> visiting)410     public Integer visitDeclared(DeclaredType t, Set<Element> visiting) {
411       Element element = t.asElement();
412       if (visiting.contains(element)) {
413         return 0;
414       }
415       Set<Element> newVisiting = new HashSet<Element>(visiting);
416       newVisiting.add(element);
417       int result = hashKind(HASH_SEED, t);
418       result *= HASH_MULTIPLIER;
419       result += t.asElement().hashCode();
420       result *= HASH_MULTIPLIER;
421       result += t.getEnclosingType().accept(this, newVisiting);
422       result *= HASH_MULTIPLIER;
423       result += hashList(t.getTypeArguments(), newVisiting);
424       return result;
425     }
426 
427     @Override
visitExecutable(ExecutableType t, Set<Element> visiting)428     public Integer visitExecutable(ExecutableType t, Set<Element> visiting) {
429       int result = hashKind(HASH_SEED, t);
430       result *= HASH_MULTIPLIER;
431       result += hashList(t.getParameterTypes(), visiting);
432       result *= HASH_MULTIPLIER;
433       result += t.getReturnType().accept(this, visiting);
434       result *= HASH_MULTIPLIER;
435       result += hashList(t.getThrownTypes(), visiting);
436       result *= HASH_MULTIPLIER;
437       result += hashList(t.getTypeVariables(), visiting);
438       return result;
439     }
440 
441     @Override
visitTypeVariable(TypeVariable t, Set<Element> visiting)442     public Integer visitTypeVariable(TypeVariable t, Set<Element> visiting) {
443       int result = hashKind(HASH_SEED, t);
444       result *= HASH_MULTIPLIER;
445       result += t.getLowerBound().accept(this, visiting);
446       TypeParameterElement element = (TypeParameterElement) t.asElement();
447       for (TypeMirror bound : element.getBounds()) {
448         result *= HASH_MULTIPLIER;
449         result += bound.accept(this, visiting);
450       }
451       return result;
452     }
453 
454     @Override
visitWildcard(WildcardType t, Set<Element> visiting)455     public Integer visitWildcard(WildcardType t, Set<Element> visiting) {
456       int result = hashKind(HASH_SEED, t);
457       result *= HASH_MULTIPLIER;
458       result += (t.getExtendsBound() == null) ? 0 : t.getExtendsBound().accept(this, visiting);
459       result *= HASH_MULTIPLIER;
460       result += (t.getSuperBound() == null) ? 0 : t.getSuperBound().accept(this, visiting);
461       return result;
462     }
463 
464     @Override
visitUnknown(TypeMirror t, Set<Element> visiting)465     public Integer visitUnknown(TypeMirror t, Set<Element> visiting) {
466       throw new UnsupportedOperationException();
467     }
468   }
469 
hashList(List<? extends TypeMirror> mirrors, Set<Element> visiting)470   private static int hashList(List<? extends TypeMirror> mirrors, Set<Element> visiting) {
471     int result = HASH_SEED;
472     for (TypeMirror mirror : mirrors) {
473       result *= HASH_MULTIPLIER;
474       result += hash(mirror, visiting);
475     }
476     return result;
477   }
478 
hash(TypeMirror mirror, Set<Element> visiting)479   private static int hash(TypeMirror mirror, Set<Element> visiting) {
480     return mirror == null ? 0 : mirror.accept(HashVisitor.INSTANCE, visiting);
481   }
482 
483   /**
484    * Returns the set of {@linkplain TypeElement types} that are referenced by the given {@link
485    * TypeMirror}.
486    */
referencedTypes(TypeMirror type)487   public static ImmutableSet<TypeElement> referencedTypes(TypeMirror type) {
488     checkNotNull(type);
489     ImmutableSet.Builder<TypeElement> elements = ImmutableSet.builder();
490     type.accept(ReferencedTypes.INSTANCE, elements);
491     return elements.build();
492   }
493 
494   private static final class ReferencedTypes
495       extends SimpleTypeVisitor8<@Nullable Void, ImmutableSet.Builder<TypeElement>> {
496     private static final ReferencedTypes INSTANCE = new ReferencedTypes();
497 
498     @Override
visitArray(ArrayType t, ImmutableSet.Builder<TypeElement> p)499     public @Nullable Void visitArray(ArrayType t, ImmutableSet.Builder<TypeElement> p) {
500       t.getComponentType().accept(this, p);
501       return null;
502     }
503 
504     @Override
visitDeclared(DeclaredType t, ImmutableSet.Builder<TypeElement> p)505     public @Nullable Void visitDeclared(DeclaredType t, ImmutableSet.Builder<TypeElement> p) {
506       p.add(MoreElements.asType(t.asElement()));
507       for (TypeMirror typeArgument : t.getTypeArguments()) {
508         typeArgument.accept(this, p);
509       }
510       return null;
511     }
512 
513     @Override
visitTypeVariable(TypeVariable t, ImmutableSet.Builder<TypeElement> p)514     public @Nullable Void visitTypeVariable(TypeVariable t, ImmutableSet.Builder<TypeElement> p) {
515       t.getLowerBound().accept(this, p);
516       t.getUpperBound().accept(this, p);
517       return null;
518     }
519 
520     @Override
visitWildcard(WildcardType t, ImmutableSet.Builder<TypeElement> p)521     public @Nullable Void visitWildcard(WildcardType t, ImmutableSet.Builder<TypeElement> p) {
522       TypeMirror extendsBound = t.getExtendsBound();
523       if (extendsBound != null) {
524         extendsBound.accept(this, p);
525       }
526       TypeMirror superBound = t.getSuperBound();
527       if (superBound != null) {
528         superBound.accept(this, p);
529       }
530       return null;
531     }
532   }
533 
534   /**
535    * An alternate implementation of {@link Types#asElement} that does not require a {@link Types}
536    * instance with the notable difference that it will throw {@link IllegalArgumentException}
537    * instead of returning null if the {@link TypeMirror} can not be converted to an {@link Element}.
538    *
539    * @throws NullPointerException if {@code typeMirror} is {@code null}
540    * @throws IllegalArgumentException if {@code typeMirror} cannot be converted to an {@link
541    *     Element}
542    */
asElement(TypeMirror typeMirror)543   public static Element asElement(TypeMirror typeMirror) {
544     return typeMirror.accept(AsElementVisitor.INSTANCE, null);
545   }
546 
547   private static final class AsElementVisitor extends SimpleTypeVisitor8<Element, Void> {
548     private static final AsElementVisitor INSTANCE = new AsElementVisitor();
549 
550     @Override
defaultAction(TypeMirror e, Void p)551     protected Element defaultAction(TypeMirror e, Void p) {
552       throw new IllegalArgumentException(e + " cannot be converted to an Element");
553     }
554 
555     @Override
visitDeclared(DeclaredType t, Void p)556     public Element visitDeclared(DeclaredType t, Void p) {
557       return t.asElement();
558     }
559 
560     @Override
visitError(ErrorType t, Void p)561     public Element visitError(ErrorType t, Void p) {
562       return t.asElement();
563     }
564 
565     @Override
visitTypeVariable(TypeVariable t, Void p)566     public Element visitTypeVariable(TypeVariable t, Void p) {
567       return t.asElement();
568     }
569   }
570   ;
571 
572   // TODO(gak): consider removing these two methods as they're pretty trivial now
asTypeElement(TypeMirror mirror)573   public static TypeElement asTypeElement(TypeMirror mirror) {
574     return MoreElements.asType(asElement(mirror));
575   }
576 
asTypeElements(Iterable<? extends TypeMirror> mirrors)577   public static ImmutableSet<TypeElement> asTypeElements(Iterable<? extends TypeMirror> mirrors) {
578     checkNotNull(mirrors);
579     ImmutableSet.Builder<TypeElement> builder = ImmutableSet.builder();
580     for (TypeMirror mirror : mirrors) {
581       builder.add(asTypeElement(mirror));
582     }
583     return builder.build();
584   }
585 
586   /**
587    * Returns a {@link ArrayType} if the {@link TypeMirror} represents an array or throws an {@link
588    * IllegalArgumentException}.
589    */
asArray(TypeMirror maybeArrayType)590   public static ArrayType asArray(TypeMirror maybeArrayType) {
591     return maybeArrayType.accept(ArrayTypeVisitor.INSTANCE, null);
592   }
593 
594   private static final class ArrayTypeVisitor extends CastingTypeVisitor<ArrayType> {
595     private static final ArrayTypeVisitor INSTANCE = new ArrayTypeVisitor();
596 
ArrayTypeVisitor()597     ArrayTypeVisitor() {
598       super("array");
599     }
600 
601     @Override
visitArray(ArrayType type, Void ignore)602     public ArrayType visitArray(ArrayType type, Void ignore) {
603       return type;
604     }
605   }
606 
607   /**
608    * Returns a {@link DeclaredType} if the {@link TypeMirror} represents a declared type such as a
609    * class, interface, union/compound, or enum or throws an {@link IllegalArgumentException}.
610    */
asDeclared(TypeMirror maybeDeclaredType)611   public static DeclaredType asDeclared(TypeMirror maybeDeclaredType) {
612     return maybeDeclaredType.accept(DeclaredTypeVisitor.INSTANCE, null);
613   }
614 
615   private static final class DeclaredTypeVisitor extends CastingTypeVisitor<DeclaredType> {
616     private static final DeclaredTypeVisitor INSTANCE = new DeclaredTypeVisitor();
617 
DeclaredTypeVisitor()618     DeclaredTypeVisitor() {
619       super("declared type");
620     }
621 
622     @Override
visitDeclared(DeclaredType type, Void ignore)623     public DeclaredType visitDeclared(DeclaredType type, Void ignore) {
624       return type;
625     }
626   }
627 
628   /**
629    * Returns a {@link ExecutableType} if the {@link TypeMirror} represents an executable type such
630    * as may result from missing code, or bad compiles or throws an {@link IllegalArgumentException}.
631    */
asError(TypeMirror maybeErrorType)632   public static ErrorType asError(TypeMirror maybeErrorType) {
633     return maybeErrorType.accept(ErrorTypeVisitor.INSTANCE, null);
634   }
635 
636   private static final class ErrorTypeVisitor extends CastingTypeVisitor<ErrorType> {
637     private static final ErrorTypeVisitor INSTANCE = new ErrorTypeVisitor();
638 
ErrorTypeVisitor()639     ErrorTypeVisitor() {
640       super("error type");
641     }
642 
643     @Override
visitError(ErrorType type, Void ignore)644     public ErrorType visitError(ErrorType type, Void ignore) {
645       return type;
646     }
647   }
648 
649   /**
650    * Returns a {@link ExecutableType} if the {@link TypeMirror} represents an executable type such
651    * as a method, constructor, or initializer or throws an {@link IllegalArgumentException}.
652    */
asExecutable(TypeMirror maybeExecutableType)653   public static ExecutableType asExecutable(TypeMirror maybeExecutableType) {
654     return maybeExecutableType.accept(ExecutableTypeVisitor.INSTANCE, null);
655   }
656 
657   private static final class ExecutableTypeVisitor extends CastingTypeVisitor<ExecutableType> {
658     private static final ExecutableTypeVisitor INSTANCE = new ExecutableTypeVisitor();
659 
ExecutableTypeVisitor()660     ExecutableTypeVisitor() {
661       super("executable type");
662     }
663 
664     @Override
visitExecutable(ExecutableType type, Void ignore)665     public ExecutableType visitExecutable(ExecutableType type, Void ignore) {
666       return type;
667     }
668   }
669 
670   /**
671    * Returns an {@link IntersectionType} if the {@link TypeMirror} represents an intersection-type
672    * or throws an {@link IllegalArgumentException}.
673    */
asIntersection(TypeMirror maybeIntersectionType)674   public static IntersectionType asIntersection(TypeMirror maybeIntersectionType) {
675     return maybeIntersectionType.accept(IntersectionTypeVisitor.INSTANCE, null);
676   }
677 
678   private static final class IntersectionTypeVisitor extends CastingTypeVisitor<IntersectionType> {
679     private static final IntersectionTypeVisitor INSTANCE = new IntersectionTypeVisitor();
680 
IntersectionTypeVisitor()681     IntersectionTypeVisitor() {
682       super("intersection type");
683     }
684 
685     @Override
visitIntersection(IntersectionType type, Void ignore)686     public IntersectionType visitIntersection(IntersectionType type, Void ignore) {
687       return type;
688     }
689   }
690 
691   /**
692    * Returns a {@link NoType} if the {@link TypeMirror} represents an non-type such as void, or
693    * package, etc. or throws an {@link IllegalArgumentException}.
694    */
asNoType(TypeMirror maybeNoType)695   public static NoType asNoType(TypeMirror maybeNoType) {
696     return maybeNoType.accept(NoTypeVisitor.INSTANCE, null);
697   }
698 
699   private static final class NoTypeVisitor extends CastingTypeVisitor<NoType> {
700     private static final NoTypeVisitor INSTANCE = new NoTypeVisitor();
701 
NoTypeVisitor()702     NoTypeVisitor() {
703       super("non-type");
704     }
705 
706     @Override
visitNoType(NoType type, Void ignore)707     public NoType visitNoType(NoType type, Void ignore) {
708       return type;
709     }
710   }
711 
712   /**
713    * Returns a {@link NullType} if the {@link TypeMirror} represents the null type or throws an
714    * {@link IllegalArgumentException}.
715    */
asNullType(TypeMirror maybeNullType)716   public static NullType asNullType(TypeMirror maybeNullType) {
717     return maybeNullType.accept(NullTypeVisitor.INSTANCE, null);
718   }
719 
720   private static final class NullTypeVisitor extends CastingTypeVisitor<NullType> {
721     private static final NullTypeVisitor INSTANCE = new NullTypeVisitor();
722 
NullTypeVisitor()723     NullTypeVisitor() {
724       super("null");
725     }
726 
727     @Override
visitNull(NullType type, Void ignore)728     public NullType visitNull(NullType type, Void ignore) {
729       return type;
730     }
731   }
732 
733   /**
734    * Returns a {@link PrimitiveType} if the {@link TypeMirror} represents a primitive type or throws
735    * an {@link IllegalArgumentException}.
736    */
asPrimitiveType(TypeMirror maybePrimitiveType)737   public static PrimitiveType asPrimitiveType(TypeMirror maybePrimitiveType) {
738     return maybePrimitiveType.accept(PrimitiveTypeVisitor.INSTANCE, null);
739   }
740 
741   private static final class PrimitiveTypeVisitor extends CastingTypeVisitor<PrimitiveType> {
742     private static final PrimitiveTypeVisitor INSTANCE = new PrimitiveTypeVisitor();
743 
PrimitiveTypeVisitor()744     PrimitiveTypeVisitor() {
745       super("primitive type");
746     }
747 
748     @Override
visitPrimitive(PrimitiveType type, Void ignore)749     public PrimitiveType visitPrimitive(PrimitiveType type, Void ignore) {
750       return type;
751     }
752   }
753 
754   //
755   // visitUnionType would go here, but isn't relevant for annotation processors
756   //
757 
758   /**
759    * Returns a {@link TypeVariable} if the {@link TypeMirror} represents a type variable or throws
760    * an {@link IllegalArgumentException}.
761    */
asTypeVariable(TypeMirror maybeTypeVariable)762   public static TypeVariable asTypeVariable(TypeMirror maybeTypeVariable) {
763     return maybeTypeVariable.accept(TypeVariableVisitor.INSTANCE, null);
764   }
765 
766   private static final class TypeVariableVisitor extends CastingTypeVisitor<TypeVariable> {
767     private static final TypeVariableVisitor INSTANCE = new TypeVariableVisitor();
768 
TypeVariableVisitor()769     TypeVariableVisitor() {
770       super("type variable");
771     }
772 
773     @Override
visitTypeVariable(TypeVariable type, Void ignore)774     public TypeVariable visitTypeVariable(TypeVariable type, Void ignore) {
775       return type;
776     }
777   }
778 
779   /**
780    * Returns a {@link WildcardType} if the {@link TypeMirror} represents a wildcard type or throws
781    * an {@link IllegalArgumentException}.
782    */
asWildcard(TypeMirror maybeWildcardType)783   public static WildcardType asWildcard(TypeMirror maybeWildcardType) {
784     return maybeWildcardType.accept(WildcardTypeVisitor.INSTANCE, null);
785   }
786 
787   private static final class WildcardTypeVisitor extends CastingTypeVisitor<WildcardType> {
788     private static final WildcardTypeVisitor INSTANCE = new WildcardTypeVisitor();
789 
WildcardTypeVisitor()790     WildcardTypeVisitor() {
791       super("wildcard type");
792     }
793 
794     @Override
visitWildcard(WildcardType type, Void ignore)795     public WildcardType visitWildcard(WildcardType type, Void ignore) {
796       return type;
797     }
798   }
799 
800   /**
801    * Returns true if the raw type underlying the given {@link TypeMirror} represents a type that can
802    * be referenced by a {@link Class}. If this returns true, then {@link #isTypeOf} is guaranteed to
803    * not throw.
804    */
isType(TypeMirror type)805   public static boolean isType(TypeMirror type) {
806     return type.accept(IsTypeVisitor.INSTANCE, null);
807   }
808 
809   private static final class IsTypeVisitor extends SimpleTypeVisitor8<Boolean, Void> {
810     private static final IsTypeVisitor INSTANCE = new IsTypeVisitor();
811 
812     @Override
defaultAction(TypeMirror type, Void ignored)813     protected Boolean defaultAction(TypeMirror type, Void ignored) {
814       return false;
815     }
816 
817     @Override
visitNoType(NoType noType, Void p)818     public Boolean visitNoType(NoType noType, Void p) {
819       return noType.getKind().equals(TypeKind.VOID);
820     }
821 
822     @Override
visitPrimitive(PrimitiveType type, Void p)823     public Boolean visitPrimitive(PrimitiveType type, Void p) {
824       return true;
825     }
826 
827     @Override
visitArray(ArrayType array, Void p)828     public Boolean visitArray(ArrayType array, Void p) {
829       return true;
830     }
831 
832     @Override
visitDeclared(DeclaredType type, Void ignored)833     public Boolean visitDeclared(DeclaredType type, Void ignored) {
834       return MoreElements.isType(type.asElement());
835     }
836   }
837 
838   /**
839    * Returns true if the raw type underlying the given {@link TypeMirror} represents the same raw
840    * type as the given {@link Class} and throws an IllegalArgumentException if the {@link
841    * TypeMirror} does not represent a type that can be referenced by a {@link Class}
842    */
isTypeOf(final Class<?> clazz, TypeMirror type)843   public static boolean isTypeOf(final Class<?> clazz, TypeMirror type) {
844     checkNotNull(clazz);
845     return type.accept(new IsTypeOf(clazz), null);
846   }
847 
848   private static final class IsTypeOf extends SimpleTypeVisitor8<Boolean, Void> {
849     private final Class<?> clazz;
850 
IsTypeOf(Class<?> clazz)851     IsTypeOf(Class<?> clazz) {
852       this.clazz = clazz;
853     }
854 
855     @Override
defaultAction(TypeMirror type, Void ignored)856     protected Boolean defaultAction(TypeMirror type, Void ignored) {
857       throw new IllegalArgumentException(type + " cannot be represented as a Class<?>.");
858     }
859 
860     @Override
visitNoType(NoType noType, Void p)861     public Boolean visitNoType(NoType noType, Void p) {
862       if (noType.getKind().equals(TypeKind.VOID)) {
863         return clazz.equals(Void.TYPE);
864       }
865       throw new IllegalArgumentException(noType + " cannot be represented as a Class<?>.");
866     }
867 
868     @Override
visitError(ErrorType errorType, Void p)869     public Boolean visitError(ErrorType errorType, Void p) {
870       return false;
871     }
872 
873     @Override
visitPrimitive(PrimitiveType type, Void p)874     public Boolean visitPrimitive(PrimitiveType type, Void p) {
875       switch (type.getKind()) {
876         case BOOLEAN:
877           return clazz.equals(Boolean.TYPE);
878         case BYTE:
879           return clazz.equals(Byte.TYPE);
880         case CHAR:
881           return clazz.equals(Character.TYPE);
882         case DOUBLE:
883           return clazz.equals(Double.TYPE);
884         case FLOAT:
885           return clazz.equals(Float.TYPE);
886         case INT:
887           return clazz.equals(Integer.TYPE);
888         case LONG:
889           return clazz.equals(Long.TYPE);
890         case SHORT:
891           return clazz.equals(Short.TYPE);
892         default:
893           throw new IllegalArgumentException(type + " cannot be represented as a Class<?>.");
894       }
895     }
896 
897     @Override
visitArray(ArrayType array, Void p)898     public Boolean visitArray(ArrayType array, Void p) {
899       return clazz.isArray() && isTypeOf(clazz.getComponentType(), array.getComponentType());
900     }
901 
902     @Override
visitDeclared(DeclaredType type, Void ignored)903     public Boolean visitDeclared(DeclaredType type, Void ignored) {
904       TypeElement typeElement = MoreElements.asType(type.asElement());
905       return typeElement.getQualifiedName().contentEquals(clazz.getCanonicalName());
906     }
907   }
908 
909   /**
910    * Returns the superclass of {@code type}, with any type parameters bound by {@code type}, or
911    * {@link Optional#absent()} if {@code type} is an interface or {@link Object} or its superclass
912    * is {@link Object}.
913    */
914   // TODO(bcorso): Remove unused parameter Elements?
nonObjectSuperclass( Types types, Elements elements, DeclaredType type)915   public static Optional<DeclaredType> nonObjectSuperclass(
916       Types types, Elements elements, DeclaredType type) {
917     checkNotNull(types);
918     checkNotNull(elements); // This is no longer used, but here to avoid changing the API.
919     checkNotNull(type);
920 
921     TypeMirror superclassType = asTypeElement(type).getSuperclass();
922     if (!isType(superclassType)) { // type is Object or an interface
923       return Optional.absent();
924     }
925 
926     DeclaredType superclass = asDeclared(superclassType);
927     if (isObjectType(superclass)) {
928       return Optional.absent();
929     }
930 
931     if (superclass.getTypeArguments().isEmpty()) {
932       return Optional.of(superclass);
933     }
934 
935     // In the case where the super class has type parameters, TypeElement#getSuperclass gives
936     // SuperClass<T> rather than SuperClass<Foo>, so use Types#directSupertypes instead. The javadoc
937     // for Types#directSupertypes guarantees that a super class, if it exists, comes before any
938     // interfaces. Thus, we can just get the first element in the list.
939     return Optional.of(asDeclared(types.directSupertypes(type).get(0)));
940   }
941 
isObjectType(DeclaredType type)942   private static boolean isObjectType(DeclaredType type) {
943     return asTypeElement(type).getQualifiedName().contentEquals("java.lang.Object");
944   }
945 
946   /**
947    * Resolves a {@link VariableElement} parameter to a method or constructor based on the given
948    * container, or a member of a class. For parameters to a method or constructor, the variable's
949    * enclosing element must be a supertype of the container type. For example, given a
950    * {@code container} of type {@code Set<String>}, and a variable corresponding to the {@code E e}
951    * parameter in the {@code Set.add(E e)} method, this will return a TypeMirror for {@code String}.
952    */
asMemberOf( Types types, DeclaredType container, VariableElement variable)953   public static TypeMirror asMemberOf(
954       Types types, DeclaredType container, VariableElement variable) {
955     if (variable.getKind().equals(ElementKind.PARAMETER)) {
956       ExecutableElement methodOrConstructor =
957           MoreElements.asExecutable(variable.getEnclosingElement());
958       ExecutableType resolvedMethodOrConstructor =
959           MoreTypes.asExecutable(types.asMemberOf(container, methodOrConstructor));
960       List<? extends VariableElement> parameters = methodOrConstructor.getParameters();
961       List<? extends TypeMirror> parameterTypes = resolvedMethodOrConstructor.getParameterTypes();
962       checkState(parameters.size() == parameterTypes.size());
963       for (int i = 0; i < parameters.size(); i++) {
964         // We need to capture the parameter type of the variable we're concerned about,
965         // for later printing.  This is the only way to do it since we can't use
966         // types.asMemberOf on variables of methods.
967         if (parameters.get(i).equals(variable)) {
968           return parameterTypes.get(i);
969         }
970       }
971       throw new IllegalStateException("Could not find variable: " + variable);
972     } else {
973       return types.asMemberOf(container, variable);
974     }
975   }
976 
977   private abstract static class CastingTypeVisitor<T> extends SimpleTypeVisitor8<T, Void> {
978     private final String label;
979 
CastingTypeVisitor(String label)980     CastingTypeVisitor(String label) {
981       this.label = label;
982     }
983 
984     @Override
defaultAction(TypeMirror e, Void v)985     protected T defaultAction(TypeMirror e, Void v) {
986       throw new IllegalArgumentException(e + " does not represent a " + label);
987     }
988   }
989 
990   /**
991    * Returns true if casting {@code Object} to the given type will elicit an unchecked warning from
992    * the compiler. Only type variables and parameterized types such as {@code List<String>} produce
993    * such warnings. There will be no warning if the type's only type parameters are simple
994    * wildcards, as in {@code Map<?, ?>}.
995    */
isConversionFromObjectUnchecked(TypeMirror type)996   public static boolean isConversionFromObjectUnchecked(TypeMirror type) {
997     return new CastingUncheckedVisitor().visit(type, null);
998   }
999 
1000   /**
1001    * Visitor that tells whether a type is erased, in the sense of {@link #castIsUnchecked}. Each
1002    * visitX method returns true if its input parameter is true or if the type being visited is
1003    * erased.
1004    */
1005   private static class CastingUncheckedVisitor extends SimpleTypeVisitor8<Boolean, Void> {
CastingUncheckedVisitor()1006     CastingUncheckedVisitor() {
1007       super(false);
1008     }
1009 
1010     @Override
visitUnknown(TypeMirror t, Void p)1011     public Boolean visitUnknown(TypeMirror t, Void p) {
1012       // We don't know whether casting is unchecked for this mysterious type but assume it is,
1013       // so we will insert a possibly unnecessary @SuppressWarnings("unchecked").
1014       return true;
1015     }
1016 
1017     @Override
visitArray(ArrayType t, Void p)1018     public Boolean visitArray(ArrayType t, Void p) {
1019       return visit(t.getComponentType(), p);
1020     }
1021 
1022     @Override
visitDeclared(DeclaredType t, Void p)1023     public Boolean visitDeclared(DeclaredType t, Void p) {
1024       return t.getTypeArguments().stream().anyMatch(CastingUncheckedVisitor::uncheckedTypeArgument);
1025     }
1026 
1027     @Override
visitTypeVariable(TypeVariable t, Void p)1028     public Boolean visitTypeVariable(TypeVariable t, Void p) {
1029       return true;
1030     }
1031 
1032     // If a type has a type argument, then casting to the type is unchecked, except if the argument
1033     // is <?> or <? extends Object>. The same applies to all type arguments, so casting to Map<?, ?>
1034     // does not produce an unchecked warning for example.
uncheckedTypeArgument(TypeMirror arg)1035     private static boolean uncheckedTypeArgument(TypeMirror arg) {
1036       if (arg.getKind().equals(TypeKind.WILDCARD)) {
1037         WildcardType wildcard = asWildcard(arg);
1038         if (wildcard.getExtendsBound() == null || isJavaLangObject(wildcard.getExtendsBound())) {
1039           // This is <?>, unless there's a super bound, in which case it is <? super Foo> and
1040           // is erased.
1041           return (wildcard.getSuperBound() != null);
1042         }
1043       }
1044       return true;
1045     }
1046 
isJavaLangObject(TypeMirror type)1047     private static boolean isJavaLangObject(TypeMirror type) {
1048       if (type.getKind() != TypeKind.DECLARED) {
1049         return false;
1050       }
1051       TypeElement typeElement = asTypeElement(type);
1052       return typeElement.getQualifiedName().contentEquals("java.lang.Object");
1053     }
1054   }
1055 
MoreTypes()1056   private MoreTypes() {}
1057 }
1058