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