blob: f78a0e601475ef6ac581c20628c7551b10197ecb [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;
dstrasburg34eeece2018-08-22 07:49:08 -070021import static com.google.common.base.Preconditions.checkState;
dpb68c77d82017-08-15 15:23:35 -070022import static dagger.internal.codegen.Accessibility.isRawTypeAccessible;
23import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
dpb3db68f02018-01-04 09:15:52 -080024import static dagger.internal.codegen.BindingType.MEMBERS_INJECTION;
25import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
dpb09fb2cb2018-01-29 08:39:33 -080026import static dagger.internal.codegen.DelegateBindingExpression.isBindsScopeStrongerThanDependencyScope;
dpb356a6842018-02-07 07:45:50 -080027import static dagger.internal.codegen.MemberSelect.staticFactoryCreation;
dpb3db68f02018-01-04 09:15:52 -080028import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK;
29import static dagger.internal.codegen.TypeNames.REFERENCE_RELEASING_PROVIDER;
30import static dagger.internal.codegen.TypeNames.SINGLE_CHECK;
dpb09fb2cb2018-01-29 08:39:33 -080031import static dagger.model.BindingKind.DELEGATE;
bcorsoaf9e0042018-04-16 14:12:23 -070032import static dagger.model.BindingKind.MULTIBOUND_MAP;
33import static dagger.model.BindingKind.MULTIBOUND_SET;
dstrasburgcf5e1bc2018-08-09 09:03:38 -070034import static javax.lang.model.element.Modifier.PUBLIC;
dpb68c77d82017-08-15 15:23:35 -070035
dpb3db68f02018-01-04 09:15:52 -080036import com.google.auto.common.MoreTypes;
dpb3db68f02018-01-04 09:15:52 -080037import com.google.common.collect.ImmutableList;
dpb68c77d82017-08-15 15:23:35 -070038import com.squareup.javapoet.ClassName;
bcorsoe643cc62017-10-24 08:57:09 -070039import com.squareup.javapoet.CodeBlock;
dpb02db2132018-01-08 07:20:23 -080040import com.squareup.javapoet.MethodSpec;
bcorso2c279662017-12-01 09:51:18 -080041import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
dpb3db68f02018-01-04 09:15:52 -080042import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
dstrasburg2e206ec2018-08-21 13:00:27 -070043import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
dstrasburg6d2a7ad2018-09-05 08:05:51 -070044import dagger.model.BindingKind;
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;
cgdecker60a5dde2018-09-07 08:44:34 -070048import java.util.HashMap;
49import java.util.Map;
bcorsof0a99fe2017-12-04 10:52:05 -080050import java.util.Optional;
dpb356a6842018-02-07 07:45:50 -080051import javax.inject.Provider;
dpb68c77d82017-08-15 15:23:35 -070052import javax.lang.model.type.TypeMirror;
53
ronshapirodc07ed52017-08-23 08:52:10 -070054/** A central repository of code expressions used to access any binding available to a component. */
dpb68c77d82017-08-15 15:23:35 -070055final class ComponentBindingExpressions {
56
ronshapirodc07ed52017-08-23 08:52:10 -070057 // TODO(dpb,ronshapiro): refactor this and ComponentRequirementFields into a
58 // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
59 // parents? If so, maybe make BindingExpression.Factory create it.
dpb68c77d82017-08-15 15:23:35 -070060
bcorsof0a99fe2017-12-04 10:52:05 -080061 private final Optional<ComponentBindingExpressions> parent;
62 private final BindingGraph graph;
dpb02db2132018-01-08 07:20:23 -080063 private final GeneratedComponentModel generatedComponentModel;
dpb73afb302018-02-12 10:59:53 -080064 private final SubcomponentNames subcomponentNames;
65 private final ComponentRequirementFields componentRequirementFields;
66 private final ReferenceReleasingManagerFields referenceReleasingManagerFields;
67 private final OptionalFactories optionalFactories;
bcorsof0a99fe2017-12-04 10:52:05 -080068 private final DaggerTypes types;
dpbe7b89582018-02-19 08:42:19 -080069 private final DaggerElements elements;
dpb73afb302018-02-12 10:59:53 -080070 private final CompilerOptions compilerOptions;
71 private final MembersInjectionMethods membersInjectionMethods;
bcorsocc739fe2018-04-23 09:16:12 -070072 private final InnerSwitchingProviders innerSwitchingProviders;
73 private final StaticSwitchingProviders staticSwitchingProviders;
cgdecker60a5dde2018-09-07 08:44:34 -070074 private final Map<BindingRequest, BindingExpression> expressions = new HashMap<>();
dpb68c77d82017-08-15 15:23:35 -070075
bcorsof0a99fe2017-12-04 10:52:05 -080076 ComponentBindingExpressions(
77 BindingGraph graph,
78 GeneratedComponentModel generatedComponentModel,
79 SubcomponentNames subcomponentNames,
80 ComponentRequirementFields componentRequirementFields,
81 OptionalFactories optionalFactories,
82 DaggerTypes types,
dpbe7b89582018-02-19 08:42:19 -080083 DaggerElements elements,
bcorsof0a99fe2017-12-04 10:52:05 -080084 CompilerOptions compilerOptions) {
85 this(
86 Optional.empty(),
87 graph,
88 generatedComponentModel,
89 subcomponentNames,
90 componentRequirementFields,
dstrasburgdd036822018-07-23 08:00:37 -070091 new ReferenceReleasingManagerFields(graph, generatedComponentModel, compilerOptions),
bcorsocc739fe2018-04-23 09:16:12 -070092 new StaticSwitchingProviders(generatedComponentModel, types),
bcorsof0a99fe2017-12-04 10:52:05 -080093 optionalFactories,
94 types,
95 elements,
96 compilerOptions);
dpb68c77d82017-08-15 15:23:35 -070097 }
98
bcorsof0a99fe2017-12-04 10:52:05 -080099 private ComponentBindingExpressions(
100 Optional<ComponentBindingExpressions> parent,
101 BindingGraph graph,
102 GeneratedComponentModel generatedComponentModel,
103 SubcomponentNames subcomponentNames,
104 ComponentRequirementFields componentRequirementFields,
105 ReferenceReleasingManagerFields referenceReleasingManagerFields,
bcorsocc739fe2018-04-23 09:16:12 -0700106 StaticSwitchingProviders staticSwitchingProviders,
bcorsof0a99fe2017-12-04 10:52:05 -0800107 OptionalFactories optionalFactories,
108 DaggerTypes types,
dpbe7b89582018-02-19 08:42:19 -0800109 DaggerElements elements,
bcorsof0a99fe2017-12-04 10:52:05 -0800110 CompilerOptions compilerOptions) {
111 this.parent = parent;
112 this.graph = graph;
dpb02db2132018-01-08 07:20:23 -0800113 this.generatedComponentModel = generatedComponentModel;
dpb73afb302018-02-12 10:59:53 -0800114 this.subcomponentNames = checkNotNull(subcomponentNames);
115 this.componentRequirementFields = checkNotNull(componentRequirementFields);
116 this.referenceReleasingManagerFields = checkNotNull(referenceReleasingManagerFields);
117 this.optionalFactories = checkNotNull(optionalFactories);
118 this.types = checkNotNull(types);
119 this.elements = checkNotNull(elements);
120 this.compilerOptions = checkNotNull(compilerOptions);
121 this.membersInjectionMethods =
122 new MembersInjectionMethods(generatedComponentModel, this, graph, elements, types);
bcorsocc739fe2018-04-23 09:16:12 -0700123 this.innerSwitchingProviders =
124 new InnerSwitchingProviders(generatedComponentModel, this, types);
125 this.staticSwitchingProviders = staticSwitchingProviders;
bcorsof0a99fe2017-12-04 10:52:05 -0800126 }
127
128 /**
129 * Returns a new object representing the bindings available from a child component of this one.
130 */
131 ComponentBindingExpressions forChildComponent(
132 BindingGraph childGraph,
133 GeneratedComponentModel childComponentModel,
134 ComponentRequirementFields childComponentRequirementFields) {
135 return new ComponentBindingExpressions(
136 Optional.of(this),
137 childGraph,
138 childComponentModel,
dpb73afb302018-02-12 10:59:53 -0800139 subcomponentNames,
bcorsof0a99fe2017-12-04 10:52:05 -0800140 childComponentRequirementFields,
dpb73afb302018-02-12 10:59:53 -0800141 referenceReleasingManagerFields,
bcorsocc739fe2018-04-23 09:16:12 -0700142 staticSwitchingProviders,
dpb73afb302018-02-12 10:59:53 -0800143 optionalFactories,
144 types,
145 elements,
146 compilerOptions);
dpb68c77d82017-08-15 15:23:35 -0700147 }
148
149 /**
150 * Returns an expression that evaluates to the value of a dependency request for a binding owned
151 * by this component or an ancestor.
152 *
153 * @param requestingClass the class that will contain the expression
154 * @throws IllegalStateException if there is no binding expression that satisfies the dependency
155 * request
156 */
ronshapiro0a277fd2017-12-22 08:30:49 -0800157 Expression getDependencyExpression(Key key, RequestKind requestKind, ClassName requestingClass) {
cgdecker60a5dde2018-09-07 08:44:34 -0700158 return getDependencyExpression(
159 BindingRequest.forDependencyRequest(key, requestKind), requestingClass);
ronshapiroba794862017-09-28 11:39:34 -0700160 }
161
162 /**
163 * Returns an expression that evaluates to the value of a dependency request for a binding owned
164 * by this component or an ancestor.
165 *
166 * @param requestingClass the class that will contain the expression
167 * @throws IllegalStateException if there is no binding expression that satisfies the dependency
168 * request
169 */
170 Expression getDependencyExpression(DependencyRequest request, ClassName requestingClass) {
cgdecker60a5dde2018-09-07 08:44:34 -0700171 return getDependencyExpression(BindingRequest.forDependencyRequest(request), requestingClass);
dpb68c77d82017-08-15 15:23:35 -0700172 }
173
174 /**
175 * Returns an expression that evaluates to the value of a framework dependency for a binding owned
176 * in this component or an ancestor.
177 *
178 * @param requestingClass the class that will contain the expression
179 * @throws IllegalStateException if there is no binding expression that satisfies the dependency
180 * request
181 */
ronshapiroba794862017-09-28 11:39:34 -0700182 Expression getDependencyExpression(
dpb68c77d82017-08-15 15:23:35 -0700183 FrameworkDependency frameworkDependency, ClassName requestingClass) {
ronshapiroba794862017-09-28 11:39:34 -0700184 return getDependencyExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700185 BindingRequest.forFrameworkDependency(frameworkDependency), requestingClass);
186 }
187
188 /**
189 * Returns an expression that evaluates to the value of a framework request for a binding owned by
190 * this component or an ancestor.
191 *
192 * @param requestingClass the class that will contain the expression
193 * @throws IllegalStateException if there is no binding expression that satisfies the framework
194 * request
195 */
196 Expression getDependencyExpression(
197 Key key, FrameworkType frameworkType, ClassName requestingClass) {
198 return getDependencyExpression(
199 BindingRequest.forFrameworkDependency(key, frameworkType), requestingClass);
200 }
201
202 private Expression getDependencyExpression(BindingRequest request, ClassName requestingClass) {
203 return getBindingExpression(request).getDependencyExpression(requestingClass);
dpb68c77d82017-08-15 15:23:35 -0700204 }
205
206 /**
bcorso5db065d2018-04-03 13:49:31 -0700207 * Returns the {@link CodeBlock} for the method argmuments used with the factory {@code create()}
208 * method for the given {@link ContributionBinding binding}.
dpb3db68f02018-01-04 09:15:52 -0800209 */
bcorso5db065d2018-04-03 13:49:31 -0700210 CodeBlock getCreateMethodArgumentsCodeBlock(ContributionBinding binding) {
211 return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding));
212 }
213
214 private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(ContributionBinding binding) {
215 ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
216
217 if (binding.requiresModuleInstance()) {
218 arguments.add(
219 componentRequirementFields.getExpressionDuringInitialization(
220 ComponentRequirement.forModule(binding.contributingModule().get().asType()),
221 generatedComponentModel.name()));
222 }
223
224 binding
225 .frameworkDependencies()
dpb3db68f02018-01-04 09:15:52 -0800226 .stream()
bcorso5db065d2018-04-03 13:49:31 -0700227 .map(dependency -> getDependencyExpression(dependency, generatedComponentModel.name()))
228 .map(Expression::codeBlock)
229 .forEach(arguments::add);
230
231 return arguments.build();
dpb3db68f02018-01-04 09:15:52 -0800232 }
233
234 /**
dpb68c77d82017-08-15 15:23:35 -0700235 * Returns an expression that evaluates to the value of a dependency request, for passing to a
236 * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
237 *
238 * <p>If the method is a generated static {@link InjectionMethods injection method}, each
239 * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
240 * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
241 *
242 * @param requestingClass the class that will contain the expression
243 */
244 // TODO(b/64024402) Merge with getDependencyExpression(DependencyRequest, ClassName) if possible.
ronshapiroba794862017-09-28 11:39:34 -0700245 Expression getDependencyArgumentExpression(
dpb68c77d82017-08-15 15:23:35 -0700246 DependencyRequest dependencyRequest, ClassName requestingClass) {
dpb68c77d82017-08-15 15:23:35 -0700247
248 TypeMirror dependencyType = dependencyRequest.key().type();
ronshapiroba794862017-09-28 11:39:34 -0700249 Expression dependencyExpression = getDependencyExpression(dependencyRequest, requestingClass);
250
bcorsoaaffd2d2018-04-16 14:44:42 -0700251 if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
252 && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
dpb68c77d82017-08-15 15:23:35 -0700253 && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
ronshapiroba794862017-09-28 11:39:34 -0700254 return dependencyExpression.castTo(types.erasure(dependencyType));
dpb68c77d82017-08-15 15:23:35 -0700255 }
256
ronshapiroba794862017-09-28 11:39:34 -0700257 return dependencyExpression;
dpb68c77d82017-08-15 15:23:35 -0700258 }
259
dstrasburg34eeece2018-08-22 07:49:08 -0700260 /**
261 * Returns the implementation of a component method. Returns {@link Optional#empty} if the
262 * component method implementation should not be emitted.
263 */
264 Optional<MethodSpec> getComponentMethod(ComponentMethodDescriptor componentMethod) {
dpb02db2132018-01-08 07:20:23 -0800265 checkArgument(componentMethod.dependencyRequest().isPresent());
cgdecker60a5dde2018-09-07 08:44:34 -0700266 BindingRequest request =
267 BindingRequest.forDependencyRequest(componentMethod.dependencyRequest().get());
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700268 MethodSpec method =
dstrasburg34eeece2018-08-22 07:49:08 -0700269 MethodSpec.overriding(
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700270 componentMethod.methodElement(),
271 MoreTypes.asDeclared(graph.componentType().asType()),
272 types)
273 .addCode(
cgdecker60a5dde2018-09-07 08:44:34 -0700274 getBindingExpression(request)
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700275 .getComponentMethodImplementation(componentMethod, generatedComponentModel))
276 .build();
dstrasburg34eeece2018-08-22 07:49:08 -0700277
cgdecker60a5dde2018-09-07 08:44:34 -0700278 ModifiableBindingType modifiableBindingType = getModifiableBindingType(request);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700279 if (modifiableBindingType.isModifiable()) {
dstrasburg34eeece2018-08-22 07:49:08 -0700280 generatedComponentModel.registerModifiableBindingMethod(
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700281 modifiableBindingType,
cgdecker60a5dde2018-09-07 08:44:34 -0700282 request,
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700283 method,
cgdecker60a5dde2018-09-07 08:44:34 -0700284 newModifiableBindingWillBeFinalized(modifiableBindingType, request));
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700285 if (!modifiableBindingType.hasBaseClassImplementation()) {
dstrasburg34eeece2018-08-22 07:49:08 -0700286 // A component method should not be emitted if it encapsulates a modifiable binding that
287 // cannot be satisfied by the abstract base class implementation of a subcomponent.
288 checkState(
289 !generatedComponentModel.supermodel().isPresent(),
290 "Attempting to generate a component method in a subtype of the abstract subcomponent "
291 + "base class.");
292 return Optional.empty();
293 }
294 }
295
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700296 return Optional.of(method);
bcorso11f9b872017-10-09 16:18:55 -0700297 }
298
dstrasburgcf5e1bc2018-08-09 09:03:38 -0700299 /**
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700300 * Returns the implementation of a modifiable binding method originally defined in a supertype
dstrasburgcf5e1bc2018-08-09 09:03:38 -0700301 * implementation of this subcomponent. Returns {@link Optional#empty()} when the binding cannot
dstrasburg2e206ec2018-08-21 13:00:27 -0700302 * or should not be modified by the current binding graph. This is only relevant for ahead-of-time
dstrasburgcf5e1bc2018-08-09 09:03:38 -0700303 * subcomponents.
304 */
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700305 Optional<ModifiableBindingMethod> getModifiableBindingMethod(
306 ModifiableBindingMethod modifiableBindingMethod) {
307 if (shouldModifyKnownBinding(modifiableBindingMethod)) {
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700308 MethodSpec baseMethod = modifiableBindingMethod.methodSpec();
dstrasburgcf5e1bc2018-08-09 09:03:38 -0700309 return Optional.of(
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700310 ModifiableBindingMethod.implement(
311 modifiableBindingMethod,
312 MethodSpec.methodBuilder(baseMethod.name)
313 .addModifiers(PUBLIC)
314 .returns(baseMethod.returnType)
315 .addAnnotation(Override.class)
316 .addCode(
cgdecker60a5dde2018-09-07 08:44:34 -0700317 getBindingExpression(modifiableBindingMethod.request())
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700318 .getModifiableBindingMethodImplementation(
319 modifiableBindingMethod, generatedComponentModel))
320 .build(),
321 knownModifiableBindingWillBeFinalized(modifiableBindingMethod)));
dstrasburgcf5e1bc2018-08-09 09:03:38 -0700322 }
323 return Optional.empty();
324 }
325
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700326 /**
327 * Returns true if a modifiable binding method that was registered in a superclass implementation
328 * of this subcomponent should be marked as "finalized" if it is being overridden by this
329 * subcomponent implementation. "Finalized" means we should not attempt to modify the binding in
330 * any subcomponent subclass. This is only relevant for ahead-of-time subcomponents.
331 */
332 // TODO(user): extract a ModifiableBindingExpressions class? This may need some dependencies
333 // (like the GCM) but could remove some concerns from this class
334 private boolean knownModifiableBindingWillBeFinalized(
335 ModifiableBindingMethod modifiableBindingMethod) {
336 ModifiableBindingType newModifiableBindingType =
cgdecker60a5dde2018-09-07 08:44:34 -0700337 getModifiableBindingType(modifiableBindingMethod.request());
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700338 if (!newModifiableBindingType.isModifiable()) {
339 // If a modifiable binding has become non-modifiable it is final by definition.
340 return true;
341 }
342 // All currently supported modifiable types are finalized upon modification.
dstrasburg09adeae2018-09-07 12:11:06 -0700343 return modifiableBindingWillBeFinalized(
344 newModifiableBindingType,
345 shouldModifyBinding(newModifiableBindingType, modifiableBindingMethod.request()));
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700346 }
347
348 /**
349 * Returns true if a newly discovered modifiable binding method, once it is defined in this
350 * subcomponent implementation, should be marked as "finalized", meaning we should not attempt to
351 * modify the binding in any subcomponent subclass. This is only relevant for ahead-of-time
352 * subcomponents.
353 */
354 private boolean newModifiableBindingWillBeFinalized(
cgdecker60a5dde2018-09-07 08:44:34 -0700355 ModifiableBindingType modifiableBindingType, BindingRequest request) {
dstrasburg09adeae2018-09-07 12:11:06 -0700356 return modifiableBindingWillBeFinalized(
357 modifiableBindingType, shouldModifyBinding(modifiableBindingType, request));
358 }
359
360 /**
361 * Returns true if we shouldn't attempt to further modify a modifiable binding once we complete
362 * the implementation for the current subcomponent.
363 */
364 private boolean modifiableBindingWillBeFinalized(
365 ModifiableBindingType modifiableBindingType, boolean modifyingBinding) {
366 switch (modifiableBindingType) {
367 case MISSING:
368 case GENERATED_INSTANCE:
369 case OPTIONAL:
370 // Once we modify any of the above a single time, then they are finalized.
371 return modifyingBinding;
372 case MULTIBINDING:
373 return false;
374 default:
375 throw new IllegalStateException(
376 String.format(
377 "Building binding expression for unsupported ModifiableBindingType [%s].",
378 modifiableBindingType));
379 }
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700380 }
381
cgdecker60a5dde2018-09-07 08:44:34 -0700382 private BindingExpression getBindingExpression(BindingRequest request) {
383 if (expressions.containsKey(request)) {
384 return expressions.get(request);
bcorsof0a99fe2017-12-04 10:52:05 -0800385 }
dstrasburg4f902cf2018-07-30 08:42:57 -0700386 Optional<BindingExpression> expression = Optional.empty();
cgdecker60a5dde2018-09-07 08:44:34 -0700387 ModifiableBindingType modifiableBindingType = getModifiableBindingType(request);
dstrasburg2e206ec2018-08-21 13:00:27 -0700388 if (modifiableBindingType.isModifiable()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700389 expression = Optional.of(createModifiableBindingExpression(modifiableBindingType, request));
390 } else if (resolvedInThisComponent(request)) {
391 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
392 expression = Optional.of(createBindingExpression(resolvedBindings, request));
dstrasburg4f902cf2018-07-30 08:42:57 -0700393 }
394 if (expression.isPresent()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700395 expressions.put(request, expression.get());
dstrasburg4f902cf2018-07-30 08:42:57 -0700396 return expression.get();
397 }
cgdecker60a5dde2018-09-07 08:44:34 -0700398 checkArgument(parent.isPresent(), "no expression found for %s", request);
399 return parent.get().getBindingExpression(request);
bcorsof0a99fe2017-12-04 10:52:05 -0800400 }
401
dpb73afb302018-02-12 10:59:53 -0800402 /** Creates a binding expression. */
403 private BindingExpression createBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700404 ResolvedBindings resolvedBindings, BindingRequest request) {
dpb73afb302018-02-12 10:59:53 -0800405 switch (resolvedBindings.bindingType()) {
406 case MEMBERS_INJECTION:
cgdecker60a5dde2018-09-07 08:44:34 -0700407 checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION));
ronshapiro9288a972018-02-14 06:02:12 -0800408 return new MembersInjectionBindingExpression(resolvedBindings, membersInjectionMethods);
bcorsof0a99fe2017-12-04 10:52:05 -0800409
dpb73afb302018-02-12 10:59:53 -0800410 case PROVISION:
cgdecker60a5dde2018-09-07 08:44:34 -0700411 return provisionBindingExpression(resolvedBindings, request);
dpb73afb302018-02-12 10:59:53 -0800412
413 case PRODUCTION:
cgdecker60a5dde2018-09-07 08:44:34 -0700414 return productionBindingExpression(resolvedBindings, request);
dpb73afb302018-02-12 10:59:53 -0800415
416 default:
417 throw new AssertionError(resolvedBindings);
bcorsof0a99fe2017-12-04 10:52:05 -0800418 }
dpb73afb302018-02-12 10:59:53 -0800419 }
bcorsof0a99fe2017-12-04 10:52:05 -0800420
dpb73afb302018-02-12 10:59:53 -0800421 /**
dstrasburg2e206ec2018-08-21 13:00:27 -0700422 * Creates a binding expression for a binding that may be modified across implementations of a
423 * subcomponent. This is only relevant for ahead-of-time subcomponents.
dstrasburg4f902cf2018-07-30 08:42:57 -0700424 */
dstrasburg2e206ec2018-08-21 13:00:27 -0700425 private BindingExpression createModifiableBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700426 ModifiableBindingType type, BindingRequest request) {
427 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700428 Optional<ModifiableBindingMethod> matchingModifiableBindingMethod =
cgdecker60a5dde2018-09-07 08:44:34 -0700429 generatedComponentModel.getModifiableBindingMethod(request);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700430 Optional<ComponentMethodDescriptor> matchingComponentMethod =
cgdecker60a5dde2018-09-07 08:44:34 -0700431 findMatchingComponentMethod(request);
dstrasburg2e206ec2018-08-21 13:00:27 -0700432 switch (type) {
433 case GENERATED_INSTANCE:
dstrasburg2e206ec2018-08-21 13:00:27 -0700434 return new GeneratedInstanceBindingExpression(
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700435 generatedComponentModel,
436 resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700437 request,
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700438 matchingModifiableBindingMethod,
439 matchingComponentMethod);
dstrasburg2e206ec2018-08-21 13:00:27 -0700440 case MISSING:
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700441 return new MissingBindingExpression(
442 generatedComponentModel,
cgdecker60a5dde2018-09-07 08:44:34 -0700443 request,
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700444 matchingModifiableBindingMethod,
445 matchingComponentMethod);
446 case OPTIONAL:
dstrasburg09adeae2018-09-07 12:11:06 -0700447 case MULTIBINDING:
448 return wrapInMethod(
449 resolvedBindings, request, createBindingExpression(resolvedBindings, request));
dstrasburg2e206ec2018-08-21 13:00:27 -0700450 default:
451 throw new IllegalStateException(
452 String.format(
453 "Building binding expression for unsupported ModifiableBindingType [%s].", type));
454 }
455 }
456
457 /**
458 * The reason why a binding may need to be modified across implementations of a subcomponent, if
459 * at all. This is only relevant for ahead-of-time subcomponents.
460 */
cgdecker60a5dde2018-09-07 08:44:34 -0700461 private ModifiableBindingType getModifiableBindingType(BindingRequest request) {
dstrasburg2e206ec2018-08-21 13:00:27 -0700462 if (!compilerOptions.aheadOfTimeSubcomponents()) {
463 return ModifiableBindingType.NONE;
464 }
465
466 // When generating a final (concrete) implementation of a (sub)component the binding is no
467 // longer considered modifiable. It cannot be further modified by a subclass implementation.
468 if (!generatedComponentModel.isAbstract()) {
469 return ModifiableBindingType.NONE;
470 }
471
cgdecker60a5dde2018-09-07 08:44:34 -0700472 if (resolvedInThisComponent(request)) {
473 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
dstrasburg2e206ec2018-08-21 13:00:27 -0700474 if (resolvedBindings.contributionBindings().isEmpty()) {
475 // TODO(ronshapiro): Confirm whether a resolved binding must have a single contribution
476 // binding.
477 return ModifiableBindingType.NONE;
478 }
479
480 ContributionBinding binding = resolvedBindings.contributionBinding();
481 if (binding.requiresGeneratedInstance()) {
482 return ModifiableBindingType.GENERATED_INSTANCE;
483 }
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700484
485 if (binding.kind().equals(BindingKind.OPTIONAL)) {
486 return ModifiableBindingType.OPTIONAL;
487 }
dstrasburg09adeae2018-09-07 12:11:06 -0700488
489 if (resolvedBindings.bindingType().equals(BindingType.PROVISION)
490 && binding.isSyntheticMultibinding()) {
491 return ModifiableBindingType.MULTIBINDING;
492 }
cgdecker60a5dde2018-09-07 08:44:34 -0700493 } else if (!resolvableBinding(request)) {
dstrasburg2e206ec2018-08-21 13:00:27 -0700494 return ModifiableBindingType.MISSING;
495 }
496
497 // TODO(b/72748365): Add support for remaining types.
498 return ModifiableBindingType.NONE;
499 }
500
501 /**
502 * Returns true if the current binding graph can, and should, modify a binding by overriding a
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700503 * modifiable binding method. This is only relevant for ahead-of-time subcomponents.
dstrasburg2e206ec2018-08-21 13:00:27 -0700504 */
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700505 private boolean shouldModifyKnownBinding(ModifiableBindingMethod modifiableBindingMethod) {
506 ModifiableBindingType newModifiableBindingType =
cgdecker60a5dde2018-09-07 08:44:34 -0700507 getModifiableBindingType(modifiableBindingMethod.request());
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700508 if (!newModifiableBindingType.equals(modifiableBindingMethod.type())) {
509 // It is possible that a binding can change types, in which case we should always modify the
510 // binding.
511 return true;
512 }
cgdecker60a5dde2018-09-07 08:44:34 -0700513 return shouldModifyBinding(modifiableBindingMethod.type(), modifiableBindingMethod.request());
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700514 }
515
516 /**
517 * Returns true if the current binding graph can, and should, modify a binding by overriding a
518 * modifiable binding method. This is only relevant for ahead-of-time subcomponents.
519 */
520 private boolean shouldModifyBinding(
cgdecker60a5dde2018-09-07 08:44:34 -0700521 ModifiableBindingType modifiableBindingType, BindingRequest request) {
dstrasburg09adeae2018-09-07 12:11:06 -0700522 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700523 switch (modifiableBindingType) {
dstrasburg2e206ec2018-08-21 13:00:27 -0700524 case GENERATED_INSTANCE:
525 return !generatedComponentModel.isAbstract();
526 case MISSING:
527 // TODO(b/72748365): investigate beder@'s comment about having intermediate component
528 // ancestors satisfy missing bindings of their children with their own missing binding
529 // methods so that we can minimize the cases where we need to reach into doubly-nested
530 // descendant component implementations
cgdecker60a5dde2018-09-07 08:44:34 -0700531 return resolvableBinding(request);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700532 case OPTIONAL:
533 // Only override optional binding methods if we have a non-empty binding.
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700534 return !resolvedBindings.contributionBinding().dependencies().isEmpty();
dstrasburg09adeae2018-09-07 12:11:06 -0700535 case MULTIBINDING:
536 // Only modify a multibinding if there are new contributions.
537 return !generatedComponentModel
538 .superclassContributionsMade(request.key())
539 .containsAll(resolvedBindings.contributionBinding().dependencies());
dstrasburg2e206ec2018-08-21 13:00:27 -0700540 default:
541 throw new IllegalStateException(
542 String.format(
543 "Overriding modifiable binding method with unsupported ModifiableBindingType [%s].",
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700544 modifiableBindingType));
dstrasburg2e206ec2018-08-21 13:00:27 -0700545 }
dstrasburg4f902cf2018-07-30 08:42:57 -0700546 }
547
548 /**
549 * Returns true if the binding can be resolved by the graph for this component or any parent
550 * component.
551 */
cgdecker60a5dde2018-09-07 08:44:34 -0700552 private boolean resolvableBinding(BindingRequest request) {
dstrasburg4f902cf2018-07-30 08:42:57 -0700553 for (ComponentBindingExpressions expressions = this;
554 expressions != null;
555 expressions = expressions.parent.orElse(null)) {
cgdecker60a5dde2018-09-07 08:44:34 -0700556 if (expressions.resolvedInThisComponent(request)) {
dstrasburg4f902cf2018-07-30 08:42:57 -0700557 return true;
558 }
559 }
560 return false;
561 }
562
563 /** Returns true if the binding can be resolved by the graph for this component. */
cgdecker60a5dde2018-09-07 08:44:34 -0700564 private boolean resolvedInThisComponent(BindingRequest request) {
565 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
dstrasburg4f902cf2018-07-30 08:42:57 -0700566 return resolvedBindings != null && !resolvedBindings.ownedBindings().isEmpty();
567 }
568
569 /**
dpb73afb302018-02-12 10:59:53 -0800570 * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
571 * or a {@link dagger.producers.Producer} for production bindings.
572 */
573 private FrameworkInstanceBindingExpression frameworkInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700574 ResolvedBindings resolvedBindings) {
bcorsoaf9e0042018-04-16 14:12:23 -0700575 // TODO(user): Consider merging the static factory creation logic into CreationExpressions?
576 Optional<MemberSelect> staticMethod =
577 useStaticFactoryCreation(resolvedBindings.contributionBinding())
578 ? staticFactoryCreation(resolvedBindings)
579 : Optional.empty();
dpb73afb302018-02-12 10:59:53 -0800580 FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
581 resolvedBindings.scope().isPresent()
582 ? scope(resolvedBindings, frameworkInstanceCreationExpression(resolvedBindings))
583 : frameworkInstanceCreationExpression(resolvedBindings);
cgdecker0bc05be2018-08-10 12:37:36 -0700584 FrameworkInstanceSupplier frameworkInstanceSupplier =
dpb73afb302018-02-12 10:59:53 -0800585 staticMethod.isPresent()
586 ? staticMethod::get
587 : new FrameworkFieldInitializer(
cgdecker0bc05be2018-08-10 12:37:36 -0700588 generatedComponentModel, resolvedBindings, frameworkInstanceCreationExpression);
589
dpbdb197502018-08-27 14:29:47 -0700590 switch (resolvedBindings.bindingType()) {
591 case PROVISION:
cgdecker0bc05be2018-08-10 12:37:36 -0700592 return new ProviderInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700593 resolvedBindings, frameworkInstanceSupplier, types, elements);
dpbdb197502018-08-27 14:29:47 -0700594 case PRODUCTION:
cgdecker0bc05be2018-08-10 12:37:36 -0700595 return new ProducerInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700596 resolvedBindings, frameworkInstanceSupplier, types, elements);
cgdecker0bc05be2018-08-10 12:37:36 -0700597 default:
dpbdb197502018-08-27 14:29:47 -0700598 throw new AssertionError("invalid binding type: " + resolvedBindings.bindingType());
cgdecker0bc05be2018-08-10 12:37:36 -0700599 }
dpb73afb302018-02-12 10:59:53 -0800600 }
dpb64861842017-12-12 08:17:18 -0800601
dpb73afb302018-02-12 10:59:53 -0800602 private FrameworkInstanceCreationExpression scope(
603 ResolvedBindings resolvedBindings, FrameworkInstanceCreationExpression unscoped) {
604 if (requiresReleasableReferences(resolvedBindings)) {
605 return () ->
606 CodeBlock.of(
607 "$T.create($L, $L)",
608 REFERENCE_RELEASING_PROVIDER,
609 unscoped.creationExpression(),
610 referenceReleasingManagerFields.getExpression(
611 resolvedBindings.scope().get(), generatedComponentModel.name()));
612 } else {
613 return () ->
614 CodeBlock.of(
615 "$T.provider($L)",
616 resolvedBindings.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
617 unscoped.creationExpression());
dpb64861842017-12-12 08:17:18 -0800618 }
dpb73afb302018-02-12 10:59:53 -0800619 }
dpb64861842017-12-12 08:17:18 -0800620
dpb73afb302018-02-12 10:59:53 -0800621 /**
622 * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
623 * {@link dagger.producers.Producer} for production bindings.
624 */
625 private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
626 ResolvedBindings resolvedBindings) {
627 checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
628 ContributionBinding binding = resolvedBindings.contributionBinding();
629 switch (binding.kind()) {
630 case COMPONENT:
631 // The cast can be removed when we drop java 7 source support
632 return new InstanceFactoryCreationExpression(
633 () -> CodeBlock.of("($T) this", binding.key().type()));
dpb64861842017-12-12 08:17:18 -0800634
dpb73afb302018-02-12 10:59:53 -0800635 case BOUND_INSTANCE:
636 return instanceFactoryCreationExpression(
637 binding, ComponentRequirement.forBoundInstance(binding));
bcorsof0a99fe2017-12-04 10:52:05 -0800638
dpb73afb302018-02-12 10:59:53 -0800639 case COMPONENT_DEPENDENCY:
640 return instanceFactoryCreationExpression(
641 binding, ComponentRequirement.forDependency(binding.key().type()));
dpb3db68f02018-01-04 09:15:52 -0800642
dpb73afb302018-02-12 10:59:53 -0800643 case COMPONENT_PROVISION:
644 return new DependencyMethodProviderCreationExpression(
645 binding, generatedComponentModel, componentRequirementFields, compilerOptions, graph);
dpb3db68f02018-01-04 09:15:52 -0800646
dpb73afb302018-02-12 10:59:53 -0800647 case SUBCOMPONENT_BUILDER:
648 return new SubcomponentBuilderProviderCreationExpression(
649 binding.key().type(), subcomponentNames.get(binding.key()));
dpb356a6842018-02-07 07:45:50 -0800650
dpb73afb302018-02-12 10:59:53 -0800651 case INJECTION:
652 case PROVISION:
bcorsocc739fe2018-04-23 09:16:12 -0700653 return compilerOptions.experimentalAndroidMode2()
654 ? staticSwitchingProviders.newCreationExpression(binding, this)
655 : new InjectionOrProvisionProviderCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800656
dpb73afb302018-02-12 10:59:53 -0800657 case COMPONENT_PRODUCTION:
658 return new DependencyMethodProducerCreationExpression(
659 binding, generatedComponentModel, componentRequirementFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800660
dpb73afb302018-02-12 10:59:53 -0800661 case PRODUCTION:
bcorso5db065d2018-04-03 13:49:31 -0700662 return new ProducerCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800663
dpb73afb302018-02-12 10:59:53 -0800664 case MULTIBOUND_SET:
665 return new SetFactoryCreationExpression(binding, generatedComponentModel, this, graph);
dpb3db68f02018-01-04 09:15:52 -0800666
dpb73afb302018-02-12 10:59:53 -0800667 case MULTIBOUND_MAP:
ronshapiro3a089642018-07-17 15:39:40 -0700668 return new MapFactoryCreationExpression(
669 binding, generatedComponentModel, this, graph, elements);
dpb3db68f02018-01-04 09:15:52 -0800670
dpb73afb302018-02-12 10:59:53 -0800671 case RELEASABLE_REFERENCE_MANAGER:
672 return new ReleasableReferenceManagerProviderCreationExpression(
673 binding, generatedComponentModel, referenceReleasingManagerFields);
dpb3db68f02018-01-04 09:15:52 -0800674
dpb73afb302018-02-12 10:59:53 -0800675 case RELEASABLE_REFERENCE_MANAGERS:
676 return new ReleasableReferenceManagerSetProviderCreationExpression(
677 binding, generatedComponentModel, referenceReleasingManagerFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800678
dpb73afb302018-02-12 10:59:53 -0800679 case DELEGATE:
680 return new DelegatingFrameworkInstanceCreationExpression(
681 binding, generatedComponentModel, this);
dpb3db68f02018-01-04 09:15:52 -0800682
dpb73afb302018-02-12 10:59:53 -0800683 case OPTIONAL:
ronshapiroe6740762018-05-01 08:37:26 -0700684 return new OptionalFactoryInstanceCreationExpression(
685 optionalFactories, binding, generatedComponentModel, this);
dpb356a6842018-02-07 07:45:50 -0800686
dpb73afb302018-02-12 10:59:53 -0800687 case MEMBERS_INJECTOR:
ronshapiroe6740762018-05-01 08:37:26 -0700688 return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
dpb73afb302018-02-12 10:59:53 -0800689
690 default:
691 throw new AssertionError(binding);
692 }
693 }
694
695 private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
696 ContributionBinding binding, ComponentRequirement componentRequirement) {
697 return new InstanceFactoryCreationExpression(
698 binding.nullableType().isPresent(),
699 () ->
700 componentRequirementFields.getExpressionDuringInitialization(
701 componentRequirement, generatedComponentModel.name()));
702 }
703
704 /** Returns a binding expression for a provision binding. */
705 private BindingExpression provisionBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700706 ResolvedBindings resolvedBindings, BindingRequest request) {
707 // All provision requests should have an associated RequestKind, even if they're a framework
708 // request.
709 checkArgument(request.requestKind().isPresent());
710 RequestKind requestKind = request.requestKind().get();
dpb73afb302018-02-12 10:59:53 -0800711 switch (requestKind) {
dpb73afb302018-02-12 10:59:53 -0800712 case INSTANCE:
713 return instanceBindingExpression(resolvedBindings);
714
ronshapiro62c8d5c2018-05-10 09:06:48 -0700715 case PROVIDER:
716 return providerBindingExpression(resolvedBindings);
dpb73afb302018-02-12 10:59:53 -0800717
718 case LAZY:
719 case PRODUCED:
720 case PROVIDER_OF_LAZY:
dpb5e03bd52018-08-10 14:21:15 -0700721 return new DerivedFromFrameworkInstanceBindingExpression(
dpbdb197502018-08-27 14:29:47 -0700722 resolvedBindings, FrameworkType.PROVIDER, requestKind, this, types);
dpb73afb302018-02-12 10:59:53 -0800723
ronshapiro62c8d5c2018-05-10 09:06:48 -0700724 case PRODUCER:
dpb5e03bd52018-08-10 14:21:15 -0700725 return producerFromProviderBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700726
727 case FUTURE:
728 return new ImmediateFutureBindingExpression(resolvedBindings, this, types);
dpb73afb302018-02-12 10:59:53 -0800729
730 case MEMBERS_INJECTION:
731 throw new IllegalArgumentException();
dpb356a6842018-02-07 07:45:50 -0800732 }
733
dpb73afb302018-02-12 10:59:53 -0800734 throw new AssertionError();
735 }
dpb356a6842018-02-07 07:45:50 -0800736
cgdecker60a5dde2018-09-07 08:44:34 -0700737 /** Returns a binding expression for a production binding. */
738 private BindingExpression productionBindingExpression(
739 ResolvedBindings resolvedBindings, BindingRequest request) {
740 if (request.frameworkType().isPresent()) {
741 return frameworkInstanceBindingExpression(resolvedBindings);
742 } else {
743 // If no FrameworkType is present, a RequestKind is guaranteed to be present.
744 return new DerivedFromFrameworkInstanceBindingExpression(
745 resolvedBindings, FrameworkType.PRODUCER, request.requestKind().get(), this, types);
746 }
747 }
748
dpb73afb302018-02-12 10:59:53 -0800749 /**
ronshapiro62c8d5c2018-05-10 09:06:48 -0700750 * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
751 *
752 * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ResolvedBindings) need to be
753 * cached} can use a {@link DelegateBindingExpression}.
754 *
bcorsod55c02d2018-06-06 15:02:34 -0700755 * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
756 * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
757 * which case, just use that Provider directly).
ronshapiro62c8d5c2018-05-10 09:06:48 -0700758 *
759 * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
760 */
761 private BindingExpression providerBindingExpression(ResolvedBindings resolvedBindings) {
762 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)
763 && !needsCaching(resolvedBindings)) {
764 return new DelegateBindingExpression(
765 resolvedBindings, RequestKind.PROVIDER, this, types, elements);
bcorsod55c02d2018-06-06 15:02:34 -0700766 } else if (compilerOptions.fastInit()
ronshapiro62c8d5c2018-05-10 09:06:48 -0700767 && frameworkInstanceCreationExpression(resolvedBindings).useInnerSwitchingProvider()
768 && !(instanceBindingExpression(resolvedBindings)
dpb5e03bd52018-08-10 14:21:15 -0700769 instanceof DerivedFromFrameworkInstanceBindingExpression)) {
ronshapiro62c8d5c2018-05-10 09:06:48 -0700770 return wrapInMethod(
771 resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700772 BindingRequest.forDependencyRequest(resolvedBindings.key(), RequestKind.PROVIDER),
ronshapiro62c8d5c2018-05-10 09:06:48 -0700773 innerSwitchingProviders.newBindingExpression(resolvedBindings.contributionBinding()));
774 }
dpb5e03bd52018-08-10 14:21:15 -0700775 return frameworkInstanceBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700776 }
777
778 /**
dpb73afb302018-02-12 10:59:53 -0800779 * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
780 * provision binding.
781 */
782 private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700783 ResolvedBindings resolvedBindings) {
dpbdb197502018-08-27 14:29:47 -0700784 checkArgument(resolvedBindings.bindingType().equals(BindingType.PROVISION));
cgdecker0bc05be2018-08-10 12:37:36 -0700785 return new ProducerInstanceBindingExpression(
dpb73afb302018-02-12 10:59:53 -0800786 resolvedBindings,
dpb73afb302018-02-12 10:59:53 -0800787 new FrameworkFieldInitializer(
788 generatedComponentModel,
789 resolvedBindings,
790 new ProducerFromProviderCreationExpression(
791 resolvedBindings.contributionBinding(), generatedComponentModel, this)),
792 types,
793 elements);
794 }
dpb356a6842018-02-07 07:45:50 -0800795
dpb73afb302018-02-12 10:59:53 -0800796 /**
797 * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
798 *
799 * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an
800 * instance of this binding, return it, wrapped in a method if the binding {@linkplain
801 * #needsCaching(ResolvedBindings) needs to be cached} or the expression has dependencies.
802 *
803 * <p>In default mode, we can use direct expressions for bindings that don't need to be cached in
804 * a reference-releasing scope.
805 *
bcorsod55c02d2018-06-06 15:02:34 -0700806 * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached.
dpb73afb302018-02-12 10:59:53 -0800807 */
808 private BindingExpression instanceBindingExpression(ResolvedBindings resolvedBindings) {
809 Optional<BindingExpression> maybeDirectInstanceExpression =
810 unscopedDirectInstanceExpression(resolvedBindings);
811 if (canUseDirectInstanceExpression(resolvedBindings)
812 && maybeDirectInstanceExpression.isPresent()) {
813 BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
814 return directInstanceExpression.requiresMethodEncapsulation()
815 || needsCaching(resolvedBindings)
cgdecker60a5dde2018-09-07 08:44:34 -0700816 ? wrapInMethod(
817 resolvedBindings,
818 BindingRequest.forDependencyRequest(resolvedBindings.key(), RequestKind.INSTANCE),
819 directInstanceExpression)
dpb73afb302018-02-12 10:59:53 -0800820 : directInstanceExpression;
dpb356a6842018-02-07 07:45:50 -0800821 }
dpb5e03bd52018-08-10 14:21:15 -0700822 return new DerivedFromFrameworkInstanceBindingExpression(
dpbdb197502018-08-27 14:29:47 -0700823 resolvedBindings, FrameworkType.PROVIDER, RequestKind.INSTANCE, this, types);
dpb73afb302018-02-12 10:59:53 -0800824 }
dpb356a6842018-02-07 07:45:50 -0800825
dpb73afb302018-02-12 10:59:53 -0800826 /**
827 * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
828 * {@code get()} on its provider, if there is one.
829 */
830 private Optional<BindingExpression> unscopedDirectInstanceExpression(
831 ResolvedBindings resolvedBindings) {
832 switch (resolvedBindings.contributionBinding().kind()) {
833 case DELEGATE:
834 return Optional.of(
835 new DelegateBindingExpression(
836 resolvedBindings, RequestKind.INSTANCE, this, types, elements));
837
838 case COMPONENT:
839 return Optional.of(
840 new ComponentInstanceBindingExpression(
841 resolvedBindings, generatedComponentModel.name()));
842
843 case COMPONENT_DEPENDENCY:
844 return Optional.of(
845 new ComponentRequirementBindingExpression(
846 resolvedBindings,
847 ComponentRequirement.forDependency(resolvedBindings.key().type()),
848 componentRequirementFields));
849
850 case COMPONENT_PROVISION:
851 return Optional.of(
852 new ComponentProvisionBindingExpression(
853 resolvedBindings, graph, componentRequirementFields, compilerOptions));
854
855 case SUBCOMPONENT_BUILDER:
856 return Optional.of(
857 new SubcomponentBuilderBindingExpression(
858 resolvedBindings, subcomponentNames.get(resolvedBindings.key())));
859
860 case MULTIBOUND_SET:
861 return Optional.of(
dstrasburg09adeae2018-09-07 12:11:06 -0700862 new SetBindingExpression(
863 resolvedBindings, generatedComponentModel, graph, this, types, elements));
dpb73afb302018-02-12 10:59:53 -0800864
865 case MULTIBOUND_MAP:
866 return Optional.of(
dstrasburg09adeae2018-09-07 12:11:06 -0700867 new MapBindingExpression(
868 resolvedBindings, generatedComponentModel, graph, this, types, elements));
dpb73afb302018-02-12 10:59:53 -0800869
870 case OPTIONAL:
871 return Optional.of(new OptionalBindingExpression(resolvedBindings, this, types));
872
873 case BOUND_INSTANCE:
874 return Optional.of(
875 new ComponentRequirementBindingExpression(
876 resolvedBindings,
877 ComponentRequirement.forBoundInstance(resolvedBindings.contributionBinding()),
878 componentRequirementFields));
879
880 case INJECTION:
881 case PROVISION:
882 return Optional.of(
883 new SimpleMethodBindingExpression(
884 resolvedBindings,
885 compilerOptions,
886 this,
887 membersInjectionMethods,
888 componentRequirementFields,
889 elements));
890
891 case MEMBERS_INJECTOR:
892 case RELEASABLE_REFERENCE_MANAGER:
893 case RELEASABLE_REFERENCE_MANAGERS:
894 // TODO(dpb): Implement direct expressions for these.
895 return Optional.empty();
896
897 case MEMBERS_INJECTION:
898 case COMPONENT_PRODUCTION:
899 case PRODUCTION:
900 throw new IllegalArgumentException(
901 resolvedBindings.contributionBinding().kind().toString());
902 }
903 throw new AssertionError();
904 }
905
906 /**
bcorsoaf9e0042018-04-16 14:12:23 -0700907 * Returns {@code true} if the binding should use the static factory creation strategy.
908 *
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700909 * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we
bcorsod55c02d2018-06-06 15:02:34 -0700910 * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700911 * however, we allow static factories that can reused across multiple bindings, e.g. {@code
912 * MapFactory} or {@code SetFactory}.
bcorsoaf9e0042018-04-16 14:12:23 -0700913 */
914 private boolean useStaticFactoryCreation(ContributionBinding binding) {
bcorsod55c02d2018-06-06 15:02:34 -0700915 return !(compilerOptions.experimentalAndroidMode2() || compilerOptions.fastInit())
bcorsoaf9e0042018-04-16 14:12:23 -0700916 || binding.kind().equals(MULTIBOUND_MAP)
917 || binding.kind().equals(MULTIBOUND_SET);
918 }
919
920 /**
dpb73afb302018-02-12 10:59:53 -0800921 * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this
922 * binding. If the binding doesn't {@linkplain #needsCaching(ResolvedBindings) need to be cached},
923 * we can.
924 *
bcorsod55c02d2018-06-06 15:02:34 -0700925 * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain
dpb73afb302018-02-12 10:59:53 -0800926 * #needsCaching(ResolvedBindings) needs to be cached} as long as it's not in a
927 * reference-releasing scope.
928 */
929 private boolean canUseDirectInstanceExpression(ResolvedBindings resolvedBindings) {
930 return !needsCaching(resolvedBindings)
bcorsod55c02d2018-06-06 15:02:34 -0700931 || (compilerOptions.fastInit() && !requiresReleasableReferences(resolvedBindings));
dpb73afb302018-02-12 10:59:53 -0800932 }
933
934 /**
dpb73afb302018-02-12 10:59:53 -0800935 * Returns a binding expression that uses a given one as the body of a method that users call. If
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700936 * a component provision method matches it, it will be the method implemented. If it does not
937 * match a component provision method and the binding is modifiable the a new public modifiable
938 * binding method will be written. If the binding doesn't match a component method nor is it
939 * modifiable, then a new private method will be written.
dpb73afb302018-02-12 10:59:53 -0800940 */
941 private BindingExpression wrapInMethod(
942 ResolvedBindings resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700943 BindingRequest request,
dpb73afb302018-02-12 10:59:53 -0800944 BindingExpression bindingExpression) {
dstrasburg09adeae2018-09-07 12:11:06 -0700945 // If we've already wrapped the expression, then use the delegate.
946 if (bindingExpression instanceof MethodBindingExpression) {
947 return bindingExpression;
948 }
949
dpb73afb302018-02-12 10:59:53 -0800950 BindingMethodImplementation methodImplementation =
cgdecker60a5dde2018-09-07 08:44:34 -0700951 methodImplementation(resolvedBindings, request, bindingExpression);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700952 Optional<ComponentMethodDescriptor> matchingComponentMethod =
cgdecker60a5dde2018-09-07 08:44:34 -0700953 findMatchingComponentMethod(request);
dpb73afb302018-02-12 10:59:53 -0800954
cgdecker60a5dde2018-09-07 08:44:34 -0700955 ModifiableBindingType modifiableBindingType = getModifiableBindingType(request);
dstrasburg09adeae2018-09-07 12:11:06 -0700956 if (shouldUseAModifiableConcreteMethodBindingExpression(
957 modifiableBindingType, matchingComponentMethod)) {
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700958 return new ModifiableConcreteMethodBindingExpression(
959 resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700960 request,
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700961 modifiableBindingType,
962 methodImplementation,
963 generatedComponentModel,
cgdecker60a5dde2018-09-07 08:44:34 -0700964 generatedComponentModel.getModifiableBindingMethod(request),
965 newModifiableBindingWillBeFinalized(modifiableBindingType, request));
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700966 }
967
968 return matchingComponentMethod
dpb73afb302018-02-12 10:59:53 -0800969 .<BindingExpression>map(
970 componentMethod ->
971 new ComponentMethodBindingExpression(
dpbd7685762018-02-16 12:20:09 -0800972 methodImplementation, generatedComponentModel, componentMethod))
dpb73afb302018-02-12 10:59:53 -0800973 .orElseGet(
974 () ->
975 new PrivateMethodBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700976 resolvedBindings, request, methodImplementation, generatedComponentModel));
dpb73afb302018-02-12 10:59:53 -0800977 }
978
dstrasburg09adeae2018-09-07 12:11:06 -0700979 /**
980 * Returns true if we should wrap a binding expression using a {@link
981 * ModifiableConcreteMethodBindingExpression}. If we're generating the abstract base class of a
982 * subcomponent and the binding matches a component method, even if it is modifiable, then it
983 * should be "wrapped" by a {@link ComponentMethodBindingExpression}. If it isn't a base class
984 * then modifiable methods should be handled by a {@link
985 * ModifiableConcreteMethodBindingExpression}. When generating an inner subcomponent it doesn't
986 * matter whether the binding matches a component method: All modifiable bindings should be
987 * handled by a {@link ModifiableConcreteMethodBindingExpression}.
988 */
989 private boolean shouldUseAModifiableConcreteMethodBindingExpression(
990 ModifiableBindingType type, Optional<ComponentMethodDescriptor> matchingComponentMethod) {
991 return type.isModifiable()
992 && (generatedComponentModel.supermodel().isPresent()
993 || !matchingComponentMethod.isPresent());
994 }
995
dpb73afb302018-02-12 10:59:53 -0800996 /** Returns the first component method associated with this request kind, if one exists. */
cgdecker60a5dde2018-09-07 08:44:34 -0700997 private Optional<ComponentMethodDescriptor> findMatchingComponentMethod(BindingRequest request) {
998 return graph.componentDescriptor().componentMethods().stream()
999 .filter(method -> doesComponentMethodMatch(method, request))
dpb73afb302018-02-12 10:59:53 -08001000 .findFirst();
1001 }
1002
cgdecker60a5dde2018-09-07 08:44:34 -07001003 /** Returns true if the component method matches the binding request. */
dpb73afb302018-02-12 10:59:53 -08001004 private boolean doesComponentMethodMatch(
cgdecker60a5dde2018-09-07 08:44:34 -07001005 ComponentMethodDescriptor componentMethod, BindingRequest request) {
dpb73afb302018-02-12 10:59:53 -08001006 return componentMethod
1007 .dependencyRequest()
cgdecker60a5dde2018-09-07 08:44:34 -07001008 .map(BindingRequest::forDependencyRequest)
dstrasburg09adeae2018-09-07 12:11:06 -07001009 .filter(request::equals)
dpb73afb302018-02-12 10:59:53 -08001010 .isPresent();
1011 }
1012
1013 private BindingMethodImplementation methodImplementation(
1014 ResolvedBindings resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -07001015 BindingRequest request,
dpb73afb302018-02-12 10:59:53 -08001016 BindingExpression bindingExpression) {
bcorsod55c02d2018-06-06 15:02:34 -07001017 if (compilerOptions.fastInit()) {
cgdecker60a5dde2018-09-07 08:44:34 -07001018 if (request.isRequestKind(RequestKind.PROVIDER)) {
bcorso567ff0e2018-03-21 13:49:09 -07001019 return new SingleCheckedMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -07001020 resolvedBindings, request, bindingExpression, types, generatedComponentModel);
1021 } else if (request.isRequestKind(RequestKind.INSTANCE) && needsCaching(resolvedBindings)) {
bcorso567ff0e2018-03-21 13:49:09 -07001022 return resolvedBindings.scope().get().isReusable()
1023 ? new SingleCheckedMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -07001024 resolvedBindings, request, bindingExpression, types, generatedComponentModel)
bcorso567ff0e2018-03-21 13:49:09 -07001025 : new DoubleCheckedMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -07001026 resolvedBindings, request, bindingExpression, types, generatedComponentModel);
bcorso567ff0e2018-03-21 13:49:09 -07001027 }
1028 }
1029
1030 return new BindingMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -07001031 resolvedBindings, request, bindingExpression, generatedComponentModel.name(), types);
dpb73afb302018-02-12 10:59:53 -08001032 }
1033
1034 /**
1035 * Returns {@code true} if the component needs to make sure the provided value is cached.
1036 *
1037 * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
1038 * bindings whose scope is no stronger than their delegate's.
1039 */
1040 private boolean needsCaching(ResolvedBindings resolvedBindings) {
1041 if (!resolvedBindings.scope().isPresent()) {
1042 return false;
bcorso3828ca22018-01-29 10:14:12 -08001043 }
dpb73afb302018-02-12 10:59:53 -08001044 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) {
1045 return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph);
1046 }
1047 return true;
1048 }
1049
bcorsod55c02d2018-06-06 15:02:34 -07001050 // TODO(user): Enable releasable references in fastInit
dpb73afb302018-02-12 10:59:53 -08001051 private boolean requiresReleasableReferences(ResolvedBindings resolvedBindings) {
1052 return resolvedBindings.scope().isPresent()
1053 && referenceReleasingManagerFields.requiresReleasableReferences(
1054 resolvedBindings.scope().get());
dpb68c77d82017-08-15 15:23:35 -07001055 }
1056}