Skip to content

Commit f397f6b

Browse files
bcorsoDagger Team
authored andcommitted
Rollback of: Combine BindingGraphFactory.Resolver's caching logic into a single location.
PiperOrigin-RevId: 661446058
1 parent 86fcef5 commit f397f6b

File tree

2 files changed

+67
-106
lines changed

2 files changed

+67
-106
lines changed

java/dagger/internal/codegen/binding/BindingGraphFactory.java

Lines changed: 67 additions & 36 deletions
Original file line numberDiff line numberDiff line change
@@ -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
}

javatests/dagger/internal/codegen/OptionalBindingTest.java

Lines changed: 0 additions & 70 deletions
Original file line numberDiff line numberDiff line change
@@ -105,74 +105,4 @@ public void provideExplicitOptionalInParent_AndBindsOptionalOfInChild() {
105105
.onLineContaining("interface Parent");
106106
});
107107
}
108-
109-
// Note: This is a regression test for an issue we ran into in CL/644086367, where an optional
110-
// binding owned by a parent component is also requested by a child component which declares an
111-
// additional @BindsOptionalOf declaration. In this case, we just want to make sure that the setup
112-
// builds successfully.
113-
@Test
114-
public void cachedInParent_succeeds() {
115-
Source parent =
116-
CompilerTests.javaSource(
117-
"test.Parent",
118-
"package test;",
119-
"",
120-
"import dagger.Component;",
121-
"import java.util.Optional;",
122-
"",
123-
"@Component(modules = ParentModule.class)",
124-
"interface Parent {",
125-
" Optional<String> optionalString();",
126-
" Child child();",
127-
"}");
128-
Source parentModule =
129-
CompilerTests.javaSource(
130-
"test.ParentModule",
131-
"package test;",
132-
"",
133-
"import dagger.BindsOptionalOf;",
134-
"import dagger.Module;",
135-
"import dagger.Provides;",
136-
"import java.util.Optional;",
137-
"",
138-
"@Module",
139-
"interface ParentModule {",
140-
" @BindsOptionalOf",
141-
" String optionalParentString();",
142-
"",
143-
" @Provides",
144-
" static String provideString() {",
145-
" return \"\";",
146-
" }",
147-
"}");
148-
Source child =
149-
CompilerTests.javaSource(
150-
"test.Child",
151-
"package test;",
152-
"",
153-
"import dagger.Subcomponent;",
154-
"import java.util.Optional;",
155-
"",
156-
"@Subcomponent(modules = ChildModule.class)",
157-
"interface Child {",
158-
" Optional<String> optionalString();",
159-
"}");
160-
Source childModule =
161-
CompilerTests.javaSource(
162-
"test.ChildModule",
163-
"package test;",
164-
"",
165-
"import dagger.BindsOptionalOf;",
166-
"import dagger.Module;",
167-
"",
168-
"@Module",
169-
"interface ChildModule {",
170-
" @BindsOptionalOf",
171-
" String optionalChildString();",
172-
"}");
173-
174-
CompilerTests.daggerCompiler(parent, parentModule, child, childModule)
175-
.withProcessingOptions(compilerMode.processorOptions())
176-
.compile(subject -> subject.hasErrorCount(0));
177-
}
178108
}

0 commit comments

Comments
 (0)