• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 Google, Inc.
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 dagger.internal.codegen;
17 
18 import com.google.auto.common.AnnotationMirrors;
19 import com.google.auto.common.MoreElements;
20 import com.google.auto.common.MoreTypes;
21 import com.google.auto.value.AutoValue;
22 import com.google.common.base.Equivalence;
23 import com.google.common.base.MoreObjects;
24 import com.google.common.base.Optional;
25 import com.google.common.collect.Iterables;
26 import com.google.common.util.concurrent.ListenableFuture;
27 import dagger.Provides;
28 import dagger.producers.Produced;
29 import dagger.producers.Producer;
30 import dagger.producers.Produces;
31 import java.util.Map;
32 import java.util.Set;
33 import javax.inject.Provider;
34 import javax.inject.Qualifier;
35 import javax.lang.model.element.AnnotationMirror;
36 import javax.lang.model.element.ElementKind;
37 import javax.lang.model.element.ExecutableElement;
38 import javax.lang.model.element.Modifier;
39 import javax.lang.model.element.TypeElement;
40 import javax.lang.model.type.DeclaredType;
41 import javax.lang.model.type.ExecutableType;
42 import javax.lang.model.type.PrimitiveType;
43 import javax.lang.model.type.TypeKind;
44 import javax.lang.model.type.TypeMirror;
45 import javax.lang.model.util.Elements;
46 import javax.lang.model.util.SimpleTypeVisitor6;
47 import javax.lang.model.util.Types;
48 
49 import static com.google.auto.common.MoreTypes.asExecutable;
50 import static com.google.common.base.Preconditions.checkArgument;
51 import static com.google.common.base.Preconditions.checkNotNull;
52 import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
53 import static dagger.internal.codegen.MapKeys.getMapKey;
54 import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
55 import static dagger.internal.codegen.Util.unwrapOptionalEquivalence;
56 import static dagger.internal.codegen.Util.wrapOptionalInEquivalence;
57 import static javax.lang.model.element.ElementKind.METHOD;
58 
59 /**
60  * Represents a unique combination of {@linkplain TypeMirror type} and
61  * {@linkplain Qualifier qualifier} to which binding can occur.
62  *
63  * @author Gregory Kick
64  */
65 @AutoValue
66 abstract class Key {
67   /**
68    * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix
69    * for the type of this key.
70    *
71    * Despite documentation in {@link AnnotationMirror}, equals and hashCode aren't implemented
72    * to represent logical equality, so {@link AnnotationMirrors#equivalence()}
73    * provides this facility.
74    */
wrappedQualifier()75   abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedQualifier();
76 
77   /**
78    * The type represented by this key.
79    *
80    * As documented in {@link TypeMirror}, equals and hashCode aren't implemented to represent
81    * logical equality, so {@link MoreTypes#equivalence()} wraps this type.
82    */
wrappedType()83   abstract Equivalence.Wrapper<TypeMirror> wrappedType();
84 
qualifier()85   Optional<AnnotationMirror> qualifier() {
86     return unwrapOptionalEquivalence(wrappedQualifier());
87   }
88 
type()89   TypeMirror type() {
90     return wrappedType().get();
91   }
92 
normalize(Types types, TypeMirror type)93   private static TypeMirror normalize(Types types, TypeMirror type) {
94     TypeKind kind = type.getKind();
95     return kind.isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type;
96   }
97 
withType(Types types, TypeMirror newType)98   Key withType(Types types, TypeMirror newType) {
99     return new AutoValue_Key(wrappedQualifier(),
100         MoreTypes.equivalence().wrap(normalize(types, newType)));
101   }
102 
isValidMembersInjectionKey()103   boolean isValidMembersInjectionKey() {
104     return !qualifier().isPresent();
105   }
106 
107   /**
108    * Returns true if the key is valid as an implicit key (that is, if it's valid for a just-in-time
109    * binding by discovering an {@code @Inject} constructor).
110    */
isValidImplicitProvisionKey(final Types types)111   boolean isValidImplicitProvisionKey(final Types types) {
112     // Qualifiers disqualify implicit provisioning.
113     if (qualifier().isPresent()) {
114       return false;
115     }
116 
117     return type().accept(new SimpleTypeVisitor6<Boolean, Void>() {
118       @Override protected Boolean defaultAction(TypeMirror e, Void p) {
119         return false; // Only declared types are allowed.
120       }
121 
122       @Override public Boolean visitDeclared(DeclaredType type, Void ignored) {
123         // Non-classes or abstract classes aren't allowed.
124         TypeElement element = MoreElements.asType(type.asElement());
125         if (!element.getKind().equals(ElementKind.CLASS)
126             || element.getModifiers().contains(Modifier.ABSTRACT)) {
127           return false;
128         }
129 
130         // If the key has type arguments, validate that each type argument is declared.
131         // Otherwise the type argument may be a wildcard (or other type), and we can't
132         // resolve that to actual types.
133         for (TypeMirror arg : type.getTypeArguments()) {
134           if (arg.getKind() != TypeKind.DECLARED) {
135             return false;
136           }
137         }
138 
139         // Also validate that the key is not the erasure of a generic type.
140         // If it is, that means the user referred to Foo<T> as just 'Foo',
141         // which we don't allow.  (This is a judgement call -- we *could*
142         // allow it and instantiate the type bounds... but we don't.)
143         return MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
144             || !types.isSameType(types.erasure(element.asType()), type());
145       }
146     }, null);
147   }
148 
149   @Override
150   public String toString() {
151     return MoreObjects.toStringHelper(Key.class)
152         .omitNullValues()
153         .add("qualifier", qualifier().orNull())
154         .add("type", type())
155         .toString();
156   }
157 
158   static final class Factory {
159     private final Types types;
160     private final Elements elements;
161 
162     Factory(Types types, Elements elements) {
163       this.types = checkNotNull(types);
164       this.elements = checkNotNull(elements);
165     }
166 
167     private TypeElement getSetElement() {
168       return elements.getTypeElement(Set.class.getCanonicalName());
169     }
170 
171     private TypeElement getMapElement() {
172       return elements.getTypeElement(Map.class.getCanonicalName());
173     }
174 
175     private TypeElement getProviderElement() {
176       return elements.getTypeElement(Provider.class.getCanonicalName());
177     }
178 
179     private TypeElement getProducerElement() {
180       return elements.getTypeElement(Producer.class.getCanonicalName());
181     }
182 
183     private TypeElement getClassElement(Class<?> cls) {
184       return elements.getTypeElement(cls.getCanonicalName());
185     }
186 
187     Key forComponentMethod(ExecutableElement componentMethod) {
188       checkNotNull(componentMethod);
189       checkArgument(componentMethod.getKind().equals(METHOD));
190       TypeMirror returnType = normalize(types, componentMethod.getReturnType());
191       return forMethod(componentMethod, returnType);
192     }
193 
194     Key forProductionComponentMethod(ExecutableElement componentMethod) {
195       checkNotNull(componentMethod);
196       checkArgument(componentMethod.getKind().equals(METHOD));
197       TypeMirror returnType = normalize(types, componentMethod.getReturnType());
198       TypeMirror keyType = returnType;
199       if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
200         keyType = Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
201       }
202       return forMethod(componentMethod, keyType);
203     }
204 
205     Key forSubcomponentBuilderMethod(
206         ExecutableElement subcomponentBuilderMethod, DeclaredType declaredContainer) {
207       checkNotNull(subcomponentBuilderMethod);
208       checkArgument(subcomponentBuilderMethod.getKind().equals(METHOD));
209       ExecutableType resolvedMethod =
210           asExecutable(types.asMemberOf(declaredContainer, subcomponentBuilderMethod));
211       TypeMirror returnType = normalize(types, resolvedMethod.getReturnType());
212       return forMethod(subcomponentBuilderMethod, returnType);
213     }
214 
215     Key forProvidesMethod(ExecutableType executableType, ExecutableElement method) {
216       checkNotNull(method);
217       checkArgument(method.getKind().equals(METHOD));
218       Provides providesAnnotation = method.getAnnotation(Provides.class);
219       checkArgument(providesAnnotation != null);
220       TypeMirror returnType = normalize(types, executableType.getReturnType());
221       TypeMirror keyType =
222           providesOrProducesKeyType(
223               returnType,
224               method,
225               Optional.of(providesAnnotation.type()),
226               Optional.<Produces.Type>absent());
227       return forMethod(method, keyType);
228     }
229 
230     // TODO(user): Reconcile this method with forProvidesMethod when Provides.Type and
231     // Produces.Type are no longer different.
232     Key forProducesMethod(ExecutableType executableType, ExecutableElement method) {
233       checkNotNull(method);
234       checkArgument(method.getKind().equals(METHOD));
235       Produces producesAnnotation = method.getAnnotation(Produces.class);
236       checkArgument(producesAnnotation != null);
237       TypeMirror returnType = normalize(types, executableType.getReturnType());
238       TypeMirror unfuturedType = returnType;
239       if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
240         unfuturedType =
241             Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
242       }
243       TypeMirror keyType =
244           providesOrProducesKeyType(
245               unfuturedType,
246               method,
247               Optional.<Provides.Type>absent(),
248               Optional.of(producesAnnotation.type()));
249       return forMethod(method, keyType);
250     }
251 
252     private TypeMirror providesOrProducesKeyType(
253         TypeMirror returnType,
254         ExecutableElement method,
255         Optional<Provides.Type> providesType,
256         Optional<Produces.Type> producesType) {
257       switch (providesType.isPresent()
258           ? providesType.get()
259           : Provides.Type.valueOf(producesType.get().name())) {
260         case UNIQUE:
261           return returnType;
262         case SET:
263           return types.getDeclaredType(getSetElement(), returnType);
264         case MAP:
265           return mapOfFactoryType(
266               method,
267               returnType,
268               providesType.isPresent() ? getProviderElement() : getProducerElement());
269         case SET_VALUES:
270           // TODO(gak): do we want to allow people to use "covariant return" here?
271           checkArgument(MoreTypes.isType(returnType) && MoreTypes.isTypeOf(Set.class, returnType));
272           return returnType;
273         default:
274           throw new AssertionError();
275       }
276     }
277 
278     private TypeMirror mapOfFactoryType(
279         ExecutableElement method, TypeMirror valueType, TypeElement factoryType) {
280       TypeMirror mapKeyType = mapKeyType(method);
281       TypeMirror mapValueFactoryType = types.getDeclaredType(factoryType, valueType);
282       return types.getDeclaredType(getMapElement(), mapKeyType, mapValueFactoryType);
283     }
284 
285     private TypeMirror mapKeyType(ExecutableElement method) {
286       AnnotationMirror mapKeyAnnotation = getMapKey(method).get();
287       return MapKeys.unwrapValue(mapKeyAnnotation).isPresent()
288           ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types)
289           : mapKeyAnnotation.getAnnotationType();
290     }
291 
292     private Key forMethod(ExecutableElement method, TypeMirror keyType) {
293       return new AutoValue_Key(
294           wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), getQualifier(method)),
295           MoreTypes.equivalence().wrap(keyType));
296     }
297 
298     Key forInjectConstructorWithResolvedType(TypeMirror type) {
299       return new AutoValue_Key(
300           Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
301           MoreTypes.equivalence().wrap(type));
302     }
303 
304     Key forComponent(TypeMirror type) {
305       return new AutoValue_Key(
306           Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
307           MoreTypes.equivalence().wrap(normalize(types, type)));
308     }
309 
310     Key forMembersInjectedType(TypeMirror type) {
311       return new AutoValue_Key(
312           Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
313           MoreTypes.equivalence().wrap(normalize(types, type)));
314     }
315 
316     Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) {
317       return new AutoValue_Key(
318           wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), qualifier),
319           MoreTypes.equivalence().wrap(normalize(types, type)));
320     }
321 
322     /**
323      * Optionally extract a {@link Key} for the underlying provision binding(s) if such a
324      * valid key can be inferred from the given key.  Specifically, if the key represents a
325      * {@link Map}{@code <K, V>}, a key of {@code Map<K, Provider<V>>} will be returned.
326      */
327     Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
328       return maybeWrapMapValue(possibleMapKey, Provider.class);
329     }
330 
331     /**
332      * Optionally extract a {@link Key} for the underlying production binding(s) if such a
333      * valid key can be inferred from the given key.  Specifically, if the key represents a
334      * {@link Map}{@code <K, V>}, a key of {@code Map<K, Producer<V>>} will be returned.
335      */
336     Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
337       return maybeWrapMapValue(possibleMapKey, Producer.class);
338     }
339 
340     /**
341      * Returns a key of {@link Map}{@code <K, WrappingClass<V>>} if the input key represents a
342      * {@code Map<K, V>}.
343      */
344     private Optional<Key> maybeWrapMapValue(Key possibleMapKey, Class<?> wrappingClass) {
345       if (MoreTypes.isTypeOf(Map.class, possibleMapKey.type())) {
346         DeclaredType declaredMapType = MoreTypes.asDeclared(possibleMapKey.type());
347         TypeMirror mapValueType = Util.getValueTypeOfMap(declaredMapType);
348         if (!MoreTypes.isTypeOf(wrappingClass, mapValueType)) {
349           TypeMirror keyType = Util.getKeyTypeOfMap(declaredMapType);
350           TypeElement wrappingElement = getClassElement(wrappingClass);
351           if (wrappingElement == null) {
352             // This target might not be compiled with Producers, so wrappingClass might not have an
353             // associated element.
354             return Optional.absent();
355           }
356           DeclaredType wrappedType = types.getDeclaredType(wrappingElement, mapValueType);
357           TypeMirror mapType = types.getDeclaredType(getMapElement(), keyType, wrappedType);
358           return Optional.<Key>of(new AutoValue_Key(
359               possibleMapKey.wrappedQualifier(),
360               MoreTypes.equivalence().wrap(mapType)));
361         }
362       }
363       return Optional.absent();
364     }
365 
366     /**
367      * Optionally extract a {@link Key} for a {@code Set<T>} if the given key is for
368      * {@code Set<Produced<T>>}.
369      */
370     Optional<Key> implicitSetKeyFromProduced(Key possibleSetOfProducedKey) {
371       if (MoreTypes.isTypeOf(Set.class, possibleSetOfProducedKey.type())) {
372         TypeMirror argType =
373             MoreTypes.asDeclared(possibleSetOfProducedKey.type()).getTypeArguments().get(0);
374         if (MoreTypes.isTypeOf(Produced.class, argType)) {
375           TypeMirror producedArgType = MoreTypes.asDeclared(argType).getTypeArguments().get(0);
376           TypeMirror setType = types.getDeclaredType(getSetElement(), producedArgType);
377           return Optional.of(possibleSetOfProducedKey.withType(types, setType));
378         }
379       }
380       return Optional.absent();
381     }
382   }
383 }
384