1/*
2 * Copyright (C) 2014 Google, Inc.
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 */
16package dagger.internal.codegen;
17
18import com.google.auto.common.MoreTypes;
19import com.google.auto.value.AutoValue;
20import com.google.common.base.Function;
21import com.google.common.base.Optional;
22import com.google.common.cache.Cache;
23import com.google.common.cache.CacheBuilder;
24import com.google.common.collect.FluentIterable;
25import com.google.common.collect.ImmutableList;
26import com.google.common.collect.ImmutableMap;
27import com.google.common.collect.ImmutableSet;
28import com.google.common.collect.ImmutableSetMultimap;
29import com.google.common.collect.Iterables;
30import com.google.common.collect.Lists;
31import com.google.common.collect.Maps;
32import com.google.common.collect.Sets;
33import com.google.common.collect.TreeTraverser;
34import dagger.Component;
35import dagger.Subcomponent;
36import dagger.internal.codegen.Binding.Type;
37import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
38import dagger.producers.Producer;
39import dagger.producers.ProductionComponent;
40import java.util.ArrayDeque;
41import java.util.Collection;
42import java.util.Deque;
43import java.util.HashSet;
44import java.util.List;
45import java.util.Map;
46import java.util.Map.Entry;
47import java.util.Set;
48import java.util.concurrent.Callable;
49import java.util.concurrent.ExecutionException;
50import java.util.concurrent.Executor;
51import javax.inject.Inject;
52import javax.lang.model.element.AnnotationMirror;
53import javax.lang.model.element.ExecutableElement;
54import javax.lang.model.element.TypeElement;
55import javax.lang.model.util.ElementFilter;
56import javax.lang.model.util.Elements;
57
58import static com.google.auto.common.MoreElements.getAnnotationMirror;
59import static com.google.common.base.Predicates.in;
60import static com.google.common.base.Verify.verify;
61import static com.google.common.collect.Iterables.any;
62import static com.google.common.collect.Sets.union;
63import static dagger.internal.codegen.BindingKey.Kind.CONTRIBUTION;
64import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
65import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod;
66import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor.isOfKind;
67import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodKind.SUBCOMPONENT_BUILDER;
68import static dagger.internal.codegen.ComponentDescriptor.Kind.PRODUCTION_COMPONENT;
69import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
70import static dagger.internal.codegen.MembersInjectionBinding.Strategy.INJECT_MEMBERS;
71import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
72import static javax.lang.model.element.Modifier.STATIC;
73
74/**
75 * The canonical representation of a full-resolved graph.
76 *
77 * @author Gregory Kick
78 */
79@AutoValue
80abstract class BindingGraph {
81  abstract ComponentDescriptor componentDescriptor();
82  abstract ImmutableMap<BindingKey, ResolvedBindings> resolvedBindings();
83  abstract ImmutableMap<ExecutableElement, BindingGraph> subgraphs();
84
85  /**
86   * Returns the set of modules that are owned by this graph regardless of whether or not any of
87   * their bindings are used in this graph. For graphs representing top-level {@link Component
88   * components}, this set will be the same as
89   * {@linkplain ComponentDescriptor#transitiveModules the component's transitive modules}. For
90   * {@linkplain Subcomponent subcomponents}, this set will be the transitive modules that are not
91   * owned by any of their ancestors.
92   */
93  abstract ImmutableSet<ModuleDescriptor> ownedModules();
94
95  ImmutableSet<TypeElement> ownedModuleTypes() {
96    return FluentIterable.from(ownedModules())
97        .transform(ModuleDescriptor.getModuleElement())
98        .toSet();
99  }
100
101  private static final TreeTraverser<BindingGraph> SUBGRAPH_TRAVERSER =
102      new TreeTraverser<BindingGraph>() {
103        @Override
104        public Iterable<BindingGraph> children(BindingGraph node) {
105          return node.subgraphs().values();
106        }
107      };
108
109  /**
110   * Returns the set of types necessary to implement the component, but are not part of the injected
111   * graph.  This includes modules, component dependencies and an {@link Executor} in the case of
112   * {@link ProductionComponent}.
113   */
114  ImmutableSet<TypeElement> componentRequirements() {
115    return SUBGRAPH_TRAVERSER
116        .preOrderTraversal(this)
117        .transformAndConcat(
118            new Function<BindingGraph, Iterable<ResolvedBindings>>() {
119              @Override
120              public Iterable<ResolvedBindings> apply(BindingGraph input) {
121                return input.resolvedBindings().values();
122              }
123            })
124        .transformAndConcat(
125            new Function<ResolvedBindings, Set<ContributionBinding>>() {
126              @Override
127              public Set<ContributionBinding> apply(ResolvedBindings input) {
128                return (input.bindingKey().kind().equals(CONTRIBUTION))
129                    ? input.contributionBindings()
130                    : ImmutableSet.<ContributionBinding>of();
131              }
132            })
133        .transformAndConcat(
134            new Function<ContributionBinding, Set<TypeElement>>() {
135              @Override
136              public Set<TypeElement> apply(ContributionBinding input) {
137                return input.bindingElement().getModifiers().contains(STATIC)
138                    ? ImmutableSet.<TypeElement>of()
139                    : input.contributedBy().asSet();
140              }
141            })
142        .filter(in(ownedModuleTypes()))
143        .append(componentDescriptor().dependencies())
144        .append(componentDescriptor().executorDependency().asSet())
145        .toSet();
146  }
147
148  ImmutableSet<TypeElement> availableDependencies() {
149    return new ImmutableSet.Builder<TypeElement>()
150        .addAll(componentDescriptor().transitiveModuleTypes())
151        .addAll(componentDescriptor().dependencies())
152        .addAll(componentDescriptor().executorDependency().asSet())
153        .build();
154  }
155
156  static final class Factory {
157    private final Elements elements;
158    private final InjectBindingRegistry injectBindingRegistry;
159    private final Key.Factory keyFactory;
160    private final ProvisionBinding.Factory provisionBindingFactory;
161    private final ProductionBinding.Factory productionBindingFactory;
162
163    Factory(Elements elements,
164        InjectBindingRegistry injectBindingRegistry,
165        Key.Factory keyFactory,
166        ProvisionBinding.Factory provisionBindingFactory,
167        ProductionBinding.Factory productionBindingFactory) {
168      this.elements = elements;
169      this.injectBindingRegistry = injectBindingRegistry;
170      this.keyFactory = keyFactory;
171      this.provisionBindingFactory = provisionBindingFactory;
172      this.productionBindingFactory = productionBindingFactory;
173    }
174
175    BindingGraph create(ComponentDescriptor componentDescriptor) {
176      return create(Optional.<Resolver>absent(), componentDescriptor);
177    }
178
179    private BindingGraph create(
180        Optional<Resolver> parentResolver, ComponentDescriptor componentDescriptor) {
181      ImmutableSet.Builder<ContributionBinding> explicitBindingsBuilder = ImmutableSet.builder();
182
183      // binding for the component itself
184      TypeElement componentDefinitionType = componentDescriptor.componentDefinitionType();
185      explicitBindingsBuilder.add(provisionBindingFactory.forComponent(componentDefinitionType));
186
187      // Collect Component dependencies.
188      Optional<AnnotationMirror> componentMirror =
189          getAnnotationMirror(componentDefinitionType, Component.class)
190              .or(getAnnotationMirror(componentDefinitionType, ProductionComponent.class));
191      ImmutableSet<TypeElement> componentDependencyTypes = componentMirror.isPresent()
192          ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror.get()))
193          : ImmutableSet.<TypeElement>of();
194      for (TypeElement componentDependency : componentDependencyTypes) {
195        explicitBindingsBuilder.add(provisionBindingFactory.forComponent(componentDependency));
196        List<ExecutableElement> dependencyMethods =
197            ElementFilter.methodsIn(elements.getAllMembers(componentDependency));
198        for (ExecutableElement method : dependencyMethods) {
199          // MembersInjection methods aren't "provided" explicitly, so ignore them.
200          if (isComponentContributionMethod(elements, method)) {
201            explicitBindingsBuilder.add(
202                componentDescriptor.kind().equals(PRODUCTION_COMPONENT)
203                        && isComponentProductionMethod(elements, method)
204                    ? productionBindingFactory.forComponentMethod(method)
205                    : provisionBindingFactory.forComponentMethod(method));
206          }
207        }
208      }
209
210      // Bindings for subcomponent builders.
211      for (ComponentMethodDescriptor subcomponentMethodDescriptor :
212          Iterables.filter(
213              componentDescriptor.subcomponents().keySet(), isOfKind(SUBCOMPONENT_BUILDER))) {
214        explicitBindingsBuilder.add(
215            provisionBindingFactory.forSubcomponentBuilderMethod(
216                subcomponentMethodDescriptor.methodElement(),
217                componentDescriptor.componentDefinitionType()));
218      }
219
220      // Collect transitive module bindings.
221      for (ModuleDescriptor moduleDescriptor : componentDescriptor.transitiveModules()) {
222        for (ContributionBinding binding : moduleDescriptor.bindings()) {
223          explicitBindingsBuilder.add(binding);
224        }
225      }
226
227      Resolver requestResolver =
228          new Resolver(
229              parentResolver,
230              componentDescriptor,
231              explicitBindingsByKey(explicitBindingsBuilder.build()));
232      for (ComponentMethodDescriptor componentMethod : componentDescriptor.componentMethods()) {
233        Optional<DependencyRequest> componentMethodRequest = componentMethod.dependencyRequest();
234        if (componentMethodRequest.isPresent()) {
235          requestResolver.resolve(componentMethodRequest.get());
236        }
237      }
238
239      ImmutableMap.Builder<ExecutableElement, BindingGraph> subgraphsBuilder =
240          ImmutableMap.builder();
241      for (Entry<ComponentMethodDescriptor, ComponentDescriptor> subcomponentEntry :
242          componentDescriptor.subcomponents().entrySet()) {
243        subgraphsBuilder.put(
244            subcomponentEntry.getKey().methodElement(),
245            create(Optional.of(requestResolver), subcomponentEntry.getValue()));
246      }
247
248      for (ResolvedBindings resolvedBindings : requestResolver.getResolvedBindings().values()) {
249        verify(
250            resolvedBindings.owningComponent().equals(componentDescriptor),
251            "%s is not owned by %s",
252            resolvedBindings,
253            componentDescriptor);
254      }
255
256      return new AutoValue_BindingGraph(
257          componentDescriptor,
258          requestResolver.getResolvedBindings(),
259          subgraphsBuilder.build(),
260          requestResolver.getOwnedModules());
261    }
262
263    private <B extends ContributionBinding> ImmutableSetMultimap<Key, B> explicitBindingsByKey(
264        Iterable<? extends B> bindings) {
265      // Multimaps.index() doesn't do ImmutableSetMultimaps.
266      ImmutableSetMultimap.Builder<Key, B> builder = ImmutableSetMultimap.builder();
267      for (B binding : bindings) {
268        builder.put(binding.key(), binding);
269      }
270      return builder.build();
271    }
272
273    private final class Resolver {
274      final Optional<Resolver> parentResolver;
275      final ComponentDescriptor componentDescriptor;
276      final ImmutableSetMultimap<Key, ContributionBinding> explicitBindings;
277      final ImmutableSet<ContributionBinding> explicitBindingsSet;
278      final Map<BindingKey, ResolvedBindings> resolvedBindings;
279      final Deque<BindingKey> cycleStack = new ArrayDeque<>();
280      final Cache<BindingKey, Boolean> dependsOnLocalMultibindingsCache =
281          CacheBuilder.newBuilder().<BindingKey, Boolean>build();
282
283      Resolver(
284          Optional<Resolver> parentResolver,
285          ComponentDescriptor componentDescriptor,
286          ImmutableSetMultimap<Key, ContributionBinding> explicitBindings) {
287        assert parentResolver != null;
288        this.parentResolver = parentResolver;
289        assert componentDescriptor != null;
290        this.componentDescriptor = componentDescriptor;
291        assert explicitBindings != null;
292        this.explicitBindings = explicitBindings;
293        this.explicitBindingsSet = ImmutableSet.copyOf(explicitBindings.values());
294        this.resolvedBindings = Maps.newLinkedHashMap();
295      }
296
297      /**
298       * Looks up the bindings associated with a given dependency request and returns them.
299       *
300       * <p>Requests for {@code Map<K, V>} for which there are only bindings for
301       * {@code Map<K, Provider<V>>} will resolve to a single implicit binding for the latter map
302       * (and similarly for {@link Producer}s).
303       *
304       * <p>If there are no explicit bindings for a contribution, looks for implicit
305       * {@link Inject @Inject}-annotated constructor types.
306       */
307      ResolvedBindings lookUpBindings(DependencyRequest request) {
308        BindingKey bindingKey = request.bindingKey();
309        switch (bindingKey.kind()) {
310          case CONTRIBUTION:
311            // First, check for explicit keys (those from modules and components)
312            ImmutableSet<ContributionBinding> explicitBindingsForKey =
313                getExplicitBindings(bindingKey.key());
314
315            // If the key is Map<K, V>, get its implicit binding keys, which are either
316            // Map<K, Provider<V>> or Map<K, Producer<V>>, and grab their explicit bindings.
317            Optional<Key> mapProviderKey = keyFactory.implicitMapProviderKeyFrom(bindingKey.key());
318            ImmutableSet.Builder<ContributionBinding> explicitMapBindingsBuilder =
319                ImmutableSet.builder();
320            if (mapProviderKey.isPresent()) {
321              explicitMapBindingsBuilder.addAll(getExplicitBindings(mapProviderKey.get()));
322            }
323
324            Optional<Key> mapProducerKey = keyFactory.implicitMapProducerKeyFrom(bindingKey.key());
325            if (mapProducerKey.isPresent()) {
326              explicitMapBindingsBuilder.addAll(getExplicitBindings(mapProducerKey.get()));
327            }
328            ImmutableSet<ContributionBinding> explicitMapBindings =
329                explicitMapBindingsBuilder.build();
330
331            // If the key is Set<Produced<T>>, then we look up bindings by the alternate key Set<T>.
332            Optional<Key> setKeyFromProduced =
333                keyFactory.implicitSetKeyFromProduced(bindingKey.key());
334            ImmutableSet<ContributionBinding> explicitSetBindings =
335                setKeyFromProduced.isPresent()
336                    ? getExplicitBindings(setKeyFromProduced.get())
337                    : ImmutableSet.<ContributionBinding>of();
338
339            if (!explicitBindingsForKey.isEmpty() || !explicitSetBindings.isEmpty()) {
340              /* If there are any explicit bindings for this key, then combine those with any
341               * conflicting Map<K, Provider<V>> bindings and let the validator fail. */
342              ImmutableSetMultimap.Builder<ComponentDescriptor, ContributionBinding> bindings =
343                  ImmutableSetMultimap.builder();
344              for (ContributionBinding binding :
345                  union(explicitBindingsForKey, union(explicitSetBindings, explicitMapBindings))) {
346                bindings.put(getOwningComponent(request, binding), binding);
347              }
348              return ResolvedBindings.forContributionBindings(
349                  bindingKey, componentDescriptor, bindings.build());
350            } else if (any(explicitMapBindings, Binding.Type.PRODUCTION)) {
351              /* If this binding is for Map<K, V> and there are no explicit Map<K, V> bindings but
352               * some explicit Map<K, Producer<V>> bindings, then this binding must have only the
353               * implicit dependency on Map<K, Producer<V>>. */
354              return ResolvedBindings.forContributionBindings(
355                  bindingKey,
356                  componentDescriptor,
357                  productionBindingFactory.implicitMapOfProducerBinding(request));
358            } else if (any(explicitMapBindings, Binding.Type.PROVISION)) {
359              /* If this binding is for Map<K, V> and there are no explicit Map<K, V> bindings but
360               * some explicit Map<K, Provider<V>> bindings, then this binding must have only the
361               * implicit dependency on Map<K, Provider<V>>. */
362              return ResolvedBindings.forContributionBindings(
363                  bindingKey,
364                  componentDescriptor,
365                  provisionBindingFactory.implicitMapOfProviderBinding(request));
366            } else {
367              /* If there are no explicit bindings at all, look for an implicit @Inject-constructed
368               * binding. */
369              Optional<ProvisionBinding> provisionBinding =
370                  injectBindingRegistry.getOrFindProvisionBinding(bindingKey.key());
371              ComponentDescriptor owningComponent =
372                  provisionBinding.isPresent()
373                          && isResolvedInParent(request, provisionBinding.get())
374                          && !shouldOwnParentBinding(request, provisionBinding.get())
375                      ? getOwningResolver(provisionBinding.get()).get().componentDescriptor
376                      : componentDescriptor;
377              return ResolvedBindings.forContributionBindings(
378                  bindingKey,
379                  componentDescriptor,
380                  ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>builder()
381                      .putAll(owningComponent, provisionBinding.asSet())
382                      .build());
383            }
384
385          case MEMBERS_INJECTION:
386            // no explicit deps for members injection, so just look it up
387            return ResolvedBindings.forMembersInjectionBinding(
388                bindingKey, componentDescriptor, rollUpMembersInjectionBindings(bindingKey.key()));
389          default:
390            throw new AssertionError();
391        }
392      }
393
394      /**
395       * If {@code binding} should be owned by a parent component, resolves the binding in that
396       * component's resolver and returns that component. Otherwise returns the component for this
397       * resolver.
398       */
399      private ComponentDescriptor getOwningComponent(
400          DependencyRequest request, ContributionBinding binding) {
401        return isResolvedInParent(request, binding) && !shouldOwnParentBinding(request, binding)
402            ? getOwningResolver(binding).get().componentDescriptor
403            : componentDescriptor;
404      }
405
406      /**
407       * Returns {@code true} if {@code binding} is owned by a parent resolver. If so, calls
408       * {@link #resolve(DependencyRequest) resolve(request)} on that resolver.
409       */
410      private boolean isResolvedInParent(DependencyRequest request, ContributionBinding binding) {
411        Optional<Resolver> owningResolver = getOwningResolver(binding);
412        if (owningResolver.isPresent() && !owningResolver.get().equals(this)) {
413          owningResolver.get().resolve(request);
414          return true;
415        } else {
416          return false;
417        }
418      }
419
420      /**
421       * Returns {@code true} if {@code binding}, which was previously resolved by a parent
422       * resolver, should be moved into this resolver's bindings for {@code request} because it is
423       * unscoped and {@linkplain #dependsOnLocalMultibindings(ResolvedBindings) depends on local
424       * multibindings}, or {@code false} if it can satisfy {@code request} as an inherited binding.
425       */
426      private boolean shouldOwnParentBinding(
427          DependencyRequest request, ContributionBinding binding) {
428        return !binding.scope().isPresent()
429            && dependsOnLocalMultibindings(
430                getPreviouslyResolvedBindings(request.bindingKey()).get());
431      }
432
433      private MembersInjectionBinding rollUpMembersInjectionBindings(Key key) {
434        MembersInjectionBinding membersInjectionBinding =
435            injectBindingRegistry.getOrFindMembersInjectionBinding(key);
436
437        if (membersInjectionBinding.parentInjectorRequest().isPresent()
438            && membersInjectionBinding.injectionStrategy().equals(INJECT_MEMBERS)) {
439          MembersInjectionBinding parentBinding =
440              rollUpMembersInjectionBindings(
441                  membersInjectionBinding.parentInjectorRequest().get().key());
442          if (parentBinding.injectionStrategy().equals(NO_OP)) {
443            return membersInjectionBinding.withoutParentInjectorRequest();
444          }
445        }
446
447        return membersInjectionBinding;
448      }
449
450      private Optional<Resolver> getOwningResolver(ContributionBinding provisionBinding) {
451        for (Resolver requestResolver : getResolverLineage().reverse()) {
452          if (requestResolver.explicitBindingsSet.contains(provisionBinding)) {
453            return Optional.of(requestResolver);
454          }
455        }
456
457        // look for scope separately.  we do this for the case where @Singleton can appear twice
458        // in the † compatibility mode
459        Scope bindingScope = provisionBinding.scope();
460        if (bindingScope.isPresent()) {
461          for (Resolver requestResolver : getResolverLineage().reverse()) {
462            if (bindingScope.equals(requestResolver.componentDescriptor.scope())) {
463              return Optional.of(requestResolver);
464            }
465          }
466        }
467        return Optional.absent();
468      }
469
470      /** Returns the resolver lineage from parent to child. */
471      private ImmutableList<Resolver> getResolverLineage() {
472        List<Resolver> resolverList = Lists.newArrayList();
473        for (Optional<Resolver> currentResolver = Optional.of(this);
474            currentResolver.isPresent();
475            currentResolver = currentResolver.get().parentResolver) {
476          resolverList.add(currentResolver.get());
477        }
478        return ImmutableList.copyOf(Lists.reverse(resolverList));
479      }
480
481      private ImmutableSet<ContributionBinding> getExplicitBindings(Key requestKey) {
482        ImmutableSet.Builder<ContributionBinding> explicitBindingsForKey = ImmutableSet.builder();
483        for (Resolver resolver : getResolverLineage()) {
484          explicitBindingsForKey.addAll(resolver.explicitBindings.get(requestKey));
485        }
486        return explicitBindingsForKey.build();
487      }
488
489      private Optional<ResolvedBindings> getPreviouslyResolvedBindings(
490          final BindingKey bindingKey) {
491        Optional<ResolvedBindings> result = Optional.fromNullable(resolvedBindings.get(bindingKey));
492        if (result.isPresent()) {
493          return result;
494        } else if (parentResolver.isPresent()) {
495          return parentResolver.get().getPreviouslyResolvedBindings(bindingKey);
496        } else {
497          return Optional.absent();
498        }
499      }
500
501      void resolve(DependencyRequest request) {
502        BindingKey bindingKey = request.bindingKey();
503
504        // If we find a cycle, stop resolving. The original request will add it with all of the
505        // other resolved deps.
506        if (cycleStack.contains(bindingKey)) {
507          return;
508        }
509
510        // If the binding was previously resolved in this (sub)component, don't resolve it again.
511        if (resolvedBindings.containsKey(bindingKey)) {
512          return;
513        }
514
515        // If the binding was previously resolved in a supercomponent, then test to see if it
516        // depends on multibindings with contributions from this subcomponent. If it does, then we
517        // have to resolve it in this subcomponent so that it sees the local contributions. If it
518        // does not, then we can stop resolving it in this subcomponent and rely on the
519        // supercomponent resolution.
520        Optional<ResolvedBindings> bindingsPreviouslyResolvedInParent =
521            getPreviouslyResolvedBindings(bindingKey);
522        if (bindingsPreviouslyResolvedInParent.isPresent()
523            && !dependsOnLocalMultibindings(bindingsPreviouslyResolvedInParent.get())) {
524          return;
525        }
526
527        cycleStack.push(bindingKey);
528        try {
529          ResolvedBindings bindings = lookUpBindings(request);
530          for (Binding binding : bindings.ownedBindings()) {
531            for (DependencyRequest dependency : binding.implicitDependencies()) {
532              resolve(dependency);
533            }
534          }
535          resolvedBindings.put(bindingKey, bindings);
536        } finally {
537          cycleStack.pop();
538        }
539      }
540
541      /**
542       * Returns {@code true} if {@code previouslyResolvedBindings} is multibindings with
543       * contributions declared within this (sub)component's modules, or if any of its unscoped
544       * provision-dependencies depend on such local multibindings.
545       *
546       * <p>We don't care about scoped dependencies or production bindings because they will never
547       * depend on multibindings with contributions from subcomponents.
548       */
549      private boolean dependsOnLocalMultibindings(ResolvedBindings previouslyResolvedBindings) {
550        return dependsOnLocalMultibindings(previouslyResolvedBindings, new HashSet<BindingKey>());
551      }
552
553      private boolean dependsOnLocalMultibindings(
554          final ResolvedBindings previouslyResolvedBindings, final Set<BindingKey> cycleChecker) {
555        // Don't recur infinitely if there are valid cycles in the dependency graph.
556        if (!cycleChecker.add(previouslyResolvedBindings.bindingKey())) {
557          return false;
558        }
559        try {
560          return dependsOnLocalMultibindingsCache.get(
561              previouslyResolvedBindings.bindingKey(),
562              new Callable<Boolean>() {
563                @Override
564                public Boolean call() {
565                  if (previouslyResolvedBindings.isMultibindings()
566                      && hasLocalContributions(previouslyResolvedBindings)) {
567                    return true;
568                  }
569
570                  for (Binding binding : previouslyResolvedBindings.bindings()) {
571                    if (!binding.scope().isPresent()
572                        && !binding.bindingType().equals(Type.PRODUCTION)) {
573                      for (DependencyRequest dependency : binding.implicitDependencies()) {
574                        if (dependsOnLocalMultibindings(
575                            getPreviouslyResolvedBindings(dependency.bindingKey()).get(),
576                            cycleChecker)) {
577                          return true;
578                        }
579                      }
580                    }
581                  }
582                  return false;
583                }
584              });
585        } catch (ExecutionException e) {
586          throw new AssertionError(e);
587        }
588      }
589
590      private boolean hasLocalContributions(ResolvedBindings resolvedBindings) {
591        return !explicitBindings.get(resolvedBindings.bindingKey().key()).isEmpty();
592      }
593
594      ImmutableMap<BindingKey, ResolvedBindings> getResolvedBindings() {
595        ImmutableMap.Builder<BindingKey, ResolvedBindings> resolvedBindingsBuilder =
596            ImmutableMap.builder();
597        resolvedBindingsBuilder.putAll(resolvedBindings);
598        if (parentResolver.isPresent()) {
599          Collection<ResolvedBindings> bindingsResolvedInParent =
600              Maps.difference(parentResolver.get().getResolvedBindings(), resolvedBindings)
601                  .entriesOnlyOnLeft()
602                  .values();
603          for (ResolvedBindings resolvedInParent : bindingsResolvedInParent) {
604            resolvedBindingsBuilder.put(
605                resolvedInParent.bindingKey(),
606                resolvedInParent.asInheritedIn(componentDescriptor));
607          }
608        }
609        return resolvedBindingsBuilder.build();
610      }
611
612      ImmutableSet<ModuleDescriptor> getInheritedModules() {
613        return parentResolver.isPresent()
614            ? Sets.union(
615                    parentResolver.get().getInheritedModules(),
616                    parentResolver.get().componentDescriptor.transitiveModules())
617                .immutableCopy()
618            : ImmutableSet.<ModuleDescriptor>of();
619      }
620
621      ImmutableSet<ModuleDescriptor> getOwnedModules() {
622        return Sets.difference(componentDescriptor.transitiveModules(), getInheritedModules())
623            .immutableCopy();
624      }
625    }
626  }
627}
628