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