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