• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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