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