blob: 20fa93c4d1ff41035cbfead69ce07857f4b9bcf8 [file] [log] [blame]
dpb68c77d82017-08-15 15:23:35 -07001/*
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
17package dagger.internal.codegen;
18
dpb64861842017-12-12 08:17:18 -080019import static com.google.common.base.Preconditions.checkArgument;
bcorsof0a99fe2017-12-04 10:52:05 -080020import static com.google.common.base.Preconditions.checkNotNull;
dpb68c77d82017-08-15 15:23:35 -070021import static dagger.internal.codegen.Accessibility.isRawTypeAccessible;
22import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
dpb3db68f02018-01-04 09:15:52 -080023import static dagger.internal.codegen.BindingType.MEMBERS_INJECTION;
24import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
dpb09fb2cb2018-01-29 08:39:33 -080025import static dagger.internal.codegen.DelegateBindingExpression.isBindsScopeStrongerThanDependencyScope;
dpb356a6842018-02-07 07:45:50 -080026import static dagger.internal.codegen.MemberSelect.staticFactoryCreation;
dpb3db68f02018-01-04 09:15:52 -080027import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK;
28import static dagger.internal.codegen.TypeNames.REFERENCE_RELEASING_PROVIDER;
29import static dagger.internal.codegen.TypeNames.SINGLE_CHECK;
dpb09fb2cb2018-01-29 08:39:33 -080030import static dagger.model.BindingKind.DELEGATE;
bcorsoaf9e0042018-04-16 14:12:23 -070031import static dagger.model.BindingKind.MULTIBOUND_MAP;
32import static dagger.model.BindingKind.MULTIBOUND_SET;
dstrasburgcf5e1bc2018-08-09 09:03:38 -070033import static javax.lang.model.element.Modifier.PUBLIC;
dpb68c77d82017-08-15 15:23:35 -070034
dpb3db68f02018-01-04 09:15:52 -080035import com.google.auto.common.MoreTypes;
bcorso8c3605d2017-12-13 13:36:49 -080036import com.google.common.collect.HashBasedTable;
dpb3db68f02018-01-04 09:15:52 -080037import com.google.common.collect.ImmutableList;
bcorso8c3605d2017-12-13 13:36:49 -080038import com.google.common.collect.Table;
dpb68c77d82017-08-15 15:23:35 -070039import com.squareup.javapoet.ClassName;
bcorsoe643cc62017-10-24 08:57:09 -070040import com.squareup.javapoet.CodeBlock;
dpb02db2132018-01-08 07:20:23 -080041import com.squareup.javapoet.MethodSpec;
bcorso2c279662017-12-01 09:51:18 -080042import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
dpb3db68f02018-01-04 09:15:52 -080043import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
dstrasburgcf5e1bc2018-08-09 09:03:38 -070044import dagger.internal.codegen.MissingBindingMethods.MissingBindingMethod;
ronshapiroa5023ca2018-01-02 12:55:01 -080045import dagger.model.DependencyRequest;
ronshapiro0a277fd2017-12-22 08:30:49 -080046import dagger.model.Key;
ronshapiro120abc62017-12-15 09:57:09 -080047import dagger.model.RequestKind;
bcorsof0a99fe2017-12-04 10:52:05 -080048import java.util.Optional;
dpb356a6842018-02-07 07:45:50 -080049import javax.inject.Provider;
dpb68c77d82017-08-15 15:23:35 -070050import javax.lang.model.type.TypeMirror;
51
ronshapirodc07ed52017-08-23 08:52:10 -070052/** A central repository of code expressions used to access any binding available to a component. */
dpb68c77d82017-08-15 15:23:35 -070053final class ComponentBindingExpressions {
54
ronshapirodc07ed52017-08-23 08:52:10 -070055 // TODO(dpb,ronshapiro): refactor this and ComponentRequirementFields into a
56 // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
57 // parents? If so, maybe make BindingExpression.Factory create it.
dpb68c77d82017-08-15 15:23:35 -070058
bcorsof0a99fe2017-12-04 10:52:05 -080059 private final Optional<ComponentBindingExpressions> parent;
60 private final BindingGraph graph;
dpb02db2132018-01-08 07:20:23 -080061 private final GeneratedComponentModel generatedComponentModel;
dpb73afb302018-02-12 10:59:53 -080062 private final SubcomponentNames subcomponentNames;
63 private final ComponentRequirementFields componentRequirementFields;
64 private final ReferenceReleasingManagerFields referenceReleasingManagerFields;
65 private final OptionalFactories optionalFactories;
bcorsof0a99fe2017-12-04 10:52:05 -080066 private final DaggerTypes types;
dpbe7b89582018-02-19 08:42:19 -080067 private final DaggerElements elements;
dpb73afb302018-02-12 10:59:53 -080068 private final CompilerOptions compilerOptions;
69 private final MembersInjectionMethods membersInjectionMethods;
bcorsocc739fe2018-04-23 09:16:12 -070070 private final InnerSwitchingProviders innerSwitchingProviders;
71 private final StaticSwitchingProviders staticSwitchingProviders;
ronshapiro0a277fd2017-12-22 08:30:49 -080072 private final Table<Key, RequestKind, BindingExpression> expressions = HashBasedTable.create();
dpb68c77d82017-08-15 15:23:35 -070073
bcorsof0a99fe2017-12-04 10:52:05 -080074 ComponentBindingExpressions(
75 BindingGraph graph,
76 GeneratedComponentModel generatedComponentModel,
77 SubcomponentNames subcomponentNames,
78 ComponentRequirementFields componentRequirementFields,
79 OptionalFactories optionalFactories,
80 DaggerTypes types,
dpbe7b89582018-02-19 08:42:19 -080081 DaggerElements elements,
bcorsof0a99fe2017-12-04 10:52:05 -080082 CompilerOptions compilerOptions) {
83 this(
84 Optional.empty(),
85 graph,
86 generatedComponentModel,
87 subcomponentNames,
88 componentRequirementFields,
dstrasburgdd036822018-07-23 08:00:37 -070089 new ReferenceReleasingManagerFields(graph, generatedComponentModel, compilerOptions),
bcorsocc739fe2018-04-23 09:16:12 -070090 new StaticSwitchingProviders(generatedComponentModel, types),
bcorsof0a99fe2017-12-04 10:52:05 -080091 optionalFactories,
92 types,
93 elements,
94 compilerOptions);
dpb68c77d82017-08-15 15:23:35 -070095 }
96
bcorsof0a99fe2017-12-04 10:52:05 -080097 private ComponentBindingExpressions(
98 Optional<ComponentBindingExpressions> parent,
99 BindingGraph graph,
100 GeneratedComponentModel generatedComponentModel,
101 SubcomponentNames subcomponentNames,
102 ComponentRequirementFields componentRequirementFields,
103 ReferenceReleasingManagerFields referenceReleasingManagerFields,
bcorsocc739fe2018-04-23 09:16:12 -0700104 StaticSwitchingProviders staticSwitchingProviders,
bcorsof0a99fe2017-12-04 10:52:05 -0800105 OptionalFactories optionalFactories,
106 DaggerTypes types,
dpbe7b89582018-02-19 08:42:19 -0800107 DaggerElements elements,
bcorsof0a99fe2017-12-04 10:52:05 -0800108 CompilerOptions compilerOptions) {
109 this.parent = parent;
110 this.graph = graph;
dpb02db2132018-01-08 07:20:23 -0800111 this.generatedComponentModel = generatedComponentModel;
dpb73afb302018-02-12 10:59:53 -0800112 this.subcomponentNames = checkNotNull(subcomponentNames);
113 this.componentRequirementFields = checkNotNull(componentRequirementFields);
114 this.referenceReleasingManagerFields = checkNotNull(referenceReleasingManagerFields);
115 this.optionalFactories = checkNotNull(optionalFactories);
116 this.types = checkNotNull(types);
117 this.elements = checkNotNull(elements);
118 this.compilerOptions = checkNotNull(compilerOptions);
119 this.membersInjectionMethods =
120 new MembersInjectionMethods(generatedComponentModel, this, graph, elements, types);
bcorsocc739fe2018-04-23 09:16:12 -0700121 this.innerSwitchingProviders =
122 new InnerSwitchingProviders(generatedComponentModel, this, types);
123 this.staticSwitchingProviders = staticSwitchingProviders;
bcorsof0a99fe2017-12-04 10:52:05 -0800124 }
125
126 /**
127 * Returns a new object representing the bindings available from a child component of this one.
128 */
129 ComponentBindingExpressions forChildComponent(
130 BindingGraph childGraph,
131 GeneratedComponentModel childComponentModel,
132 ComponentRequirementFields childComponentRequirementFields) {
133 return new ComponentBindingExpressions(
134 Optional.of(this),
135 childGraph,
136 childComponentModel,
dpb73afb302018-02-12 10:59:53 -0800137 subcomponentNames,
bcorsof0a99fe2017-12-04 10:52:05 -0800138 childComponentRequirementFields,
dpb73afb302018-02-12 10:59:53 -0800139 referenceReleasingManagerFields,
bcorsocc739fe2018-04-23 09:16:12 -0700140 staticSwitchingProviders,
dpb73afb302018-02-12 10:59:53 -0800141 optionalFactories,
142 types,
143 elements,
144 compilerOptions);
dpb68c77d82017-08-15 15:23:35 -0700145 }
146
147 /**
148 * Returns an expression that evaluates to the value of a dependency request for a binding owned
149 * by this component or an ancestor.
150 *
151 * @param requestingClass the class that will contain the expression
152 * @throws IllegalStateException if there is no binding expression that satisfies the dependency
153 * request
154 */
ronshapiro0a277fd2017-12-22 08:30:49 -0800155 Expression getDependencyExpression(Key key, RequestKind requestKind, ClassName requestingClass) {
156 return getBindingExpression(key, requestKind).getDependencyExpression(requestingClass);
ronshapiroba794862017-09-28 11:39:34 -0700157 }
158
159 /**
160 * Returns an expression that evaluates to the value of a dependency request for a binding owned
161 * by this component or an ancestor.
162 *
163 * @param requestingClass the class that will contain the expression
164 * @throws IllegalStateException if there is no binding expression that satisfies the dependency
165 * request
166 */
167 Expression getDependencyExpression(DependencyRequest request, ClassName requestingClass) {
ronshapiro0a277fd2017-12-22 08:30:49 -0800168 return getDependencyExpression(request.key(), request.kind(), requestingClass);
dpb68c77d82017-08-15 15:23:35 -0700169 }
170
171 /**
172 * Returns an expression that evaluates to the value of a framework dependency for a binding owned
173 * in this component or an ancestor.
174 *
175 * @param requestingClass the class that will contain the expression
176 * @throws IllegalStateException if there is no binding expression that satisfies the dependency
177 * request
178 */
ronshapiroba794862017-09-28 11:39:34 -0700179 Expression getDependencyExpression(
dpb68c77d82017-08-15 15:23:35 -0700180 FrameworkDependency frameworkDependency, ClassName requestingClass) {
ronshapiroba794862017-09-28 11:39:34 -0700181 return getDependencyExpression(
ronshapiro0a277fd2017-12-22 08:30:49 -0800182 frameworkDependency.key(), frameworkDependency.dependencyRequestKind(), requestingClass);
dpb68c77d82017-08-15 15:23:35 -0700183 }
184
185 /**
bcorso5db065d2018-04-03 13:49:31 -0700186 * Returns the {@link CodeBlock} for the method argmuments used with the factory {@code create()}
187 * method for the given {@link ContributionBinding binding}.
dpb3db68f02018-01-04 09:15:52 -0800188 */
bcorso5db065d2018-04-03 13:49:31 -0700189 CodeBlock getCreateMethodArgumentsCodeBlock(ContributionBinding binding) {
190 return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding));
191 }
192
193 private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(ContributionBinding binding) {
194 ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
195
196 if (binding.requiresModuleInstance()) {
197 arguments.add(
198 componentRequirementFields.getExpressionDuringInitialization(
199 ComponentRequirement.forModule(binding.contributingModule().get().asType()),
200 generatedComponentModel.name()));
201 }
202
203 binding
204 .frameworkDependencies()
dpb3db68f02018-01-04 09:15:52 -0800205 .stream()
bcorso5db065d2018-04-03 13:49:31 -0700206 .map(dependency -> getDependencyExpression(dependency, generatedComponentModel.name()))
207 .map(Expression::codeBlock)
208 .forEach(arguments::add);
209
210 return arguments.build();
dpb3db68f02018-01-04 09:15:52 -0800211 }
212
213 /**
dpb68c77d82017-08-15 15:23:35 -0700214 * Returns an expression that evaluates to the value of a dependency request, for passing to a
215 * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
216 *
217 * <p>If the method is a generated static {@link InjectionMethods injection method}, each
218 * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
219 * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
220 *
221 * @param requestingClass the class that will contain the expression
222 */
223 // TODO(b/64024402) Merge with getDependencyExpression(DependencyRequest, ClassName) if possible.
ronshapiroba794862017-09-28 11:39:34 -0700224 Expression getDependencyArgumentExpression(
dpb68c77d82017-08-15 15:23:35 -0700225 DependencyRequest dependencyRequest, ClassName requestingClass) {
dpb68c77d82017-08-15 15:23:35 -0700226
227 TypeMirror dependencyType = dependencyRequest.key().type();
ronshapiroba794862017-09-28 11:39:34 -0700228 Expression dependencyExpression = getDependencyExpression(dependencyRequest, requestingClass);
229
bcorsoaaffd2d2018-04-16 14:44:42 -0700230 if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
231 && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
dpb68c77d82017-08-15 15:23:35 -0700232 && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
ronshapiroba794862017-09-28 11:39:34 -0700233 return dependencyExpression.castTo(types.erasure(dependencyType));
dpb68c77d82017-08-15 15:23:35 -0700234 }
235
ronshapiroba794862017-09-28 11:39:34 -0700236 return dependencyExpression;
dpb68c77d82017-08-15 15:23:35 -0700237 }
238
dpb02db2132018-01-08 07:20:23 -0800239 /** Returns the implementation of a component method. */
240 MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
241 checkArgument(componentMethod.dependencyRequest().isPresent());
242 DependencyRequest dependencyRequest = componentMethod.dependencyRequest().get();
243 return MethodSpec.overriding(
244 componentMethod.methodElement(),
245 MoreTypes.asDeclared(graph.componentType().asType()),
246 types)
247 .addCode(
248 getBindingExpression(dependencyRequest.key(), dependencyRequest.kind())
249 .getComponentMethodImplementation(componentMethod, generatedComponentModel.name()))
250 .build();
bcorso11f9b872017-10-09 16:18:55 -0700251 }
252
dstrasburgcf5e1bc2018-08-09 09:03:38 -0700253 /**
254 * Returns the implementation of a method encapsulating a missing binding in a supertype
255 * implementation of this subcomponent. Returns {@link Optional#empty()} when the binding cannot
256 * be satisfied by the current binding graph. This is only relevant for ahead-of-time
257 * subcomponents.
258 */
259 Optional<MethodSpec> getMissingBindingMethodImplementation(MissingBindingMethod missingBinding) {
260 // TODO(b/72748365): investigate beder@'s comment about having intermediate component ancestors
261 // satisfy missing bindings of their children with their own missing binding methods so that
262 // we can minimize the cases where we need to reach into doubly-nested descendant component
263 // implementations
264 if (resolvableBinding(missingBinding.key(), missingBinding.kind())) {
265 Expression bindingExpression =
266 getDependencyExpression(
267 missingBinding.key(), missingBinding.kind(), generatedComponentModel.name());
268 MethodSpec unimplementedMethod = missingBinding.unimplementedMethod();
269 return Optional.of(
270 MethodSpec.methodBuilder(unimplementedMethod.name)
271 .addModifiers(PUBLIC)
272 .returns(unimplementedMethod.returnType)
273 .addAnnotation(Override.class)
274 .addStatement("return $L", bindingExpression.codeBlock())
275 .build());
276 }
277 return Optional.empty();
278 }
279
ronshapiro0a277fd2017-12-22 08:30:49 -0800280 private BindingExpression getBindingExpression(Key key, RequestKind requestKind) {
dstrasburg4f902cf2018-07-30 08:42:57 -0700281 if (expressions.contains(key, requestKind)) {
ronshapiro0a277fd2017-12-22 08:30:49 -0800282 return expressions.get(key, requestKind);
bcorsof0a99fe2017-12-04 10:52:05 -0800283 }
dstrasburg4f902cf2018-07-30 08:42:57 -0700284 Optional<BindingExpression> expression = Optional.empty();
285 if (resolvedInThisComponent(key, requestKind)) {
286 ResolvedBindings resolvedBindings = graph.resolvedBindings(requestKind, key);
287 expression = Optional.of(createBindingExpression(resolvedBindings, requestKind));
288 } else if (!resolvableBinding(key, requestKind) && generatedComponentModel.isAbstract()) {
dstrasburgcf5e1bc2018-08-09 09:03:38 -0700289 expression =
290 Optional.of(new MissingBindingExpression(generatedComponentModel, key, requestKind));
dstrasburg4f902cf2018-07-30 08:42:57 -0700291 }
292 if (expression.isPresent()) {
293 expressions.put(key, requestKind, expression.get());
294 return expression.get();
295 }
dpb80eda692018-03-05 11:31:42 -0800296 checkArgument(parent.isPresent(), "no expression found for %s-%s", key, requestKind);
297 return parent.get().getBindingExpression(key, requestKind);
bcorsof0a99fe2017-12-04 10:52:05 -0800298 }
299
dpb73afb302018-02-12 10:59:53 -0800300 /** Creates a binding expression. */
301 private BindingExpression createBindingExpression(
302 ResolvedBindings resolvedBindings, RequestKind requestKind) {
dstrasburg4f902cf2018-07-30 08:42:57 -0700303 if (generatedInstanceForAbstractSubcomponent(resolvedBindings)) {
304 return new GeneratedInstanceBindingExpression(resolvedBindings);
305 }
dpb73afb302018-02-12 10:59:53 -0800306 switch (resolvedBindings.bindingType()) {
307 case MEMBERS_INJECTION:
308 checkArgument(requestKind.equals(RequestKind.MEMBERS_INJECTION));
ronshapiro9288a972018-02-14 06:02:12 -0800309 return new MembersInjectionBindingExpression(resolvedBindings, membersInjectionMethods);
bcorsof0a99fe2017-12-04 10:52:05 -0800310
dpb73afb302018-02-12 10:59:53 -0800311 case PROVISION:
312 return provisionBindingExpression(resolvedBindings, requestKind);
313
314 case PRODUCTION:
315 return frameworkInstanceBindingExpression(resolvedBindings, requestKind);
316
317 default:
318 throw new AssertionError(resolvedBindings);
bcorsof0a99fe2017-12-04 10:52:05 -0800319 }
dpb73afb302018-02-12 10:59:53 -0800320 }
bcorsof0a99fe2017-12-04 10:52:05 -0800321
dpb73afb302018-02-12 10:59:53 -0800322 /**
dstrasburg4f902cf2018-07-30 08:42:57 -0700323 * Returns true if the binding exposes an instance of a generated type, but no concrete
324 * implementation of that type is available.
325 */
326 private boolean generatedInstanceForAbstractSubcomponent(ResolvedBindings resolvedBindings) {
327 return !resolvedBindings.contributionBindings().isEmpty()
328 && resolvedBindings.contributionBinding().requiresGeneratedInstance()
329 && generatedComponentModel.isAbstract();
330 }
331
332 /**
333 * Returns true if the binding can be resolved by the graph for this component or any parent
334 * component.
335 */
336 private boolean resolvableBinding(Key key, RequestKind requestKind) {
337 for (ComponentBindingExpressions expressions = this;
338 expressions != null;
339 expressions = expressions.parent.orElse(null)) {
340 if (expressions.resolvedInThisComponent(key, requestKind)) {
341 return true;
342 }
343 }
344 return false;
345 }
346
347 /** Returns true if the binding can be resolved by the graph for this component. */
348 private boolean resolvedInThisComponent(Key key, RequestKind requestKind) {
349 ResolvedBindings resolvedBindings = graph.resolvedBindings(requestKind, key);
350 return resolvedBindings != null && !resolvedBindings.ownedBindings().isEmpty();
351 }
352
353 /**
dpb73afb302018-02-12 10:59:53 -0800354 * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
355 * or a {@link dagger.producers.Producer} for production bindings.
356 */
357 private FrameworkInstanceBindingExpression frameworkInstanceBindingExpression(
358 ResolvedBindings resolvedBindings, RequestKind requestKind) {
bcorsoaf9e0042018-04-16 14:12:23 -0700359 // TODO(user): Consider merging the static factory creation logic into CreationExpressions?
360 Optional<MemberSelect> staticMethod =
361 useStaticFactoryCreation(resolvedBindings.contributionBinding())
362 ? staticFactoryCreation(resolvedBindings)
363 : Optional.empty();
dpb73afb302018-02-12 10:59:53 -0800364 FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
365 resolvedBindings.scope().isPresent()
366 ? scope(resolvedBindings, frameworkInstanceCreationExpression(resolvedBindings))
367 : frameworkInstanceCreationExpression(resolvedBindings);
cgdecker0bc05be2018-08-10 12:37:36 -0700368 FrameworkInstanceSupplier frameworkInstanceSupplier =
dpb73afb302018-02-12 10:59:53 -0800369 staticMethod.isPresent()
370 ? staticMethod::get
371 : new FrameworkFieldInitializer(
cgdecker0bc05be2018-08-10 12:37:36 -0700372 generatedComponentModel, resolvedBindings, frameworkInstanceCreationExpression);
373
374 FrameworkType frameworkType = resolvedBindings.bindingType().frameworkType();
375 switch (frameworkType) {
376 case PROVIDER:
377 return new ProviderInstanceBindingExpression(
378 resolvedBindings, requestKind, this, frameworkInstanceSupplier, types, elements);
379 case PRODUCER:
380 return new ProducerInstanceBindingExpression(
381 resolvedBindings, requestKind, this, frameworkInstanceSupplier, types, elements);
382 default:
383 throw new AssertionError("invalid framework type: " + frameworkType);
384 }
dpb73afb302018-02-12 10:59:53 -0800385 }
dpb64861842017-12-12 08:17:18 -0800386
dpb73afb302018-02-12 10:59:53 -0800387 private FrameworkInstanceCreationExpression scope(
388 ResolvedBindings resolvedBindings, FrameworkInstanceCreationExpression unscoped) {
389 if (requiresReleasableReferences(resolvedBindings)) {
390 return () ->
391 CodeBlock.of(
392 "$T.create($L, $L)",
393 REFERENCE_RELEASING_PROVIDER,
394 unscoped.creationExpression(),
395 referenceReleasingManagerFields.getExpression(
396 resolvedBindings.scope().get(), generatedComponentModel.name()));
397 } else {
398 return () ->
399 CodeBlock.of(
400 "$T.provider($L)",
401 resolvedBindings.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
402 unscoped.creationExpression());
dpb64861842017-12-12 08:17:18 -0800403 }
dpb73afb302018-02-12 10:59:53 -0800404 }
dpb64861842017-12-12 08:17:18 -0800405
dpb73afb302018-02-12 10:59:53 -0800406 /**
407 * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
408 * {@link dagger.producers.Producer} for production bindings.
409 */
410 private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
411 ResolvedBindings resolvedBindings) {
412 checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
413 ContributionBinding binding = resolvedBindings.contributionBinding();
414 switch (binding.kind()) {
415 case COMPONENT:
416 // The cast can be removed when we drop java 7 source support
417 return new InstanceFactoryCreationExpression(
418 () -> CodeBlock.of("($T) this", binding.key().type()));
dpb64861842017-12-12 08:17:18 -0800419
dpb73afb302018-02-12 10:59:53 -0800420 case BOUND_INSTANCE:
421 return instanceFactoryCreationExpression(
422 binding, ComponentRequirement.forBoundInstance(binding));
bcorsof0a99fe2017-12-04 10:52:05 -0800423
dpb73afb302018-02-12 10:59:53 -0800424 case COMPONENT_DEPENDENCY:
425 return instanceFactoryCreationExpression(
426 binding, ComponentRequirement.forDependency(binding.key().type()));
dpb3db68f02018-01-04 09:15:52 -0800427
dpb73afb302018-02-12 10:59:53 -0800428 case COMPONENT_PROVISION:
429 return new DependencyMethodProviderCreationExpression(
430 binding, generatedComponentModel, componentRequirementFields, compilerOptions, graph);
dpb3db68f02018-01-04 09:15:52 -0800431
dpb73afb302018-02-12 10:59:53 -0800432 case SUBCOMPONENT_BUILDER:
433 return new SubcomponentBuilderProviderCreationExpression(
434 binding.key().type(), subcomponentNames.get(binding.key()));
dpb356a6842018-02-07 07:45:50 -0800435
dpb73afb302018-02-12 10:59:53 -0800436 case INJECTION:
437 case PROVISION:
bcorsocc739fe2018-04-23 09:16:12 -0700438 return compilerOptions.experimentalAndroidMode2()
439 ? staticSwitchingProviders.newCreationExpression(binding, this)
440 : new InjectionOrProvisionProviderCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800441
dpb73afb302018-02-12 10:59:53 -0800442 case COMPONENT_PRODUCTION:
443 return new DependencyMethodProducerCreationExpression(
444 binding, generatedComponentModel, componentRequirementFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800445
dpb73afb302018-02-12 10:59:53 -0800446 case PRODUCTION:
bcorso5db065d2018-04-03 13:49:31 -0700447 return new ProducerCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800448
dpb73afb302018-02-12 10:59:53 -0800449 case MULTIBOUND_SET:
450 return new SetFactoryCreationExpression(binding, generatedComponentModel, this, graph);
dpb3db68f02018-01-04 09:15:52 -0800451
dpb73afb302018-02-12 10:59:53 -0800452 case MULTIBOUND_MAP:
ronshapiro3a089642018-07-17 15:39:40 -0700453 return new MapFactoryCreationExpression(
454 binding, generatedComponentModel, this, graph, elements);
dpb3db68f02018-01-04 09:15:52 -0800455
dpb73afb302018-02-12 10:59:53 -0800456 case RELEASABLE_REFERENCE_MANAGER:
457 return new ReleasableReferenceManagerProviderCreationExpression(
458 binding, generatedComponentModel, referenceReleasingManagerFields);
dpb3db68f02018-01-04 09:15:52 -0800459
dpb73afb302018-02-12 10:59:53 -0800460 case RELEASABLE_REFERENCE_MANAGERS:
461 return new ReleasableReferenceManagerSetProviderCreationExpression(
462 binding, generatedComponentModel, referenceReleasingManagerFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800463
dpb73afb302018-02-12 10:59:53 -0800464 case DELEGATE:
465 return new DelegatingFrameworkInstanceCreationExpression(
466 binding, generatedComponentModel, this);
dpb3db68f02018-01-04 09:15:52 -0800467
dpb73afb302018-02-12 10:59:53 -0800468 case OPTIONAL:
ronshapiroe6740762018-05-01 08:37:26 -0700469 return new OptionalFactoryInstanceCreationExpression(
470 optionalFactories, binding, generatedComponentModel, this);
dpb356a6842018-02-07 07:45:50 -0800471
dpb73afb302018-02-12 10:59:53 -0800472 case MEMBERS_INJECTOR:
ronshapiroe6740762018-05-01 08:37:26 -0700473 return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
dpb73afb302018-02-12 10:59:53 -0800474
475 default:
476 throw new AssertionError(binding);
477 }
478 }
479
480 private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
481 ContributionBinding binding, ComponentRequirement componentRequirement) {
482 return new InstanceFactoryCreationExpression(
483 binding.nullableType().isPresent(),
484 () ->
485 componentRequirementFields.getExpressionDuringInitialization(
486 componentRequirement, generatedComponentModel.name()));
487 }
488
489 /** Returns a binding expression for a provision binding. */
490 private BindingExpression provisionBindingExpression(
491 ResolvedBindings resolvedBindings, RequestKind requestKind) {
492 switch (requestKind) {
dpb73afb302018-02-12 10:59:53 -0800493 case INSTANCE:
494 return instanceBindingExpression(resolvedBindings);
495
ronshapiro62c8d5c2018-05-10 09:06:48 -0700496 case PROVIDER:
497 return providerBindingExpression(resolvedBindings);
dpb73afb302018-02-12 10:59:53 -0800498
499 case LAZY:
500 case PRODUCED:
501 case PROVIDER_OF_LAZY:
502 return new DerivedFromProviderBindingExpression(resolvedBindings, requestKind, this, types);
503
ronshapiro62c8d5c2018-05-10 09:06:48 -0700504 case PRODUCER:
505 return producerFromProviderBindingExpression(resolvedBindings, requestKind);
506
507 case FUTURE:
508 return new ImmediateFutureBindingExpression(resolvedBindings, this, types);
dpb73afb302018-02-12 10:59:53 -0800509
510 case MEMBERS_INJECTION:
511 throw new IllegalArgumentException();
dpb356a6842018-02-07 07:45:50 -0800512 }
513
dpb73afb302018-02-12 10:59:53 -0800514 throw new AssertionError();
515 }
dpb356a6842018-02-07 07:45:50 -0800516
dpb73afb302018-02-12 10:59:53 -0800517 /**
ronshapiro62c8d5c2018-05-10 09:06:48 -0700518 * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
519 *
520 * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ResolvedBindings) need to be
521 * cached} can use a {@link DelegateBindingExpression}.
522 *
bcorsod55c02d2018-06-06 15:02:34 -0700523 * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
524 * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
525 * which case, just use that Provider directly).
ronshapiro62c8d5c2018-05-10 09:06:48 -0700526 *
527 * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
528 */
529 private BindingExpression providerBindingExpression(ResolvedBindings resolvedBindings) {
530 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)
531 && !needsCaching(resolvedBindings)) {
532 return new DelegateBindingExpression(
533 resolvedBindings, RequestKind.PROVIDER, this, types, elements);
bcorsod55c02d2018-06-06 15:02:34 -0700534 } else if (compilerOptions.fastInit()
ronshapiro62c8d5c2018-05-10 09:06:48 -0700535 && frameworkInstanceCreationExpression(resolvedBindings).useInnerSwitchingProvider()
536 && !(instanceBindingExpression(resolvedBindings)
537 instanceof DerivedFromProviderBindingExpression)) {
538 return wrapInMethod(
539 resolvedBindings,
540 RequestKind.PROVIDER,
541 innerSwitchingProviders.newBindingExpression(resolvedBindings.contributionBinding()));
542 }
543 return frameworkInstanceBindingExpression(resolvedBindings, RequestKind.PROVIDER);
544 }
545
546 /**
dpb73afb302018-02-12 10:59:53 -0800547 * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
548 * provision binding.
549 */
550 private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
551 ResolvedBindings resolvedBindings, RequestKind requestKind) {
552 checkArgument(resolvedBindings.bindingType().frameworkType().equals(FrameworkType.PROVIDER));
cgdecker0bc05be2018-08-10 12:37:36 -0700553 return new ProducerInstanceBindingExpression(
dpb73afb302018-02-12 10:59:53 -0800554 resolvedBindings,
555 requestKind,
556 this,
dpb73afb302018-02-12 10:59:53 -0800557 new FrameworkFieldInitializer(
558 generatedComponentModel,
559 resolvedBindings,
560 new ProducerFromProviderCreationExpression(
561 resolvedBindings.contributionBinding(), generatedComponentModel, this)),
562 types,
563 elements);
564 }
dpb356a6842018-02-07 07:45:50 -0800565
dpb73afb302018-02-12 10:59:53 -0800566 /**
567 * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
568 *
569 * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an
570 * instance of this binding, return it, wrapped in a method if the binding {@linkplain
571 * #needsCaching(ResolvedBindings) needs to be cached} or the expression has dependencies.
572 *
573 * <p>In default mode, we can use direct expressions for bindings that don't need to be cached in
574 * a reference-releasing scope.
575 *
bcorsod55c02d2018-06-06 15:02:34 -0700576 * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached.
dpb73afb302018-02-12 10:59:53 -0800577 */
578 private BindingExpression instanceBindingExpression(ResolvedBindings resolvedBindings) {
579 Optional<BindingExpression> maybeDirectInstanceExpression =
580 unscopedDirectInstanceExpression(resolvedBindings);
581 if (canUseDirectInstanceExpression(resolvedBindings)
582 && maybeDirectInstanceExpression.isPresent()) {
583 BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
584 return directInstanceExpression.requiresMethodEncapsulation()
585 || needsCaching(resolvedBindings)
586 ? wrapInMethod(resolvedBindings, RequestKind.INSTANCE, directInstanceExpression)
587 : directInstanceExpression;
dpb356a6842018-02-07 07:45:50 -0800588 }
dpb73afb302018-02-12 10:59:53 -0800589 return new DerivedFromProviderBindingExpression(
590 resolvedBindings, RequestKind.INSTANCE, this, types);
591 }
dpb356a6842018-02-07 07:45:50 -0800592
dpb73afb302018-02-12 10:59:53 -0800593 /**
594 * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
595 * {@code get()} on its provider, if there is one.
596 */
597 private Optional<BindingExpression> unscopedDirectInstanceExpression(
598 ResolvedBindings resolvedBindings) {
599 switch (resolvedBindings.contributionBinding().kind()) {
600 case DELEGATE:
601 return Optional.of(
602 new DelegateBindingExpression(
603 resolvedBindings, RequestKind.INSTANCE, this, types, elements));
604
605 case COMPONENT:
606 return Optional.of(
607 new ComponentInstanceBindingExpression(
608 resolvedBindings, generatedComponentModel.name()));
609
610 case COMPONENT_DEPENDENCY:
611 return Optional.of(
612 new ComponentRequirementBindingExpression(
613 resolvedBindings,
614 ComponentRequirement.forDependency(resolvedBindings.key().type()),
615 componentRequirementFields));
616
617 case COMPONENT_PROVISION:
618 return Optional.of(
619 new ComponentProvisionBindingExpression(
620 resolvedBindings, graph, componentRequirementFields, compilerOptions));
621
622 case SUBCOMPONENT_BUILDER:
623 return Optional.of(
624 new SubcomponentBuilderBindingExpression(
625 resolvedBindings, subcomponentNames.get(resolvedBindings.key())));
626
627 case MULTIBOUND_SET:
628 return Optional.of(
629 new SetBindingExpression(resolvedBindings, graph, this, types, elements));
630
631 case MULTIBOUND_MAP:
632 return Optional.of(
633 new MapBindingExpression(resolvedBindings, graph, this, types, elements));
634
635 case OPTIONAL:
636 return Optional.of(new OptionalBindingExpression(resolvedBindings, this, types));
637
638 case BOUND_INSTANCE:
639 return Optional.of(
640 new ComponentRequirementBindingExpression(
641 resolvedBindings,
642 ComponentRequirement.forBoundInstance(resolvedBindings.contributionBinding()),
643 componentRequirementFields));
644
645 case INJECTION:
646 case PROVISION:
647 return Optional.of(
648 new SimpleMethodBindingExpression(
649 resolvedBindings,
650 compilerOptions,
651 this,
652 membersInjectionMethods,
653 componentRequirementFields,
654 elements));
655
656 case MEMBERS_INJECTOR:
657 case RELEASABLE_REFERENCE_MANAGER:
658 case RELEASABLE_REFERENCE_MANAGERS:
659 // TODO(dpb): Implement direct expressions for these.
660 return Optional.empty();
661
662 case MEMBERS_INJECTION:
663 case COMPONENT_PRODUCTION:
664 case PRODUCTION:
665 throw new IllegalArgumentException(
666 resolvedBindings.contributionBinding().kind().toString());
667 }
668 throw new AssertionError();
669 }
670
671 /**
bcorsoaf9e0042018-04-16 14:12:23 -0700672 * Returns {@code true} if the binding should use the static factory creation strategy.
673 *
bcorsod55c02d2018-06-06 15:02:34 -0700674 * In default mode, we always use the static factory creation strategy. In fastInit mode, we
675 * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
676 * however, we allow static factories that can reused across multiple bindings, e.g.
677 * {@code MapFactory} or {@code SetFactory}.
bcorsoaf9e0042018-04-16 14:12:23 -0700678 */
679 private boolean useStaticFactoryCreation(ContributionBinding binding) {
bcorsod55c02d2018-06-06 15:02:34 -0700680 return !(compilerOptions.experimentalAndroidMode2() || compilerOptions.fastInit())
bcorsoaf9e0042018-04-16 14:12:23 -0700681 || binding.kind().equals(MULTIBOUND_MAP)
682 || binding.kind().equals(MULTIBOUND_SET);
683 }
684
685 /**
dpb73afb302018-02-12 10:59:53 -0800686 * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this
687 * binding. If the binding doesn't {@linkplain #needsCaching(ResolvedBindings) need to be cached},
688 * we can.
689 *
bcorsod55c02d2018-06-06 15:02:34 -0700690 * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain
dpb73afb302018-02-12 10:59:53 -0800691 * #needsCaching(ResolvedBindings) needs to be cached} as long as it's not in a
692 * reference-releasing scope.
693 */
694 private boolean canUseDirectInstanceExpression(ResolvedBindings resolvedBindings) {
695 return !needsCaching(resolvedBindings)
bcorsod55c02d2018-06-06 15:02:34 -0700696 || (compilerOptions.fastInit() && !requiresReleasableReferences(resolvedBindings));
dpb73afb302018-02-12 10:59:53 -0800697 }
698
699 /**
dpb73afb302018-02-12 10:59:53 -0800700 * Returns a binding expression that uses a given one as the body of a method that users call. If
701 * a component provision method matches it, it will be the method implemented. If not, a new
702 * private method will be written.
703 */
704 private BindingExpression wrapInMethod(
705 ResolvedBindings resolvedBindings,
706 RequestKind requestKind,
707 BindingExpression bindingExpression) {
708 BindingMethodImplementation methodImplementation =
709 methodImplementation(resolvedBindings, requestKind, bindingExpression);
710
711 return findMatchingComponentMethod(resolvedBindings.key(), requestKind)
712 .<BindingExpression>map(
713 componentMethod ->
714 new ComponentMethodBindingExpression(
dpbd7685762018-02-16 12:20:09 -0800715 methodImplementation, generatedComponentModel, componentMethod))
dpb73afb302018-02-12 10:59:53 -0800716 .orElseGet(
717 () ->
718 new PrivateMethodBindingExpression(
719 resolvedBindings, requestKind, methodImplementation, generatedComponentModel));
720 }
721
722 /** Returns the first component method associated with this request kind, if one exists. */
723 private Optional<ComponentMethodDescriptor> findMatchingComponentMethod(
724 Key key, RequestKind requestKind) {
725 return graph
726 .componentDescriptor()
727 .componentMethods()
728 .stream()
729 .filter(method -> doesComponentMethodMatch(method, key, requestKind))
730 .findFirst();
731 }
732
733 /** Returns true if the component method matches the dependency request binding key and kind. */
734 private boolean doesComponentMethodMatch(
735 ComponentMethodDescriptor componentMethod, Key key, RequestKind requestKind) {
736 return componentMethod
737 .dependencyRequest()
738 .filter(request -> request.key().equals(key))
739 .filter(request -> request.kind().equals(requestKind))
740 .isPresent();
741 }
742
743 private BindingMethodImplementation methodImplementation(
744 ResolvedBindings resolvedBindings,
745 RequestKind requestKind,
746 BindingExpression bindingExpression) {
bcorsod55c02d2018-06-06 15:02:34 -0700747 if (compilerOptions.fastInit()) {
bcorso567ff0e2018-03-21 13:49:09 -0700748 if (requestKind.equals(RequestKind.PROVIDER)) {
749 return new SingleCheckedMethodImplementation(
750 resolvedBindings, requestKind, bindingExpression, types, generatedComponentModel);
751 } else if (requestKind.equals(RequestKind.INSTANCE) && needsCaching(resolvedBindings)) {
752 return resolvedBindings.scope().get().isReusable()
753 ? new SingleCheckedMethodImplementation(
754 resolvedBindings, requestKind, bindingExpression, types, generatedComponentModel)
755 : new DoubleCheckedMethodImplementation(
756 resolvedBindings, requestKind, bindingExpression, types, generatedComponentModel);
757 }
758 }
759
760 return new BindingMethodImplementation(
761 resolvedBindings, requestKind, bindingExpression, generatedComponentModel.name(), types);
dpb73afb302018-02-12 10:59:53 -0800762 }
763
764 /**
765 * Returns {@code true} if the component needs to make sure the provided value is cached.
766 *
767 * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
768 * bindings whose scope is no stronger than their delegate's.
769 */
770 private boolean needsCaching(ResolvedBindings resolvedBindings) {
771 if (!resolvedBindings.scope().isPresent()) {
772 return false;
bcorso3828ca22018-01-29 10:14:12 -0800773 }
dpb73afb302018-02-12 10:59:53 -0800774 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) {
775 return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph);
776 }
777 return true;
778 }
779
bcorsod55c02d2018-06-06 15:02:34 -0700780 // TODO(user): Enable releasable references in fastInit
dpb73afb302018-02-12 10:59:53 -0800781 private boolean requiresReleasableReferences(ResolvedBindings resolvedBindings) {
782 return resolvedBindings.scope().isPresent()
783 && referenceReleasingManagerFields.requiresReleasableReferences(
784 resolvedBindings.scope().get());
dpb68c77d82017-08-15 15:23:35 -0700785 }
786}