• 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.binding;
18 
19 import static com.google.auto.common.MoreTypes.isTypeOf;
20 import static com.google.common.base.Preconditions.checkArgument;
21 import static com.google.common.base.Preconditions.checkNotNull;
22 import static com.google.common.base.Preconditions.checkState;
23 import static com.google.common.collect.Iterables.getOnlyElement;
24 import static dagger.internal.codegen.base.RequestKinds.extractKeyType;
25 import static dagger.internal.codegen.base.RequestKinds.frameworkClass;
26 import static dagger.internal.codegen.base.RequestKinds.getRequestKind;
27 import static dagger.internal.codegen.binding.ConfigurationAnnotations.getNullableType;
28 import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType;
29 import static dagger.model.RequestKind.FUTURE;
30 import static dagger.model.RequestKind.INSTANCE;
31 import static dagger.model.RequestKind.MEMBERS_INJECTION;
32 import static dagger.model.RequestKind.PRODUCER;
33 import static dagger.model.RequestKind.PROVIDER;
34 
35 import com.google.common.collect.ImmutableSet;
36 import com.google.common.util.concurrent.ListenableFuture;
37 import dagger.Lazy;
38 import dagger.internal.codegen.base.MapType;
39 import dagger.internal.codegen.base.OptionalType;
40 import dagger.model.DependencyRequest;
41 import dagger.model.Key;
42 import dagger.model.RequestKind;
43 import java.util.List;
44 import java.util.Optional;
45 import javax.inject.Inject;
46 import javax.inject.Provider;
47 import javax.lang.model.element.AnnotationMirror;
48 import javax.lang.model.element.Element;
49 import javax.lang.model.element.ExecutableElement;
50 import javax.lang.model.element.VariableElement;
51 import javax.lang.model.type.DeclaredType;
52 import javax.lang.model.type.ExecutableType;
53 import javax.lang.model.type.TypeMirror;
54 
55 /**
56  * Factory for {@link DependencyRequest}s.
57  *
58  * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available, which
59  * may mean that the type will be generated in a later round of processing.
60  */
61 public final class DependencyRequestFactory {
62   private final KeyFactory keyFactory;
63   private final InjectionAnnotations injectionAnnotations;
64 
65   @Inject
DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations)66   DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations) {
67     this.keyFactory = keyFactory;
68     this.injectionAnnotations = injectionAnnotations;
69   }
70 
forRequiredResolvedVariables( List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes)71   ImmutableSet<DependencyRequest> forRequiredResolvedVariables(
72       List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) {
73     checkState(resolvedTypes.size() == variables.size());
74     ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder();
75     for (int i = 0; i < variables.size(); i++) {
76       builder.add(forRequiredResolvedVariable(variables.get(i), resolvedTypes.get(i)));
77     }
78     return builder.build();
79   }
80 
81   /**
82    * Creates synthetic dependency requests for each individual multibinding contribution in {@code
83    * multibindingContributions}.
84    */
forMultibindingContributions( Key multibindingKey, Iterable<ContributionBinding> multibindingContributions)85   ImmutableSet<DependencyRequest> forMultibindingContributions(
86       Key multibindingKey, Iterable<ContributionBinding> multibindingContributions) {
87     ImmutableSet.Builder<DependencyRequest> requests = ImmutableSet.builder();
88     for (ContributionBinding multibindingContribution : multibindingContributions) {
89       requests.add(forMultibindingContribution(multibindingKey, multibindingContribution));
90     }
91     return requests.build();
92   }
93 
94   /** Creates a synthetic dependency request for one individual {@code multibindingContribution}. */
forMultibindingContribution( Key multibindingKey, ContributionBinding multibindingContribution)95   private DependencyRequest forMultibindingContribution(
96       Key multibindingKey, ContributionBinding multibindingContribution) {
97     checkArgument(
98         multibindingContribution.key().multibindingContributionIdentifier().isPresent(),
99         "multibindingContribution's key must have a multibinding contribution identifier: %s",
100         multibindingContribution);
101     return DependencyRequest.builder()
102         .kind(multibindingContributionRequestKind(multibindingKey, multibindingContribution))
103         .key(multibindingContribution.key())
104         .build();
105   }
106 
107   // TODO(b/28555349): support PROVIDER_OF_LAZY here too
108   private static final ImmutableSet<RequestKind> WRAPPING_MAP_VALUE_FRAMEWORK_TYPES =
109       ImmutableSet.of(PROVIDER, PRODUCER);
110 
multibindingContributionRequestKind( Key multibindingKey, ContributionBinding multibindingContribution)111   private RequestKind multibindingContributionRequestKind(
112       Key multibindingKey, ContributionBinding multibindingContribution) {
113     switch (multibindingContribution.contributionType()) {
114       case MAP:
115         MapType mapType = MapType.from(multibindingKey);
116         for (RequestKind kind : WRAPPING_MAP_VALUE_FRAMEWORK_TYPES) {
117           if (mapType.valuesAreTypeOf(frameworkClass(kind))) {
118             return kind;
119           }
120         }
121         // fall through
122       case SET:
123       case SET_VALUES:
124         return INSTANCE;
125       case UNIQUE:
126         throw new IllegalArgumentException(
127             "multibindingContribution must be a multibinding: " + multibindingContribution);
128     }
129     throw new AssertionError(multibindingContribution.toString());
130   }
131 
forRequiredResolvedVariable( VariableElement variableElement, TypeMirror resolvedType)132   DependencyRequest forRequiredResolvedVariable(
133       VariableElement variableElement, TypeMirror resolvedType) {
134     checkNotNull(variableElement);
135     checkNotNull(resolvedType);
136     // Ban @Assisted parameters, they are not considered dependency requests.
137     checkArgument(!AssistedInjectionAnnotations.isAssistedParameter(variableElement));
138     Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(variableElement);
139     return newDependencyRequest(variableElement, resolvedType, qualifier);
140   }
141 
forComponentProvisionMethod( ExecutableElement provisionMethod, ExecutableType provisionMethodType)142   public DependencyRequest forComponentProvisionMethod(
143       ExecutableElement provisionMethod, ExecutableType provisionMethodType) {
144     checkNotNull(provisionMethod);
145     checkNotNull(provisionMethodType);
146     checkArgument(
147         provisionMethod.getParameters().isEmpty(),
148         "Component provision methods must be empty: %s",
149         provisionMethod);
150     Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(provisionMethod);
151     return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier);
152   }
153 
forComponentProductionMethod( ExecutableElement productionMethod, ExecutableType productionMethodType)154   public DependencyRequest forComponentProductionMethod(
155       ExecutableElement productionMethod, ExecutableType productionMethodType) {
156     checkNotNull(productionMethod);
157     checkNotNull(productionMethodType);
158     checkArgument(
159         productionMethod.getParameters().isEmpty(),
160         "Component production methods must be empty: %s",
161         productionMethod);
162     TypeMirror type = productionMethodType.getReturnType();
163     Optional<AnnotationMirror> qualifier = injectionAnnotations.getQualifier(productionMethod);
164     // Only a component production method can be a request for a ListenableFuture, so we
165     // special-case it here.
166     if (isTypeOf(ListenableFuture.class, type)) {
167       return DependencyRequest.builder()
168           .kind(FUTURE)
169           .key(keyFactory.forQualifiedType(qualifier, unwrapType(type)))
170           .requestElement(productionMethod)
171           .build();
172     } else {
173       return newDependencyRequest(productionMethod, type, qualifier);
174     }
175   }
176 
forComponentMembersInjectionMethod( ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType)177   DependencyRequest forComponentMembersInjectionMethod(
178       ExecutableElement membersInjectionMethod, ExecutableType membersInjectionMethodType) {
179     checkNotNull(membersInjectionMethod);
180     checkNotNull(membersInjectionMethodType);
181     Optional<AnnotationMirror> qualifier =
182         injectionAnnotations.getQualifier(membersInjectionMethod);
183     checkArgument(!qualifier.isPresent());
184     TypeMirror membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes());
185     return DependencyRequest.builder()
186         .kind(MEMBERS_INJECTION)
187         .key(keyFactory.forMembersInjectedType(membersInjectedType))
188         .requestElement(membersInjectionMethod)
189         .build();
190   }
191 
forProductionImplementationExecutor()192   DependencyRequest forProductionImplementationExecutor() {
193     return DependencyRequest.builder()
194         .kind(PROVIDER)
195         .key(keyFactory.forProductionImplementationExecutor())
196         .build();
197   }
198 
forProductionComponentMonitor()199   DependencyRequest forProductionComponentMonitor() {
200     return DependencyRequest.builder()
201         .kind(PROVIDER)
202         .key(keyFactory.forProductionComponentMonitor())
203         .build();
204   }
205 
206   /**
207    * Returns a synthetic request for the present value of an optional binding generated from a
208    * {@link dagger.BindsOptionalOf} declaration.
209    */
forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind)210   DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey, RequestKind kind) {
211     Optional<Key> key = keyFactory.unwrapOptional(requestKey);
212     checkArgument(key.isPresent(), "not a request for optional: %s", requestKey);
213     return DependencyRequest.builder()
214         .kind(kind)
215         .key(key.get())
216         .isNullable(
217             allowsNull(getRequestKind(OptionalType.from(requestKey).valueType()), Optional.empty()))
218         .build();
219   }
220 
newDependencyRequest( Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier)221   private DependencyRequest newDependencyRequest(
222       Element requestElement, TypeMirror type, Optional<AnnotationMirror> qualifier) {
223     RequestKind requestKind = getRequestKind(type);
224     return DependencyRequest.builder()
225         .kind(requestKind)
226         .key(keyFactory.forQualifiedType(qualifier, extractKeyType(type)))
227         .requestElement(requestElement)
228         .isNullable(allowsNull(requestKind, getNullableType(requestElement)))
229         .build();
230   }
231 
232   /**
233    * Returns {@code true} if a given request element allows null values. {@link
234    * RequestKind#INSTANCE} requests must be annotated with {@code @Nullable} in order to allow null
235    * values. All other request kinds implicitly allow null values because they are are wrapped
236    * inside {@link Provider}, {@link Lazy}, etc.
237    */
allowsNull(RequestKind kind, Optional<DeclaredType> nullableType)238   private boolean allowsNull(RequestKind kind, Optional<DeclaredType> nullableType) {
239     return nullableType.isPresent() || !kind.equals(INSTANCE);
240   }
241 }
242