• 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 com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static com.google.common.collect.Iterables.getOnlyElement;
22 
23 import com.google.auto.common.MoreElements;
24 import com.google.auto.common.MoreTypes;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.graph.Traverser;
27 import com.google.common.util.concurrent.FluentFuture;
28 import com.google.common.util.concurrent.ListenableFuture;
29 import com.squareup.javapoet.ClassName;
30 import java.util.List;
31 import java.util.Optional;
32 import java.util.function.Predicate;
33 import javax.inject.Inject;
34 import javax.lang.model.element.Element;
35 import javax.lang.model.element.ExecutableElement;
36 import javax.lang.model.element.TypeElement;
37 import javax.lang.model.type.ArrayType;
38 import javax.lang.model.type.DeclaredType;
39 import javax.lang.model.type.ErrorType;
40 import javax.lang.model.type.ExecutableType;
41 import javax.lang.model.type.NoType;
42 import javax.lang.model.type.NullType;
43 import javax.lang.model.type.PrimitiveType;
44 import javax.lang.model.type.TypeKind;
45 import javax.lang.model.type.TypeMirror;
46 import javax.lang.model.type.TypeVariable;
47 import javax.lang.model.type.WildcardType;
48 import javax.lang.model.util.SimpleTypeVisitor8;
49 import javax.lang.model.util.Types;
50 
51 /** Extension of {@link Types} that adds Dagger-specific methods. */
52 public final class DaggerTypes implements Types {
53   private final Types types;
54   private final DaggerElements elements;
55 
56   @Inject
DaggerTypes(Types types, DaggerElements elements)57   public DaggerTypes(Types types, DaggerElements elements) {
58     this.types = checkNotNull(types);
59     this.elements = checkNotNull(elements);
60   }
61 
62   /**
63    * Returns the non-{@link Object} superclass of the type with the proper type parameters. An empty
64    * {@link Optional} is returned if there is no non-{@link Object} superclass.
65    */
nonObjectSuperclass(DeclaredType type)66   public Optional<DeclaredType> nonObjectSuperclass(DeclaredType type) {
67     return Optional.ofNullable(MoreTypes.nonObjectSuperclass(types, elements, type).orNull());
68   }
69 
70   /**
71    * Returns the {@linkplain #directSupertypes(TypeMirror) supertype}s of a type in breadth-first
72    * order.
73    */
supertypes(TypeMirror type)74   public Iterable<TypeMirror> supertypes(TypeMirror type) {
75     return Traverser.<TypeMirror>forGraph(this::directSupertypes).breadthFirst(type);
76   }
77 
78   /**
79    * Returns {@code type}'s single type argument.
80    *
81    * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}.
82    *
83    * @throws IllegalArgumentException if {@code type} is not a declared type or has zero or more
84    *     than one type arguments.
85    */
unwrapType(TypeMirror type)86   public static TypeMirror unwrapType(TypeMirror type) {
87     TypeMirror unwrapped = unwrapTypeOrDefault(type, null);
88     checkArgument(unwrapped != null, "%s is a raw type", type);
89     return unwrapped;
90   }
91 
92   /**
93    * Returns {@code type}'s single type argument, if one exists, or {@link Object} if not.
94    *
95    * <p>For example, if {@code type} is {@code List<Number>} this will return {@code Number}.
96    *
97    * @throws IllegalArgumentException if {@code type} is not a declared type or has more than one
98    *     type argument.
99    */
unwrapTypeOrObject(TypeMirror type)100   public TypeMirror unwrapTypeOrObject(TypeMirror type) {
101     return unwrapTypeOrDefault(type, elements.getTypeElement(Object.class).asType());
102   }
103 
unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType)104   private static TypeMirror unwrapTypeOrDefault(TypeMirror type, TypeMirror defaultType) {
105     DeclaredType declaredType = MoreTypes.asDeclared(type);
106     TypeElement typeElement = MoreElements.asType(declaredType.asElement());
107     checkArgument(
108         !typeElement.getTypeParameters().isEmpty(),
109         "%s does not have a type parameter",
110         typeElement.getQualifiedName());
111     return getOnlyElement(declaredType.getTypeArguments(), defaultType);
112   }
113 
114   /**
115    * Returns {@code type} wrapped in {@code wrappingClass}.
116    *
117    * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code
118    * Set.class}, this will return {@code Set<List<Number>>}.
119    */
wrapType(TypeMirror type, Class<?> wrappingClass)120   public DeclaredType wrapType(TypeMirror type, Class<?> wrappingClass) {
121     return types.getDeclaredType(elements.getTypeElement(wrappingClass), type);
122   }
123 
124   /**
125    * Returns {@code type}'s single type argument wrapped in {@code wrappingClass}.
126    *
127    * <p>For example, if {@code type} is {@code List<Number>} and {@code wrappingClass} is {@code
128    * Set.class}, this will return {@code Set<Number>}.
129    *
130    * <p>If {@code type} has no type parameters, returns a {@link TypeMirror} for {@code
131    * wrappingClass} as a raw type.
132    *
133    * @throws IllegalArgumentException if {@code} has more than one type argument.
134    */
rewrapType(TypeMirror type, Class<?> wrappingClass)135   public DeclaredType rewrapType(TypeMirror type, Class<?> wrappingClass) {
136     List<? extends TypeMirror> typeArguments = MoreTypes.asDeclared(type).getTypeArguments();
137     TypeElement wrappingType = elements.getTypeElement(wrappingClass);
138     switch (typeArguments.size()) {
139       case 0:
140         return getDeclaredType(wrappingType);
141       case 1:
142         return getDeclaredType(wrappingType, getOnlyElement(typeArguments));
143       default:
144         throw new IllegalArgumentException(type + " has more than 1 type argument");
145     }
146   }
147 
148   /**
149    * Returns a publicly accessible type based on {@code type}:
150    *
151    * <ul>
152    *   <li>If {@code type} is publicly accessible, returns it.
153    *   <li>If not, but {@code type}'s raw type is publicly accessible, returns the raw type.
154    *   <li>Otherwise returns {@link Object}.
155    * </ul>
156    */
publiclyAccessibleType(TypeMirror type)157   public TypeMirror publiclyAccessibleType(TypeMirror type) {
158     return accessibleType(
159         type, Accessibility::isTypePubliclyAccessible, Accessibility::isRawTypePubliclyAccessible);
160   }
161 
162   /**
163    * Returns an accessible type in {@code requestingClass}'s package based on {@code type}:
164    *
165    * <ul>
166    *   <li>If {@code type} is accessible from the package, returns it.
167    *   <li>If not, but {@code type}'s raw type is accessible from the package, returns the raw type.
168    *   <li>Otherwise returns {@link Object}.
169    * </ul>
170    */
accessibleType(TypeMirror type, ClassName requestingClass)171   public TypeMirror accessibleType(TypeMirror type, ClassName requestingClass) {
172     return accessibleType(
173         type,
174         t -> Accessibility.isTypeAccessibleFrom(t, requestingClass.packageName()),
175         t -> Accessibility.isRawTypeAccessible(t, requestingClass.packageName()));
176   }
177 
accessibleType( TypeMirror type, Predicate<TypeMirror> accessibilityPredicate, Predicate<TypeMirror> rawTypeAccessibilityPredicate)178   private TypeMirror accessibleType(
179       TypeMirror type,
180       Predicate<TypeMirror> accessibilityPredicate,
181       Predicate<TypeMirror> rawTypeAccessibilityPredicate) {
182     if (accessibilityPredicate.test(type)) {
183       return type;
184     } else if (type.getKind().equals(TypeKind.DECLARED)
185         && rawTypeAccessibilityPredicate.test(type)) {
186       return getDeclaredType(MoreTypes.asTypeElement(type));
187     } else {
188       return elements.getTypeElement(Object.class).asType();
189     }
190   }
191 
192   /**
193    * Throws {@link TypeNotPresentException} if {@code type} is an {@link
194    * javax.lang.model.type.ErrorType}.
195    */
checkTypePresent(TypeMirror type)196   public static void checkTypePresent(TypeMirror type) {
197     type.accept(
198         // TODO(ronshapiro): Extract a base class that visits all components of a complex type
199         // and put it in auto.common
200         new SimpleTypeVisitor8<Void, Void>() {
201           @Override
202           public Void visitArray(ArrayType arrayType, Void p) {
203             return arrayType.getComponentType().accept(this, p);
204           }
205 
206           @Override
207           public Void visitDeclared(DeclaredType declaredType, Void p) {
208             declaredType.getTypeArguments().forEach(t -> t.accept(this, p));
209             return null;
210           }
211 
212           @Override
213           public Void visitError(ErrorType errorType, Void p) {
214             throw new TypeNotPresentException(type.toString(), null);
215           }
216         },
217         null);
218   }
219 
220   private static final ImmutableSet<Class<?>> FUTURE_TYPES =
221       ImmutableSet.of(ListenableFuture.class, FluentFuture.class);
222 
isFutureType(TypeMirror type)223   public static boolean isFutureType(TypeMirror type) {
224     return FUTURE_TYPES.stream().anyMatch(t -> MoreTypes.isTypeOf(t, type));
225   }
226 
hasTypeVariable(TypeMirror type)227   public static boolean hasTypeVariable(TypeMirror type) {
228     return type.accept(
229         new SimpleTypeVisitor8<Boolean, Void>() {
230           @Override
231           public Boolean visitArray(ArrayType arrayType, Void p) {
232             return arrayType.getComponentType().accept(this, p);
233           }
234 
235           @Override
236           public Boolean visitDeclared(DeclaredType declaredType, Void p) {
237             return declaredType.getTypeArguments().stream().anyMatch(type -> type.accept(this, p));
238           }
239 
240           @Override
241           public Boolean visitTypeVariable(TypeVariable t, Void aVoid) {
242             return true;
243           }
244 
245           @Override
246           protected Boolean defaultAction(TypeMirror e, Void aVoid) {
247             return false;
248           }
249         },
250         null);
251   }
252 
253   /**
254    * Resolves the type of the given executable element as a member of the given type. This may
255    * resolve type variables to concrete types, etc.
256    */
257   public ExecutableType resolveExecutableType(ExecutableElement element, TypeMirror containerType) {
258     return MoreTypes.asExecutable(asMemberOf(MoreTypes.asDeclared(containerType), element));
259   }
260 
261   // Implementation of Types methods, delegating to types.
262 
263   @Override
264   public Element asElement(TypeMirror t) {
265     return types.asElement(t);
266   }
267 
268   @Override
269   public boolean isSameType(TypeMirror t1, TypeMirror t2) {
270     return types.isSameType(t1, t2);
271   }
272 
273   @Override
274   public boolean isSubtype(TypeMirror t1, TypeMirror t2) {
275     return types.isSubtype(t1, t2);
276   }
277 
278   @Override
279   public boolean isAssignable(TypeMirror t1, TypeMirror t2) {
280     return types.isAssignable(t1, t2);
281   }
282 
283   @Override
284   public boolean contains(TypeMirror t1, TypeMirror t2) {
285     return types.contains(t1, t2);
286   }
287 
288   @Override
289   public boolean isSubsignature(ExecutableType m1, ExecutableType m2) {
290     return types.isSubsignature(m1, m2);
291   }
292 
293   @Override
294   public List<? extends TypeMirror> directSupertypes(TypeMirror t) {
295     return types.directSupertypes(t);
296   }
297 
298   @Override
299   public TypeMirror erasure(TypeMirror t) {
300     return types.erasure(t);
301   }
302 
303   @Override
304   public TypeElement boxedClass(PrimitiveType p) {
305     return types.boxedClass(p);
306   }
307 
308   @Override
309   public PrimitiveType unboxedType(TypeMirror t) {
310     return types.unboxedType(t);
311   }
312 
313   @Override
314   public TypeMirror capture(TypeMirror t) {
315     return types.capture(t);
316   }
317 
318   @Override
319   public PrimitiveType getPrimitiveType(TypeKind kind) {
320     return types.getPrimitiveType(kind);
321   }
322 
323   @Override
324   public NullType getNullType() {
325     return types.getNullType();
326   }
327 
328   @Override
329   public NoType getNoType(TypeKind kind) {
330     return types.getNoType(kind);
331   }
332 
333   @Override
334   public ArrayType getArrayType(TypeMirror componentType) {
335     return types.getArrayType(componentType);
336   }
337 
338   @Override
339   public WildcardType getWildcardType(TypeMirror extendsBound, TypeMirror superBound) {
340     return types.getWildcardType(extendsBound, superBound);
341   }
342 
343   @Override
344   public DeclaredType getDeclaredType(TypeElement typeElem, TypeMirror... typeArgs) {
345     return types.getDeclaredType(typeElem, typeArgs);
346   }
347 
348   @Override
349   public DeclaredType getDeclaredType(
350       DeclaredType containing, TypeElement typeElem, TypeMirror... typeArgs) {
351     return types.getDeclaredType(containing, typeElem, typeArgs);
352   }
353 
354   @Override
355   public TypeMirror asMemberOf(DeclaredType containing, Element element) {
356     return types.asMemberOf(containing, element);
357   }
358 }
359