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