@@ -335,22 +335,13 @@ && isAssistedFactoryType(requestKey.type().xprocessing().getTypeElement())) {
335335 requestKey ,
336336 bindings .stream ()
337337 .map (
338- binding -> {
339- Optional <BindingNode > bindingNodeOwnedByAncestor =
340- getBindingNodeOwnedByAncestor (requestKey , binding );
341- // If a binding is owned by an ancestor we use the corresponding BindingNode
342- // instance directly rather than creating a new instance to avoid accidentally
343- // including additional multi/optional/subcomponent declarations that don't
344- // exist in the ancestor's BindingNode instance.
345- return bindingNodeOwnedByAncestor .isPresent ()
346- ? bindingNodeOwnedByAncestor .get ()
347- : bindingNodeFactory .forContributionBindings (
348- componentPath ,
349- binding ,
350- multibindingDeclarations ,
351- optionalBindingDeclarations ,
352- subcomponentDeclarations );
353- })
338+ binding ->
339+ bindingNodeFactory .forContributionBindings (
340+ getOwningComponentPath (requestKey , binding ),
341+ binding ,
342+ multibindingDeclarations ,
343+ optionalBindingDeclarations ,
344+ subcomponentDeclarations ))
354345 .collect (toImmutableSet ()));
355346 }
356347
@@ -452,32 +443,38 @@ private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDe
452443 }
453444
454445 /**
455- * Returns a {@link BindingNode} for the given binding that is owned by an ancestor component,
456- * if one exists. Otherwise returns {@link Optional#empty()}.
446+ * Returns the component that should contain the framework field for {@code binding}.
447+ *
448+ * <p>If {@code binding} is either not bound in an ancestor component or depends transitively on
449+ * bindings in this component, returns this component.
450+ *
451+ * <p>Otherwise, resolves {@code request} in this component's parent in order to resolve any
452+ * multibinding contributions in the parent, and returns the parent-resolved {@link
453+ * ResolvedBindings#owningComponent(ContributionBinding)}.
457454 */
458- private Optional <BindingNode > getBindingNodeOwnedByAncestor (
459- Key requestKey , ContributionBinding binding ) {
460- if (canBeResolvedInParent (requestKey , binding )) {
461- // Resolve in the parent to make sure we have the most recent multi/optional contributions.
462- parentResolver .get ().resolve (requestKey );
463- if (!requiresResolution (binding )) {
464- return Optional .of (getPreviouslyResolvedBindings (requestKey ).get ().forBinding (binding ));
465- }
455+ private ComponentPath getOwningComponentPath (Key requestKey , ContributionBinding binding ) {
456+ if (isResolvedInParent (requestKey , binding ) && !requiresResolution (binding )) {
457+ ResolvedBindings parentResolvedBindings =
458+ parentResolver .get ().resolvedContributionBindings .get (requestKey );
459+ return parentResolvedBindings .forBinding (binding ).componentPath ();
460+ } else {
461+ return componentPath ;
466462 }
467- return Optional .empty ();
468463 }
469464
470- private boolean canBeResolvedInParent (Key requestKey , ContributionBinding binding ) {
471- if (parentResolver .isEmpty ()) {
465+ /**
466+ * Returns {@code true} if {@code binding} is owned by an ancestor. If so, {@linkplain #resolve
467+ * resolves} the {@link Key} in this component's parent. Don't resolve directly in the owning
468+ * component in case it depends on multibindings in any of its descendants.
469+ */
470+ private boolean isResolvedInParent (Key requestKey , ContributionBinding binding ) {
471+ Optional <Resolver > owningResolver = getOwningResolver (binding );
472+ if (owningResolver .isPresent () && !owningResolver .get ().equals (this )) {
473+ parentResolver .get ().resolve (requestKey );
474+ return true ;
475+ } else {
472476 return false ;
473477 }
474- Optional <Resolver > owningResolver = getOwningResolver (binding );
475- return (owningResolver .isPresent () && !owningResolver .get ().equals (this ))
476- || (!Keys .isComponentOrCreator (requestKey )
477- // TODO(b/305748522): Allow caching for assisted injection bindings.
478- && binding .kind () != BindingKind .ASSISTED_INJECTION
479- && getPreviouslyResolvedBindings (requestKey ).isPresent ()
480- && getPreviouslyResolvedBindings (requestKey ).get ().bindings ().contains (binding ));
481478 }
482479
483480 private Optional <Resolver > getOwningResolver (ContributionBinding binding ) {
@@ -650,6 +647,36 @@ void resolve(Key key) {
650647 return ;
651648 }
652649
650+ /*
651+ * If the binding was previously resolved in an ancestor component, then we may be able to
652+ * avoid resolving it here and just depend on the ancestor component resolution.
653+ *
654+ * 1. If it depends transitively on multibinding contributions or optional bindings with
655+ * bindings from this subcomponent, then we have to resolve it in this subcomponent so
656+ * that it sees the local bindings.
657+ *
658+ * 2. If there are any explicit bindings in this component, they may conflict with those in
659+ * the ancestor component, so resolve them here so that conflicts can be caught.
660+ */
661+ if (getPreviouslyResolvedBindings (key ).isPresent () && !Keys .isComponentOrCreator (key )) {
662+ /* Resolve in the parent in case there are multibinding contributions or conflicts in some
663+ * component between this one and the previously-resolved one. */
664+ parentResolver .get ().resolve (key );
665+ ResolvedBindings previouslyResolvedBindings = getPreviouslyResolvedBindings (key ).get ();
666+ // TODO(b/305748522): Allow caching for assisted injection bindings.
667+ boolean isAssistedInjectionBinding =
668+ previouslyResolvedBindings .bindings ().stream ()
669+ .anyMatch (binding -> binding .kind () == BindingKind .ASSISTED_INJECTION );
670+ if (!isAssistedInjectionBinding
671+ && !requiresResolution (key )
672+ && !hasLocalExplicitBindings (key )) {
673+ /* Cache the inherited parent component's bindings in case resolving at the parent found
674+ * bindings in some component between this one and the previously-resolved one. */
675+ resolvedContributionBindings .put (key , previouslyResolvedBindings );
676+ return ;
677+ }
678+ }
679+
653680 cycleStack .push (key );
654681 try {
655682 ResolvedBindings bindings = lookUpBindings (key );
@@ -686,6 +713,10 @@ private ResolvedBindings getResolvedMembersInjectionBindings(Key key) {
686713 return resolvedMembersInjectionBindings .get (key );
687714 }
688715
716+ private boolean requiresResolution (Key key ) {
717+ return new LegacyRequiresResolutionChecker ().requiresResolution (key );
718+ }
719+
689720 private boolean requiresResolution (Binding binding ) {
690721 return new LegacyRequiresResolutionChecker ().requiresResolution (binding );
691722 }
0 commit comments