blob: 6755825a2d7ccedfa7435e7ff8e8c8a65e405aa6 [file] [log] [blame]
dstrasburgf0f6dfb2018-09-27 12:00:42 -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
ronshapirodb0d66b2018-11-19 12:16:43 -080019import static com.google.common.base.Preconditions.checkState;
ronshapiro28f06f22018-11-12 14:03:15 -080020import static com.google.common.collect.Iterables.getOnlyElement;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070021import static dagger.internal.codegen.BindingRequest.bindingRequest;
ronshapiroa46aea82018-10-29 10:08:01 -070022import static javax.lang.model.element.Modifier.FINAL;
ronshapiroad1ed9f2018-11-19 07:32:53 -080023import static javax.lang.model.element.Modifier.PROTECTED;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070024import static javax.lang.model.element.Modifier.PUBLIC;
25
ronshapiroa46aea82018-10-29 10:08:01 -070026import com.google.common.collect.ImmutableSet;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070027import com.squareup.javapoet.MethodSpec;
28import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
29import dagger.internal.codegen.ModifiableBindingMethods.ModifiableBindingMethod;
30import dagger.model.BindingKind;
ronshapiroac53c252018-11-26 08:04:55 -080031import dagger.model.Scope;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070032import java.util.Optional;
33
34/**
35 * A central repository of code expressions used to access modifiable bindings available to a
36 * component. A binding is modifiable if it can be modified across implementations of a
37 * subcomponent. This is only relevant for ahead-of-time subcomponents.
38 */
39final class ModifiableBindingExpressions {
40 private final Optional<ModifiableBindingExpressions> parent;
41 private final ComponentBindingExpressions bindingExpressions;
42 private final BindingGraph graph;
dpb159d81b2018-11-01 14:06:17 -070043 private final ComponentImplementation componentImplementation;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070044 private final CompilerOptions compilerOptions;
ronshapiro8d759b22018-11-05 09:57:39 -080045 private final DaggerTypes types;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070046
47 ModifiableBindingExpressions(
48 Optional<ModifiableBindingExpressions> parent,
49 ComponentBindingExpressions bindingExpressions,
50 BindingGraph graph,
dpb159d81b2018-11-01 14:06:17 -070051 ComponentImplementation componentImplementation,
ronshapiro8d759b22018-11-05 09:57:39 -080052 CompilerOptions compilerOptions,
53 DaggerTypes types) {
dstrasburgf0f6dfb2018-09-27 12:00:42 -070054 this.parent = parent;
55 this.bindingExpressions = bindingExpressions;
56 this.graph = graph;
dpb159d81b2018-11-01 14:06:17 -070057 this.componentImplementation = componentImplementation;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070058 this.compilerOptions = compilerOptions;
ronshapiro8d759b22018-11-05 09:57:39 -080059 this.types = types;
dstrasburgf0f6dfb2018-09-27 12:00:42 -070060 }
61
62 /**
63 * Records the binding exposed by the given component method as modifiable, if it is, and returns
64 * the {@link ModifiableBindingType} associated with the binding.
65 */
66 ModifiableBindingType registerComponentMethodIfModifiable(
67 ComponentMethodDescriptor componentMethod, MethodSpec method) {
68 BindingRequest request = bindingRequest(componentMethod.dependencyRequest().get());
69 ModifiableBindingType modifiableBindingType = getModifiableBindingType(request);
70 if (modifiableBindingType.isModifiable()) {
dpb159d81b2018-11-01 14:06:17 -070071 componentImplementation.registerModifiableBindingMethod(
dstrasburgf0f6dfb2018-09-27 12:00:42 -070072 modifiableBindingType,
73 request,
74 method,
75 newModifiableBindingWillBeFinalized(modifiableBindingType, request));
76 }
77 return modifiableBindingType;
78 }
79
80 /**
81 * Returns the implementation of a modifiable binding method originally defined in a supertype
82 * implementation of this subcomponent. Returns {@link Optional#empty()} when the binding cannot
83 * or should not be modified by the current binding graph.
84 */
ronshapirodb0d66b2018-11-19 12:16:43 -080085 Optional<ModifiableBindingMethod> reimplementedModifiableBindingMethod(
dstrasburgf0f6dfb2018-09-27 12:00:42 -070086 ModifiableBindingMethod modifiableBindingMethod) {
ronshapirodb0d66b2018-11-19 12:16:43 -080087 checkState(componentImplementation.superclassImplementation().isPresent());
88 if (modifiableBindingTypeChanged(modifiableBindingMethod)
89 || shouldModifyImplementation(
90 modifiableBindingMethod.type(), modifiableBindingMethod.request())) {
dstrasburgf0f6dfb2018-09-27 12:00:42 -070091 MethodSpec baseMethod = modifiableBindingMethod.methodSpec();
ronshapiroa46aea82018-10-29 10:08:01 -070092 boolean markMethodFinal =
93 knownModifiableBindingWillBeFinalized(modifiableBindingMethod)
94 // no need to mark the method final if the component implementation will be final
dpb159d81b2018-11-01 14:06:17 -070095 && componentImplementation.isAbstract();
dstrasburgf0f6dfb2018-09-27 12:00:42 -070096 return Optional.of(
97 ModifiableBindingMethod.implement(
98 modifiableBindingMethod,
99 MethodSpec.methodBuilder(baseMethod.name)
ronshapiroad1ed9f2018-11-19 07:32:53 -0800100 .addModifiers(baseMethod.modifiers.contains(PUBLIC) ? PUBLIC : PROTECTED)
ronshapiroa46aea82018-10-29 10:08:01 -0700101 .addModifiers(markMethodFinal ? ImmutableSet.of(FINAL) : ImmutableSet.of())
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700102 .returns(baseMethod.returnType)
103 .addAnnotation(Override.class)
104 .addCode(
105 bindingExpressions
106 .getBindingExpression(modifiableBindingMethod.request())
107 .getModifiableBindingMethodImplementation(
ronshapiro66dd69f2018-11-27 08:49:26 -0800108 modifiableBindingMethod, componentImplementation, types))
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700109 .build(),
ronshapiroa46aea82018-10-29 10:08:01 -0700110 markMethodFinal));
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700111 }
112 return Optional.empty();
113 }
114
115 /**
116 * Returns true if a modifiable binding method that was registered in a superclass implementation
117 * of this subcomponent should be marked as "finalized" if it is being overridden by this
118 * subcomponent implementation. "Finalized" means we should not attempt to modify the binding in
119 * any subcomponent subclass.
120 */
121 private boolean knownModifiableBindingWillBeFinalized(
122 ModifiableBindingMethod modifiableBindingMethod) {
123 ModifiableBindingType newModifiableBindingType =
124 getModifiableBindingType(modifiableBindingMethod.request());
125 if (!newModifiableBindingType.isModifiable()) {
126 // If a modifiable binding has become non-modifiable it is final by definition.
127 return true;
128 }
129 return modifiableBindingWillBeFinalized(
130 newModifiableBindingType,
ronshapirodb0d66b2018-11-19 12:16:43 -0800131 shouldModifyImplementation(newModifiableBindingType, modifiableBindingMethod.request()));
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700132 }
133
134 /**
135 * Returns true if a newly discovered modifiable binding method, once it is defined in this
136 * subcomponent implementation, should be marked as "finalized", meaning we should not attempt to
137 * modify the binding in any subcomponent subclass.
138 */
139 private boolean newModifiableBindingWillBeFinalized(
140 ModifiableBindingType modifiableBindingType, BindingRequest request) {
141 return modifiableBindingWillBeFinalized(
ronshapirodb0d66b2018-11-19 12:16:43 -0800142 modifiableBindingType, shouldModifyImplementation(modifiableBindingType, request));
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700143 }
144
145 /**
146 * Returns true if we shouldn't attempt to further modify a modifiable binding once we complete
147 * the implementation for the current subcomponent.
148 */
149 private boolean modifiableBindingWillBeFinalized(
150 ModifiableBindingType modifiableBindingType, boolean modifyingBinding) {
151 switch (modifiableBindingType) {
152 case MISSING:
153 case GENERATED_INSTANCE:
154 case OPTIONAL:
155 case INJECTION:
156 // Once we modify any of the above a single time, then they are finalized.
157 return modifyingBinding;
ronshapiroac53c252018-11-26 08:04:55 -0800158 case PRODUCTION:
159 // For production bindings, we know that the binding will be finalized if the parent is a
160 // non-production component, but for @ProductionScope bindings we don't ever know because an
161 // ancestor non-production component can apply @ProductionScope. We therefore return false
162 // always. If we wanted, we could create a separate ModifiableBindingType for production
163 // scope to allow us to make this distinction.
164 return false;
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700165 case MULTIBINDING:
dstrasburgdd0e7b02018-10-04 08:24:41 -0700166 case MODULE_INSTANCE:
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700167 return false;
168 default:
169 throw new IllegalStateException(
170 String.format(
171 "Building binding expression for unsupported ModifiableBindingType [%s].",
172 modifiableBindingType));
173 }
174 }
175
176 /**
177 * Creates a binding expression for a binding if it may be modified across implementations of a
178 * subcomponent.
179 */
180 Optional<BindingExpression> maybeCreateModifiableBindingExpression(BindingRequest request) {
181 ModifiableBindingType type = getModifiableBindingType(request);
182 if (!type.isModifiable()) {
183 return Optional.empty();
184 }
185 return Optional.of(createModifiableBindingExpression(type, request));
186 }
187
188 /** Creates a binding expression for a modifiable binding. */
189 private BindingExpression createModifiableBindingExpression(
190 ModifiableBindingType type, BindingRequest request) {
191 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
192 Optional<ModifiableBindingMethod> matchingModifiableBindingMethod =
dpb159d81b2018-11-01 14:06:17 -0700193 componentImplementation.getModifiableBindingMethod(request);
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700194 Optional<ComponentMethodDescriptor> matchingComponentMethod =
dpb115b10e2018-11-14 09:08:31 -0800195 graph.componentDescriptor().firstMatchingComponentMethod(request);
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700196 switch (type) {
197 case GENERATED_INSTANCE:
dstrasburge38705f2018-10-16 18:26:35 -0700198 // If the subcomponent is abstract then we need to define an (un-implemented)
199 // GeneratedInstanceBindingExpression.
dpb159d81b2018-11-01 14:06:17 -0700200 if (componentImplementation.isAbstract()) {
dstrasburge38705f2018-10-16 18:26:35 -0700201 return new GeneratedInstanceBindingExpression(
dpb159d81b2018-11-01 14:06:17 -0700202 componentImplementation,
dstrasburge38705f2018-10-16 18:26:35 -0700203 resolvedBindings,
204 request,
205 matchingModifiableBindingMethod,
ronshapiro1ae4c002018-11-16 08:23:34 -0800206 matchingComponentMethod,
207 types);
dstrasburge38705f2018-10-16 18:26:35 -0700208 }
209 // Otherwise return a concrete implementation.
ronshapiroa9185312018-11-20 18:03:13 -0800210 return bindingExpressions.createBindingExpression(resolvedBindings, request);
211
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700212 case MISSING:
dstrasburge38705f2018-10-16 18:26:35 -0700213 // If we need an expression for a missing binding and the current implementation is
214 // abstract, then we need an (un-implemented) MissingBindingExpression.
dpb159d81b2018-11-01 14:06:17 -0700215 if (componentImplementation.isAbstract()) {
dstrasburge38705f2018-10-16 18:26:35 -0700216 return new MissingBindingExpression(
dpb159d81b2018-11-01 14:06:17 -0700217 componentImplementation,
dstrasburge38705f2018-10-16 18:26:35 -0700218 request,
219 matchingModifiableBindingMethod,
ronshapiro1ae4c002018-11-16 08:23:34 -0800220 matchingComponentMethod,
221 types);
dstrasburge38705f2018-10-16 18:26:35 -0700222 }
223 // Otherwise we assume that it is valid to have a missing binding as it is part of a
224 // dependency chain that has been passively pruned.
225 // TODO(b/117833324): Identify pruned bindings when generating the subcomponent
dpb159d81b2018-11-01 14:06:17 -0700226 // implementation in which the bindings are pruned. If we hold a reference to the binding
227 // graph used to generate a given implementation then we can compare a implementation's
228 // graph with its superclass implementation's graph to detect pruned dependency branches.
dstrasburge38705f2018-10-16 18:26:35 -0700229 return new PrunedConcreteMethodBindingExpression();
ronshapiroa9185312018-11-20 18:03:13 -0800230
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700231 case OPTIONAL:
232 case MULTIBINDING:
233 case INJECTION:
dstrasburgdd0e7b02018-10-04 08:24:41 -0700234 case MODULE_INSTANCE:
ronshapiroac53c252018-11-26 08:04:55 -0800235 case PRODUCTION:
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700236 return bindingExpressions.wrapInMethod(
237 resolvedBindings,
238 request,
239 bindingExpressions.createBindingExpression(resolvedBindings, request));
240 default:
241 throw new IllegalStateException(
242 String.format(
243 "Building binding expression for unsupported ModifiableBindingType [%s].", type));
244 }
245 }
246
247 /**
248 * The reason why a binding may need to be modified across implementations of a subcomponent, if
249 * at all.
250 */
ronshapiroab61b702018-11-21 12:23:33 -0800251 ModifiableBindingType getModifiableBindingType(BindingRequest request) {
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700252 if (!compilerOptions.aheadOfTimeSubcomponents()) {
253 return ModifiableBindingType.NONE;
254 }
255
dstrasburge38705f2018-10-16 18:26:35 -0700256 // When generating a component the binding is not considered modifiable. Bindings are modifiable
257 // only across subcomponent implementations.
dpb159d81b2018-11-01 14:06:17 -0700258 if (componentImplementation.componentDescriptor().kind().isTopLevel()) {
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700259 return ModifiableBindingType.NONE;
260 }
261
262 if (resolvedInThisComponent(request)) {
263 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
264 if (resolvedBindings.contributionBindings().isEmpty()) {
265 // TODO(ronshapiro): Confirm whether a resolved binding must have a single contribution
266 // binding.
267 return ModifiableBindingType.NONE;
268 }
269
270 ContributionBinding binding = resolvedBindings.contributionBinding();
271 if (binding.requiresGeneratedInstance()) {
272 return ModifiableBindingType.GENERATED_INSTANCE;
273 }
274
ronshapiro28f06f22018-11-12 14:03:15 -0800275 if (binding.kind().equals(BindingKind.DELEGATE)
276 && graph
277 .contributionBindings()
278 .get(getOnlyElement(binding.dependencies()).key())
279 .isEmpty()) {
280 // There's not much to do for @Binds bindings if the dependency is missing - at best, if the
281 // dependency is a weaker scope/unscoped, we save only a few lines that implement the
282 // scoping. But it's also possible, if the dependency is the same or stronger scope, that
283 // no extra code is necessary, in which case we'd be overriding a method that just returns
284 // another.
285 return ModifiableBindingType.MISSING;
286 }
287
ronshapiro3bd86322018-10-29 13:18:38 -0700288 if (binding.kind().equals(BindingKind.OPTIONAL) && binding.dependencies().isEmpty()) {
289 // only empty optional bindings can be modified
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700290 return ModifiableBindingType.OPTIONAL;
291 }
292
ronshapiro8d759b22018-11-05 09:57:39 -0800293 if (binding.isSyntheticMultibinding()) {
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700294 return ModifiableBindingType.MULTIBINDING;
295 }
296
297 if (binding.kind().equals(BindingKind.INJECTION)) {
298 return ModifiableBindingType.INJECTION;
299 }
dstrasburgdd0e7b02018-10-04 08:24:41 -0700300
ronshapiroba2e3802018-11-26 18:30:29 -0800301 // TODO(b/117833324): Check whether we need to modify a module instance binding if we are
dstrasburgdd0e7b02018-10-04 08:24:41 -0700302 // correctly installing the new module instance. In other words, if there is a subcomponent
303 // builder should we consider a module instance binding modifiable?
304 if (binding.requiresModuleInstance()) {
305 return ModifiableBindingType.MODULE_INSTANCE;
306 }
ronshapiroac53c252018-11-26 08:04:55 -0800307
308 if ((binding.scope().map(Scope::isProductionScope).orElse(false)
309 && componentImplementation.isAbstract())
310 || binding.bindingType().equals(BindingType.PRODUCTION)) {
311 return ModifiableBindingType.PRODUCTION;
312 }
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700313 } else if (!resolvableBinding(request)) {
314 return ModifiableBindingType.MISSING;
315 }
316
317 return ModifiableBindingType.NONE;
318 }
319
320 /**
ronshapirodb0d66b2018-11-19 12:16:43 -0800321 * Returns true if the modifiable binding type of a {@code modifiableBindingMethod}'s request is
322 * different in this implementation from what it was in the super implementation.
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700323 */
ronshapirodb0d66b2018-11-19 12:16:43 -0800324 private boolean modifiableBindingTypeChanged(ModifiableBindingMethod modifiableBindingMethod) {
325 checkState(componentImplementation.superclassImplementation().isPresent());
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700326 ModifiableBindingType newModifiableBindingType =
327 getModifiableBindingType(modifiableBindingMethod.request());
ronshapirodb0d66b2018-11-19 12:16:43 -0800328 return !newModifiableBindingType.equals(modifiableBindingMethod.type());
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700329 }
330
331 /**
332 * Returns true if the current binding graph can, and should, modify a binding by overriding a
333 * modifiable binding method.
334 */
ronshapirodb0d66b2018-11-19 12:16:43 -0800335 private boolean shouldModifyImplementation(
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700336 ModifiableBindingType modifiableBindingType, BindingRequest request) {
ronshapiro8d759b22018-11-05 09:57:39 -0800337 if (request.requestKind().isPresent()) {
338 switch (request.requestKind().get()) {
339 case FUTURE:
340 // Futures are always requested by a Producer.get() call, so if the binding is modifiable,
341 // the producer will be wrapped in a modifiable method and the future can refer to that
342 // method; even if the producer binding is modified, getModifiableProducer().get() will
343 // never need to be modified. Furthermore, because cancellation is treated by wrapped
344 // producers, and those producers point to the modifiable producer wrapper methods, we
345 // never need or want to change the access of these wrapped producers for entry
346 // methods
347 return false;
348
349 case LAZY:
350 case PROVIDER_OF_LAZY:
351 // Lazy and ProviderOfLazy are always created from a Provider, and therefore this request
352 // never needs to be modifiable. It will refer (via DoubleCheck.lazy() or
353 // ProviderOfLazy.create()) to the modifiable method and not the framework instance.
354 return false;
355
356 case MEMBERS_INJECTION:
357 case PRODUCED:
358 // MEMBERS_INJECTION has a completely different code path for binding expressions, and
359 // PRODUCED requests are only requestable in @Produces methods, which are hidden from
360 // generated components inside Producer factories
361 throw new AssertionError(request);
362
363 case INSTANCE:
364 case PROVIDER:
365 case PRODUCER:
366 // These may be modifiable, so run through the regular logic. They're spelled out
367 // explicitly so that ErrorProne will detect if a new enum value is created and missing
368 // from this list.
369 break;
370 }
371 }
372
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700373 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
374 switch (modifiableBindingType) {
375 case GENERATED_INSTANCE:
dpb159d81b2018-11-01 14:06:17 -0700376 return !componentImplementation.isAbstract();
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700377 case MISSING:
ronshapiroba2e3802018-11-26 18:30:29 -0800378 // TODO(b/117833324): investigate beder@'s comment about having intermediate component
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700379 // ancestors satisfy missing bindings of their children with their own missing binding
380 // methods so that we can minimize the cases where we need to reach into doubly-nested
dstrasburge38705f2018-10-16 18:26:35 -0700381 // descendant component implementations.
382
383 // Implement a missing binding if it is resolvable, or if we're generating a concrete
384 // subcomponent implementation. If a binding is still missing when the subcomponent
385 // implementation is concrete then it is assumed to be part of a dependency that would have
386 // been passively pruned when implementing the full component hierarchy.
dpb159d81b2018-11-01 14:06:17 -0700387 return resolvableBinding(request) || !componentImplementation.isAbstract();
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700388 case OPTIONAL:
389 // Only override optional binding methods if we have a non-empty binding.
390 return !resolvedBindings.contributionBinding().dependencies().isEmpty();
391 case MULTIBINDING:
392 // Only modify a multibinding if there are new contributions.
dpb159d81b2018-11-01 14:06:17 -0700393 return !componentImplementation
ronshapiro8d759b22018-11-05 09:57:39 -0800394 .superclassContributionsMade(request)
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700395 .containsAll(resolvedBindings.contributionBinding().dependencies());
396 case INJECTION:
397 return !resolvedBindings.contributionBinding().kind().equals(BindingKind.INJECTION);
dstrasburgdd0e7b02018-10-04 08:24:41 -0700398 case MODULE_INSTANCE:
399 // At the moment we have no way of detecting whether a new module instance is installed and
400 // the implementation has changed, so we implement the binding once in the base
401 // implementation of the subcomponent. It will be re-implemented when generating the
402 // component.
dpb159d81b2018-11-01 14:06:17 -0700403 return !componentImplementation.superclassImplementation().isPresent()
404 || !componentImplementation.isAbstract();
ronshapiroac53c252018-11-26 08:04:55 -0800405 case PRODUCTION:
406 // TODO(b/117833324): Profile this to see if this check is slow
407 return !resolvedBindings
408 .owningComponent()
409 .equals(componentImplementation.componentDescriptor());
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700410 default:
411 throw new IllegalStateException(
412 String.format(
413 "Overriding modifiable binding method with unsupported ModifiableBindingType [%s].",
414 modifiableBindingType));
415 }
416 }
417
418 /**
419 * Returns true if the binding can be resolved by the graph for this component or any parent
420 * component.
421 */
422 private boolean resolvableBinding(BindingRequest request) {
423 for (ModifiableBindingExpressions expressions = this;
424 expressions != null;
425 expressions = expressions.parent.orElse(null)) {
426 if (expressions.resolvedInThisComponent(request)) {
427 return true;
428 }
429 }
430 return false;
431 }
432
433 /** Returns true if the binding can be resolved by the graph for this component. */
434 private boolean resolvedInThisComponent(BindingRequest request) {
435 ResolvedBindings resolvedBindings = graph.resolvedBindings(request);
436 return resolvedBindings != null && !resolvedBindings.ownedBindings().isEmpty();
437 }
438
439 /**
ronshapiroab61b702018-11-21 12:23:33 -0800440 * Wraps a modifiable binding expression in a method that can be overridden in a subclass
441 * implementation.
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700442 */
ronshapiroab61b702018-11-21 12:23:33 -0800443 BindingExpression wrapInModifiableMethodBindingExpression(
444 ContributionBinding binding,
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700445 BindingRequest request,
ronshapiroab61b702018-11-21 12:23:33 -0800446 BindingMethodImplementation methodImplementation) {
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700447 ModifiableBindingType modifiableBindingType = getModifiableBindingType(request);
ronshapiroab61b702018-11-21 12:23:33 -0800448 checkState(modifiableBindingType.isModifiable());
449 return new ModifiableConcreteMethodBindingExpression(
450 binding,
451 request,
452 modifiableBindingType,
453 methodImplementation,
454 componentImplementation,
455 newModifiableBindingWillBeFinalized(modifiableBindingType, request),
456 types);
dstrasburgf0f6dfb2018-09-27 12:00:42 -0700457 }
458}