blob: 91a0cd0b7623aa9536967a9d0b0c9c5797088388 [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;
cgdeckerea48dfd2018-10-02 10:37:46 -070021import static com.google.common.base.Verify.verify;
dpb68c77d82017-08-15 15:23:35 -070022import static dagger.internal.codegen.Accessibility.isRawTypeAccessible;
23import static dagger.internal.codegen.Accessibility.isTypeAccessibleFrom;
dpb3379b952018-09-24 13:39:04 -070024import static dagger.internal.codegen.BindingRequest.bindingRequest;
dpb3db68f02018-01-04 09:15:52 -080025import static dagger.internal.codegen.BindingType.MEMBERS_INJECTION;
26import static dagger.internal.codegen.CodeBlocks.makeParametersCodeBlock;
dpb09fb2cb2018-01-29 08:39:33 -080027import static dagger.internal.codegen.DelegateBindingExpression.isBindsScopeStrongerThanDependencyScope;
dpb356a6842018-02-07 07:45:50 -080028import static dagger.internal.codegen.MemberSelect.staticFactoryCreation;
dpb3db68f02018-01-04 09:15:52 -080029import static dagger.internal.codegen.TypeNames.DOUBLE_CHECK;
dpb3db68f02018-01-04 09:15:52 -080030import 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;
dpb68c77d82017-08-15 15:23:35 -070034
dpb3db68f02018-01-04 09:15:52 -080035import com.google.auto.common.MoreTypes;
dpb3db68f02018-01-04 09:15:52 -080036import com.google.common.collect.ImmutableList;
dpb68c77d82017-08-15 15:23:35 -070037import com.squareup.javapoet.ClassName;
bcorsoe643cc62017-10-24 08:57:09 -070038import com.squareup.javapoet.CodeBlock;
dpb02db2132018-01-08 07:20:23 -080039import com.squareup.javapoet.MethodSpec;
bcorso2c279662017-12-01 09:51:18 -080040import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
dpb3db68f02018-01-04 09:15:52 -080041import dagger.internal.codegen.FrameworkFieldInitializer.FrameworkInstanceCreationExpression;
dstrasburg92031832018-10-17 08:48:40 -070042import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
ronshapiroa5023ca2018-01-02 12:55:01 -080043import dagger.model.DependencyRequest;
ronshapiro120abc62017-12-15 09:57:09 -080044import dagger.model.RequestKind;
cgdecker60a5dde2018-09-07 08:44:34 -070045import java.util.HashMap;
46import java.util.Map;
bcorsof0a99fe2017-12-04 10:52:05 -080047import java.util.Optional;
dpb356a6842018-02-07 07:45:50 -080048import javax.inject.Provider;
dpb68c77d82017-08-15 15:23:35 -070049import javax.lang.model.type.TypeMirror;
50
ronshapirodc07ed52017-08-23 08:52:10 -070051/** A central repository of code expressions used to access any binding available to a component. */
dpb68c77d82017-08-15 15:23:35 -070052final class ComponentBindingExpressions {
53
ronshapirodc07ed52017-08-23 08:52:10 -070054 // TODO(dpb,ronshapiro): refactor this and ComponentRequirementFields into a
55 // HierarchicalComponentMap<K, V>, or perhaps this use a flattened ImmutableMap, built from its
56 // parents? If so, maybe make BindingExpression.Factory create it.
dpb68c77d82017-08-15 15:23:35 -070057
bcorsof0a99fe2017-12-04 10:52:05 -080058 private final Optional<ComponentBindingExpressions> parent;
59 private final BindingGraph graph;
dpb02db2132018-01-08 07:20:23 -080060 private final GeneratedComponentModel generatedComponentModel;
dpb73afb302018-02-12 10:59:53 -080061 private final ComponentRequirementFields componentRequirementFields;
dpb73afb302018-02-12 10:59:53 -080062 private final OptionalFactories optionalFactories;
bcorsof0a99fe2017-12-04 10:52:05 -080063 private final DaggerTypes types;
dpbe7b89582018-02-19 08:42:19 -080064 private final DaggerElements elements;
dpb73afb302018-02-12 10:59:53 -080065 private final CompilerOptions compilerOptions;
66 private final MembersInjectionMethods membersInjectionMethods;
bcorsocc739fe2018-04-23 09:16:12 -070067 private final InnerSwitchingProviders innerSwitchingProviders;
68 private final StaticSwitchingProviders staticSwitchingProviders;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070069 private final ModifiableBindingExpressions modifiableBindingExpressions;
cgdecker60a5dde2018-09-07 08:44:34 -070070 private final Map<BindingRequest, BindingExpression> expressions = new HashMap<>();
dpb68c77d82017-08-15 15:23:35 -070071
bcorsof0a99fe2017-12-04 10:52:05 -080072 ComponentBindingExpressions(
73 BindingGraph graph,
74 GeneratedComponentModel generatedComponentModel,
bcorsof0a99fe2017-12-04 10:52:05 -080075 ComponentRequirementFields componentRequirementFields,
76 OptionalFactories optionalFactories,
77 DaggerTypes types,
dpbe7b89582018-02-19 08:42:19 -080078 DaggerElements elements,
bcorsof0a99fe2017-12-04 10:52:05 -080079 CompilerOptions compilerOptions) {
80 this(
81 Optional.empty(),
82 graph,
83 generatedComponentModel,
bcorsof0a99fe2017-12-04 10:52:05 -080084 componentRequirementFields,
bcorsocc739fe2018-04-23 09:16:12 -070085 new StaticSwitchingProviders(generatedComponentModel, types),
bcorsof0a99fe2017-12-04 10:52:05 -080086 optionalFactories,
87 types,
88 elements,
89 compilerOptions);
dpb68c77d82017-08-15 15:23:35 -070090 }
91
bcorsof0a99fe2017-12-04 10:52:05 -080092 private ComponentBindingExpressions(
93 Optional<ComponentBindingExpressions> parent,
94 BindingGraph graph,
95 GeneratedComponentModel generatedComponentModel,
bcorsof0a99fe2017-12-04 10:52:05 -080096 ComponentRequirementFields componentRequirementFields,
bcorsocc739fe2018-04-23 09:16:12 -070097 StaticSwitchingProviders staticSwitchingProviders,
bcorsof0a99fe2017-12-04 10:52:05 -080098 OptionalFactories optionalFactories,
99 DaggerTypes types,
dpbe7b89582018-02-19 08:42:19 -0800100 DaggerElements elements,
bcorsof0a99fe2017-12-04 10:52:05 -0800101 CompilerOptions compilerOptions) {
102 this.parent = parent;
103 this.graph = graph;
dpb02db2132018-01-08 07:20:23 -0800104 this.generatedComponentModel = generatedComponentModel;
dpb73afb302018-02-12 10:59:53 -0800105 this.componentRequirementFields = checkNotNull(componentRequirementFields);
dpb73afb302018-02-12 10:59:53 -0800106 this.optionalFactories = checkNotNull(optionalFactories);
107 this.types = checkNotNull(types);
108 this.elements = checkNotNull(elements);
109 this.compilerOptions = checkNotNull(compilerOptions);
110 this.membersInjectionMethods =
111 new MembersInjectionMethods(generatedComponentModel, this, graph, elements, types);
bcorsocc739fe2018-04-23 09:16:12 -0700112 this.innerSwitchingProviders =
113 new InnerSwitchingProviders(generatedComponentModel, this, types);
114 this.staticSwitchingProviders = staticSwitchingProviders;
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700115 this.modifiableBindingExpressions =
116 new ModifiableBindingExpressions(
117 parent.map(cbe -> cbe.modifiableBindingExpressions),
118 this,
119 graph,
120 generatedComponentModel,
121 compilerOptions);
bcorsof0a99fe2017-12-04 10:52:05 -0800122 }
123
124 /**
125 * Returns a new object representing the bindings available from a child component of this one.
126 */
127 ComponentBindingExpressions forChildComponent(
128 BindingGraph childGraph,
129 GeneratedComponentModel childComponentModel,
130 ComponentRequirementFields childComponentRequirementFields) {
131 return new ComponentBindingExpressions(
132 Optional.of(this),
133 childGraph,
134 childComponentModel,
bcorsof0a99fe2017-12-04 10:52:05 -0800135 childComponentRequirementFields,
bcorsocc739fe2018-04-23 09:16:12 -0700136 staticSwitchingProviders,
dpb73afb302018-02-12 10:59:53 -0800137 optionalFactories,
138 types,
139 elements,
140 compilerOptions);
dpb68c77d82017-08-15 15:23:35 -0700141 }
142
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700143 /* Returns the {@link ModifiableBindingExpressions} for this component. */
144 ModifiableBindingExpressions modifiableBindingExpressions() {
145 return modifiableBindingExpressions;
146 }
147
dpb68c77d82017-08-15 15:23:35 -0700148 /**
dpb3379b952018-09-24 13:39:04 -0700149 * Returns an expression that evaluates to the value of a binding request for a binding owned by
cgdecker60a5dde2018-09-07 08:44:34 -0700150 * this component or an ancestor.
151 *
152 * @param requestingClass the class that will contain the expression
dpb3379b952018-09-24 13:39:04 -0700153 * @throws IllegalStateException if there is no binding expression that satisfies the request
cgdecker60a5dde2018-09-07 08:44:34 -0700154 */
dpb3379b952018-09-24 13:39:04 -0700155 Expression getDependencyExpression(BindingRequest request, ClassName requestingClass) {
cgdecker60a5dde2018-09-07 08:44:34 -0700156 return getBindingExpression(request).getDependencyExpression(requestingClass);
dpb68c77d82017-08-15 15:23:35 -0700157 }
158
159 /**
cgdeckerea48dfd2018-10-02 10:37:46 -0700160 * Equivalent to {@link #getDependencyExpression(BindingRequest, ClassName)} that is used only
161 * when the request is for implementation of a component method.
162 *
163 * @throws IllegalStateException if there is no binding expression that satisfies the request
164 */
165 Expression getDependencyExpressionForComponentMethod(
166 BindingRequest request,
167 ComponentMethodDescriptor componentMethod,
168 GeneratedComponentModel componentModel) {
169 return getBindingExpression(request)
170 .getDependencyExpressionForComponentMethod(componentMethod, componentModel);
171 }
172
173 /**
174 * Returns the {@link CodeBlock} for the method arguments used with the factory {@code create()}
bcorso5db065d2018-04-03 13:49:31 -0700175 * method for the given {@link ContributionBinding binding}.
dpb3db68f02018-01-04 09:15:52 -0800176 */
bcorso5db065d2018-04-03 13:49:31 -0700177 CodeBlock getCreateMethodArgumentsCodeBlock(ContributionBinding binding) {
178 return makeParametersCodeBlock(getCreateMethodArgumentsCodeBlocks(binding));
179 }
180
181 private ImmutableList<CodeBlock> getCreateMethodArgumentsCodeBlocks(ContributionBinding binding) {
182 ImmutableList.Builder<CodeBlock> arguments = ImmutableList.builder();
183
184 if (binding.requiresModuleInstance()) {
185 arguments.add(
186 componentRequirementFields.getExpressionDuringInitialization(
187 ComponentRequirement.forModule(binding.contributingModule().get().asType()),
188 generatedComponentModel.name()));
189 }
190
dpb3379b952018-09-24 13:39:04 -0700191 binding.frameworkDependencies().stream()
192 .map(BindingRequest::bindingRequest)
193 .map(
194 request ->
195 getDependencyExpression(request, generatedComponentModel.name()))
bcorso5db065d2018-04-03 13:49:31 -0700196 .map(Expression::codeBlock)
197 .forEach(arguments::add);
198
199 return arguments.build();
dpb3db68f02018-01-04 09:15:52 -0800200 }
201
202 /**
dpb68c77d82017-08-15 15:23:35 -0700203 * Returns an expression that evaluates to the value of a dependency request, for passing to a
204 * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
205 *
206 * <p>If the method is a generated static {@link InjectionMethods injection method}, each
207 * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
208 * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
209 *
210 * @param requestingClass the class that will contain the expression
211 */
ronshapiroba794862017-09-28 11:39:34 -0700212 Expression getDependencyArgumentExpression(
dpb68c77d82017-08-15 15:23:35 -0700213 DependencyRequest dependencyRequest, ClassName requestingClass) {
dpb68c77d82017-08-15 15:23:35 -0700214
215 TypeMirror dependencyType = dependencyRequest.key().type();
dpb3379b952018-09-24 13:39:04 -0700216 Expression dependencyExpression =
217 getDependencyExpression(bindingRequest(dependencyRequest), requestingClass);
ronshapiroba794862017-09-28 11:39:34 -0700218
bcorsoaaffd2d2018-04-16 14:44:42 -0700219 if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
220 && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
dpb68c77d82017-08-15 15:23:35 -0700221 && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
ronshapiroba794862017-09-28 11:39:34 -0700222 return dependencyExpression.castTo(types.erasure(dependencyType));
dpb68c77d82017-08-15 15:23:35 -0700223 }
224
ronshapiroba794862017-09-28 11:39:34 -0700225 return dependencyExpression;
dpb68c77d82017-08-15 15:23:35 -0700226 }
227
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700228 /** Returns the implementation of a component method. */
229 MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
dpb02db2132018-01-08 07:20:23 -0800230 checkArgument(componentMethod.dependencyRequest().isPresent());
dpb3379b952018-09-24 13:39:04 -0700231 BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700232 return MethodSpec.overriding(
233 componentMethod.methodElement(),
234 MoreTypes.asDeclared(graph.componentType().asType()),
235 types)
236 .addCode(
237 getBindingExpression(request)
238 .getComponentMethodImplementation(componentMethod, generatedComponentModel))
239 .build();
bcorso11f9b872017-10-09 16:18:55 -0700240 }
241
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700242 /** Returns the {@link BindingExpression} for the given {@link BindingRequest}. */
243 BindingExpression getBindingExpression(BindingRequest request) {
cgdecker60a5dde2018-09-07 08:44:34 -0700244 if (expressions.containsKey(request)) {
245 return expressions.get(request);
bcorsof0a99fe2017-12-04 10:52:05 -0800246 }
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700247 Optional<BindingExpression> expression =
248 modifiableBindingExpressions.maybeCreateModifiableBindingExpression(request);
249 if (!expression.isPresent()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700250 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700251 if (resolvedBindings != null && !resolvedBindings.ownedBindings().isEmpty()) {
252 expression = Optional.of(createBindingExpression(resolvedBindings, request));
253 }
dstrasburg4f902cf2018-07-30 08:42:57 -0700254 }
255 if (expression.isPresent()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700256 expressions.put(request, expression.get());
dstrasburg4f902cf2018-07-30 08:42:57 -0700257 return expression.get();
258 }
cgdecker60a5dde2018-09-07 08:44:34 -0700259 checkArgument(parent.isPresent(), "no expression found for %s", request);
260 return parent.get().getBindingExpression(request);
bcorsof0a99fe2017-12-04 10:52:05 -0800261 }
262
dpb73afb302018-02-12 10:59:53 -0800263 /** Creates a binding expression. */
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700264 BindingExpression createBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700265 ResolvedBindings resolvedBindings, BindingRequest request) {
dpb73afb302018-02-12 10:59:53 -0800266 switch (resolvedBindings.bindingType()) {
267 case MEMBERS_INJECTION:
cgdecker60a5dde2018-09-07 08:44:34 -0700268 checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION));
ronshapiro9288a972018-02-14 06:02:12 -0800269 return new MembersInjectionBindingExpression(resolvedBindings, membersInjectionMethods);
bcorsof0a99fe2017-12-04 10:52:05 -0800270
dpb73afb302018-02-12 10:59:53 -0800271 case PROVISION:
cgdecker60a5dde2018-09-07 08:44:34 -0700272 return provisionBindingExpression(resolvedBindings, request);
dpb73afb302018-02-12 10:59:53 -0800273
274 case PRODUCTION:
cgdecker60a5dde2018-09-07 08:44:34 -0700275 return productionBindingExpression(resolvedBindings, request);
dpb73afb302018-02-12 10:59:53 -0800276
277 default:
278 throw new AssertionError(resolvedBindings);
bcorsof0a99fe2017-12-04 10:52:05 -0800279 }
dpb73afb302018-02-12 10:59:53 -0800280 }
bcorsof0a99fe2017-12-04 10:52:05 -0800281
dpb73afb302018-02-12 10:59:53 -0800282 /**
283 * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
284 * or a {@link dagger.producers.Producer} for production bindings.
285 */
286 private FrameworkInstanceBindingExpression frameworkInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700287 ResolvedBindings resolvedBindings) {
bcorsoaf9e0042018-04-16 14:12:23 -0700288 // TODO(user): Consider merging the static factory creation logic into CreationExpressions?
289 Optional<MemberSelect> staticMethod =
290 useStaticFactoryCreation(resolvedBindings.contributionBinding())
291 ? staticFactoryCreation(resolvedBindings)
292 : Optional.empty();
dpb73afb302018-02-12 10:59:53 -0800293 FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
294 resolvedBindings.scope().isPresent()
295 ? scope(resolvedBindings, frameworkInstanceCreationExpression(resolvedBindings))
296 : frameworkInstanceCreationExpression(resolvedBindings);
cgdecker0bc05be2018-08-10 12:37:36 -0700297 FrameworkInstanceSupplier frameworkInstanceSupplier =
dpb73afb302018-02-12 10:59:53 -0800298 staticMethod.isPresent()
299 ? staticMethod::get
300 : new FrameworkFieldInitializer(
cgdecker0bc05be2018-08-10 12:37:36 -0700301 generatedComponentModel, resolvedBindings, frameworkInstanceCreationExpression);
302
dpbdb197502018-08-27 14:29:47 -0700303 switch (resolvedBindings.bindingType()) {
304 case PROVISION:
cgdecker0bc05be2018-08-10 12:37:36 -0700305 return new ProviderInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700306 resolvedBindings, frameworkInstanceSupplier, types, elements);
dpbdb197502018-08-27 14:29:47 -0700307 case PRODUCTION:
cgdeckerea48dfd2018-10-02 10:37:46 -0700308 return new ProducerNodeInstanceBindingExpression(
309 resolvedBindings, frameworkInstanceSupplier, types, elements, generatedComponentModel);
cgdecker0bc05be2018-08-10 12:37:36 -0700310 default:
dpbdb197502018-08-27 14:29:47 -0700311 throw new AssertionError("invalid binding type: " + resolvedBindings.bindingType());
cgdecker0bc05be2018-08-10 12:37:36 -0700312 }
dpb73afb302018-02-12 10:59:53 -0800313 }
dpb64861842017-12-12 08:17:18 -0800314
dpb73afb302018-02-12 10:59:53 -0800315 private FrameworkInstanceCreationExpression scope(
316 ResolvedBindings resolvedBindings, FrameworkInstanceCreationExpression unscoped) {
ronshapiroa72c3422018-10-30 15:14:05 -0700317 return () ->
318 CodeBlock.of(
319 "$T.provider($L)",
320 resolvedBindings.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
321 unscoped.creationExpression());
dpb73afb302018-02-12 10:59:53 -0800322 }
dpb64861842017-12-12 08:17:18 -0800323
dpb73afb302018-02-12 10:59:53 -0800324 /**
325 * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
326 * {@link dagger.producers.Producer} for production bindings.
327 */
328 private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
329 ResolvedBindings resolvedBindings) {
330 checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
331 ContributionBinding binding = resolvedBindings.contributionBinding();
332 switch (binding.kind()) {
333 case COMPONENT:
334 // The cast can be removed when we drop java 7 source support
335 return new InstanceFactoryCreationExpression(
336 () -> CodeBlock.of("($T) this", binding.key().type()));
dpb64861842017-12-12 08:17:18 -0800337
dpb73afb302018-02-12 10:59:53 -0800338 case BOUND_INSTANCE:
339 return instanceFactoryCreationExpression(
340 binding, ComponentRequirement.forBoundInstance(binding));
bcorsof0a99fe2017-12-04 10:52:05 -0800341
dpb73afb302018-02-12 10:59:53 -0800342 case COMPONENT_DEPENDENCY:
343 return instanceFactoryCreationExpression(
344 binding, ComponentRequirement.forDependency(binding.key().type()));
dpb3db68f02018-01-04 09:15:52 -0800345
dpb73afb302018-02-12 10:59:53 -0800346 case COMPONENT_PROVISION:
347 return new DependencyMethodProviderCreationExpression(
348 binding, generatedComponentModel, componentRequirementFields, compilerOptions, graph);
dpb3db68f02018-01-04 09:15:52 -0800349
dpb73afb302018-02-12 10:59:53 -0800350 case SUBCOMPONENT_BUILDER:
351 return new SubcomponentBuilderProviderCreationExpression(
dstrasburg61274ab2018-09-26 08:11:04 -0700352 binding.key().type(), generatedComponentModel.getSubcomponentName(binding.key()));
dpb356a6842018-02-07 07:45:50 -0800353
dpb73afb302018-02-12 10:59:53 -0800354 case INJECTION:
355 case PROVISION:
bcorsocc739fe2018-04-23 09:16:12 -0700356 return compilerOptions.experimentalAndroidMode2()
357 ? staticSwitchingProviders.newCreationExpression(binding, this)
358 : new InjectionOrProvisionProviderCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800359
dpb73afb302018-02-12 10:59:53 -0800360 case COMPONENT_PRODUCTION:
361 return new DependencyMethodProducerCreationExpression(
362 binding, generatedComponentModel, componentRequirementFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800363
dpb73afb302018-02-12 10:59:53 -0800364 case PRODUCTION:
bcorso5db065d2018-04-03 13:49:31 -0700365 return new ProducerCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800366
dpb73afb302018-02-12 10:59:53 -0800367 case MULTIBOUND_SET:
368 return new SetFactoryCreationExpression(binding, generatedComponentModel, this, graph);
dpb3db68f02018-01-04 09:15:52 -0800369
dpb73afb302018-02-12 10:59:53 -0800370 case MULTIBOUND_MAP:
ronshapiro3a089642018-07-17 15:39:40 -0700371 return new MapFactoryCreationExpression(
372 binding, generatedComponentModel, this, graph, elements);
dpb3db68f02018-01-04 09:15:52 -0800373
dpb73afb302018-02-12 10:59:53 -0800374 case DELEGATE:
375 return new DelegatingFrameworkInstanceCreationExpression(
376 binding, generatedComponentModel, this);
dpb3db68f02018-01-04 09:15:52 -0800377
dpb73afb302018-02-12 10:59:53 -0800378 case OPTIONAL:
ronshapiroe6740762018-05-01 08:37:26 -0700379 return new OptionalFactoryInstanceCreationExpression(
380 optionalFactories, binding, generatedComponentModel, this);
dpb356a6842018-02-07 07:45:50 -0800381
dpb73afb302018-02-12 10:59:53 -0800382 case MEMBERS_INJECTOR:
ronshapiroe6740762018-05-01 08:37:26 -0700383 return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
dpb73afb302018-02-12 10:59:53 -0800384
385 default:
386 throw new AssertionError(binding);
387 }
388 }
389
390 private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
391 ContributionBinding binding, ComponentRequirement componentRequirement) {
392 return new InstanceFactoryCreationExpression(
393 binding.nullableType().isPresent(),
394 () ->
395 componentRequirementFields.getExpressionDuringInitialization(
396 componentRequirement, generatedComponentModel.name()));
397 }
398
399 /** Returns a binding expression for a provision binding. */
400 private BindingExpression provisionBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700401 ResolvedBindings resolvedBindings, BindingRequest request) {
cgdeckerea48dfd2018-10-02 10:37:46 -0700402 if (!request.requestKind().isPresent()) {
403 verify(
404 request.frameworkType().get().equals(FrameworkType.PRODUCER_NODE),
405 "expected a PRODUCER_NODE: %s",
406 request);
407 return producerFromProviderBindingExpression(resolvedBindings);
408 }
cgdecker60a5dde2018-09-07 08:44:34 -0700409 RequestKind requestKind = request.requestKind().get();
dpb73afb302018-02-12 10:59:53 -0800410 switch (requestKind) {
dpb73afb302018-02-12 10:59:53 -0800411 case INSTANCE:
412 return instanceBindingExpression(resolvedBindings);
413
ronshapiro62c8d5c2018-05-10 09:06:48 -0700414 case PROVIDER:
415 return providerBindingExpression(resolvedBindings);
dpb73afb302018-02-12 10:59:53 -0800416
417 case LAZY:
418 case PRODUCED:
419 case PROVIDER_OF_LAZY:
dpb5e03bd52018-08-10 14:21:15 -0700420 return new DerivedFromFrameworkInstanceBindingExpression(
dpbdb197502018-08-27 14:29:47 -0700421 resolvedBindings, FrameworkType.PROVIDER, requestKind, this, types);
dpb73afb302018-02-12 10:59:53 -0800422
ronshapiro62c8d5c2018-05-10 09:06:48 -0700423 case PRODUCER:
dpb5e03bd52018-08-10 14:21:15 -0700424 return producerFromProviderBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700425
426 case FUTURE:
427 return new ImmediateFutureBindingExpression(resolvedBindings, this, types);
dpb73afb302018-02-12 10:59:53 -0800428
429 case MEMBERS_INJECTION:
430 throw new IllegalArgumentException();
dpb356a6842018-02-07 07:45:50 -0800431 }
432
dpb73afb302018-02-12 10:59:53 -0800433 throw new AssertionError();
434 }
dpb356a6842018-02-07 07:45:50 -0800435
cgdecker60a5dde2018-09-07 08:44:34 -0700436 /** Returns a binding expression for a production binding. */
437 private BindingExpression productionBindingExpression(
438 ResolvedBindings resolvedBindings, BindingRequest request) {
439 if (request.frameworkType().isPresent()) {
440 return frameworkInstanceBindingExpression(resolvedBindings);
441 } else {
442 // If no FrameworkType is present, a RequestKind is guaranteed to be present.
443 return new DerivedFromFrameworkInstanceBindingExpression(
cgdeckerea48dfd2018-10-02 10:37:46 -0700444 resolvedBindings, FrameworkType.PRODUCER_NODE, request.requestKind().get(), this, types);
cgdecker60a5dde2018-09-07 08:44:34 -0700445 }
446 }
447
dpb73afb302018-02-12 10:59:53 -0800448 /**
ronshapiro62c8d5c2018-05-10 09:06:48 -0700449 * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
450 *
451 * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ResolvedBindings) need to be
452 * cached} can use a {@link DelegateBindingExpression}.
453 *
bcorsod55c02d2018-06-06 15:02:34 -0700454 * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
455 * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
456 * which case, just use that Provider directly).
ronshapiro62c8d5c2018-05-10 09:06:48 -0700457 *
458 * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
459 */
460 private BindingExpression providerBindingExpression(ResolvedBindings resolvedBindings) {
461 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)
462 && !needsCaching(resolvedBindings)) {
463 return new DelegateBindingExpression(
464 resolvedBindings, RequestKind.PROVIDER, this, types, elements);
bcorsod55c02d2018-06-06 15:02:34 -0700465 } else if (compilerOptions.fastInit()
ronshapiro62c8d5c2018-05-10 09:06:48 -0700466 && frameworkInstanceCreationExpression(resolvedBindings).useInnerSwitchingProvider()
467 && !(instanceBindingExpression(resolvedBindings)
dpb5e03bd52018-08-10 14:21:15 -0700468 instanceof DerivedFromFrameworkInstanceBindingExpression)) {
ronshapiro62c8d5c2018-05-10 09:06:48 -0700469 return wrapInMethod(
470 resolvedBindings,
dpb3379b952018-09-24 13:39:04 -0700471 bindingRequest(resolvedBindings.key(), RequestKind.PROVIDER),
ronshapiro62c8d5c2018-05-10 09:06:48 -0700472 innerSwitchingProviders.newBindingExpression(resolvedBindings.contributionBinding()));
473 }
dpb5e03bd52018-08-10 14:21:15 -0700474 return frameworkInstanceBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700475 }
476
477 /**
dpb73afb302018-02-12 10:59:53 -0800478 * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
479 * provision binding.
480 */
481 private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700482 ResolvedBindings resolvedBindings) {
dpbdb197502018-08-27 14:29:47 -0700483 checkArgument(resolvedBindings.bindingType().equals(BindingType.PROVISION));
cgdeckerea48dfd2018-10-02 10:37:46 -0700484 return new ProducerNodeInstanceBindingExpression(
dpb73afb302018-02-12 10:59:53 -0800485 resolvedBindings,
dpb73afb302018-02-12 10:59:53 -0800486 new FrameworkFieldInitializer(
487 generatedComponentModel,
488 resolvedBindings,
489 new ProducerFromProviderCreationExpression(
490 resolvedBindings.contributionBinding(), generatedComponentModel, this)),
491 types,
cgdeckerea48dfd2018-10-02 10:37:46 -0700492 elements,
493 generatedComponentModel);
dpb73afb302018-02-12 10:59:53 -0800494 }
dpb356a6842018-02-07 07:45:50 -0800495
dpb73afb302018-02-12 10:59:53 -0800496 /**
497 * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
498 *
499 * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an
500 * instance of this binding, return it, wrapped in a method if the binding {@linkplain
501 * #needsCaching(ResolvedBindings) needs to be cached} or the expression has dependencies.
502 *
bcorsod55c02d2018-06-06 15:02:34 -0700503 * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached.
dpb73afb302018-02-12 10:59:53 -0800504 */
505 private BindingExpression instanceBindingExpression(ResolvedBindings resolvedBindings) {
506 Optional<BindingExpression> maybeDirectInstanceExpression =
507 unscopedDirectInstanceExpression(resolvedBindings);
508 if (canUseDirectInstanceExpression(resolvedBindings)
509 && maybeDirectInstanceExpression.isPresent()) {
510 BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
511 return directInstanceExpression.requiresMethodEncapsulation()
512 || needsCaching(resolvedBindings)
cgdecker60a5dde2018-09-07 08:44:34 -0700513 ? wrapInMethod(
514 resolvedBindings,
dpb3379b952018-09-24 13:39:04 -0700515 bindingRequest(resolvedBindings.key(), RequestKind.INSTANCE),
cgdecker60a5dde2018-09-07 08:44:34 -0700516 directInstanceExpression)
dpb73afb302018-02-12 10:59:53 -0800517 : directInstanceExpression;
dpb356a6842018-02-07 07:45:50 -0800518 }
dpb5e03bd52018-08-10 14:21:15 -0700519 return new DerivedFromFrameworkInstanceBindingExpression(
dpbdb197502018-08-27 14:29:47 -0700520 resolvedBindings, FrameworkType.PROVIDER, RequestKind.INSTANCE, this, types);
dpb73afb302018-02-12 10:59:53 -0800521 }
dpb356a6842018-02-07 07:45:50 -0800522
dpb73afb302018-02-12 10:59:53 -0800523 /**
524 * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
525 * {@code get()} on its provider, if there is one.
526 */
527 private Optional<BindingExpression> unscopedDirectInstanceExpression(
528 ResolvedBindings resolvedBindings) {
529 switch (resolvedBindings.contributionBinding().kind()) {
530 case DELEGATE:
531 return Optional.of(
532 new DelegateBindingExpression(
533 resolvedBindings, RequestKind.INSTANCE, this, types, elements));
534
535 case COMPONENT:
536 return Optional.of(
537 new ComponentInstanceBindingExpression(
538 resolvedBindings, generatedComponentModel.name()));
539
540 case COMPONENT_DEPENDENCY:
541 return Optional.of(
542 new ComponentRequirementBindingExpression(
543 resolvedBindings,
544 ComponentRequirement.forDependency(resolvedBindings.key().type()),
545 componentRequirementFields));
546
547 case COMPONENT_PROVISION:
548 return Optional.of(
549 new ComponentProvisionBindingExpression(
550 resolvedBindings, graph, componentRequirementFields, compilerOptions));
551
552 case SUBCOMPONENT_BUILDER:
553 return Optional.of(
554 new SubcomponentBuilderBindingExpression(
dstrasburg61274ab2018-09-26 08:11:04 -0700555 resolvedBindings,
556 generatedComponentModel.getSubcomponentName(resolvedBindings.key())));
dpb73afb302018-02-12 10:59:53 -0800557
558 case MULTIBOUND_SET:
559 return Optional.of(
dstrasburg09adeae2018-09-07 12:11:06 -0700560 new SetBindingExpression(
561 resolvedBindings, generatedComponentModel, graph, this, types, elements));
dpb73afb302018-02-12 10:59:53 -0800562
563 case MULTIBOUND_MAP:
564 return Optional.of(
dstrasburg09adeae2018-09-07 12:11:06 -0700565 new MapBindingExpression(
566 resolvedBindings, generatedComponentModel, graph, this, types, elements));
dpb73afb302018-02-12 10:59:53 -0800567
568 case OPTIONAL:
569 return Optional.of(new OptionalBindingExpression(resolvedBindings, this, types));
570
571 case BOUND_INSTANCE:
572 return Optional.of(
573 new ComponentRequirementBindingExpression(
574 resolvedBindings,
575 ComponentRequirement.forBoundInstance(resolvedBindings.contributionBinding()),
576 componentRequirementFields));
577
578 case INJECTION:
579 case PROVISION:
580 return Optional.of(
581 new SimpleMethodBindingExpression(
582 resolvedBindings,
583 compilerOptions,
584 this,
585 membersInjectionMethods,
586 componentRequirementFields,
587 elements));
588
589 case MEMBERS_INJECTOR:
dpb73afb302018-02-12 10:59:53 -0800590 return Optional.empty();
591
592 case MEMBERS_INJECTION:
593 case COMPONENT_PRODUCTION:
594 case PRODUCTION:
595 throw new IllegalArgumentException(
596 resolvedBindings.contributionBinding().kind().toString());
597 }
598 throw new AssertionError();
599 }
600
601 /**
bcorsoaf9e0042018-04-16 14:12:23 -0700602 * Returns {@code true} if the binding should use the static factory creation strategy.
603 *
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700604 * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we
bcorsod55c02d2018-06-06 15:02:34 -0700605 * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700606 * however, we allow static factories that can reused across multiple bindings, e.g. {@code
607 * MapFactory} or {@code SetFactory}.
bcorsoaf9e0042018-04-16 14:12:23 -0700608 */
609 private boolean useStaticFactoryCreation(ContributionBinding binding) {
bcorsod55c02d2018-06-06 15:02:34 -0700610 return !(compilerOptions.experimentalAndroidMode2() || compilerOptions.fastInit())
bcorsoaf9e0042018-04-16 14:12:23 -0700611 || binding.kind().equals(MULTIBOUND_MAP)
612 || binding.kind().equals(MULTIBOUND_SET);
613 }
614
615 /**
dpb73afb302018-02-12 10:59:53 -0800616 * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this
617 * binding. If the binding doesn't {@linkplain #needsCaching(ResolvedBindings) need to be cached},
618 * we can.
619 *
bcorsod55c02d2018-06-06 15:02:34 -0700620 * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain
ronshapiroa72c3422018-10-30 15:14:05 -0700621 * #needsCaching(ResolvedBindings) needs to be cached}.
dpb73afb302018-02-12 10:59:53 -0800622 */
623 private boolean canUseDirectInstanceExpression(ResolvedBindings resolvedBindings) {
ronshapiroa72c3422018-10-30 15:14:05 -0700624 return !needsCaching(resolvedBindings) || compilerOptions.fastInit();
dpb73afb302018-02-12 10:59:53 -0800625 }
626
627 /**
dpb73afb302018-02-12 10:59:53 -0800628 * 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 -0700629 * a component provision method matches it, it will be the method implemented. If it does not
dpb10dcfba2018-09-20 09:08:38 -0700630 * match a component provision method and the binding is modifiable, then a new public modifiable
631 * binding method will be written. If the binding doesn't match a component method and is not
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700632 * modifiable, then a new private method will be written.
dpb73afb302018-02-12 10:59:53 -0800633 */
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700634 BindingExpression wrapInMethod(
dpb73afb302018-02-12 10:59:53 -0800635 ResolvedBindings resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700636 BindingRequest request,
dpb73afb302018-02-12 10:59:53 -0800637 BindingExpression bindingExpression) {
dstrasburg09adeae2018-09-07 12:11:06 -0700638 // If we've already wrapped the expression, then use the delegate.
639 if (bindingExpression instanceof MethodBindingExpression) {
640 return bindingExpression;
641 }
642
dpb73afb302018-02-12 10:59:53 -0800643 BindingMethodImplementation methodImplementation =
cgdecker60a5dde2018-09-07 08:44:34 -0700644 methodImplementation(resolvedBindings, request, bindingExpression);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700645 Optional<ComponentMethodDescriptor> matchingComponentMethod =
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700646 graph.componentDescriptor().findMatchingComponentMethod(request);
dstrasburg92031832018-10-17 08:48:40 -0700647 Optional<ModifiableBindingMethod> matchingModifiableBindingMethod =
648 generatedComponentModel.getModifiableBindingMethod(request);
dpb73afb302018-02-12 10:59:53 -0800649
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700650 Optional<BindingExpression> modifiableBindingExpression =
651 modifiableBindingExpressions.maybeWrapInModifiableMethodBindingExpression(
652 resolvedBindings,
653 request,
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700654 methodImplementation,
dstrasburg92031832018-10-17 08:48:40 -0700655 matchingComponentMethod,
656 matchingModifiableBindingMethod);
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700657 if (modifiableBindingExpression.isPresent()) {
658 return modifiableBindingExpression.get();
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700659 }
660
661 return matchingComponentMethod
dpb73afb302018-02-12 10:59:53 -0800662 .<BindingExpression>map(
663 componentMethod ->
664 new ComponentMethodBindingExpression(
dstrasburg92031832018-10-17 08:48:40 -0700665 methodImplementation,
666 generatedComponentModel,
667 componentMethod,
668 matchingModifiableBindingMethod))
dpb73afb302018-02-12 10:59:53 -0800669 .orElseGet(
670 () ->
671 new PrivateMethodBindingExpression(
dstrasburg92031832018-10-17 08:48:40 -0700672 resolvedBindings,
673 request,
674 methodImplementation,
675 generatedComponentModel,
676 matchingModifiableBindingMethod));
dpb73afb302018-02-12 10:59:53 -0800677 }
678
dpb73afb302018-02-12 10:59:53 -0800679 private BindingMethodImplementation methodImplementation(
680 ResolvedBindings resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700681 BindingRequest request,
dpb73afb302018-02-12 10:59:53 -0800682 BindingExpression bindingExpression) {
bcorsod55c02d2018-06-06 15:02:34 -0700683 if (compilerOptions.fastInit()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700684 if (request.isRequestKind(RequestKind.PROVIDER)) {
bcorso567ff0e2018-03-21 13:49:09 -0700685 return new SingleCheckedMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -0700686 resolvedBindings, request, bindingExpression, types, generatedComponentModel);
687 } else if (request.isRequestKind(RequestKind.INSTANCE) && needsCaching(resolvedBindings)) {
bcorso567ff0e2018-03-21 13:49:09 -0700688 return resolvedBindings.scope().get().isReusable()
689 ? new SingleCheckedMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -0700690 resolvedBindings, request, bindingExpression, types, generatedComponentModel)
bcorso567ff0e2018-03-21 13:49:09 -0700691 : new DoubleCheckedMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -0700692 resolvedBindings, request, bindingExpression, types, generatedComponentModel);
bcorso567ff0e2018-03-21 13:49:09 -0700693 }
694 }
695
696 return new BindingMethodImplementation(
cgdecker60a5dde2018-09-07 08:44:34 -0700697 resolvedBindings, request, bindingExpression, generatedComponentModel.name(), types);
dpb73afb302018-02-12 10:59:53 -0800698 }
699
700 /**
701 * Returns {@code true} if the component needs to make sure the provided value is cached.
702 *
703 * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
704 * bindings whose scope is no stronger than their delegate's.
705 */
706 private boolean needsCaching(ResolvedBindings resolvedBindings) {
707 if (!resolvedBindings.scope().isPresent()) {
708 return false;
bcorso3828ca22018-01-29 10:14:12 -0800709 }
dpb73afb302018-02-12 10:59:53 -0800710 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) {
711 return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph);
712 }
713 return true;
714 }
dpb68c77d82017-08-15 15:23:35 -0700715}