blob: f8a9d654cd44d19b15cba6005065a0d49ad2f5e6 [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:
dpb5e03bd52018-08-10 14:21:15 -0700315 if (requestKind.equals(RequestKind.PRODUCER)) {
316 return frameworkInstanceBindingExpression(resolvedBindings);
317 } else {
318 return new DerivedFromFrameworkInstanceBindingExpression(
319 resolvedBindings, requestKind, this, types);
320 }
dpb73afb302018-02-12 10:59:53 -0800321
322 default:
323 throw new AssertionError(resolvedBindings);
bcorsof0a99fe2017-12-04 10:52:05 -0800324 }
dpb73afb302018-02-12 10:59:53 -0800325 }
bcorsof0a99fe2017-12-04 10:52:05 -0800326
dpb73afb302018-02-12 10:59:53 -0800327 /**
dstrasburg4f902cf2018-07-30 08:42:57 -0700328 * Returns true if the binding exposes an instance of a generated type, but no concrete
329 * implementation of that type is available.
330 */
331 private boolean generatedInstanceForAbstractSubcomponent(ResolvedBindings resolvedBindings) {
332 return !resolvedBindings.contributionBindings().isEmpty()
333 && resolvedBindings.contributionBinding().requiresGeneratedInstance()
334 && generatedComponentModel.isAbstract();
335 }
336
337 /**
338 * Returns true if the binding can be resolved by the graph for this component or any parent
339 * component.
340 */
341 private boolean resolvableBinding(Key key, RequestKind requestKind) {
342 for (ComponentBindingExpressions expressions = this;
343 expressions != null;
344 expressions = expressions.parent.orElse(null)) {
345 if (expressions.resolvedInThisComponent(key, requestKind)) {
346 return true;
347 }
348 }
349 return false;
350 }
351
352 /** Returns true if the binding can be resolved by the graph for this component. */
353 private boolean resolvedInThisComponent(Key key, RequestKind requestKind) {
354 ResolvedBindings resolvedBindings = graph.resolvedBindings(requestKind, key);
355 return resolvedBindings != null && !resolvedBindings.ownedBindings().isEmpty();
356 }
357
358 /**
dpb73afb302018-02-12 10:59:53 -0800359 * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
360 * or a {@link dagger.producers.Producer} for production bindings.
361 */
362 private FrameworkInstanceBindingExpression frameworkInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700363 ResolvedBindings resolvedBindings) {
bcorsoaf9e0042018-04-16 14:12:23 -0700364 // TODO(user): Consider merging the static factory creation logic into CreationExpressions?
365 Optional<MemberSelect> staticMethod =
366 useStaticFactoryCreation(resolvedBindings.contributionBinding())
367 ? staticFactoryCreation(resolvedBindings)
368 : Optional.empty();
dpb73afb302018-02-12 10:59:53 -0800369 FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
370 resolvedBindings.scope().isPresent()
371 ? scope(resolvedBindings, frameworkInstanceCreationExpression(resolvedBindings))
372 : frameworkInstanceCreationExpression(resolvedBindings);
cgdecker0bc05be2018-08-10 12:37:36 -0700373 FrameworkInstanceSupplier frameworkInstanceSupplier =
dpb73afb302018-02-12 10:59:53 -0800374 staticMethod.isPresent()
375 ? staticMethod::get
376 : new FrameworkFieldInitializer(
cgdecker0bc05be2018-08-10 12:37:36 -0700377 generatedComponentModel, resolvedBindings, frameworkInstanceCreationExpression);
378
379 FrameworkType frameworkType = resolvedBindings.bindingType().frameworkType();
380 switch (frameworkType) {
381 case PROVIDER:
382 return new ProviderInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700383 resolvedBindings, frameworkInstanceSupplier, types, elements);
cgdecker0bc05be2018-08-10 12:37:36 -0700384 case PRODUCER:
385 return new ProducerInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700386 resolvedBindings, frameworkInstanceSupplier, types, elements);
cgdecker0bc05be2018-08-10 12:37:36 -0700387 default:
388 throw new AssertionError("invalid framework type: " + frameworkType);
389 }
dpb73afb302018-02-12 10:59:53 -0800390 }
dpb64861842017-12-12 08:17:18 -0800391
dpb73afb302018-02-12 10:59:53 -0800392 private FrameworkInstanceCreationExpression scope(
393 ResolvedBindings resolvedBindings, FrameworkInstanceCreationExpression unscoped) {
394 if (requiresReleasableReferences(resolvedBindings)) {
395 return () ->
396 CodeBlock.of(
397 "$T.create($L, $L)",
398 REFERENCE_RELEASING_PROVIDER,
399 unscoped.creationExpression(),
400 referenceReleasingManagerFields.getExpression(
401 resolvedBindings.scope().get(), generatedComponentModel.name()));
402 } else {
403 return () ->
404 CodeBlock.of(
405 "$T.provider($L)",
406 resolvedBindings.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
407 unscoped.creationExpression());
dpb64861842017-12-12 08:17:18 -0800408 }
dpb73afb302018-02-12 10:59:53 -0800409 }
dpb64861842017-12-12 08:17:18 -0800410
dpb73afb302018-02-12 10:59:53 -0800411 /**
412 * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
413 * {@link dagger.producers.Producer} for production bindings.
414 */
415 private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
416 ResolvedBindings resolvedBindings) {
417 checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
418 ContributionBinding binding = resolvedBindings.contributionBinding();
419 switch (binding.kind()) {
420 case COMPONENT:
421 // The cast can be removed when we drop java 7 source support
422 return new InstanceFactoryCreationExpression(
423 () -> CodeBlock.of("($T) this", binding.key().type()));
dpb64861842017-12-12 08:17:18 -0800424
dpb73afb302018-02-12 10:59:53 -0800425 case BOUND_INSTANCE:
426 return instanceFactoryCreationExpression(
427 binding, ComponentRequirement.forBoundInstance(binding));
bcorsof0a99fe2017-12-04 10:52:05 -0800428
dpb73afb302018-02-12 10:59:53 -0800429 case COMPONENT_DEPENDENCY:
430 return instanceFactoryCreationExpression(
431 binding, ComponentRequirement.forDependency(binding.key().type()));
dpb3db68f02018-01-04 09:15:52 -0800432
dpb73afb302018-02-12 10:59:53 -0800433 case COMPONENT_PROVISION:
434 return new DependencyMethodProviderCreationExpression(
435 binding, generatedComponentModel, componentRequirementFields, compilerOptions, graph);
dpb3db68f02018-01-04 09:15:52 -0800436
dpb73afb302018-02-12 10:59:53 -0800437 case SUBCOMPONENT_BUILDER:
438 return new SubcomponentBuilderProviderCreationExpression(
439 binding.key().type(), subcomponentNames.get(binding.key()));
dpb356a6842018-02-07 07:45:50 -0800440
dpb73afb302018-02-12 10:59:53 -0800441 case INJECTION:
442 case PROVISION:
bcorsocc739fe2018-04-23 09:16:12 -0700443 return compilerOptions.experimentalAndroidMode2()
444 ? staticSwitchingProviders.newCreationExpression(binding, this)
445 : new InjectionOrProvisionProviderCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800446
dpb73afb302018-02-12 10:59:53 -0800447 case COMPONENT_PRODUCTION:
448 return new DependencyMethodProducerCreationExpression(
449 binding, generatedComponentModel, componentRequirementFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800450
dpb73afb302018-02-12 10:59:53 -0800451 case PRODUCTION:
bcorso5db065d2018-04-03 13:49:31 -0700452 return new ProducerCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800453
dpb73afb302018-02-12 10:59:53 -0800454 case MULTIBOUND_SET:
455 return new SetFactoryCreationExpression(binding, generatedComponentModel, this, graph);
dpb3db68f02018-01-04 09:15:52 -0800456
dpb73afb302018-02-12 10:59:53 -0800457 case MULTIBOUND_MAP:
ronshapiro3a089642018-07-17 15:39:40 -0700458 return new MapFactoryCreationExpression(
459 binding, generatedComponentModel, this, graph, elements);
dpb3db68f02018-01-04 09:15:52 -0800460
dpb73afb302018-02-12 10:59:53 -0800461 case RELEASABLE_REFERENCE_MANAGER:
462 return new ReleasableReferenceManagerProviderCreationExpression(
463 binding, generatedComponentModel, referenceReleasingManagerFields);
dpb3db68f02018-01-04 09:15:52 -0800464
dpb73afb302018-02-12 10:59:53 -0800465 case RELEASABLE_REFERENCE_MANAGERS:
466 return new ReleasableReferenceManagerSetProviderCreationExpression(
467 binding, generatedComponentModel, referenceReleasingManagerFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800468
dpb73afb302018-02-12 10:59:53 -0800469 case DELEGATE:
470 return new DelegatingFrameworkInstanceCreationExpression(
471 binding, generatedComponentModel, this);
dpb3db68f02018-01-04 09:15:52 -0800472
dpb73afb302018-02-12 10:59:53 -0800473 case OPTIONAL:
ronshapiroe6740762018-05-01 08:37:26 -0700474 return new OptionalFactoryInstanceCreationExpression(
475 optionalFactories, binding, generatedComponentModel, this);
dpb356a6842018-02-07 07:45:50 -0800476
dpb73afb302018-02-12 10:59:53 -0800477 case MEMBERS_INJECTOR:
ronshapiroe6740762018-05-01 08:37:26 -0700478 return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
dpb73afb302018-02-12 10:59:53 -0800479
480 default:
481 throw new AssertionError(binding);
482 }
483 }
484
485 private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
486 ContributionBinding binding, ComponentRequirement componentRequirement) {
487 return new InstanceFactoryCreationExpression(
488 binding.nullableType().isPresent(),
489 () ->
490 componentRequirementFields.getExpressionDuringInitialization(
491 componentRequirement, generatedComponentModel.name()));
492 }
493
494 /** Returns a binding expression for a provision binding. */
495 private BindingExpression provisionBindingExpression(
496 ResolvedBindings resolvedBindings, RequestKind requestKind) {
497 switch (requestKind) {
dpb73afb302018-02-12 10:59:53 -0800498 case INSTANCE:
499 return instanceBindingExpression(resolvedBindings);
500
ronshapiro62c8d5c2018-05-10 09:06:48 -0700501 case PROVIDER:
502 return providerBindingExpression(resolvedBindings);
dpb73afb302018-02-12 10:59:53 -0800503
504 case LAZY:
505 case PRODUCED:
506 case PROVIDER_OF_LAZY:
dpb5e03bd52018-08-10 14:21:15 -0700507 return new DerivedFromFrameworkInstanceBindingExpression(
508 resolvedBindings, requestKind, this, types);
dpb73afb302018-02-12 10:59:53 -0800509
ronshapiro62c8d5c2018-05-10 09:06:48 -0700510 case PRODUCER:
dpb5e03bd52018-08-10 14:21:15 -0700511 return producerFromProviderBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700512
513 case FUTURE:
514 return new ImmediateFutureBindingExpression(resolvedBindings, this, types);
dpb73afb302018-02-12 10:59:53 -0800515
516 case MEMBERS_INJECTION:
517 throw new IllegalArgumentException();
dpb356a6842018-02-07 07:45:50 -0800518 }
519
dpb73afb302018-02-12 10:59:53 -0800520 throw new AssertionError();
521 }
dpb356a6842018-02-07 07:45:50 -0800522
dpb73afb302018-02-12 10:59:53 -0800523 /**
ronshapiro62c8d5c2018-05-10 09:06:48 -0700524 * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
525 *
526 * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ResolvedBindings) need to be
527 * cached} can use a {@link DelegateBindingExpression}.
528 *
bcorsod55c02d2018-06-06 15:02:34 -0700529 * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
530 * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
531 * which case, just use that Provider directly).
ronshapiro62c8d5c2018-05-10 09:06:48 -0700532 *
533 * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
534 */
535 private BindingExpression providerBindingExpression(ResolvedBindings resolvedBindings) {
536 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)
537 && !needsCaching(resolvedBindings)) {
538 return new DelegateBindingExpression(
539 resolvedBindings, RequestKind.PROVIDER, this, types, elements);
bcorsod55c02d2018-06-06 15:02:34 -0700540 } else if (compilerOptions.fastInit()
ronshapiro62c8d5c2018-05-10 09:06:48 -0700541 && frameworkInstanceCreationExpression(resolvedBindings).useInnerSwitchingProvider()
542 && !(instanceBindingExpression(resolvedBindings)
dpb5e03bd52018-08-10 14:21:15 -0700543 instanceof DerivedFromFrameworkInstanceBindingExpression)) {
ronshapiro62c8d5c2018-05-10 09:06:48 -0700544 return wrapInMethod(
545 resolvedBindings,
546 RequestKind.PROVIDER,
547 innerSwitchingProviders.newBindingExpression(resolvedBindings.contributionBinding()));
548 }
dpb5e03bd52018-08-10 14:21:15 -0700549 return frameworkInstanceBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700550 }
551
552 /**
dpb73afb302018-02-12 10:59:53 -0800553 * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
554 * provision binding.
555 */
556 private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700557 ResolvedBindings resolvedBindings) {
dpb73afb302018-02-12 10:59:53 -0800558 checkArgument(resolvedBindings.bindingType().frameworkType().equals(FrameworkType.PROVIDER));
cgdecker0bc05be2018-08-10 12:37:36 -0700559 return new ProducerInstanceBindingExpression(
dpb73afb302018-02-12 10:59:53 -0800560 resolvedBindings,
dpb73afb302018-02-12 10:59:53 -0800561 new FrameworkFieldInitializer(
562 generatedComponentModel,
563 resolvedBindings,
564 new ProducerFromProviderCreationExpression(
565 resolvedBindings.contributionBinding(), generatedComponentModel, this)),
566 types,
567 elements);
568 }
dpb356a6842018-02-07 07:45:50 -0800569
dpb73afb302018-02-12 10:59:53 -0800570 /**
571 * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
572 *
573 * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an
574 * instance of this binding, return it, wrapped in a method if the binding {@linkplain
575 * #needsCaching(ResolvedBindings) needs to be cached} or the expression has dependencies.
576 *
577 * <p>In default mode, we can use direct expressions for bindings that don't need to be cached in
578 * a reference-releasing scope.
579 *
bcorsod55c02d2018-06-06 15:02:34 -0700580 * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached.
dpb73afb302018-02-12 10:59:53 -0800581 */
582 private BindingExpression instanceBindingExpression(ResolvedBindings resolvedBindings) {
583 Optional<BindingExpression> maybeDirectInstanceExpression =
584 unscopedDirectInstanceExpression(resolvedBindings);
585 if (canUseDirectInstanceExpression(resolvedBindings)
586 && maybeDirectInstanceExpression.isPresent()) {
587 BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
588 return directInstanceExpression.requiresMethodEncapsulation()
589 || needsCaching(resolvedBindings)
590 ? wrapInMethod(resolvedBindings, RequestKind.INSTANCE, directInstanceExpression)
591 : directInstanceExpression;
dpb356a6842018-02-07 07:45:50 -0800592 }
dpb5e03bd52018-08-10 14:21:15 -0700593 return new DerivedFromFrameworkInstanceBindingExpression(
dpb73afb302018-02-12 10:59:53 -0800594 resolvedBindings, RequestKind.INSTANCE, this, types);
595 }
dpb356a6842018-02-07 07:45:50 -0800596
dpb73afb302018-02-12 10:59:53 -0800597 /**
598 * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
599 * {@code get()} on its provider, if there is one.
600 */
601 private Optional<BindingExpression> unscopedDirectInstanceExpression(
602 ResolvedBindings resolvedBindings) {
603 switch (resolvedBindings.contributionBinding().kind()) {
604 case DELEGATE:
605 return Optional.of(
606 new DelegateBindingExpression(
607 resolvedBindings, RequestKind.INSTANCE, this, types, elements));
608
609 case COMPONENT:
610 return Optional.of(
611 new ComponentInstanceBindingExpression(
612 resolvedBindings, generatedComponentModel.name()));
613
614 case COMPONENT_DEPENDENCY:
615 return Optional.of(
616 new ComponentRequirementBindingExpression(
617 resolvedBindings,
618 ComponentRequirement.forDependency(resolvedBindings.key().type()),
619 componentRequirementFields));
620
621 case COMPONENT_PROVISION:
622 return Optional.of(
623 new ComponentProvisionBindingExpression(
624 resolvedBindings, graph, componentRequirementFields, compilerOptions));
625
626 case SUBCOMPONENT_BUILDER:
627 return Optional.of(
628 new SubcomponentBuilderBindingExpression(
629 resolvedBindings, subcomponentNames.get(resolvedBindings.key())));
630
631 case MULTIBOUND_SET:
632 return Optional.of(
633 new SetBindingExpression(resolvedBindings, graph, this, types, elements));
634
635 case MULTIBOUND_MAP:
636 return Optional.of(
637 new MapBindingExpression(resolvedBindings, graph, this, types, elements));
638
639 case OPTIONAL:
640 return Optional.of(new OptionalBindingExpression(resolvedBindings, this, types));
641
642 case BOUND_INSTANCE:
643 return Optional.of(
644 new ComponentRequirementBindingExpression(
645 resolvedBindings,
646 ComponentRequirement.forBoundInstance(resolvedBindings.contributionBinding()),
647 componentRequirementFields));
648
649 case INJECTION:
650 case PROVISION:
651 return Optional.of(
652 new SimpleMethodBindingExpression(
653 resolvedBindings,
654 compilerOptions,
655 this,
656 membersInjectionMethods,
657 componentRequirementFields,
658 elements));
659
660 case MEMBERS_INJECTOR:
661 case RELEASABLE_REFERENCE_MANAGER:
662 case RELEASABLE_REFERENCE_MANAGERS:
663 // TODO(dpb): Implement direct expressions for these.
664 return Optional.empty();
665
666 case MEMBERS_INJECTION:
667 case COMPONENT_PRODUCTION:
668 case PRODUCTION:
669 throw new IllegalArgumentException(
670 resolvedBindings.contributionBinding().kind().toString());
671 }
672 throw new AssertionError();
673 }
674
675 /**
bcorsoaf9e0042018-04-16 14:12:23 -0700676 * Returns {@code true} if the binding should use the static factory creation strategy.
677 *
bcorsod55c02d2018-06-06 15:02:34 -0700678 * In default mode, we always use the static factory creation strategy. In fastInit mode, we
679 * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
680 * however, we allow static factories that can reused across multiple bindings, e.g.
681 * {@code MapFactory} or {@code SetFactory}.
bcorsoaf9e0042018-04-16 14:12:23 -0700682 */
683 private boolean useStaticFactoryCreation(ContributionBinding binding) {
bcorsod55c02d2018-06-06 15:02:34 -0700684 return !(compilerOptions.experimentalAndroidMode2() || compilerOptions.fastInit())
bcorsoaf9e0042018-04-16 14:12:23 -0700685 || binding.kind().equals(MULTIBOUND_MAP)
686 || binding.kind().equals(MULTIBOUND_SET);
687 }
688
689 /**
dpb73afb302018-02-12 10:59:53 -0800690 * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this
691 * binding. If the binding doesn't {@linkplain #needsCaching(ResolvedBindings) need to be cached},
692 * we can.
693 *
bcorsod55c02d2018-06-06 15:02:34 -0700694 * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain
dpb73afb302018-02-12 10:59:53 -0800695 * #needsCaching(ResolvedBindings) needs to be cached} as long as it's not in a
696 * reference-releasing scope.
697 */
698 private boolean canUseDirectInstanceExpression(ResolvedBindings resolvedBindings) {
699 return !needsCaching(resolvedBindings)
bcorsod55c02d2018-06-06 15:02:34 -0700700 || (compilerOptions.fastInit() && !requiresReleasableReferences(resolvedBindings));
dpb73afb302018-02-12 10:59:53 -0800701 }
702
703 /**
dpb73afb302018-02-12 10:59:53 -0800704 * Returns a binding expression that uses a given one as the body of a method that users call. If
705 * a component provision method matches it, it will be the method implemented. If not, a new
706 * private method will be written.
707 */
708 private BindingExpression wrapInMethod(
709 ResolvedBindings resolvedBindings,
710 RequestKind requestKind,
711 BindingExpression bindingExpression) {
712 BindingMethodImplementation methodImplementation =
713 methodImplementation(resolvedBindings, requestKind, bindingExpression);
714
715 return findMatchingComponentMethod(resolvedBindings.key(), requestKind)
716 .<BindingExpression>map(
717 componentMethod ->
718 new ComponentMethodBindingExpression(
dpbd7685762018-02-16 12:20:09 -0800719 methodImplementation, generatedComponentModel, componentMethod))
dpb73afb302018-02-12 10:59:53 -0800720 .orElseGet(
721 () ->
722 new PrivateMethodBindingExpression(
723 resolvedBindings, requestKind, methodImplementation, generatedComponentModel));
724 }
725
726 /** Returns the first component method associated with this request kind, if one exists. */
727 private Optional<ComponentMethodDescriptor> findMatchingComponentMethod(
728 Key key, RequestKind requestKind) {
729 return graph
730 .componentDescriptor()
731 .componentMethods()
732 .stream()
733 .filter(method -> doesComponentMethodMatch(method, key, requestKind))
734 .findFirst();
735 }
736
737 /** Returns true if the component method matches the dependency request binding key and kind. */
738 private boolean doesComponentMethodMatch(
739 ComponentMethodDescriptor componentMethod, Key key, RequestKind requestKind) {
740 return componentMethod
741 .dependencyRequest()
742 .filter(request -> request.key().equals(key))
743 .filter(request -> request.kind().equals(requestKind))
744 .isPresent();
745 }
746
747 private BindingMethodImplementation methodImplementation(
748 ResolvedBindings resolvedBindings,
749 RequestKind requestKind,
750 BindingExpression bindingExpression) {
bcorsod55c02d2018-06-06 15:02:34 -0700751 if (compilerOptions.fastInit()) {
bcorso567ff0e2018-03-21 13:49:09 -0700752 if (requestKind.equals(RequestKind.PROVIDER)) {
753 return new SingleCheckedMethodImplementation(
754 resolvedBindings, requestKind, bindingExpression, types, generatedComponentModel);
755 } else if (requestKind.equals(RequestKind.INSTANCE) && needsCaching(resolvedBindings)) {
756 return resolvedBindings.scope().get().isReusable()
757 ? new SingleCheckedMethodImplementation(
758 resolvedBindings, requestKind, bindingExpression, types, generatedComponentModel)
759 : new DoubleCheckedMethodImplementation(
760 resolvedBindings, requestKind, bindingExpression, types, generatedComponentModel);
761 }
762 }
763
764 return new BindingMethodImplementation(
765 resolvedBindings, requestKind, bindingExpression, generatedComponentModel.name(), types);
dpb73afb302018-02-12 10:59:53 -0800766 }
767
768 /**
769 * Returns {@code true} if the component needs to make sure the provided value is cached.
770 *
771 * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
772 * bindings whose scope is no stronger than their delegate's.
773 */
774 private boolean needsCaching(ResolvedBindings resolvedBindings) {
775 if (!resolvedBindings.scope().isPresent()) {
776 return false;
bcorso3828ca22018-01-29 10:14:12 -0800777 }
dpb73afb302018-02-12 10:59:53 -0800778 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) {
779 return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph);
780 }
781 return true;
782 }
783
bcorsod55c02d2018-06-06 15:02:34 -0700784 // TODO(user): Enable releasable references in fastInit
dpb73afb302018-02-12 10:59:53 -0800785 private boolean requiresReleasableReferences(ResolvedBindings resolvedBindings) {
786 return resolvedBindings.scope().isPresent()
787 && referenceReleasingManagerFields.requiresReleasableReferences(
788 resolvedBindings.scope().get());
dpb68c77d82017-08-15 15:23:35 -0700789 }
790}