• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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;
18 
19 import static com.google.auto.common.MoreTypes.asDeclared;
20 import static com.google.auto.common.MoreTypes.isType;
21 import static com.google.auto.common.MoreTypes.isTypeOf;
22 import static com.google.common.base.Preconditions.checkArgument;
23 import static com.google.common.collect.Iterables.getOnlyElement;
24 import static dagger.internal.codegen.javapoet.TypeNames.lazyOf;
25 import static dagger.internal.codegen.javapoet.TypeNames.listenableFutureOf;
26 import static dagger.internal.codegen.javapoet.TypeNames.producedOf;
27 import static dagger.internal.codegen.javapoet.TypeNames.producerOf;
28 import static dagger.internal.codegen.javapoet.TypeNames.providerOf;
29 import static dagger.internal.codegen.langmodel.DaggerTypes.checkTypePresent;
30 import static dagger.model.RequestKind.INSTANCE;
31 import static dagger.model.RequestKind.LAZY;
32 import static dagger.model.RequestKind.PRODUCED;
33 import static dagger.model.RequestKind.PRODUCER;
34 import static dagger.model.RequestKind.PROVIDER;
35 import static dagger.model.RequestKind.PROVIDER_OF_LAZY;
36 
37 import com.google.auto.common.MoreTypes;
38 import com.google.common.collect.ImmutableMap;
39 import com.google.common.util.concurrent.ListenableFuture;
40 import com.squareup.javapoet.TypeName;
41 import dagger.Lazy;
42 import dagger.internal.codegen.langmodel.DaggerTypes;
43 import dagger.model.RequestKind;
44 import dagger.producers.Produced;
45 import dagger.producers.Producer;
46 import javax.inject.Provider;
47 import javax.lang.model.type.TypeMirror;
48 
49 /** Utility methods for {@link RequestKind}s. */
50 final class RequestKinds {
51   /** Returns the type of a request of this kind for a key with a given type. */
requestType(RequestKind requestKind, TypeMirror type, DaggerTypes types)52   static TypeMirror requestType(RequestKind requestKind, TypeMirror type, DaggerTypes types) {
53     switch (requestKind) {
54       case INSTANCE:
55         return type;
56 
57       case PROVIDER_OF_LAZY:
58         return types.wrapType(requestType(LAZY, type, types), Provider.class);
59 
60       case FUTURE:
61         return types.wrapType(type, ListenableFuture.class);
62 
63       default:
64         return types.wrapType(type, frameworkClass(requestKind));
65     }
66   }
67 
68   /** Returns the type of a request of this kind for a key with a given type. */
requestTypeName(RequestKind requestKind, TypeName keyType)69   static TypeName requestTypeName(RequestKind requestKind, TypeName keyType) {
70     switch (requestKind) {
71       case INSTANCE:
72         return keyType;
73 
74       case PROVIDER:
75         return providerOf(keyType);
76 
77       case LAZY:
78         return lazyOf(keyType);
79 
80       case PROVIDER_OF_LAZY:
81         return providerOf(lazyOf(keyType));
82 
83       case PRODUCER:
84         return producerOf(keyType);
85 
86       case PRODUCED:
87         return producedOf(keyType);
88 
89       case FUTURE:
90         return listenableFutureOf(keyType);
91 
92       default:
93         throw new AssertionError(requestKind);
94     }
95   }
96 
97   private static final ImmutableMap<RequestKind, Class<?>> FRAMEWORK_CLASSES =
98       ImmutableMap.of(
99           PROVIDER, Provider.class,
100           LAZY, Lazy.class,
101           PRODUCER, Producer.class,
102           PRODUCED, Produced.class);
103 
104   /** Returns the {@link RequestKind} that matches the wrapping types (if any) of {@code type}. */
getRequestKind(TypeMirror type)105   static RequestKind getRequestKind(TypeMirror type) {
106     checkTypePresent(type);
107     for (RequestKind kind : FRAMEWORK_CLASSES.keySet()) {
108       if (matchesKind(kind, type)) {
109         if (kind.equals(PROVIDER) && matchesKind(LAZY, extractKeyType(kind, type))) {
110           return PROVIDER_OF_LAZY;
111         }
112         return kind;
113       }
114     }
115     return INSTANCE;
116   }
117 
118   /**
119    * Returns {@code true} if {@code type} is a parameterized type of {@code kind}'s {@link
120    * #frameworkClass(RequestKind) framework class}.
121    */
matchesKind(RequestKind kind, TypeMirror type)122   private static boolean matchesKind(RequestKind kind, TypeMirror type) {
123     return isType(type)
124         && isTypeOf(frameworkClass(kind), type)
125         && !asDeclared(type).getTypeArguments().isEmpty();
126   }
127 
128   /**
129    * Unwraps the framework class(es) of {@code requestKind} from {@code type}. If {@code
130    * requestKind} is {@link RequestKind#INSTANCE}, this acts as an identity function.
131    *
132    * @throws TypeNotPresentException if {@code type} is an {@link javax.lang.model.type.ErrorType},
133    *     which may mean that the type will be generated in a later round of processing
134    * @throws IllegalArgumentException if {@code type} is not wrapped with {@code requestKind}'s
135    *     framework class(es).
136    */
extractKeyType(RequestKind requestKind, TypeMirror type)137   static TypeMirror extractKeyType(RequestKind requestKind, TypeMirror type) {
138     checkTypePresent(type);
139     switch (requestKind) {
140       case INSTANCE:
141         return type;
142       case PROVIDER_OF_LAZY:
143         return extractKeyType(LAZY, extractKeyType(PROVIDER, type));
144       default:
145         checkArgument(isType(type) && isTypeOf(frameworkClass(requestKind), type));
146         return getOnlyElement(MoreTypes.asDeclared(type).getTypeArguments());
147     }
148   }
149 
150   /**
151    * A dagger- or {@code javax.inject}-defined class for {@code requestKind} that that can wrap
152    * another type but share the same {@link dagger.model.Key}.
153    *
154    * <p>For example, {@code Provider<String>} and {@code Lazy<String>} can both be requested if a
155    * key exists for {@code String}; they all share the same key.
156    *
157    * <p>This concept is not well defined and should probably be removed and inlined into the cases
158    * that need it. For example, {@link RequestKind#PROVIDER_OF_LAZY} has <em>2</em> wrapping
159    * classes, and {@link RequestKind#FUTURE} is wrapped with a {@link ListenableFuture}, but for
160    * historical/implementation reasons has not had an associated framework class.
161    */
frameworkClass(RequestKind requestKind)162   static Class<?> frameworkClass(RequestKind requestKind) {
163     Class<?> result = FRAMEWORK_CLASSES.get(requestKind);
164     checkArgument(result != null, "no framework class for %s", requestKind);
165     return result;
166   }
167 
168   /**
169    * Returns {@code true} if requests for {@code requestKind} can be satisfied by a production
170    * binding.
171    */
canBeSatisfiedByProductionBinding(RequestKind requestKind)172   static boolean canBeSatisfiedByProductionBinding(RequestKind requestKind) {
173     switch (requestKind) {
174       case INSTANCE:
175       case PROVIDER:
176       case LAZY:
177       case PROVIDER_OF_LAZY:
178       case MEMBERS_INJECTION:
179         return false;
180       case PRODUCER:
181       case PRODUCED:
182       case FUTURE:
183         return true;
184     }
185     throw new AssertionError();
186   }
187 
188   /**
189    * Returns true if {@code requestKind} is always derived from a {@link RequestKind#PROVIDER}
190    * instance.
191    */
isDerivedFromProvider(RequestKind requestKind)192   static boolean isDerivedFromProvider(RequestKind requestKind) {
193     switch (requestKind) {
194       case LAZY:
195       case PROVIDER_OF_LAZY:
196         return true;
197       default:
198         return false;
199     }
200   }
201 
RequestKinds()202   private RequestKinds() {}
203 }
204