1 /* 2 * Copyright (C) 2014 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.base.Preconditions.checkNotNull; 21 import static com.google.common.base.Preconditions.checkState; 22 import static com.google.common.collect.Iterables.getOnlyElement; 23 import static dagger.internal.codegen.base.RequestKinds.extractKeyType; 24 import static dagger.internal.codegen.base.RequestKinds.getRequestKind; 25 import static dagger.internal.codegen.binding.AssistedInjectionAnnotations.isAssistedParameter; 26 import static dagger.internal.codegen.model.RequestKind.FUTURE; 27 import static dagger.internal.codegen.model.RequestKind.INSTANCE; 28 import static dagger.internal.codegen.model.RequestKind.MEMBERS_INJECTION; 29 import static dagger.internal.codegen.model.RequestKind.PROVIDER; 30 import static dagger.internal.codegen.xprocessing.XTypes.isTypeOf; 31 import static dagger.internal.codegen.xprocessing.XTypes.unwrapType; 32 33 import androidx.room.compiler.processing.XAnnotation; 34 import androidx.room.compiler.processing.XElement; 35 import androidx.room.compiler.processing.XMethodElement; 36 import androidx.room.compiler.processing.XMethodType; 37 import androidx.room.compiler.processing.XType; 38 import androidx.room.compiler.processing.XVariableElement; 39 import com.google.common.collect.ImmutableSet; 40 import dagger.Lazy; 41 import dagger.internal.codegen.base.MapType; 42 import dagger.internal.codegen.base.OptionalType; 43 import dagger.internal.codegen.javapoet.TypeNames; 44 import dagger.internal.codegen.model.DaggerElement; 45 import dagger.internal.codegen.model.DependencyRequest; 46 import dagger.internal.codegen.model.Key; 47 import dagger.internal.codegen.model.RequestKind; 48 import dagger.internal.codegen.xprocessing.Nullability; 49 import java.util.List; 50 import java.util.Optional; 51 import javax.inject.Inject; 52 import javax.inject.Provider; 53 54 /** 55 * Factory for {@link DependencyRequest}s. 56 * 57 * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available, which 58 * may mean that the type will be generated in a later round of processing. 59 */ 60 public final class DependencyRequestFactory { 61 private final KeyFactory keyFactory; 62 private final InjectionAnnotations injectionAnnotations; 63 64 @Inject DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations)65 DependencyRequestFactory(KeyFactory keyFactory, InjectionAnnotations injectionAnnotations) { 66 this.keyFactory = keyFactory; 67 this.injectionAnnotations = injectionAnnotations; 68 } 69 forRequiredResolvedVariables( List<? extends XVariableElement> variables, List<XType> resolvedTypes)70 ImmutableSet<DependencyRequest> forRequiredResolvedVariables( 71 List<? extends XVariableElement> variables, List<XType> resolvedTypes) { 72 checkState(resolvedTypes.size() == variables.size()); 73 ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder(); 74 for (int i = 0; i < variables.size(); i++) { 75 builder.add(forRequiredResolvedVariable(variables.get(i), resolvedTypes.get(i))); 76 } 77 return builder.build(); 78 } 79 80 /** 81 * Creates synthetic dependency requests for each individual multibinding contribution in {@code 82 * multibindingContributions}. 83 */ forMultibindingContributions( Key multibindingKey, Iterable<ContributionBinding> multibindingContributions)84 ImmutableSet<DependencyRequest> forMultibindingContributions( 85 Key multibindingKey, Iterable<ContributionBinding> multibindingContributions) { 86 ImmutableSet.Builder<DependencyRequest> requests = ImmutableSet.builder(); 87 for (ContributionBinding multibindingContribution : multibindingContributions) { 88 requests.add(forMultibindingContribution(multibindingKey, multibindingContribution)); 89 } 90 return requests.build(); 91 } 92 93 /** Creates a synthetic dependency request for one individual {@code multibindingContribution}. */ forMultibindingContribution( Key multibindingKey, ContributionBinding multibindingContribution)94 private DependencyRequest forMultibindingContribution( 95 Key multibindingKey, ContributionBinding multibindingContribution) { 96 checkArgument( 97 multibindingContribution.key().multibindingContributionIdentifier().isPresent(), 98 "multibindingContribution's key must have a multibinding contribution identifier: %s", 99 multibindingContribution); 100 return DependencyRequest.builder() 101 .kind(multibindingContributionRequestKind(multibindingKey, multibindingContribution)) 102 .key(multibindingContribution.key()) 103 .build(); 104 } 105 multibindingContributionRequestKind( Key multibindingKey, ContributionBinding multibindingContribution)106 private RequestKind multibindingContributionRequestKind( 107 Key multibindingKey, ContributionBinding multibindingContribution) { 108 switch (multibindingContribution.contributionType()) { 109 case MAP: 110 return MapType.from(multibindingKey).valueRequestKind(); 111 case SET: 112 case SET_VALUES: 113 return INSTANCE; 114 case UNIQUE: 115 throw new IllegalArgumentException( 116 "multibindingContribution must be a multibinding: " + multibindingContribution); 117 } 118 throw new AssertionError(multibindingContribution.toString()); 119 } 120 forRequiredResolvedVariable( XVariableElement variableElement, XType resolvedType)121 DependencyRequest forRequiredResolvedVariable( 122 XVariableElement variableElement, XType resolvedType) { 123 checkNotNull(variableElement); 124 checkNotNull(resolvedType); 125 // Ban @Assisted parameters, they are not considered dependency requests. 126 checkArgument(!isAssistedParameter(variableElement)); 127 Optional<XAnnotation> qualifier = injectionAnnotations.getQualifier(variableElement); 128 return newDependencyRequest(variableElement, resolvedType, qualifier); 129 } 130 forComponentProvisionMethod( XMethodElement provisionMethod, XMethodType provisionMethodType)131 public DependencyRequest forComponentProvisionMethod( 132 XMethodElement provisionMethod, XMethodType provisionMethodType) { 133 checkNotNull(provisionMethod); 134 checkNotNull(provisionMethodType); 135 checkArgument( 136 provisionMethod.getParameters().isEmpty(), 137 "Component provision methods must be empty: %s", 138 provisionMethod); 139 Optional<XAnnotation> qualifier = injectionAnnotations.getQualifier(provisionMethod); 140 return newDependencyRequest(provisionMethod, provisionMethodType.getReturnType(), qualifier); 141 } 142 forComponentProductionMethod( XMethodElement productionMethod, XMethodType productionMethodType)143 public DependencyRequest forComponentProductionMethod( 144 XMethodElement productionMethod, XMethodType productionMethodType) { 145 checkNotNull(productionMethod); 146 checkNotNull(productionMethodType); 147 checkArgument( 148 productionMethod.getParameters().isEmpty(), 149 "Component production methods must be empty: %s", 150 productionMethod); 151 XType type = productionMethodType.getReturnType(); 152 Optional<XAnnotation> qualifier = injectionAnnotations.getQualifier(productionMethod); 153 // Only a component production method can be a request for a ListenableFuture, so we 154 // special-case it here. 155 if (isTypeOf(type, TypeNames.LISTENABLE_FUTURE)) { 156 return DependencyRequest.builder() 157 .kind(FUTURE) 158 .key(keyFactory.forQualifiedType(qualifier, unwrapType(type))) 159 .requestElement(DaggerElement.from(productionMethod)) 160 .build(); 161 } else { 162 return newDependencyRequest(productionMethod, type, qualifier); 163 } 164 } 165 forComponentMembersInjectionMethod( XMethodElement membersInjectionMethod, XMethodType membersInjectionMethodType)166 DependencyRequest forComponentMembersInjectionMethod( 167 XMethodElement membersInjectionMethod, XMethodType membersInjectionMethodType) { 168 checkNotNull(membersInjectionMethod); 169 checkNotNull(membersInjectionMethodType); 170 Optional<XAnnotation> qualifier = injectionAnnotations.getQualifier(membersInjectionMethod); 171 checkArgument(!qualifier.isPresent()); 172 XType membersInjectedType = getOnlyElement(membersInjectionMethodType.getParameterTypes()); 173 return DependencyRequest.builder() 174 .kind(MEMBERS_INJECTION) 175 .key(keyFactory.forMembersInjectedType(membersInjectedType)) 176 .requestElement(DaggerElement.from(membersInjectionMethod)) 177 .build(); 178 } 179 forProductionImplementationExecutor()180 DependencyRequest forProductionImplementationExecutor() { 181 return DependencyRequest.builder() 182 .kind(PROVIDER) 183 .key(keyFactory.forProductionImplementationExecutor()) 184 .build(); 185 } 186 forProductionComponentMonitor()187 DependencyRequest forProductionComponentMonitor() { 188 return DependencyRequest.builder() 189 .kind(PROVIDER) 190 .key(keyFactory.forProductionComponentMonitor()) 191 .build(); 192 } 193 194 /** 195 * Returns a synthetic request for the present value of an optional binding generated from a 196 * {@link dagger.BindsOptionalOf} declaration. 197 */ forSyntheticPresentOptionalBinding(Key requestKey)198 DependencyRequest forSyntheticPresentOptionalBinding(Key requestKey) { 199 Optional<Key> key = keyFactory.unwrapOptional(requestKey); 200 checkArgument(key.isPresent(), "not a request for optional: %s", requestKey); 201 RequestKind kind = getRequestKind(OptionalType.from(requestKey).valueType()); 202 return DependencyRequest.builder() 203 .kind(kind) 204 .key(key.get()) 205 .isNullable(requestKindImplicitlyAllowsNull(kind)) 206 .build(); 207 } 208 newDependencyRequest( XElement requestElement, XType type, Optional<XAnnotation> qualifier)209 private DependencyRequest newDependencyRequest( 210 XElement requestElement, XType type, Optional<XAnnotation> qualifier) { 211 RequestKind requestKind = getRequestKind(type); 212 return DependencyRequest.builder() 213 .kind(requestKind) 214 .key(keyFactory.forQualifiedType(qualifier, extractKeyType(type))) 215 .requestElement(DaggerElement.from(requestElement)) 216 .isNullable(allowsNull(requestKind, Nullability.of(requestElement))) 217 .build(); 218 } 219 220 /** 221 * Returns {@code true} if a given request element allows null values. {@link 222 * RequestKind#INSTANCE} requests must be nullable in order to allow null values. All other 223 * request kinds implicitly allow null values because they are are wrapped inside {@link 224 * Provider}, {@link Lazy}, etc. 225 */ allowsNull(RequestKind kind, Nullability nullability)226 private boolean allowsNull(RequestKind kind, Nullability nullability) { 227 return nullability.isNullable() || requestKindImplicitlyAllowsNull(kind); 228 } 229 requestKindImplicitlyAllowsNull(RequestKind kind)230 private boolean requestKindImplicitlyAllowsNull(RequestKind kind) { 231 return !kind.equals(INSTANCE); 232 } 233 } 234