1 /* 2 * Copyright (C) 2016 The Dagger Authors. 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 17 package dagger.internal.codegen.langmodel; 18 19 import static androidx.room.compiler.processing.compat.XConverters.toJavac; 20 import static com.google.auto.common.MoreTypes.asDeclared; 21 import static com.google.common.base.Preconditions.checkArgument; 22 import static com.google.common.base.Preconditions.checkNotNull; 23 import static com.google.common.collect.Iterables.getOnlyElement; 24 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; 25 26 import androidx.room.compiler.processing.XType; 27 import androidx.room.compiler.processing.XTypeElement; 28 import com.google.auto.common.MoreElements; 29 import com.google.auto.common.MoreTypes; 30 import com.google.common.collect.ImmutableSet; 31 import com.google.common.graph.Traverser; 32 import com.google.common.util.concurrent.FluentFuture; 33 import com.google.common.util.concurrent.ListenableFuture; 34 import com.squareup.javapoet.ArrayTypeName; 35 import com.squareup.javapoet.ClassName; 36 import com.squareup.javapoet.TypeName; 37 import java.util.List; 38 import java.util.Optional; 39 import java.util.function.Predicate; 40 import javax.lang.model.element.Element; 41 import javax.lang.model.element.TypeElement; 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.NoType; 47 import javax.lang.model.type.NullType; 48 import javax.lang.model.type.PrimitiveType; 49 import javax.lang.model.type.TypeKind; 50 import javax.lang.model.type.TypeMirror; 51 import javax.lang.model.type.WildcardType; 52 import javax.lang.model.util.SimpleTypeVisitor8; 53 import javax.lang.model.util.Types; 54 55 /** Extension of {@link Types} that adds Dagger-specific methods. */ 56 public final class DaggerTypes implements Types { 57 private final Types types; 58 private final DaggerElements elements; 59 DaggerTypes(Types types, DaggerElements elements)60 public DaggerTypes(Types types, DaggerElements elements) { 61 this.types = checkNotNull(types); 62 this.elements = checkNotNull(elements); 63 } 64 65 // Note: This is similar to auto-common's MoreTypes except using ClassName rather than Class. 66 // TODO(bcorso): Contribute a String version to auto-common's MoreTypes? 67 /** 68 * Returns true if the raw type underlying the given {@link TypeMirror} represents the same raw 69 * type as the given {@link Class} and throws an IllegalArgumentException if the {@link 70 * TypeMirror} does not represent a type that can be referenced by a {@link Class} 71 */ isTypeOf(final TypeName typeName, TypeMirror type)72 public static boolean isTypeOf(final TypeName typeName, TypeMirror type) { 73 checkNotNull(typeName); 74 return type.accept(new IsTypeOf(typeName), null); 75 } 76 77 private static final class IsTypeOf extends SimpleTypeVisitor8<Boolean, Void> { 78 private final TypeName typeName; 79 IsTypeOf(TypeName typeName)80 IsTypeOf(TypeName typeName) { 81 this.typeName = typeName; 82 } 83 84 @Override defaultAction(TypeMirror type, Void ignored)85 protected Boolean defaultAction(TypeMirror type, Void ignored) { 86 throw new IllegalArgumentException(type + " cannot be represented as a Class<?>."); 87 } 88 89 @Override visitNoType(NoType noType, Void p)90 public Boolean visitNoType(NoType noType, Void p) { 91 if (noType.getKind().equals(TypeKind.VOID)) { 92 return typeName.equals(TypeName.VOID); 93 } 94 throw new IllegalArgumentException(noType + " cannot be represented as a Class<?>."); 95 } 96 97 @Override visitError(ErrorType errorType, Void p)98 public Boolean visitError(ErrorType errorType, Void p) { 99 return false; 100 } 101 102 @Override visitPrimitive(PrimitiveType type, Void p)103 public Boolean visitPrimitive(PrimitiveType type, Void p) { 104 switch (type.getKind()) { 105 case BOOLEAN: 106 return typeName.equals(TypeName.BOOLEAN); 107 case BYTE: 108 return typeName.equals(TypeName.BYTE); 109 case CHAR: 110 return typeName.equals(TypeName.CHAR); 111 case DOUBLE: 112 return typeName.equals(TypeName.DOUBLE); 113 case FLOAT: 114 return typeName.equals(TypeName.FLOAT); 115 case INT: 116 return typeName.equals(TypeName.INT); 117 case LONG: 118 return typeName.equals(TypeName.LONG); 119 case SHORT: 120 return typeName.equals(TypeName.SHORT); 121 default: 122 throw new IllegalArgumentException(type + " cannot be represented as a Class<?>."); 123 } 124 } 125 126 @Override visitArray(ArrayType array, Void p)127 public Boolean visitArray(ArrayType array, Void p) { 128 return (typeName instanceof ArrayTypeName) 129 && isTypeOf(((ArrayTypeName) typeName).componentType, array.getComponentType()); 130 } 131 132 @Override visitDeclared(DeclaredType type, Void ignored)133 public Boolean visitDeclared(DeclaredType type, Void ignored) { 134 TypeElement typeElement = MoreElements.asType(type.asElement()); 135 return (typeName instanceof ClassName) 136 && typeElement.getQualifiedName().contentEquals(((ClassName) typeName).canonicalName()); 137 } 138 } 139 140 /** 141 * Returns the non-{@link Object} superclass of the type with the proper type parameters. An empty 142 * {@link Optional} is returned if there is no non-{@link Object} superclass. 143 */ nonObjectSuperclass(XType type)144 public Optional<DeclaredType> nonObjectSuperclass(XType type) { 145 return isDeclared(type) ? nonObjectSuperclass(asDeclared(toJavac(type))) : Optional.empty(); 146 } 147 148 /** 149 * Returns the non-{@link Object} superclass of the type with the proper type parameters. An empty 150 * {@link Optional} is returned if there is no non-{@link Object} superclass. 151 */ nonObjectSuperclass(DeclaredType type)152 public Optional<DeclaredType> nonObjectSuperclass(DeclaredType type) { 153 return Optional.ofNullable(MoreTypes.nonObjectSuperclass(types, elements, type).orNull()); 154 } 155 156 /** 157 * Returns the {@linkplain #directSupertypes(TypeMirror) supertype}s of a type in breadth-first 158 * order. 159 */ supertypes(TypeMirror type)160 public Iterable<TypeMirror> supertypes(TypeMirror type) { 161 return Traverser.<TypeMirror>forGraph(this::directSupertypes).breadthFirst(type); 162 } 163 164 /** 165 * Returns {@code type}'s single type argument. 166 * 167 * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}. 168 * 169 * @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more 170 * than one type arguments. 171 */ unwrapType(XType type)172 public static XType unwrapType(XType type) { 173 XType unwrapped = unwrapTypeOrDefault(type, null); 174 checkArgument(unwrapped != null, "%s is a raw type", type); 175 return unwrapped; 176 } 177 178 /** 179 * Returns {@code type}'s single type argument. 180 * 181 * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}. 182 * 183 * @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more 184 * than one type arguments. 185 */ unwrapType(TypeMirror type)186 public static TypeMirror unwrapType(TypeMirror type) { 187 TypeMirror unwrapped = unwrapTypeOrDefault(type, null); 188 checkArgument(unwrapped != null, "%s is a raw type", type); 189 return unwrapped; 190 } 191 unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType)192 private static TypeMirror unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType) { 193 DeclaredType declaredType = MoreTypes.asDeclared(type); 194 TypeElement typeElement = MoreElements.asType(declaredType.asElement()); 195 checkArgument( 196 !typeElement.getTypeParameters().isEmpty(), 197 "%s does not have a type parameter", 198 typeElement.getQualifiedName()); 199 return getOnlyElement(declaredType.getTypeArguments(), defaultType); 200 } 201 unwrapTypeOrDefault(XType type, XType defaultType)202 private static XType unwrapTypeOrDefault(XType type, XType defaultType) { 203 // Check the type parameters of the element's XType since the input XType could be raw. 204 checkArgument(isDeclared(type)); 205 XTypeElement typeElement = type.getTypeElement(); 206 checkArgument( 207 typeElement.getType().getTypeArguments().size() == 1, 208 "%s does not have exactly 1 type parameter. Found: %s", 209 typeElement.getQualifiedName(), 210 typeElement.getType().getTypeArguments()); 211 return getOnlyElement(type.getTypeArguments(), defaultType); 212 } 213 214 /** 215 * Returns {@code type}'s single type argument, if one exists, or {@link Object} if not. 216 * 217 * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}. 218 * 219 * @throws IllegalArgumentException if {@code type} is not a declared type or has more than one 220 * type argument. 221 */ unwrapTypeOrObject(TypeMirror type)222 public TypeMirror unwrapTypeOrObject(TypeMirror type) { 223 return unwrapTypeOrDefault(type, elements.getTypeElement(TypeName.OBJECT).asType()); 224 } 225 226 /** 227 * Returns {@code type} wrapped in {@code wrappingClass}. 228 * 229 * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code 230 * Set.class}, this will return {@code Set<List<Number>>}. 231 */ wrapType(XType type, ClassName wrappingClassName)232 public DeclaredType wrapType(XType type, ClassName wrappingClassName) { 233 return wrapType(toJavac(type), wrappingClassName); 234 } 235 236 /** 237 * Returns {@code type} wrapped in {@code wrappingClass}. 238 * 239 * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code 240 * Set.class}, this will return {@code Set<List<Number>>}. 241 */ wrapType(TypeMirror type, ClassName wrappingClassName)242 public DeclaredType wrapType(TypeMirror type, ClassName wrappingClassName) { 243 return types.getDeclaredType(elements.getTypeElement(wrappingClassName.canonicalName()), type); 244 } 245 246 /** 247 * Returns {@code type}'s single type argument wrapped in {@code wrappingClass}. 248 * 249 * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code 250 * Set.class}, this will return {@code Set<Number>}. 251 * 252 * <p>If {@code type} has no type parameters, returns a {@link TypeMirror} for {@code 253 * wrappingClass} as a raw type. 254 * 255 * @throws IllegalArgumentException if {@code} has more than one type argument. 256 */ rewrapType(TypeMirror type, ClassName wrappingClassName)257 public DeclaredType rewrapType(TypeMirror type, ClassName wrappingClassName) { 258 List<? extends TypeMirror> typeArguments = MoreTypes.asDeclared(type).getTypeArguments(); 259 TypeElement wrappingType = elements.getTypeElement(wrappingClassName.canonicalName()); 260 switch (typeArguments.size()) { 261 case 0: 262 return getDeclaredType(wrappingType); 263 case 1: 264 return getDeclaredType(wrappingType, getOnlyElement(typeArguments)); 265 default: 266 throw new IllegalArgumentException(type + " has more than 1 type argument"); 267 } 268 } 269 270 /** 271 * Returns an accessible type in {@code requestingClass}'s package based on {@code type}: 272 * 273 * <ul> 274 * <li>If {@code type} is accessible from the package, returns it. 275 * <li>If not, but {@code type}'s raw type is accessible from the package, returns the raw type. 276 * <li>Otherwise returns {@link Object}. 277 * </ul> 278 */ accessibleType(XType type, ClassName requestingClass)279 public TypeMirror accessibleType(XType type, ClassName requestingClass) { 280 return accessibleType(toJavac(type), requestingClass); 281 } 282 283 /** 284 * Returns an accessible type in {@code requestingClass}'s package based on {@code type}: 285 * 286 * <ul> 287 * <li>If {@code type} is accessible from the package, returns it. 288 * <li>If not, but {@code type}'s raw type is accessible from the package, returns the raw type. 289 * <li>Otherwise returns {@link Object}. 290 * </ul> 291 */ accessibleType(TypeMirror type, ClassName requestingClass)292 public TypeMirror accessibleType(TypeMirror type, ClassName requestingClass) { 293 return accessibleType( 294 type, 295 t -> Accessibility.isTypeAccessibleFrom(t, requestingClass.packageName()), 296 t -> Accessibility.isRawTypeAccessible(t, requestingClass.packageName())); 297 } 298 accessibleType( TypeMirror type, Predicate<TypeMirror> accessibilityPredicate, Predicate<TypeMirror> rawTypeAccessibilityPredicate)299 private TypeMirror accessibleType( 300 TypeMirror type, 301 Predicate<TypeMirror> accessibilityPredicate, 302 Predicate<TypeMirror> rawTypeAccessibilityPredicate) { 303 if (accessibilityPredicate.test(type)) { 304 return type; 305 } else if (type.getKind().equals(TypeKind.DECLARED) 306 && rawTypeAccessibilityPredicate.test(type)) { 307 return getDeclaredType(MoreTypes.asTypeElement(type)); 308 } else { 309 return elements.getTypeElement(TypeName.OBJECT).asType(); 310 } 311 } 312 313 /** 314 * Throws {@link TypeNotPresentException} if {@code type} is an {@link 315 * javax.lang.model.type.ErrorType}. 316 */ checkTypePresent(TypeMirror type)317 public static void checkTypePresent(TypeMirror type) { 318 type.accept( 319 // TODO(ronshapiro): Extract a base class that visits all components of a complex type 320 // and put it in auto.common 321 new SimpleTypeVisitor8<Void, Void>() { 322 @Override 323 public Void visitArray(ArrayType arrayType, Void p) { 324 return arrayType.getComponentType().accept(this, p); 325 } 326 327 @Override 328 public Void visitDeclared(DeclaredType declaredType, Void p) { 329 declaredType.getTypeArguments().forEach(t -> t.accept(this, p)); 330 return null; 331 } 332 333 @Override 334 public Void visitError(ErrorType errorType, Void p) { 335 throw new TypeNotPresentException(type.toString(), null); 336 } 337 }, 338 null); 339 } 340 341 private static final ImmutableSet<Class<?>> FUTURE_TYPES = 342 ImmutableSet.of(ListenableFuture.class, FluentFuture.class); 343 isFutureType(XType type)344 public static boolean isFutureType(XType type) { 345 return isFutureType(toJavac(type)); 346 } 347 isFutureType(TypeMirror type)348 public static boolean isFutureType(TypeMirror type) { 349 return FUTURE_TYPES.stream().anyMatch(t -> MoreTypes.isTypeOf(t, type)); 350 } 351 352 // Implementation of Types methods, delegating to types. 353 354 @Override asElement(TypeMirror t)355 public Element asElement(TypeMirror t) { 356 return types.asElement(t); 357 } 358 359 @Override isSameType(TypeMirror t1, TypeMirror t2)360 public boolean isSameType(TypeMirror t1, TypeMirror t2) { 361 return types.isSameType(t1, t2); 362 } 363 isSubtype(XType t1, XType t2)364 public boolean isSubtype(XType t1, XType t2) { 365 return isSubtype(toJavac(t1), toJavac(t2)); 366 } 367 368 @Override isSubtype(TypeMirror t1, TypeMirror t2)369 public boolean isSubtype(TypeMirror t1, TypeMirror t2) { 370 return types.isSubtype(t1, t2); 371 } 372 373 @Override isAssignable(TypeMirror t1, TypeMirror t2)374 public boolean isAssignable(TypeMirror t1, TypeMirror t2) { 375 return types.isAssignable(t1, t2); 376 } 377 378 @Override contains(TypeMirror t1, TypeMirror t2)379 public boolean contains(TypeMirror t1, TypeMirror t2) { 380 return types.contains(t1, t2); 381 } 382 383 @Override isSubsignature(ExecutableType m1, ExecutableType m2)384 public boolean isSubsignature(ExecutableType m1, ExecutableType m2) { 385 return types.isSubsignature(m1, m2); 386 } 387 388 @Override directSupertypes(TypeMirror t)389 public List<? extends TypeMirror> directSupertypes(TypeMirror t) { 390 return types.directSupertypes(t); 391 } 392 393 @Override erasure(TypeMirror t)394 public TypeMirror erasure(TypeMirror t) { 395 return types.erasure(t); 396 } 397 398 @Override boxedClass(PrimitiveType p)399 public TypeElement boxedClass(PrimitiveType p) { 400 return types.boxedClass(p); 401 } 402 403 @Override unboxedType(TypeMirror t)404 public PrimitiveType unboxedType(TypeMirror t) { 405 return types.unboxedType(t); 406 } 407 408 @Override capture(TypeMirror t)409 public TypeMirror capture(TypeMirror t) { 410 return types.capture(t); 411 } 412 413 @Override getPrimitiveType(TypeKind kind)414 public PrimitiveType getPrimitiveType(TypeKind kind) { 415 return types.getPrimitiveType(kind); 416 } 417 418 @Override getNullType()419 public NullType getNullType() { 420 return types.getNullType(); 421 } 422 423 @Override getNoType(TypeKind kind)424 public NoType getNoType(TypeKind kind) { 425 return types.getNoType(kind); 426 } 427 428 @Override getArrayType(TypeMirror componentType)429 public ArrayType getArrayType(TypeMirror componentType) { 430 return types.getArrayType(componentType); 431 } 432 433 @Override getWildcardType(TypeMirror extendsBound, TypeMirror superBound)434 public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) { 435 return types.getWildcardType(extendsBound, superBound); 436 } 437 438 @Override getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs)439 public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) { 440 return types.getDeclaredType(typeElem, typeArgs); 441 } 442 443 @Override getDeclaredType( DeclaredType containing, TypeElement typeElem, TypeMirror... typeArgs)444 public DeclaredType getDeclaredType( 445 DeclaredType containing, TypeElement typeElem, TypeMirror... typeArgs) { 446 return types.getDeclaredType(containing, typeElem, typeArgs); 447 } 448 449 @Override asMemberOf(DeclaredType containing, Element element)450 public TypeMirror asMemberOf(DeclaredType containing, Element element) { 451 return types.asMemberOf(containing, element); 452 } 453 } 454