• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2014 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 
17 package dagger.internal.codegen.binding;
18 
19 import static com.google.common.base.Preconditions.checkArgument;
20 import static com.google.common.base.Preconditions.checkNotNull;
21 import static dagger.internal.codegen.base.Util.reentrantComputeIfAbsent;
22 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedFactoryType;
23 import static dagger.internal.codegen.extension.DaggerCollectors.onlyElement;
24 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
25 import static dagger.internal.codegen.model.BindingKind.ASSISTED_INJECTION;
26 import static dagger.internal.codegen.model.BindingKind.DELEGATE;
27 import static dagger.internal.codegen.model.BindingKind.INJECTION;
28 import static dagger.internal.codegen.model.BindingKind.OPTIONAL;
29 import static dagger.internal.codegen.model.BindingKind.SUBCOMPONENT_CREATOR;
30 import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION;
31 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared;
32 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf;
33 import static java.util.function.Predicate.isEqual;
34 
35 import androidx.room.compiler.processing.XTypeElement;
36 import com.google.auto.value.AutoValue;
37 import com.google.auto.value.extension.memoized.Memoized;
38 import com.google.common.collect.ImmutableList;
39 import com.google.common.collect.ImmutableSet;
40 import com.google.common.collect.Iterables;
41 import dagger.Reusable;
42 import dagger.internal.codegen.base.ContributionType;
43 import dagger.internal.codegen.base.Keys;
44 import dagger.internal.codegen.base.MapType;
45 import dagger.internal.codegen.base.SetType;
46 import dagger.internal.codegen.compileroption.CompilerOptions;
47 import dagger.internal.codegen.javapoet.TypeNames;
48 import dagger.internal.codegen.model.BindingGraph.ComponentNode;
49 import dagger.internal.codegen.model.BindingKind;
50 import dagger.internal.codegen.model.ComponentPath;
51 import dagger.internal.codegen.model.DaggerTypeElement;
52 import dagger.internal.codegen.model.DependencyRequest;
53 import dagger.internal.codegen.model.Key;
54 import dagger.internal.codegen.model.RequestKind;
55 import dagger.internal.codegen.model.Scope;
56 import java.util.ArrayDeque;
57 import java.util.Deque;
58 import java.util.HashMap;
59 import java.util.HashSet;
60 import java.util.LinkedHashMap;
61 import java.util.LinkedHashSet;
62 import java.util.Map;
63 import java.util.Optional;
64 import java.util.Queue;
65 import java.util.Set;
66 import javax.inject.Inject;
67 
68 /** A factory for {@link BindingGraph} objects. */
69 public final class LegacyBindingGraphFactory {
70 
useLegacyBindingGraphFactory( CompilerOptions compilerOptions, ComponentDescriptor componentDescriptor)71   static boolean useLegacyBindingGraphFactory(
72       CompilerOptions compilerOptions, ComponentDescriptor componentDescriptor) {
73     return !compilerOptions.useBindingGraphFix();
74   }
75 
hasStrictMultibindingsExemption( CompilerOptions compilerOptions, ContributionBinding binding)76   static boolean hasStrictMultibindingsExemption(
77       CompilerOptions compilerOptions, ContributionBinding binding) {
78     // We only give the exemption to multibound map contributions.
79     if (!binding.contributionType().equals(ContributionType.MAP)) {
80       return false;
81     }
82     return !compilerOptions.strictMultibindingValidation();
83   }
84 
85   private final InjectBindingRegistry injectBindingRegistry;
86   private final KeyFactory keyFactory;
87   private final BindingFactory bindingFactory;
88   private final BindingNode.Factory bindingNodeFactory;
89   private final ComponentDeclarations.Factory componentDeclarationsFactory;
90   private final LegacyBindingGraphConverter legacyBindingGraphConverter;
91   private final CompilerOptions compilerOptions;
92 
93   @Inject
LegacyBindingGraphFactory( InjectBindingRegistry injectBindingRegistry, KeyFactory keyFactory, BindingFactory bindingFactory, BindingNode.Factory bindingNodeFactory, ComponentDeclarations.Factory componentDeclarationsFactory, LegacyBindingGraphConverter legacyBindingGraphConverter, CompilerOptions compilerOptions)94   LegacyBindingGraphFactory(
95       InjectBindingRegistry injectBindingRegistry,
96       KeyFactory keyFactory,
97       BindingFactory bindingFactory,
98       BindingNode.Factory bindingNodeFactory,
99       ComponentDeclarations.Factory componentDeclarationsFactory,
100       LegacyBindingGraphConverter legacyBindingGraphConverter,
101       CompilerOptions compilerOptions) {
102     this.injectBindingRegistry = injectBindingRegistry;
103     this.keyFactory = keyFactory;
104     this.bindingFactory = bindingFactory;
105     this.bindingNodeFactory = bindingNodeFactory;
106     this.componentDeclarationsFactory = componentDeclarationsFactory;
107     this.legacyBindingGraphConverter = legacyBindingGraphConverter;
108     this.compilerOptions = compilerOptions;
109   }
110 
111   /**
112    * Creates a binding graph for a component.
113    *
114    * @param createFullBindingGraph if {@code true}, the binding graph will include all bindings;
115    *     otherwise it will include only bindings reachable from at least one entry point
116    */
create( ComponentDescriptor componentDescriptor, boolean createFullBindingGraph)117   public BindingGraph create(
118       ComponentDescriptor componentDescriptor, boolean createFullBindingGraph) {
119     return legacyBindingGraphConverter.convert(
120         createLegacyBindingGraph(Optional.empty(), componentDescriptor, createFullBindingGraph),
121         createFullBindingGraph);
122   }
123 
createLegacyBindingGraph( Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor, boolean createFullBindingGraph)124   private LegacyBindingGraph createLegacyBindingGraph(
125       Optional<Resolver> parentResolver,
126       ComponentDescriptor componentDescriptor,
127       boolean createFullBindingGraph) {
128     Resolver requestResolver = new Resolver(parentResolver, componentDescriptor);
129 
130     componentDescriptor.entryPointMethods().stream()
131         .map(method -> method.dependencyRequest().get())
132         .forEach(
133             entryPoint -> {
134               if (entryPoint.kind().equals(MEMBERS_INJECTION)) {
135                 requestResolver.resolveMembersInjection(entryPoint.key());
136               } else {
137                 requestResolver.resolve(entryPoint.key());
138               }
139             });
140 
141     if (createFullBindingGraph) {
142       // Resolve the keys for all bindings in all modules, stripping any multibinding contribution
143       // identifier so that the multibinding itself is resolved.
144       requestResolver.declarations.allDeclarations().stream()
145           // TODO(b/349155899): Consider resolving all declarations in full binding graph mode, not
146           //   just those from modules.
147           .filter(declaration -> declaration.contributingModule().isPresent())
148           .map(Declaration::key)
149           .map(Key::withoutMultibindingContributionIdentifier)
150           .forEach(requestResolver::resolve);
151     }
152 
153     // Resolve all bindings for subcomponents, creating subgraphs for all subcomponents that have
154     // been detected during binding resolution. If a binding for a subcomponent is never resolved,
155     // no BindingGraph will be created for it and no implementation will be generated. This is
156     // done in a queue since resolving one subcomponent might resolve a key for a subcomponent
157     // from a parent graph. This is done until no more new subcomponents are resolved.
158     Set<ComponentDescriptor> resolvedSubcomponents = new HashSet<>();
159     ImmutableList.Builder<LegacyBindingGraph> subgraphs = ImmutableList.builder();
160     for (ComponentDescriptor subcomponent :
161         Iterables.consumingIterable(requestResolver.subcomponentsToResolve)) {
162       if (resolvedSubcomponents.add(subcomponent)) {
163         subgraphs.add(
164             createLegacyBindingGraph(
165                 Optional.of(requestResolver), subcomponent, createFullBindingGraph));
166       }
167     }
168 
169     return new LegacyBindingGraph(requestResolver, subgraphs.build());
170   }
171 
172   /** Represents a fully resolved binding graph. */
173   static final class LegacyBindingGraph {
174     private final Resolver resolver;
175     private final ImmutableList<LegacyBindingGraph> resolvedSubgraphs;
176     private final ComponentNode componentNode;
177 
LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs)178     LegacyBindingGraph(Resolver resolver, ImmutableList<LegacyBindingGraph> resolvedSubgraphs) {
179       this.resolver = resolver;
180       this.resolvedSubgraphs = resolvedSubgraphs;
181       this.componentNode =
182           ComponentNodeImpl.create(resolver.componentPath, resolver.componentDescriptor);
183     }
184 
185     /** Returns the {@link ComponentNode} associated with this binding graph. */
componentNode()186     public ComponentNode componentNode() {
187       return componentNode;
188     }
189 
190     /** Returns the {@link ComponentPath} associated with this binding graph. */
componentPath()191     public ComponentPath componentPath() {
192       return resolver.componentPath;
193     }
194 
195     /** Returns the {@link ComponentDescriptor} associated with this binding graph. */
componentDescriptor()196     public ComponentDescriptor componentDescriptor() {
197       return resolver.componentDescriptor;
198     }
199 
200     /**
201      * Returns the {@link LegacyResolvedBindings} in this graph or a parent graph that matches the
202      * given request.
203      *
204      * <p>An exception is thrown if there are no resolved bindings found for the request; however,
205      * this should never happen since all dependencies should have been resolved at this point.
206      */
resolvedBindings(BindingRequest request)207     public LegacyResolvedBindings resolvedBindings(BindingRequest request) {
208       return request.isRequestKind(RequestKind.MEMBERS_INJECTION)
209           ? resolver.getResolvedMembersInjectionBindings(request.key())
210           : resolver.getResolvedContributionBindings(request.key());
211     }
212 
213     /**
214      * Returns all {@link LegacyResolvedBindings} for the given request.
215      *
216      * <p>Note that this only returns the bindings resolved in this component. Bindings resolved in
217      * parent components are not included.
218      */
resolvedBindings()219     public Iterable<LegacyResolvedBindings> resolvedBindings() {
220       // Don't return an immutable collection - this is only ever used for looping over all bindings
221       // in the graph. Copying is wasteful, especially if is a hashing collection, since the values
222       // should all, by definition, be distinct.
223       return Iterables.concat(
224           resolver.resolvedMembersInjectionBindings.values(),
225           resolver.resolvedContributionBindings.values());
226     }
227 
228     /** Returns the resolved subgraphs. */
subgraphs()229     public ImmutableList<LegacyBindingGraph> subgraphs() {
230       return resolvedSubgraphs;
231     }
232   }
233 
234   /**
235    * The collection of bindings that have been resolved for a key. For valid graphs, contains
236    * exactly one binding.
237    *
238    * <p>Separate {@link LegacyResolvedBindings} instances should be used if a {@link
239    * MembersInjectionBinding} and a {@link ProvisionBinding} for the same key exist in the same
240    * component. (This will only happen if a type has an {@code @Inject} constructor and members, the
241    * component has a members injection method, and the type is also requested normally.)
242    */
243   @AutoValue
244   abstract static class LegacyResolvedBindings {
245     /**
246      * Creates a {@link LegacyResolvedBindings} appropriate for when there are no bindings for a
247      * key.
248      */
create(Key key)249     static LegacyResolvedBindings create(Key key) {
250       return create(key, ImmutableSet.of());
251     }
252 
253     /** Creates a {@link LegacyResolvedBindings} for a single binding. */
create(Key key, BindingNode bindingNode)254     static LegacyResolvedBindings create(Key key, BindingNode bindingNode) {
255       return create(key, ImmutableSet.of(bindingNode));
256     }
257 
258     /** Creates a {@link LegacyResolvedBindings} for multiple bindings. */
create(Key key, ImmutableSet<BindingNode> bindingNodes)259     static LegacyResolvedBindings create(Key key, ImmutableSet<BindingNode> bindingNodes) {
260       return new AutoValue_LegacyBindingGraphFactory_LegacyResolvedBindings(key, bindingNodes);
261     }
262 
263     /** The binding key for which the {@link #bindings()} have been resolved. */
key()264     abstract Key key();
265 
266     /** All binding nodes for {@link #key()}, regardless of which component owns them. */
bindingNodes()267     abstract ImmutableSet<BindingNode> bindingNodes();
268 
269     // Computing the hash code is an expensive operation.
270     @Memoized
271     @Override
hashCode()272     public abstract int hashCode();
273 
274     // Suppresses ErrorProne warning that hashCode was overridden w/o equals
275     @Override
equals(Object other)276     public abstract boolean equals(Object other);
277 
278     /** All bindings for {@link #key()}, regardless of which component owns them. */
bindings()279     final ImmutableSet<Binding> bindings() {
280       return bindingNodes().stream()
281           .map(BindingNode::delegate)
282           .collect(toImmutableSet());
283     }
284 
285     /** Returns {@code true} if there are no {@link #bindings()}. */
isEmpty()286     final boolean isEmpty() {
287       return bindingNodes().isEmpty();
288     }
289 
290     /** All bindings for {@link #key()} that are owned by a component. */
bindingNodesOwnedBy(ComponentPath componentPath)291     ImmutableSet<BindingNode> bindingNodesOwnedBy(ComponentPath componentPath) {
292       return bindingNodes().stream()
293           .filter(bindingNode -> bindingNode.componentPath().equals(componentPath))
294           .collect(toImmutableSet());
295     }
296 
297     /** Returns the binding node representing the given binding, or throws ISE if none exist. */
forBinding(Binding binding)298     final BindingNode forBinding(Binding binding) {
299       return bindingNodes().stream()
300           .filter(bindingNode -> bindingNode.delegate().equals(binding))
301           .collect(onlyElement());
302     }
303   }
304 
305   private final class Resolver {
306     final ComponentPath componentPath;
307     final Optional<Resolver> parentResolver;
308     final ComponentDescriptor componentDescriptor;
309     final ComponentDeclarations declarations;
310     final Map<Key, LegacyResolvedBindings> resolvedContributionBindings = new LinkedHashMap<>();
311     final Map<Key, LegacyResolvedBindings> resolvedMembersInjectionBindings = new LinkedHashMap<>();
312     final Deque<Key> cycleStack = new ArrayDeque<>();
313     final Map<Key, Boolean> keyDependsOnLocalBindingsCache = new HashMap<>();
314     final Map<Binding, Boolean> bindingDependsOnLocalBindingsCache = new HashMap<>();
315     final Queue<ComponentDescriptor> subcomponentsToResolve = new ArrayDeque<>();
316 
Resolver(Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor)317     Resolver(Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) {
318       this.parentResolver = parentResolver;
319       this.componentDescriptor = checkNotNull(componentDescriptor);
320       DaggerTypeElement componentType = DaggerTypeElement.from(componentDescriptor.typeElement());
321       componentPath =
322           parentResolver.isPresent()
323               ? parentResolver.get().componentPath.childPath(componentType)
324               : ComponentPath.create(ImmutableList.of(componentType));
325       declarations =
326           componentDeclarationsFactory.create(
327               parentResolver.map(parent -> parent.componentDescriptor),
328               componentDescriptor);
329       subcomponentsToResolve.addAll(
330           componentDescriptor.childComponentsDeclaredByFactoryMethods().values());
331       subcomponentsToResolve.addAll(
332           componentDescriptor.childComponentsDeclaredByBuilderEntryPoints().values());
333     }
334 
335     /**
336      * Returns the resolved contribution bindings for the given {@link Key}:
337      *
338      * <ul>
339      *   <li>All explicit bindings for:
340      *       <ul>
341      *         <li>the requested key
342      *         <li>{@code Set<T>} if the requested key's type is {@code Set<Produced<T>>}
343      *         <li>{@code Map<K, Provider<V>>} if the requested key's type is {@code Map<K,
344      *             Producer<V>>}.
345      *       </ul>
346      *   <li>An implicit {@link Inject @Inject}-annotated constructor binding if there is one and
347      *       there are no explicit bindings or synthetic bindings.
348      * </ul>
349      */
lookUpBindings(Key requestKey)350     LegacyResolvedBindings lookUpBindings(Key requestKey) {
351       Set<ContributionBinding> bindings = new LinkedHashSet<>();
352       Set<ContributionBinding> multibindingContributions = new LinkedHashSet<>();
353       Set<MultibindingDeclaration> multibindingDeclarations = new LinkedHashSet<>();
354       Set<OptionalBindingDeclaration> optionalBindingDeclarations = new LinkedHashSet<>();
355       Set<SubcomponentDeclaration> subcomponentDeclarations = new LinkedHashSet<>();
356 
357       // Gather all bindings, multibindings, optional, and subcomponent declarations/contributions.
358       for (Resolver resolver : getResolverLineage()) {
359         bindings.addAll(resolver.getLocalExplicitBindings(requestKey));
360         multibindingContributions.addAll(resolver.getLocalMultibindingContributions(requestKey));
361         multibindingDeclarations.addAll(resolver.declarations.multibindings(requestKey));
362         subcomponentDeclarations.addAll(resolver.declarations.subcomponents(requestKey));
363         // The optional binding declarations are keyed by the unwrapped type.
364         keyFactory.unwrapOptional(requestKey)
365             .map(resolver.declarations::optionalBindings)
366             .ifPresent(optionalBindingDeclarations::addAll);
367       }
368 
369       // Add synthetic multibinding
370       if (!multibindingContributions.isEmpty() || !multibindingDeclarations.isEmpty()) {
371         if (MapType.isMap(requestKey)) {
372           bindings.add(bindingFactory.multiboundMap(requestKey, multibindingContributions));
373         } else if (SetType.isSet(requestKey)) {
374           bindings.add(bindingFactory.multiboundSet(requestKey, multibindingContributions));
375         } else {
376           throw new AssertionError("Unexpected type in multibinding key: " + requestKey);
377         }
378       }
379 
380       // Add synthetic optional binding
381       if (!optionalBindingDeclarations.isEmpty()) {
382         ImmutableSet<Binding> optionalContributions =
383             lookUpBindings(keyFactory.unwrapOptional(requestKey).get()).bindings();
384         bindings.add(
385             optionalContributions.isEmpty()
386                 ? bindingFactory.syntheticAbsentOptionalDeclaration(requestKey)
387                 : bindingFactory.syntheticPresentOptionalDeclaration(
388                     requestKey, optionalContributions));
389       }
390 
391       // Add subcomponent creator binding
392       if (!subcomponentDeclarations.isEmpty()) {
393         ContributionBinding binding =
394             bindingFactory.subcomponentCreatorBinding(
395                 ImmutableSet.copyOf(subcomponentDeclarations));
396         bindings.add(binding);
397         addSubcomponentToOwningResolver(binding);
398       }
399 
400       // Add members injector binding
401       if (isTypeOf(requestKey.type().xprocessing(), TypeNames.MEMBERS_INJECTOR)) {
402         injectBindingRegistry.getOrFindMembersInjectorBinding(requestKey).ifPresent(bindings::add);
403       }
404 
405       // Add Assisted Factory binding
406       if (isDeclared(requestKey.type().xprocessing())
407           && isAssistedFactoryType(requestKey.type().xprocessing().getTypeElement())) {
408         bindings.add(
409             bindingFactory.assistedFactoryBinding(
410                 requestKey.type().xprocessing().getTypeElement(),
411                 Optional.of(requestKey.type().xprocessing())));
412       }
413 
414       // If there are no bindings, add the implicit @Inject-constructed binding if there is one.
415       if (bindings.isEmpty()) {
416         injectBindingRegistry
417             .getOrFindInjectionBinding(requestKey)
418             .filter(this::isCorrectlyScopedInSubcomponent)
419             .ifPresent(bindings::add);
420       }
421 
422       return LegacyResolvedBindings.create(
423           requestKey,
424           bindings.stream()
425               .map(
426                   binding -> {
427                     Optional<BindingNode> bindingNodeOwnedByAncestor =
428                         getBindingNodeOwnedByAncestor(requestKey, binding);
429                     // If a binding is owned by an ancestor we use the corresponding BindingNode
430                     // instance directly rather than creating a new instance to avoid accidentally
431                     // including additional multi/optional/subcomponent declarations that don't
432                     // exist in the ancestor's BindingNode instance.
433                     return bindingNodeOwnedByAncestor.isPresent()
434                           ? bindingNodeOwnedByAncestor.get()
435                           : bindingNodeFactory.forContributionBindings(
436                               componentPath,
437                               binding,
438                               multibindingDeclarations,
439                               optionalBindingDeclarations,
440                               subcomponentDeclarations);
441                   })
442               .collect(toImmutableSet()));
443     }
444 
445     /**
446      * Returns true if this binding graph resolution is for a subcomponent and the {@code @Inject}
447      * binding's scope correctly matches one of the components in the current component ancestry.
448      * If not, it means the binding is not owned by any of the currently known components, and will
449      * be owned by a future ancestor (or, if never owned, will result in an incompatibly scoped
450      * binding error at the root component).
451      */
isCorrectlyScopedInSubcomponent(ContributionBinding binding)452     private boolean isCorrectlyScopedInSubcomponent(ContributionBinding binding) {
453       checkArgument(binding.kind() == INJECTION || binding.kind() == ASSISTED_INJECTION);
454       if (!rootComponent().isSubcomponent()
455           || !binding.scope().isPresent()
456           || binding.scope().get().isReusable()) {
457         return true;
458       }
459 
460       Resolver owningResolver = getOwningResolver(binding).orElse(this);
461       ComponentDescriptor owningComponent = owningResolver.componentDescriptor;
462       return owningComponent.scopes().contains(binding.scope().get());
463     }
464 
rootComponent()465     private ComponentDescriptor rootComponent() {
466       return parentResolver.map(Resolver::rootComponent).orElse(componentDescriptor);
467     }
468 
469     /** Returns the resolved members injection bindings for the given {@link Key}. */
lookUpMembersInjectionBinding(Key requestKey)470     LegacyResolvedBindings lookUpMembersInjectionBinding(Key requestKey) {
471       // no explicit deps for members injection, so just look it up
472       Optional<MembersInjectionBinding> binding =
473           injectBindingRegistry.getOrFindMembersInjectionBinding(requestKey);
474       return binding.isPresent()
475           ? LegacyResolvedBindings.create(
476               requestKey,
477               bindingNodeFactory.forMembersInjectionBinding(componentPath, binding.get()))
478           : LegacyResolvedBindings.create(requestKey);
479     }
480 
481     /**
482      * When a binding is resolved for a {@link SubcomponentDeclaration}, adds corresponding {@link
483      * ComponentDescriptor subcomponent} to a queue in the owning component's resolver. The queue
484      * will be used to detect which subcomponents need to be resolved.
485      */
addSubcomponentToOwningResolver(ContributionBinding subcomponentCreatorBinding)486     private void addSubcomponentToOwningResolver(ContributionBinding subcomponentCreatorBinding) {
487       checkArgument(subcomponentCreatorBinding.kind().equals(SUBCOMPONENT_CREATOR));
488       Resolver owningResolver = getOwningResolver(subcomponentCreatorBinding).get();
489 
490       XTypeElement builderType =
491           subcomponentCreatorBinding.key().type().xprocessing().getTypeElement();
492       owningResolver.subcomponentsToResolve.add(
493           owningResolver.componentDescriptor.getChildComponentWithBuilderType(builderType));
494     }
495 
createDelegateBindings( ImmutableSet<DelegateDeclaration> delegateDeclarations)496     private ImmutableSet<ContributionBinding> createDelegateBindings(
497         ImmutableSet<DelegateDeclaration> delegateDeclarations) {
498       ImmutableSet.Builder<ContributionBinding> builder = ImmutableSet.builder();
499       for (DelegateDeclaration delegateDeclaration : delegateDeclarations) {
500         builder.add(createDelegateBinding(delegateDeclaration));
501       }
502       return builder.build();
503     }
504 
505     /**
506      * Creates one (and only one) delegate binding for a delegate declaration, based on the resolved
507      * bindings of the right-hand-side of a {@link dagger.Binds} method. If there are duplicate
508      * bindings for the dependency key, there should still be only one binding for the delegate key.
509      */
createDelegateBinding(DelegateDeclaration delegateDeclaration)510     private ContributionBinding createDelegateBinding(DelegateDeclaration delegateDeclaration) {
511       Key delegateKey = delegateDeclaration.delegateRequest().key();
512       if (cycleStack.contains(delegateKey)) {
513         return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
514       }
515 
516       LegacyResolvedBindings resolvedDelegate;
517       try {
518         cycleStack.push(delegateKey);
519         resolvedDelegate = lookUpBindings(delegateKey);
520       } finally {
521         cycleStack.pop();
522       }
523       if (resolvedDelegate.bindings().isEmpty()) {
524         // This is guaranteed to result in a missing binding error, so it doesn't matter if the
525         // binding is a Provision or Production, except if it is a @IntoMap method, in which
526         // case the key will be of type Map<K, Provider<V>>, which will be "upgraded" into a
527         // Map<K, Producer<V>> if it's requested in a ProductionComponent. This may result in a
528         // strange error, that the RHS needs to be provided with an @Inject or @Provides
529         // annotated method, but a user should be able to figure out if a @Produces annotation
530         // is needed.
531         // TODO(gak): revisit how we model missing delegates if/when we clean up how we model
532         // binding declarations
533         return bindingFactory.unresolvedDelegateBinding(delegateDeclaration);
534       }
535       // It doesn't matter which of these is selected, since they will later on produce a
536       // duplicate binding error.
537       ContributionBinding explicitDelegate =
538           (ContributionBinding) resolvedDelegate.bindings().iterator().next();
539       return bindingFactory.delegateBinding(delegateDeclaration, explicitDelegate);
540     }
541 
542     /**
543      * Returns a {@link BindingNode} for the given binding that is owned by an ancestor component,
544      * if one exists. Otherwise returns {@link Optional#empty()}.
545      */
getBindingNodeOwnedByAncestor( Key requestKey, ContributionBinding binding)546     private Optional<BindingNode> getBindingNodeOwnedByAncestor(
547         Key requestKey, ContributionBinding binding) {
548       if (canBeResolvedInParent(requestKey, binding)) {
549         // Resolve in the parent to make sure we have the most recent multi/optional contributions.
550         parentResolver.get().resolve(requestKey);
551         if (!requiresResolution(binding)) {
552           return Optional.of(getPreviouslyResolvedBindings(requestKey).get().forBinding(binding));
553         }
554       }
555       return Optional.empty();
556     }
557 
canBeResolvedInParent(Key requestKey, ContributionBinding binding)558     private boolean canBeResolvedInParent(Key requestKey, ContributionBinding binding) {
559       if (parentResolver.isEmpty()) {
560         return false;
561       }
562       Optional<Resolver> owningResolver = getOwningResolver(binding);
563       if (owningResolver.isPresent()) {
564         return !owningResolver.get().equals(this);
565       }
566       return !Keys.isComponentOrCreator(requestKey)
567           // TODO(b/305748522): Allow caching for assisted injection bindings.
568           && binding.kind() != BindingKind.ASSISTED_INJECTION
569           && getPreviouslyResolvedBindings(requestKey).isPresent()
570           && getPreviouslyResolvedBindings(requestKey).get().bindings().contains(binding);
571     }
572 
getOwningResolver(ContributionBinding binding)573     private Optional<Resolver> getOwningResolver(ContributionBinding binding) {
574       // TODO(ronshapiro): extract the different pieces of this method into their own methods
575       if ((binding.scope().isPresent() && binding.scope().get().isProductionScope())
576           || binding.kind().equals(BindingKind.PRODUCTION)) {
577         for (Resolver requestResolver : getResolverLineage()) {
578           // Resolve @Inject @ProductionScope bindings at the highest production component.
579           if (binding.kind().equals(INJECTION)
580               && requestResolver.componentDescriptor.isProduction()) {
581             return Optional.of(requestResolver);
582           }
583 
584           // Resolve explicit @Produces and @ProductionScope bindings at the highest component that
585           // installs the binding.
586           if (requestResolver.containsExplicitBinding(binding)) {
587             return Optional.of(requestResolver);
588           }
589         }
590       }
591 
592       if (binding.scope().isPresent() && binding.scope().get().isReusable()) {
593         for (Resolver requestResolver : getResolverLineage().reverse()) {
594           // If a @Reusable binding was resolved in an ancestor, use that component.
595           LegacyResolvedBindings resolvedBindings =
596               requestResolver.resolvedContributionBindings.get(binding.key());
597           if (resolvedBindings != null && resolvedBindings.bindings().contains(binding)) {
598             return Optional.of(requestResolver);
599           }
600         }
601         // If a @Reusable binding was not resolved in any ancestor, resolve it here.
602         return Optional.empty();
603       }
604 
605       // TODO(b/359893922): we currently iterate from child to parent to find an owning resolver,
606       // but we probably want to iterate from parent to child to catch missing bindings in
607       // misconfigured repeated modules.
608       for (Resolver requestResolver : getResolverLineage().reverse()) {
609         if (requestResolver.containsExplicitBinding(binding)) {
610           return Optional.of(requestResolver);
611         }
612       }
613 
614       // look for scope separately.  we do this for the case where @Singleton can appear twice
615       // in the † compatibility mode
616       Optional<Scope> bindingScope = binding.scope();
617       if (bindingScope.isPresent()) {
618         for (Resolver requestResolver : getResolverLineage().reverse()) {
619           if (requestResolver.componentDescriptor.scopes().contains(bindingScope.get())) {
620             return Optional.of(requestResolver);
621           }
622         }
623       }
624       return Optional.empty();
625     }
626 
containsExplicitBinding(ContributionBinding binding)627     private boolean containsExplicitBinding(ContributionBinding binding) {
628       return declarations.bindings(binding.key()).contains(binding)
629           || resolverContainsDelegateDeclarationForBinding(binding)
630           || !declarations.subcomponents(binding.key()).isEmpty();
631     }
632 
633     /** Returns true if {@code binding} was installed in a module in this resolver's component. */
resolverContainsDelegateDeclarationForBinding(ContributionBinding binding)634     private boolean resolverContainsDelegateDeclarationForBinding(ContributionBinding binding) {
635       if (!binding.kind().equals(DELEGATE)) {
636         return false;
637       }
638       if (hasStrictMultibindingsExemption(compilerOptions, binding)) {
639         return false;
640       }
641       return declarations.delegates(binding.key()).stream()
642           .anyMatch(
643               declaration ->
644                   declaration.contributingModule().equals(binding.contributingModule())
645                   && declaration.bindingElement().equals(binding.bindingElement()));
646     }
647 
648     /** Returns the resolver lineage from parent to child. */
getResolverLineage()649     private ImmutableList<Resolver> getResolverLineage() {
650       ImmutableList.Builder<Resolver> resolverList = ImmutableList.builder();
651       for (Optional<Resolver> currentResolver = Optional.of(this);
652           currentResolver.isPresent();
653           currentResolver = currentResolver.get().parentResolver) {
654         resolverList.add(currentResolver.get());
655       }
656       return resolverList.build().reverse();
657     }
658 
659     /**
660      * Returns the explicit {@link ContributionBinding}s that match the {@code key} from this
661      * resolver.
662      */
getLocalExplicitBindings(Key key)663     private ImmutableSet<ContributionBinding> getLocalExplicitBindings(Key key) {
664       return ImmutableSet.<ContributionBinding>builder()
665           .addAll(declarations.bindings(key))
666           .addAll(createDelegateBindings(declarations.delegates(key)))
667           .build();
668     }
669 
670     /**
671      * Returns the explicit multibinding contributions that contribute to the map or set requested
672      * by {@code key} from this resolver.
673      */
getLocalMultibindingContributions(Key key)674     private ImmutableSet<ContributionBinding> getLocalMultibindingContributions(Key key) {
675       return ImmutableSet.<ContributionBinding>builder()
676           .addAll(declarations.multibindingContributions(key))
677           .addAll(createDelegateBindings(declarations.delegateMultibindingContributions(key)))
678           .build();
679     }
680 
681     /**
682      * Returns the {@link OptionalBindingDeclaration}s that match the {@code key} from this and all
683      * ancestor resolvers.
684      */
getOptionalBindingDeclarations(Key key)685     private ImmutableSet<OptionalBindingDeclaration> getOptionalBindingDeclarations(Key key) {
686       Optional<Key> unwrapped = keyFactory.unwrapOptional(key);
687       if (unwrapped.isEmpty()) {
688         return ImmutableSet.of();
689       }
690       ImmutableSet.Builder<OptionalBindingDeclaration> declarations = ImmutableSet.builder();
691       for (Resolver resolver : getResolverLineage()) {
692         declarations.addAll(resolver.declarations.optionalBindings(unwrapped.get()));
693       }
694       return declarations.build();
695     }
696 
697     /**
698      * Returns the {@link LegacyResolvedBindings} for {@code key} that was resolved in this resolver
699      * or an ancestor resolver. Only checks for {@link ContributionBinding}s as {@link
700      * MembersInjectionBinding}s are not inherited.
701      */
getPreviouslyResolvedBindings(Key key)702     private Optional<LegacyResolvedBindings> getPreviouslyResolvedBindings(Key key) {
703       Optional<LegacyResolvedBindings> result =
704           Optional.ofNullable(resolvedContributionBindings.get(key));
705       if (result.isPresent()) {
706         return result;
707       } else if (parentResolver.isPresent()) {
708         return parentResolver.get().getPreviouslyResolvedBindings(key);
709       } else {
710         return Optional.empty();
711       }
712     }
713 
resolveMembersInjection(Key key)714     private void resolveMembersInjection(Key key) {
715       LegacyResolvedBindings bindings = lookUpMembersInjectionBinding(key);
716       resolveDependencies(bindings);
717       resolvedMembersInjectionBindings.put(key, bindings);
718     }
719 
resolve(Key key)720     void resolve(Key key) {
721       // If we find a cycle, stop resolving. The original request will add it with all of the
722       // other resolved deps.
723       if (cycleStack.contains(key)) {
724         return;
725       }
726 
727       // If the binding was previously resolved in this (sub)component, don't resolve it again.
728       if (resolvedContributionBindings.containsKey(key)) {
729         return;
730       }
731 
732       cycleStack.push(key);
733       try {
734         LegacyResolvedBindings bindings = lookUpBindings(key);
735         resolvedContributionBindings.put(key, bindings);
736         resolveDependencies(bindings);
737       } finally {
738         cycleStack.pop();
739       }
740     }
741 
742     /**
743      * {@link #resolve(Key) Resolves} each of the dependencies of the bindings owned by this
744      * component.
745      */
resolveDependencies(LegacyResolvedBindings resolvedBindings)746     private void resolveDependencies(LegacyResolvedBindings resolvedBindings) {
747       for (BindingNode binding : resolvedBindings.bindingNodesOwnedBy(componentPath)) {
748         for (DependencyRequest dependency : binding.dependencies()) {
749           resolve(dependency.key());
750         }
751       }
752     }
753 
getResolvedContributionBindings(Key key)754     private LegacyResolvedBindings getResolvedContributionBindings(Key key) {
755       if (resolvedContributionBindings.containsKey(key)) {
756         return resolvedContributionBindings.get(key);
757       }
758       if (parentResolver.isPresent()) {
759         return parentResolver.get().getResolvedContributionBindings(key);
760       }
761       throw new AssertionError("No resolved bindings for key: " + key);
762     }
763 
getResolvedMembersInjectionBindings(Key key)764     private LegacyResolvedBindings getResolvedMembersInjectionBindings(Key key) {
765       return resolvedMembersInjectionBindings.get(key);
766     }
767 
requiresResolution(Binding binding)768     private boolean requiresResolution(Binding binding) {
769       return new RequiresResolutionChecker().requiresResolution(binding);
770     }
771 
772     private final class RequiresResolutionChecker {
773       private final Set<Object> cycleChecker = new HashSet<>();
774 
775       /**
776        * Returns {@code true} if any of the bindings resolved for {@code key} are multibindings with
777        * contributions declared within this component's modules or optional bindings with present
778        * values declared within this component's modules, or if any of its unscoped dependencies
779        * depend on such bindings.
780        *
781        * <p>We don't care about scoped dependencies because they will never depend on bindings from
782        * subcomponents.
783        *
784        * @throws IllegalArgumentException if {@link #getPreviouslyResolvedBindings(Key)} is empty
785        */
requiresResolution(Key key)786       private boolean requiresResolution(Key key) {
787         // Don't recur infinitely if there are valid cycles in the dependency graph.
788         // http://b/23032377
789         if (!cycleChecker.add(key)) {
790           return false;
791         }
792         return reentrantComputeIfAbsent(
793             keyDependsOnLocalBindingsCache, key, this::requiresResolutionUncached);
794       }
795 
796       /**
797        * Returns {@code true} if {@code binding} is unscoped (or has {@link Reusable @Reusable}
798        * scope) and depends on multibindings with contributions declared within this component's
799        * modules, or if any of its unscoped or {@link Reusable @Reusable} scoped dependencies depend
800        * on such local multibindings.
801        *
802        * <p>We don't care about non-reusable scoped dependencies because they will never depend on
803        * multibindings with contributions from subcomponents.
804        */
requiresResolution(Binding binding)805       private boolean requiresResolution(Binding binding) {
806         if (!cycleChecker.add(binding)) {
807           return false;
808         }
809         return reentrantComputeIfAbsent(
810             bindingDependsOnLocalBindingsCache, binding, this::requiresResolutionUncached);
811       }
812 
requiresResolutionUncached(Key key)813       private boolean requiresResolutionUncached(Key key) {
814         checkArgument(
815             getPreviouslyResolvedBindings(key).isPresent(),
816             "no previously resolved bindings in %s for %s",
817             Resolver.this,
818             key);
819         LegacyResolvedBindings previouslyResolvedBindings =
820             getPreviouslyResolvedBindings(key).get();
821         if (hasLocalBindings(previouslyResolvedBindings)) {
822           return true;
823         }
824 
825         for (Binding binding : previouslyResolvedBindings.bindings()) {
826           if (requiresResolution(binding)) {
827             return true;
828           }
829         }
830         return false;
831       }
832 
requiresResolutionUncached(Binding binding)833       private boolean requiresResolutionUncached(Binding binding) {
834         if ((!binding.scope().isPresent() || binding.scope().get().isReusable())
835             // TODO(beder): Figure out what happens with production subcomponents.
836             && !binding.kind().equals(BindingKind.PRODUCTION)) {
837           for (DependencyRequest dependency : binding.dependencies()) {
838             if (requiresResolution(dependency.key())) {
839               return true;
840             }
841           }
842         }
843         return false;
844       }
845     }
846 
hasLocalBindings(LegacyResolvedBindings resolvedBindings)847     private boolean hasLocalBindings(LegacyResolvedBindings resolvedBindings) {
848       return hasLocalMultibindingContributions(resolvedBindings.key())
849           || hasLocalOptionalBindingContribution(resolvedBindings);
850     }
851 
852     /**
853      * Returns {@code true} if there is at least one multibinding contribution declared within
854      * this component's modules that matches the key.
855      */
hasLocalMultibindingContributions(Key requestKey)856     private boolean hasLocalMultibindingContributions(Key requestKey) {
857       return !declarations.multibindingContributions(requestKey).isEmpty()
858           || !declarations.delegateMultibindingContributions(requestKey).isEmpty();
859     }
860 
861     /**
862      * Returns {@code true} if there is a contribution in this component for an {@code
863      * Optional<Foo>} key that has not been contributed in a parent.
864      */
hasLocalOptionalBindingContribution(LegacyResolvedBindings resolvedBindings)865     private boolean hasLocalOptionalBindingContribution(LegacyResolvedBindings resolvedBindings) {
866       return hasLocalOptionalBindingContribution(
867           resolvedBindings.key(), resolvedBindings.bindings());
868     }
869 
hasLocalOptionalBindingContribution( Key key, ImmutableSet<? extends Binding> previouslyResolvedBindings)870     private boolean hasLocalOptionalBindingContribution(
871           Key key, ImmutableSet<? extends Binding> previouslyResolvedBindings) {
872       if (previouslyResolvedBindings.stream()
873           .map(Binding::kind)
874           .anyMatch(isEqual(OPTIONAL))) {
875         return hasLocalExplicitBindings(keyFactory.unwrapOptional(key).get());
876       } else {
877         // If a parent contributes a @Provides Optional<Foo> binding and a child has a
878         // @BindsOptionalOf Foo method, the two should conflict, even if there is no binding for
879         // Foo on its own
880         return !getOptionalBindingDeclarations(key).isEmpty();
881       }
882     }
883 
884     /**
885      * Returns {@code true} if there is at least one explicit binding that matches the given key.
886      */
hasLocalExplicitBindings(Key requestKey)887     private boolean hasLocalExplicitBindings(Key requestKey) {
888       return !declarations.bindings(requestKey).isEmpty()
889           || !declarations.delegates(requestKey).isEmpty();
890     }
891   }
892 }
893