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