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    */
bindingKey()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    */
owningComponent()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    */
allContributionBindings()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    */
allMembersInjectionBindings()64   abstract ImmutableMap<ComponentDescriptor, MembersInjectionBinding> allMembersInjectionBindings();
65 
66   /**
67    * All bindings for {@link #bindingKey()}, regardless of in which component they were resolved.
68    */
bindings()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    */
ownedBindings()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    */
contributionBindings()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    */
ownedContributionBindings()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    */
membersInjectionBinding()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    */
ownedMembersInjectionBinding()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    */
forContributionBindings( BindingKey bindingKey, ComponentDescriptor owningComponent, Multimap<ComponentDescriptor, ? extends ContributionBinding> contributionBindings)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    */
forContributionBindings( BindingKey bindingKey, ComponentDescriptor owningComponent, ContributionBinding... ownedContributionBindings)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    */
forMembersInjectionBinding( BindingKey bindingKey, ComponentDescriptor owningComponent, MembersInjectionBinding ownedMembersInjectionBinding)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    */
noBindings(BindingKey bindingKey, ComponentDescriptor owningComponent)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    */
asInheritedIn(ComponentDescriptor owningComponent)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    */
isMultibindings()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    */
isUniqueContribution()223   boolean isUniqueContribution() {
224     return bindingKey().kind().equals(BindingKey.Kind.CONTRIBUTION)
225         && !contributionBindings().isEmpty()
226         && !contributionTypeFor(contributionBindings()).isMultibinding();
227   }
228 }
229