Home | History | Annotate | Download | only in codegen
      1 /*
      2  * Copyright (C) 2015 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.value.AutoValue;
     19 import com.google.common.base.Optional;
     20 import com.google.common.collect.FluentIterable;
     21 import com.google.common.collect.ImmutableMap;
     22 import com.google.common.collect.ImmutableSet;
     23 import com.google.common.collect.ImmutableSetMultimap;
     24 import com.google.common.collect.Iterables;
     25 import com.google.common.collect.Multimap;
     26 
     27 import static com.google.common.base.Preconditions.checkArgument;
     28 import static com.google.common.base.Preconditions.checkState;
     29 import static dagger.internal.codegen.ContributionBinding.contributionTypeFor;
     30 
     31 /**
     32  * The collection of bindings that have been resolved for a binding key.
     33  *
     34  * @author Gregory Kick
     35  */
     36 @AutoValue
     37 abstract class ResolvedBindings {
     38   /**
     39    * The binding key for which the {@link #bindings()} have been resolved.
     40    */
     41   abstract BindingKey bindingKey();
     42 
     43   /**
     44    * The component in which the bindings in {@link #ownedBindings()},
     45    * {@link #ownedContributionBindings()}, and {@link #ownedMembersInjectionBinding()} were
     46    * resolved.
     47    */
     48   abstract ComponentDescriptor owningComponent();
     49 
     50   /**
     51    * The contribution bindings for {@link #bindingKey()} that were resolved in
     52    * {@link #owningComponent()} or its ancestor components, keyed by the component in which the
     53    * binding was resolved. If {@link #bindingKey()}'s kind is not
     54    * {@link BindingKey.Kind#CONTRIBUTION}, this is empty.
     55    */
     56   abstract ImmutableSetMultimap<ComponentDescriptor, ContributionBinding> allContributionBindings();
     57 
     58   /**
     59    * The members-injection bindings for {@link #bindingKey()} that were resolved in
     60    * {@link #owningComponent()} or its ancestor components, keyed by the component in which the
     61    * binding was resolved. If {@link #bindingKey()}'s kind is not
     62    * {@link BindingKey.Kind#MEMBERS_INJECTION}, this is empty.
     63    */
     64   abstract ImmutableMap<ComponentDescriptor, MembersInjectionBinding> allMembersInjectionBindings();
     65 
     66   /**
     67    * All bindings for {@link #bindingKey()}, regardless of in which component they were resolved.
     68    */
     69   ImmutableSet<? extends Binding> bindings() {
     70     switch (bindingKey().kind()) {
     71       case CONTRIBUTION:
     72         return contributionBindings();
     73 
     74       case MEMBERS_INJECTION:
     75         return ImmutableSet.copyOf(membersInjectionBinding().asSet());
     76 
     77       default:
     78         throw new AssertionError(bindingKey());
     79     }
     80   }
     81 
     82   /**
     83    * All bindings for {@link #bindingKey()} that were resolved in {@link #owningComponent()}.
     84    */
     85   ImmutableSet<? extends Binding> ownedBindings() {
     86     switch (bindingKey().kind()) {
     87       case CONTRIBUTION:
     88         return ownedContributionBindings();
     89 
     90       case MEMBERS_INJECTION:
     91         return ImmutableSet.copyOf(ownedMembersInjectionBinding().asSet());
     92 
     93       default:
     94         throw new AssertionError(bindingKey());
     95     }
     96   }
     97 
     98   /**
     99    * All contribution bindings, regardless of owning component.
    100    *
    101    * @throws IllegalStateException if {@link #bindingKey()} is not a
    102    * {@link BindingKey.Kind#CONTRIBUTION}.
    103    */
    104   ImmutableSet<ContributionBinding> contributionBindings() {
    105     checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION));
    106     return ImmutableSet.copyOf(allContributionBindings().values());
    107   }
    108 
    109   /**
    110    * The contribution bindings that were resolved in {@link #owningComponent()}.
    111    *
    112    * @throws IllegalStateException if {@link #bindingKey()} is not a
    113    * {@link BindingKey.Kind#CONTRIBUTION}.
    114    */
    115   ImmutableSet<ContributionBinding> ownedContributionBindings() {
    116     checkState(bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION));
    117     return allContributionBindings().get(owningComponent());
    118   }
    119 
    120   /**
    121    * The members-injection binding, regardless of owning component.
    122    *
    123    * @throws IllegalStateException if {@link #bindingKey()} is not a
    124    * {@link BindingKey.Kind#MEMBERS_INJECTION}.
    125    */
    126   Optional<MembersInjectionBinding> membersInjectionBinding() {
    127     checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION));
    128     ImmutableSet<MembersInjectionBinding> membersInjectionBindings =
    129         FluentIterable.from(allMembersInjectionBindings().values()).toSet();
    130     return membersInjectionBindings.isEmpty()
    131         ? Optional.<MembersInjectionBinding>absent()
    132         : Optional.of(Iterables.getOnlyElement(membersInjectionBindings));
    133   }
    134 
    135   /**
    136    * The members-injection binding that was resolved in {@link #owningComponent()}.
    137    *
    138    * @throws IllegalStateException if {@link #bindingKey()} is not a
    139    * {@link BindingKey.Kind#MEMBERS_INJECTION}.
    140    */
    141   Optional<MembersInjectionBinding> ownedMembersInjectionBinding() {
    142     checkState(bindingKey().kind().equals(BindingKey.Kind.MEMBERS_INJECTION));
    143     return Optional.fromNullable(allMembersInjectionBindings().get(owningComponent()));
    144   }
    145 
    146   /**
    147    * Creates a {@link ResolvedBindings} for contribution bindings.
    148    */
    149   static ResolvedBindings forContributionBindings(
    150       BindingKey bindingKey,
    151       ComponentDescriptor owningComponent,
    152       Multimap<ComponentDescriptor, ? extends ContributionBinding> contributionBindings) {
    153     checkArgument(bindingKey.kind().equals(BindingKey.Kind.CONTRIBUTION));
    154     return new AutoValue_ResolvedBindings(
    155         bindingKey,
    156         owningComponent,
    157         ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>copyOf(contributionBindings),
    158         ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of());
    159   }
    160 
    161   /**
    162    * Creates a {@link ResolvedBindings} for contribution bindings.
    163    */
    164   static ResolvedBindings forContributionBindings(
    165       BindingKey bindingKey,
    166       ComponentDescriptor owningComponent,
    167       ContributionBinding... ownedContributionBindings) {
    168     return forContributionBindings(
    169         bindingKey,
    170         owningComponent,
    171         ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>builder()
    172             .putAll(owningComponent, ownedContributionBindings)
    173             .build());
    174   }
    175 
    176   /**
    177    * Creates a {@link ResolvedBindings} for members injection bindings.
    178    */
    179   static ResolvedBindings forMembersInjectionBinding(
    180       BindingKey bindingKey,
    181       ComponentDescriptor owningComponent,
    182       MembersInjectionBinding ownedMembersInjectionBinding) {
    183     checkArgument(bindingKey.kind().equals(BindingKey.Kind.MEMBERS_INJECTION));
    184     return new AutoValue_ResolvedBindings(
    185         bindingKey,
    186         owningComponent,
    187         ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(),
    188         ImmutableMap.of(owningComponent, ownedMembersInjectionBinding));
    189   }
    190 
    191   /**
    192    * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key.
    193    */
    194   static ResolvedBindings noBindings(BindingKey bindingKey, ComponentDescriptor owningComponent) {
    195     return new AutoValue_ResolvedBindings(
    196         bindingKey,
    197         owningComponent,
    198         ImmutableSetMultimap.<ComponentDescriptor, ContributionBinding>of(),
    199         ImmutableMap.<ComponentDescriptor, MembersInjectionBinding>of());
    200   }
    201 
    202   /**
    203    * Returns a {@code ResolvedBindings} with the same {@link #bindingKey()} and {@link #bindings()}
    204    * as this one, but no {@link #ownedBindings()}.
    205    */
    206   ResolvedBindings asInheritedIn(ComponentDescriptor owningComponent) {
    207     return new AutoValue_ResolvedBindings(
    208         bindingKey(), owningComponent, allContributionBindings(), allMembersInjectionBindings());
    209   }
    210 
    211   /**
    212    * {@code true} if this is a multibindings contribution.
    213    */
    214   boolean isMultibindings() {
    215     return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)
    216         && !contributionBindings().isEmpty()
    217         && contributionTypeFor(contributionBindings()).isMultibinding();
    218   }
    219 
    220   /**
    221    * {@code true} if this is a unique contribution binding.
    222    */
    223   boolean isUniqueContribution() {
    224     return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)
    225         && !contributionBindings().isEmpty()
    226         && !contributionTypeFor(contributionBindings()).isMultibinding();
    227   }
    228 }
    229