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