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