blob: 391418364d4b467db84dd15d98474c7328944570 [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;
dpb159d81b2018-11-01 14:06:17 -070060 private final ComponentImplementation componentImplementation;
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,
dpb159d81b2018-11-01 14:06:17 -070074 ComponentImplementation componentImplementation,
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,
dpb159d81b2018-11-01 14:06:17 -070083 componentImplementation,
bcorsof0a99fe2017-12-04 10:52:05 -080084 componentRequirementFields,
dpb159d81b2018-11-01 14:06:17 -070085 new StaticSwitchingProviders(componentImplementation, 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,
dpb159d81b2018-11-01 14:06:17 -070095 ComponentImplementation componentImplementation,
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;
dpb159d81b2018-11-01 14:06:17 -0700104 this.componentImplementation = componentImplementation;
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 =
dpb159d81b2018-11-01 14:06:17 -0700111 new MembersInjectionMethods(componentImplementation, this, graph, elements, types);
bcorsocc739fe2018-04-23 09:16:12 -0700112 this.innerSwitchingProviders =
dpb159d81b2018-11-01 14:06:17 -0700113 new InnerSwitchingProviders(componentImplementation, this, types);
bcorsocc739fe2018-04-23 09:16:12 -0700114 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,
dpb159d81b2018-11-01 14:06:17 -0700120 componentImplementation,
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700121 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,
dpb159d81b2018-11-01 14:06:17 -0700129 ComponentImplementation childComponentImplementation,
bcorsof0a99fe2017-12-04 10:52:05 -0800130 ComponentRequirementFields childComponentRequirementFields) {
131 return new ComponentBindingExpressions(
132 Optional.of(this),
133 childGraph,
dpb159d81b2018-11-01 14:06:17 -0700134 childComponentImplementation,
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,
dpb159d81b2018-11-01 14:06:17 -0700168 ComponentImplementation componentImplementation) {
cgdeckerea48dfd2018-10-02 10:37:46 -0700169 return getBindingExpression(request)
dpb159d81b2018-11-01 14:06:17 -0700170 .getDependencyExpressionForComponentMethod(componentMethod, componentImplementation);
cgdeckerea48dfd2018-10-02 10:37:46 -0700171 }
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()),
dpb159d81b2018-11-01 14:06:17 -0700188 componentImplementation.name()));
bcorso5db065d2018-04-03 13:49:31 -0700189 }
190
dpb3379b952018-09-24 13:39:04 -0700191 binding.frameworkDependencies().stream()
192 .map(BindingRequest::bindingRequest)
dpb159d81b2018-11-01 14:06:17 -0700193 .map(request -> getDependencyExpression(request, componentImplementation.name()))
bcorso5db065d2018-04-03 13:49:31 -0700194 .map(Expression::codeBlock)
195 .forEach(arguments::add);
196
197 return arguments.build();
dpb3db68f02018-01-04 09:15:52 -0800198 }
199
200 /**
dpb68c77d82017-08-15 15:23:35 -0700201 * Returns an expression that evaluates to the value of a dependency request, for passing to a
202 * binding method, an {@code @Inject}-annotated constructor or member, or a proxy for one.
203 *
204 * <p>If the method is a generated static {@link InjectionMethods injection method}, each
205 * parameter will be {@link Object} if the dependency's raw type is inaccessible. If that is the
206 * case for this dependency, the returned expression will use a cast to evaluate to the raw type.
207 *
208 * @param requestingClass the class that will contain the expression
209 */
ronshapiroba794862017-09-28 11:39:34 -0700210 Expression getDependencyArgumentExpression(
dpb68c77d82017-08-15 15:23:35 -0700211 DependencyRequest dependencyRequest, ClassName requestingClass) {
dpb68c77d82017-08-15 15:23:35 -0700212
213 TypeMirror dependencyType = dependencyRequest.key().type();
dpb3379b952018-09-24 13:39:04 -0700214 Expression dependencyExpression =
215 getDependencyExpression(bindingRequest(dependencyRequest), requestingClass);
ronshapiroba794862017-09-28 11:39:34 -0700216
bcorsoaaffd2d2018-04-16 14:44:42 -0700217 if (dependencyRequest.kind().equals(RequestKind.INSTANCE)
218 && !isTypeAccessibleFrom(dependencyType, requestingClass.packageName())
dpb68c77d82017-08-15 15:23:35 -0700219 && isRawTypeAccessible(dependencyType, requestingClass.packageName())) {
ronshapiroba794862017-09-28 11:39:34 -0700220 return dependencyExpression.castTo(types.erasure(dependencyType));
dpb68c77d82017-08-15 15:23:35 -0700221 }
222
ronshapiroba794862017-09-28 11:39:34 -0700223 return dependencyExpression;
dpb68c77d82017-08-15 15:23:35 -0700224 }
225
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700226 /** Returns the implementation of a component method. */
227 MethodSpec getComponentMethod(ComponentMethodDescriptor componentMethod) {
dpb02db2132018-01-08 07:20:23 -0800228 checkArgument(componentMethod.dependencyRequest().isPresent());
dpb3379b952018-09-24 13:39:04 -0700229 BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700230 return MethodSpec.overriding(
231 componentMethod.methodElement(),
232 MoreTypes.asDeclared(graph.componentType().asType()),
233 types)
234 .addCode(
235 getBindingExpression(request)
dpb159d81b2018-11-01 14:06:17 -0700236 .getComponentMethodImplementation(componentMethod, componentImplementation))
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700237 .build();
bcorso11f9b872017-10-09 16:18:55 -0700238 }
239
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700240 /** Returns the {@link BindingExpression} for the given {@link BindingRequest}. */
241 BindingExpression getBindingExpression(BindingRequest request) {
cgdecker60a5dde2018-09-07 08:44:34 -0700242 if (expressions.containsKey(request)) {
243 return expressions.get(request);
bcorsof0a99fe2017-12-04 10:52:05 -0800244 }
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700245 Optional<BindingExpression> expression =
246 modifiableBindingExpressions.maybeCreateModifiableBindingExpression(request);
247 if (!expression.isPresent()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700248 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700249 if (resolvedBindings != null && !resolvedBindings.ownedBindings().isEmpty()) {
250 expression = Optional.of(createBindingExpression(resolvedBindings, request));
251 }
dstrasburg4f902cf2018-07-30 08:42:57 -0700252 }
253 if (expression.isPresent()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700254 expressions.put(request, expression.get());
dstrasburg4f902cf2018-07-30 08:42:57 -0700255 return expression.get();
256 }
cgdecker60a5dde2018-09-07 08:44:34 -0700257 checkArgument(parent.isPresent(), "no expression found for %s", request);
258 return parent.get().getBindingExpression(request);
bcorsof0a99fe2017-12-04 10:52:05 -0800259 }
260
dpb73afb302018-02-12 10:59:53 -0800261 /** Creates a binding expression. */
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700262 BindingExpression createBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700263 ResolvedBindings resolvedBindings, BindingRequest request) {
dpb73afb302018-02-12 10:59:53 -0800264 switch (resolvedBindings.bindingType()) {
265 case MEMBERS_INJECTION:
cgdecker60a5dde2018-09-07 08:44:34 -0700266 checkArgument(request.isRequestKind(RequestKind.MEMBERS_INJECTION));
ronshapiro9288a972018-02-14 06:02:12 -0800267 return new MembersInjectionBindingExpression(resolvedBindings, membersInjectionMethods);
bcorsof0a99fe2017-12-04 10:52:05 -0800268
dpb73afb302018-02-12 10:59:53 -0800269 case PROVISION:
cgdecker60a5dde2018-09-07 08:44:34 -0700270 return provisionBindingExpression(resolvedBindings, request);
dpb73afb302018-02-12 10:59:53 -0800271
272 case PRODUCTION:
cgdecker60a5dde2018-09-07 08:44:34 -0700273 return productionBindingExpression(resolvedBindings, request);
dpb73afb302018-02-12 10:59:53 -0800274
275 default:
276 throw new AssertionError(resolvedBindings);
bcorsof0a99fe2017-12-04 10:52:05 -0800277 }
dpb73afb302018-02-12 10:59:53 -0800278 }
bcorsof0a99fe2017-12-04 10:52:05 -0800279
dpb73afb302018-02-12 10:59:53 -0800280 /**
281 * Returns a binding expression that uses a {@link javax.inject.Provider} for provision bindings
282 * or a {@link dagger.producers.Producer} for production bindings.
283 */
284 private FrameworkInstanceBindingExpression frameworkInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700285 ResolvedBindings resolvedBindings) {
bcorsoaf9e0042018-04-16 14:12:23 -0700286 // TODO(user): Consider merging the static factory creation logic into CreationExpressions?
287 Optional<MemberSelect> staticMethod =
288 useStaticFactoryCreation(resolvedBindings.contributionBinding())
289 ? staticFactoryCreation(resolvedBindings)
290 : Optional.empty();
dpb73afb302018-02-12 10:59:53 -0800291 FrameworkInstanceCreationExpression frameworkInstanceCreationExpression =
292 resolvedBindings.scope().isPresent()
293 ? scope(resolvedBindings, frameworkInstanceCreationExpression(resolvedBindings))
294 : frameworkInstanceCreationExpression(resolvedBindings);
cgdecker0bc05be2018-08-10 12:37:36 -0700295 FrameworkInstanceSupplier frameworkInstanceSupplier =
dpb73afb302018-02-12 10:59:53 -0800296 staticMethod.isPresent()
297 ? staticMethod::get
298 : new FrameworkFieldInitializer(
dpb159d81b2018-11-01 14:06:17 -0700299 componentImplementation, resolvedBindings, frameworkInstanceCreationExpression);
cgdecker0bc05be2018-08-10 12:37:36 -0700300
dpbdb197502018-08-27 14:29:47 -0700301 switch (resolvedBindings.bindingType()) {
302 case PROVISION:
cgdecker0bc05be2018-08-10 12:37:36 -0700303 return new ProviderInstanceBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700304 resolvedBindings, frameworkInstanceSupplier, types, elements);
dpbdb197502018-08-27 14:29:47 -0700305 case PRODUCTION:
cgdeckerea48dfd2018-10-02 10:37:46 -0700306 return new ProducerNodeInstanceBindingExpression(
dpb159d81b2018-11-01 14:06:17 -0700307 resolvedBindings, frameworkInstanceSupplier, types, elements, componentImplementation);
cgdecker0bc05be2018-08-10 12:37:36 -0700308 default:
dpbdb197502018-08-27 14:29:47 -0700309 throw new AssertionError("invalid binding type: " + resolvedBindings.bindingType());
cgdecker0bc05be2018-08-10 12:37:36 -0700310 }
dpb73afb302018-02-12 10:59:53 -0800311 }
dpb64861842017-12-12 08:17:18 -0800312
dpb73afb302018-02-12 10:59:53 -0800313 private FrameworkInstanceCreationExpression scope(
314 ResolvedBindings resolvedBindings, FrameworkInstanceCreationExpression unscoped) {
ronshapiroa72c3422018-10-30 15:14:05 -0700315 return () ->
316 CodeBlock.of(
317 "$T.provider($L)",
318 resolvedBindings.scope().get().isReusable() ? SINGLE_CHECK : DOUBLE_CHECK,
319 unscoped.creationExpression());
dpb73afb302018-02-12 10:59:53 -0800320 }
dpb64861842017-12-12 08:17:18 -0800321
dpb73afb302018-02-12 10:59:53 -0800322 /**
323 * Returns a creation expression for a {@link javax.inject.Provider} for provision bindings or a
324 * {@link dagger.producers.Producer} for production bindings.
325 */
326 private FrameworkInstanceCreationExpression frameworkInstanceCreationExpression(
327 ResolvedBindings resolvedBindings) {
328 checkArgument(!resolvedBindings.bindingType().equals(MEMBERS_INJECTION));
329 ContributionBinding binding = resolvedBindings.contributionBinding();
330 switch (binding.kind()) {
331 case COMPONENT:
332 // The cast can be removed when we drop java 7 source support
333 return new InstanceFactoryCreationExpression(
334 () -> CodeBlock.of("($T) this", binding.key().type()));
dpb64861842017-12-12 08:17:18 -0800335
dpb73afb302018-02-12 10:59:53 -0800336 case BOUND_INSTANCE:
337 return instanceFactoryCreationExpression(
338 binding, ComponentRequirement.forBoundInstance(binding));
bcorsof0a99fe2017-12-04 10:52:05 -0800339
dpb73afb302018-02-12 10:59:53 -0800340 case COMPONENT_DEPENDENCY:
341 return instanceFactoryCreationExpression(
342 binding, ComponentRequirement.forDependency(binding.key().type()));
dpb3db68f02018-01-04 09:15:52 -0800343
dpb73afb302018-02-12 10:59:53 -0800344 case COMPONENT_PROVISION:
345 return new DependencyMethodProviderCreationExpression(
dpb159d81b2018-11-01 14:06:17 -0700346 binding, componentImplementation, componentRequirementFields, compilerOptions, graph);
dpb3db68f02018-01-04 09:15:52 -0800347
dpb73afb302018-02-12 10:59:53 -0800348 case SUBCOMPONENT_BUILDER:
349 return new SubcomponentBuilderProviderCreationExpression(
dpb159d81b2018-11-01 14:06:17 -0700350 binding.key().type(), componentImplementation.getSubcomponentName(binding.key()));
dpb356a6842018-02-07 07:45:50 -0800351
dpb73afb302018-02-12 10:59:53 -0800352 case INJECTION:
353 case PROVISION:
bcorsocc739fe2018-04-23 09:16:12 -0700354 return compilerOptions.experimentalAndroidMode2()
355 ? staticSwitchingProviders.newCreationExpression(binding, this)
356 : new InjectionOrProvisionProviderCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800357
dpb73afb302018-02-12 10:59:53 -0800358 case COMPONENT_PRODUCTION:
359 return new DependencyMethodProducerCreationExpression(
dpb159d81b2018-11-01 14:06:17 -0700360 binding, componentImplementation, componentRequirementFields, graph);
dpb3db68f02018-01-04 09:15:52 -0800361
dpb73afb302018-02-12 10:59:53 -0800362 case PRODUCTION:
bcorso5db065d2018-04-03 13:49:31 -0700363 return new ProducerCreationExpression(binding, this);
dpb3db68f02018-01-04 09:15:52 -0800364
dpb73afb302018-02-12 10:59:53 -0800365 case MULTIBOUND_SET:
dpb159d81b2018-11-01 14:06:17 -0700366 return new SetFactoryCreationExpression(binding, componentImplementation, this, graph);
dpb3db68f02018-01-04 09:15:52 -0800367
dpb73afb302018-02-12 10:59:53 -0800368 case MULTIBOUND_MAP:
ronshapiro3a089642018-07-17 15:39:40 -0700369 return new MapFactoryCreationExpression(
dpb159d81b2018-11-01 14:06:17 -0700370 binding, componentImplementation, this, graph, elements);
dpb3db68f02018-01-04 09:15:52 -0800371
dpb73afb302018-02-12 10:59:53 -0800372 case DELEGATE:
373 return new DelegatingFrameworkInstanceCreationExpression(
dpb159d81b2018-11-01 14:06:17 -0700374 binding, componentImplementation, this);
dpb3db68f02018-01-04 09:15:52 -0800375
dpb73afb302018-02-12 10:59:53 -0800376 case OPTIONAL:
ronshapiroe6740762018-05-01 08:37:26 -0700377 return new OptionalFactoryInstanceCreationExpression(
dpb159d81b2018-11-01 14:06:17 -0700378 optionalFactories, binding, componentImplementation, this);
dpb356a6842018-02-07 07:45:50 -0800379
dpb73afb302018-02-12 10:59:53 -0800380 case MEMBERS_INJECTOR:
ronshapiroe6740762018-05-01 08:37:26 -0700381 return new MembersInjectorProviderCreationExpression((ProvisionBinding) binding, this);
dpb73afb302018-02-12 10:59:53 -0800382
383 default:
384 throw new AssertionError(binding);
385 }
386 }
387
388 private InstanceFactoryCreationExpression instanceFactoryCreationExpression(
389 ContributionBinding binding, ComponentRequirement componentRequirement) {
390 return new InstanceFactoryCreationExpression(
391 binding.nullableType().isPresent(),
392 () ->
393 componentRequirementFields.getExpressionDuringInitialization(
dpb159d81b2018-11-01 14:06:17 -0700394 componentRequirement, componentImplementation.name()));
dpb73afb302018-02-12 10:59:53 -0800395 }
396
397 /** Returns a binding expression for a provision binding. */
398 private BindingExpression provisionBindingExpression(
cgdecker60a5dde2018-09-07 08:44:34 -0700399 ResolvedBindings resolvedBindings, BindingRequest request) {
cgdeckerea48dfd2018-10-02 10:37:46 -0700400 if (!request.requestKind().isPresent()) {
401 verify(
402 request.frameworkType().get().equals(FrameworkType.PRODUCER_NODE),
403 "expected a PRODUCER_NODE: %s",
404 request);
405 return producerFromProviderBindingExpression(resolvedBindings);
406 }
cgdecker60a5dde2018-09-07 08:44:34 -0700407 RequestKind requestKind = request.requestKind().get();
dpb73afb302018-02-12 10:59:53 -0800408 switch (requestKind) {
dpb73afb302018-02-12 10:59:53 -0800409 case INSTANCE:
410 return instanceBindingExpression(resolvedBindings);
411
ronshapiro62c8d5c2018-05-10 09:06:48 -0700412 case PROVIDER:
413 return providerBindingExpression(resolvedBindings);
dpb73afb302018-02-12 10:59:53 -0800414
415 case LAZY:
416 case PRODUCED:
417 case PROVIDER_OF_LAZY:
dpb5e03bd52018-08-10 14:21:15 -0700418 return new DerivedFromFrameworkInstanceBindingExpression(
dpbdb197502018-08-27 14:29:47 -0700419 resolvedBindings, FrameworkType.PROVIDER, requestKind, this, types);
dpb73afb302018-02-12 10:59:53 -0800420
ronshapiro62c8d5c2018-05-10 09:06:48 -0700421 case PRODUCER:
dpb5e03bd52018-08-10 14:21:15 -0700422 return producerFromProviderBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700423
424 case FUTURE:
425 return new ImmediateFutureBindingExpression(resolvedBindings, this, types);
dpb73afb302018-02-12 10:59:53 -0800426
427 case MEMBERS_INJECTION:
428 throw new IllegalArgumentException();
dpb356a6842018-02-07 07:45:50 -0800429 }
430
dpb73afb302018-02-12 10:59:53 -0800431 throw new AssertionError();
432 }
dpb356a6842018-02-07 07:45:50 -0800433
cgdecker60a5dde2018-09-07 08:44:34 -0700434 /** Returns a binding expression for a production binding. */
435 private BindingExpression productionBindingExpression(
436 ResolvedBindings resolvedBindings, BindingRequest request) {
437 if (request.frameworkType().isPresent()) {
438 return frameworkInstanceBindingExpression(resolvedBindings);
439 } else {
440 // If no FrameworkType is present, a RequestKind is guaranteed to be present.
441 return new DerivedFromFrameworkInstanceBindingExpression(
cgdeckerea48dfd2018-10-02 10:37:46 -0700442 resolvedBindings, FrameworkType.PRODUCER_NODE, request.requestKind().get(), this, types);
cgdecker60a5dde2018-09-07 08:44:34 -0700443 }
444 }
445
dpb73afb302018-02-12 10:59:53 -0800446 /**
ronshapiro62c8d5c2018-05-10 09:06:48 -0700447 * Returns a binding expression for {@link RequestKind#PROVIDER} requests.
448 *
449 * <p>{@code @Binds} bindings that don't {@linkplain #needsCaching(ResolvedBindings) need to be
450 * cached} can use a {@link DelegateBindingExpression}.
451 *
bcorsod55c02d2018-06-06 15:02:34 -0700452 * <p>In fastInit mode, use an {@link InnerSwitchingProviders inner switching provider} unless
453 * that provider's case statement will simply call {@code get()} on another {@link Provider} (in
454 * which case, just use that Provider directly).
ronshapiro62c8d5c2018-05-10 09:06:48 -0700455 *
456 * <p>Otherwise, return a {@link FrameworkInstanceBindingExpression}.
457 */
458 private BindingExpression providerBindingExpression(ResolvedBindings resolvedBindings) {
459 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)
460 && !needsCaching(resolvedBindings)) {
461 return new DelegateBindingExpression(
462 resolvedBindings, RequestKind.PROVIDER, this, types, elements);
bcorsod55c02d2018-06-06 15:02:34 -0700463 } else if (compilerOptions.fastInit()
ronshapiro62c8d5c2018-05-10 09:06:48 -0700464 && frameworkInstanceCreationExpression(resolvedBindings).useInnerSwitchingProvider()
465 && !(instanceBindingExpression(resolvedBindings)
dpb5e03bd52018-08-10 14:21:15 -0700466 instanceof DerivedFromFrameworkInstanceBindingExpression)) {
ronshapiro62c8d5c2018-05-10 09:06:48 -0700467 return wrapInMethod(
468 resolvedBindings,
dpb3379b952018-09-24 13:39:04 -0700469 bindingRequest(resolvedBindings.key(), RequestKind.PROVIDER),
ronshapiro62c8d5c2018-05-10 09:06:48 -0700470 innerSwitchingProviders.newBindingExpression(resolvedBindings.contributionBinding()));
471 }
dpb5e03bd52018-08-10 14:21:15 -0700472 return frameworkInstanceBindingExpression(resolvedBindings);
ronshapiro62c8d5c2018-05-10 09:06:48 -0700473 }
474
475 /**
dpb73afb302018-02-12 10:59:53 -0800476 * Returns a binding expression that uses a {@link dagger.producers.Producer} field for a
477 * provision binding.
478 */
479 private FrameworkInstanceBindingExpression producerFromProviderBindingExpression(
dpb5e03bd52018-08-10 14:21:15 -0700480 ResolvedBindings resolvedBindings) {
dpbdb197502018-08-27 14:29:47 -0700481 checkArgument(resolvedBindings.bindingType().equals(BindingType.PROVISION));
cgdeckerea48dfd2018-10-02 10:37:46 -0700482 return new ProducerNodeInstanceBindingExpression(
dpb73afb302018-02-12 10:59:53 -0800483 resolvedBindings,
dpb73afb302018-02-12 10:59:53 -0800484 new FrameworkFieldInitializer(
dpb159d81b2018-11-01 14:06:17 -0700485 componentImplementation,
dpb73afb302018-02-12 10:59:53 -0800486 resolvedBindings,
487 new ProducerFromProviderCreationExpression(
dpb159d81b2018-11-01 14:06:17 -0700488 resolvedBindings.contributionBinding(), componentImplementation, this)),
dpb73afb302018-02-12 10:59:53 -0800489 types,
cgdeckerea48dfd2018-10-02 10:37:46 -0700490 elements,
dpb159d81b2018-11-01 14:06:17 -0700491 componentImplementation);
dpb73afb302018-02-12 10:59:53 -0800492 }
dpb356a6842018-02-07 07:45:50 -0800493
dpb73afb302018-02-12 10:59:53 -0800494 /**
495 * Returns a binding expression for {@link RequestKind#INSTANCE} requests.
496 *
497 * <p>If there is a direct expression (not calling {@link Provider#get()}) we can use for an
498 * instance of this binding, return it, wrapped in a method if the binding {@linkplain
499 * #needsCaching(ResolvedBindings) needs to be cached} or the expression has dependencies.
500 *
bcorsod55c02d2018-06-06 15:02:34 -0700501 * <p>In fastInit mode, we can use direct expressions unless the binding needs to be cached.
dpb73afb302018-02-12 10:59:53 -0800502 */
503 private BindingExpression instanceBindingExpression(ResolvedBindings resolvedBindings) {
504 Optional<BindingExpression> maybeDirectInstanceExpression =
505 unscopedDirectInstanceExpression(resolvedBindings);
506 if (canUseDirectInstanceExpression(resolvedBindings)
507 && maybeDirectInstanceExpression.isPresent()) {
508 BindingExpression directInstanceExpression = maybeDirectInstanceExpression.get();
509 return directInstanceExpression.requiresMethodEncapsulation()
510 || needsCaching(resolvedBindings)
cgdecker60a5dde2018-09-07 08:44:34 -0700511 ? wrapInMethod(
512 resolvedBindings,
dpb3379b952018-09-24 13:39:04 -0700513 bindingRequest(resolvedBindings.key(), RequestKind.INSTANCE),
cgdecker60a5dde2018-09-07 08:44:34 -0700514 directInstanceExpression)
dpb73afb302018-02-12 10:59:53 -0800515 : directInstanceExpression;
dpb356a6842018-02-07 07:45:50 -0800516 }
dpb5e03bd52018-08-10 14:21:15 -0700517 return new DerivedFromFrameworkInstanceBindingExpression(
dpbdb197502018-08-27 14:29:47 -0700518 resolvedBindings, FrameworkType.PROVIDER, RequestKind.INSTANCE, this, types);
dpb73afb302018-02-12 10:59:53 -0800519 }
dpb356a6842018-02-07 07:45:50 -0800520
dpb73afb302018-02-12 10:59:53 -0800521 /**
522 * Returns an unscoped binding expression for an {@link RequestKind#INSTANCE} that does not call
523 * {@code get()} on its provider, if there is one.
524 */
525 private Optional<BindingExpression> unscopedDirectInstanceExpression(
526 ResolvedBindings resolvedBindings) {
527 switch (resolvedBindings.contributionBinding().kind()) {
528 case DELEGATE:
529 return Optional.of(
530 new DelegateBindingExpression(
531 resolvedBindings, RequestKind.INSTANCE, this, types, elements));
532
533 case COMPONENT:
534 return Optional.of(
535 new ComponentInstanceBindingExpression(
dpb159d81b2018-11-01 14:06:17 -0700536 resolvedBindings, componentImplementation.name()));
dpb73afb302018-02-12 10:59:53 -0800537
538 case COMPONENT_DEPENDENCY:
539 return Optional.of(
540 new ComponentRequirementBindingExpression(
541 resolvedBindings,
542 ComponentRequirement.forDependency(resolvedBindings.key().type()),
543 componentRequirementFields));
544
545 case COMPONENT_PROVISION:
546 return Optional.of(
547 new ComponentProvisionBindingExpression(
548 resolvedBindings, graph, componentRequirementFields, compilerOptions));
549
550 case SUBCOMPONENT_BUILDER:
551 return Optional.of(
552 new SubcomponentBuilderBindingExpression(
dstrasburg61274ab2018-09-26 08:11:04 -0700553 resolvedBindings,
dpb159d81b2018-11-01 14:06:17 -0700554 componentImplementation.getSubcomponentName(resolvedBindings.key())));
dpb73afb302018-02-12 10:59:53 -0800555
556 case MULTIBOUND_SET:
557 return Optional.of(
dstrasburg09adeae2018-09-07 12:11:06 -0700558 new SetBindingExpression(
dpb159d81b2018-11-01 14:06:17 -0700559 resolvedBindings, componentImplementation, graph, this, types, elements));
dpb73afb302018-02-12 10:59:53 -0800560
561 case MULTIBOUND_MAP:
562 return Optional.of(
dstrasburg09adeae2018-09-07 12:11:06 -0700563 new MapBindingExpression(
dpb159d81b2018-11-01 14:06:17 -0700564 resolvedBindings, componentImplementation, graph, this, types, elements));
dpb73afb302018-02-12 10:59:53 -0800565
566 case OPTIONAL:
567 return Optional.of(new OptionalBindingExpression(resolvedBindings, this, types));
568
569 case BOUND_INSTANCE:
570 return Optional.of(
571 new ComponentRequirementBindingExpression(
572 resolvedBindings,
573 ComponentRequirement.forBoundInstance(resolvedBindings.contributionBinding()),
574 componentRequirementFields));
575
576 case INJECTION:
577 case PROVISION:
578 return Optional.of(
579 new SimpleMethodBindingExpression(
580 resolvedBindings,
581 compilerOptions,
582 this,
583 membersInjectionMethods,
584 componentRequirementFields,
585 elements));
586
587 case MEMBERS_INJECTOR:
dpb73afb302018-02-12 10:59:53 -0800588 return Optional.empty();
589
590 case MEMBERS_INJECTION:
591 case COMPONENT_PRODUCTION:
592 case PRODUCTION:
593 throw new IllegalArgumentException(
594 resolvedBindings.contributionBinding().kind().toString());
595 }
596 throw new AssertionError();
597 }
598
599 /**
bcorsoaf9e0042018-04-16 14:12:23 -0700600 * Returns {@code true} if the binding should use the static factory creation strategy.
601 *
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700602 * <p>In default mode, we always use the static factory creation strategy. In fastInit mode, we
bcorsod55c02d2018-06-06 15:02:34 -0700603 * prefer to use a SwitchingProvider instead of static factories in order to reduce class loading;
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700604 * however, we allow static factories that can reused across multiple bindings, e.g. {@code
605 * MapFactory} or {@code SetFactory}.
bcorsoaf9e0042018-04-16 14:12:23 -0700606 */
607 private boolean useStaticFactoryCreation(ContributionBinding binding) {
bcorsod55c02d2018-06-06 15:02:34 -0700608 return !(compilerOptions.experimentalAndroidMode2() || compilerOptions.fastInit())
bcorsoaf9e0042018-04-16 14:12:23 -0700609 || binding.kind().equals(MULTIBOUND_MAP)
610 || binding.kind().equals(MULTIBOUND_SET);
611 }
612
613 /**
dpb73afb302018-02-12 10:59:53 -0800614 * Returns {@code true} if we can use a direct (not {@code Provider.get()}) expression for this
615 * binding. If the binding doesn't {@linkplain #needsCaching(ResolvedBindings) need to be cached},
616 * we can.
617 *
bcorsod55c02d2018-06-06 15:02:34 -0700618 * <p>In fastInit mode, we can use a direct expression even if the binding {@linkplain
ronshapiroa72c3422018-10-30 15:14:05 -0700619 * #needsCaching(ResolvedBindings) needs to be cached}.
dpb73afb302018-02-12 10:59:53 -0800620 */
621 private boolean canUseDirectInstanceExpression(ResolvedBindings resolvedBindings) {
ronshapiroa72c3422018-10-30 15:14:05 -0700622 return !needsCaching(resolvedBindings) || compilerOptions.fastInit();
dpb73afb302018-02-12 10:59:53 -0800623 }
624
625 /**
dpb73afb302018-02-12 10:59:53 -0800626 * 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 -0700627 * a component provision method matches it, it will be the method implemented. If it does not
dpb10dcfba2018-09-20 09:08:38 -0700628 * match a component provision method and the binding is modifiable, then a new public modifiable
629 * binding method will be written. If the binding doesn't match a component method and is not
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700630 * modifiable, then a new private method will be written.
dpb73afb302018-02-12 10:59:53 -0800631 */
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700632 BindingExpression wrapInMethod(
dpb73afb302018-02-12 10:59:53 -0800633 ResolvedBindings resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700634 BindingRequest request,
dpb73afb302018-02-12 10:59:53 -0800635 BindingExpression bindingExpression) {
dstrasburg09adeae2018-09-07 12:11:06 -0700636 // If we've already wrapped the expression, then use the delegate.
637 if (bindingExpression instanceof MethodBindingExpression) {
638 return bindingExpression;
639 }
640
dpb73afb302018-02-12 10:59:53 -0800641 BindingMethodImplementation methodImplementation =
cgdecker60a5dde2018-09-07 08:44:34 -0700642 methodImplementation(resolvedBindings, request, bindingExpression);
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700643 Optional<ComponentMethodDescriptor> matchingComponentMethod =
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700644 graph.componentDescriptor().findMatchingComponentMethod(request);
dstrasburg92031832018-10-17 08:48:40 -0700645 Optional<ModifiableBindingMethod> matchingModifiableBindingMethod =
dpb159d81b2018-11-01 14:06:17 -0700646 componentImplementation.getModifiableBindingMethod(request);
dpb73afb302018-02-12 10:59:53 -0800647
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700648 Optional<BindingExpression> modifiableBindingExpression =
649 modifiableBindingExpressions.maybeWrapInModifiableMethodBindingExpression(
650 resolvedBindings,
651 request,
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700652 methodImplementation,
dstrasburg92031832018-10-17 08:48:40 -0700653 matchingComponentMethod,
654 matchingModifiableBindingMethod);
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700655 if (modifiableBindingExpression.isPresent()) {
656 return modifiableBindingExpression.get();
dstrasburg6d2a7ad2018-09-05 08:05:51 -0700657 }
658
659 return matchingComponentMethod
dpb73afb302018-02-12 10:59:53 -0800660 .<BindingExpression>map(
661 componentMethod ->
662 new ComponentMethodBindingExpression(
dstrasburg92031832018-10-17 08:48:40 -0700663 methodImplementation,
dpb159d81b2018-11-01 14:06:17 -0700664 componentImplementation,
dstrasburg92031832018-10-17 08:48:40 -0700665 componentMethod,
666 matchingModifiableBindingMethod))
dpb73afb302018-02-12 10:59:53 -0800667 .orElseGet(
668 () ->
669 new PrivateMethodBindingExpression(
dstrasburg92031832018-10-17 08:48:40 -0700670 resolvedBindings,
671 request,
672 methodImplementation,
dpb159d81b2018-11-01 14:06:17 -0700673 componentImplementation,
dstrasburg92031832018-10-17 08:48:40 -0700674 matchingModifiableBindingMethod));
dpb73afb302018-02-12 10:59:53 -0800675 }
676
dpb73afb302018-02-12 10:59:53 -0800677 private BindingMethodImplementation methodImplementation(
678 ResolvedBindings resolvedBindings,
cgdecker60a5dde2018-09-07 08:44:34 -0700679 BindingRequest request,
dpb73afb302018-02-12 10:59:53 -0800680 BindingExpression bindingExpression) {
bcorsod55c02d2018-06-06 15:02:34 -0700681 if (compilerOptions.fastInit()) {
cgdecker60a5dde2018-09-07 08:44:34 -0700682 if (request.isRequestKind(RequestKind.PROVIDER)) {
bcorso567ff0e2018-03-21 13:49:09 -0700683 return new SingleCheckedMethodImplementation(
dpb159d81b2018-11-01 14:06:17 -0700684 resolvedBindings, request, bindingExpression, types, componentImplementation);
cgdecker60a5dde2018-09-07 08:44:34 -0700685 } else if (request.isRequestKind(RequestKind.INSTANCE) && needsCaching(resolvedBindings)) {
bcorso567ff0e2018-03-21 13:49:09 -0700686 return resolvedBindings.scope().get().isReusable()
687 ? new SingleCheckedMethodImplementation(
dpb159d81b2018-11-01 14:06:17 -0700688 resolvedBindings, request, bindingExpression, types, componentImplementation)
bcorso567ff0e2018-03-21 13:49:09 -0700689 : new DoubleCheckedMethodImplementation(
dpb159d81b2018-11-01 14:06:17 -0700690 resolvedBindings, request, bindingExpression, types, componentImplementation);
bcorso567ff0e2018-03-21 13:49:09 -0700691 }
692 }
693
694 return new BindingMethodImplementation(
dpb159d81b2018-11-01 14:06:17 -0700695 resolvedBindings, request, bindingExpression, componentImplementation.name(), types);
dpb73afb302018-02-12 10:59:53 -0800696 }
697
698 /**
699 * Returns {@code true} if the component needs to make sure the provided value is cached.
700 *
701 * <p>The component needs to cache the value for scoped bindings except for {@code @Binds}
702 * bindings whose scope is no stronger than their delegate's.
703 */
704 private boolean needsCaching(ResolvedBindings resolvedBindings) {
705 if (!resolvedBindings.scope().isPresent()) {
706 return false;
bcorso3828ca22018-01-29 10:14:12 -0800707 }
dpb73afb302018-02-12 10:59:53 -0800708 if (resolvedBindings.contributionBinding().kind().equals(DELEGATE)) {
709 return isBindsScopeStrongerThanDependencyScope(resolvedBindings, graph);
710 }
711 return true;
712 }
dpb68c77d82017-08-15 15:23:35 -0700713}