• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
2  * Copyright (C) 2015 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.collect.Iterables.getOnlyElement;
21 
22 import com.google.auto.value.AutoValue;
23 import com.google.auto.value.extension.memoized.Memoized;
24 import com.google.common.collect.ImmutableCollection;
25 import com.google.common.collect.ImmutableMap;
26 import com.google.common.collect.ImmutableSet;
27 import com.google.common.collect.ImmutableSetMultimap;
28 import com.google.common.collect.Multimap;
29 import dagger.model.Key;
30 import javax.lang.model.element.TypeElement;
31 
32 /**
33  * The collection of bindings that have been resolved for a key. For valid graphs, contains exactly
34  * one binding.
35  *
36  * <p>Separate {@link ResolvedBindings} instances should be used if a {@link
37  * MembersInjectionBinding} and a {@link ProvisionBinding} for the same key exist in the same
38  * component. (This will only happen if a type has an {@code @Inject} constructor and members, the
39  * component has a members injection method, and the type is also requested normally.)
40  */
41 @AutoValue
42 abstract class ResolvedBindings {
43   /** The binding key for which the {@link #bindings()} have been resolved. */
key()44   abstract Key key();
45 
46   /**
47    * The {@link ContributionBinding}s for {@link #key()} indexed by the component that owns the
48    * binding. Each key in the multimap is a part of the same component ancestry.
49    */
allContributionBindings()50   abstract ImmutableSetMultimap<TypeElement, ContributionBinding> allContributionBindings();
51 
52   /**
53    * The {@link MembersInjectionBinding}s for {@link #key()} indexed by the component that owns the
54    * binding.  Each key in the map is a part of the same component ancestry.
55    */
allMembersInjectionBindings()56   abstract ImmutableMap<TypeElement, MembersInjectionBinding> allMembersInjectionBindings();
57 
58   /** The multibinding declarations for {@link #key()}. */
multibindingDeclarations()59   abstract ImmutableSet<MultibindingDeclaration> multibindingDeclarations();
60 
61   /** The subcomponent declarations for {@link #key()}. */
subcomponentDeclarations()62   abstract ImmutableSet<SubcomponentDeclaration> subcomponentDeclarations();
63 
64   /** The optional binding declarations for {@link #key()}. */
optionalBindingDeclarations()65   abstract ImmutableSet<OptionalBindingDeclaration> optionalBindingDeclarations();
66 
67   // Computing the hash code is an expensive operation.
68   @Memoized
69   @Override
hashCode()70   public abstract int hashCode();
71 
72   // Suppresses ErrorProne warning that hashCode was overridden w/o equals
73   @Override
equals(Object other)74   public abstract boolean equals(Object other);
75 
76   /** All bindings for {@link #key()}, indexed by the component that owns the binding. */
allBindings()77   final ImmutableSetMultimap<TypeElement, ? extends Binding> allBindings() {
78     return !allMembersInjectionBindings().isEmpty()
79         ? allMembersInjectionBindings().asMultimap()
80         : allContributionBindings();
81   }
82 
83   /** All bindings for {@link #key()}, regardless of which component owns them. */
bindings()84   final ImmutableCollection<? extends Binding> bindings() {
85     return allBindings().values();
86   }
87 
88   /**
89    * {@code true} if there are no {@link #bindings()}, {@link #multibindingDeclarations()}, {@link
90    * #optionalBindingDeclarations()}, or {@link #subcomponentDeclarations()}.
91    */
isEmpty()92   final boolean isEmpty() {
93     return allMembersInjectionBindings().isEmpty()
94         && allContributionBindings().isEmpty()
95         && multibindingDeclarations().isEmpty()
96         && optionalBindingDeclarations().isEmpty()
97         && subcomponentDeclarations().isEmpty();
98   }
99 
100   /** All bindings for {@link #key()} that are owned by a component. */
bindingsOwnedBy(ComponentDescriptor component)101   ImmutableSet<? extends Binding> bindingsOwnedBy(ComponentDescriptor component) {
102     return allBindings().get(component.typeElement());
103   }
104 
105   /**
106    * All contribution bindings, regardless of owning component. Empty if this is a members-injection
107    * binding.
108    */
109   @Memoized
contributionBindings()110   ImmutableSet<ContributionBinding> contributionBindings() {
111     // TODO(ronshapiro): consider optimizing ImmutableSet.copyOf(Collection) for small immutable
112     // collections so that it doesn't need to call toArray(). Even though this method is memoized,
113     // toArray() can take ~150ms for large components, and there are surely other places in the
114     // processor that can benefit from this.
115     return ImmutableSet.copyOf(allContributionBindings().values());
116   }
117 
118   /** The component that owns {@code binding}. */
owningComponent(ContributionBinding binding)119   final TypeElement owningComponent(ContributionBinding binding) {
120     checkArgument(
121         contributionBindings().contains(binding),
122         "binding is not resolved for %s: %s",
123         key(),
124         binding);
125     return getOnlyElement(allContributionBindings().inverse().get(binding));
126   }
127 
128   /** Creates a {@link ResolvedBindings} for contribution bindings. */
forContributionBindings( Key key, Multimap<TypeElement, ContributionBinding> contributionBindings, Iterable<MultibindingDeclaration> multibindings, Iterable<SubcomponentDeclaration> subcomponentDeclarations, Iterable<OptionalBindingDeclaration> optionalBindingDeclarations)129   static ResolvedBindings forContributionBindings(
130       Key key,
131       Multimap<TypeElement, ContributionBinding> contributionBindings,
132       Iterable<MultibindingDeclaration> multibindings,
133       Iterable<SubcomponentDeclaration> subcomponentDeclarations,
134       Iterable<OptionalBindingDeclaration> optionalBindingDeclarations) {
135     return new AutoValue_ResolvedBindings(
136         key,
137         ImmutableSetMultimap.copyOf(contributionBindings),
138         ImmutableMap.of(),
139         ImmutableSet.copyOf(multibindings),
140         ImmutableSet.copyOf(subcomponentDeclarations),
141         ImmutableSet.copyOf(optionalBindingDeclarations));
142   }
143 
144   /**
145    * Creates a {@link ResolvedBindings} for members injection bindings.
146    */
forMembersInjectionBinding( Key key, ComponentDescriptor owningComponent, MembersInjectionBinding ownedMembersInjectionBinding)147   static ResolvedBindings forMembersInjectionBinding(
148       Key key,
149       ComponentDescriptor owningComponent,
150       MembersInjectionBinding ownedMembersInjectionBinding) {
151     return new AutoValue_ResolvedBindings(
152         key,
153         ImmutableSetMultimap.of(),
154         ImmutableMap.of(owningComponent.typeElement(), ownedMembersInjectionBinding),
155         ImmutableSet.of(),
156         ImmutableSet.of(),
157         ImmutableSet.of());
158   }
159 
160   /**
161    * Creates a {@link ResolvedBindings} appropriate for when there are no bindings for the key.
162    */
noBindings(Key key)163   static ResolvedBindings noBindings(Key key) {
164     return new AutoValue_ResolvedBindings(
165         key,
166         ImmutableSetMultimap.of(),
167         ImmutableMap.of(),
168         ImmutableSet.of(),
169         ImmutableSet.of(),
170         ImmutableSet.of());
171   }
172 }
173