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