Home | History | Annotate | Download | only in codegen
      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  */
     16 package dagger.internal.codegen;
     17 
     18 import com.google.auto.common.MoreTypes;
     19 import com.google.auto.value.AutoValue;
     20 import com.google.common.base.Function;
     21 import com.google.common.base.Optional;
     22 import com.google.common.cache.Cache;
     23 import com.google.common.cache.CacheBuilder;
     24 import com.google.common.collect.FluentIterable;
     25 import com.google.common.collect.ImmutableList;
     26 import com.google.common.collect.ImmutableMap;
     27 import com.google.common.collect.ImmutableSet;
     28 import com.google.common.collect.ImmutableSetMultimap;
     29 import com.google.common.collect.Iterables;
     30 import com.google.common.collect.Lists;
     31 import com.google.common.collect.Maps;
     32 import com.google.common.collect.Sets;
     33 import com.google.common.collect.TreeTraverser;
     34 import dagger.Component;
     35 import dagger.Subcomponent;
     36 import dagger.internal.codegen.Binding.Type;
     37 import dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor;
     38 import dagger.producers.Producer;
     39 import dagger.producers.ProductionComponent;
     40 import java.util.ArrayDeque;
     41 import java.util.Collection;
     42 import java.util.Deque;
     43 import java.util.HashSet;
     44 import java.util.List;
     45 import java.util.Map;
     46 import java.util.Map.Entry;
     47 import java.util.Set;
     48 import java.util.concurrent.Callable;
     49 import java.util.concurrent.ExecutionException;
     50 import java.util.concurrent.Executor;
     51 import javax.inject.Inject;
     52 import javax.lang.model.element.AnnotationMirror;
     53 import javax.lang.model.element.ExecutableElement;
     54 import javax.lang.model.element.TypeElement;
     55 import javax.lang.model.util.ElementFilter;
     56 import javax.lang.model.util.Elements;
     57 
     58 import static com.google.auto.common.MoreElements.getAnnotationMirror;
     59 import static com.google.common.base.Predicates.in;
     60 import static com.google.common.base.Verify.verify;
     61 import static com.google.common.collect.Iterables.any;
     62 import static com.google.common.collect.Sets.union;
     63 import static dagger.internal.codegen.BindingKey.Kind.CONTRIBUTION;
     64 import static dagger.internal.codegen.ComponentDescriptor.isComponentContributionMethod;
     65 import static dagger.internal.codegen.ComponentDescriptor.isComponentProductionMethod;
     66 import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodDescriptor.isOfKind;
     67 import static dagger.internal.codegen.ComponentDescriptor.ComponentMethodKind.SUBCOMPONENT_BUILDER;
     68 import static dagger.internal.codegen.ComponentDescriptor.Kind.PRODUCTION_COMPONENT;
     69 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
     70 import static dagger.internal.codegen.MembersInjectionBinding.Strategy.INJECT_MEMBERS;
     71 import static dagger.internal.codegen.MembersInjectionBinding.Strategy.NO_OP;
     72 import 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
     80 abstract 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