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.auto.common.MoreElements.isAnnotationPresent; 20 import static com.google.auto.common.MoreTypes.asExecutable; 21 import static com.google.auto.common.MoreTypes.isType; 22 import static com.google.common.base.Preconditions.checkArgument; 23 import static com.google.common.base.Preconditions.checkNotNull; 24 import static com.google.common.collect.Iterables.getOnlyElement; 25 import static dagger.internal.codegen.base.RequestKinds.extractKeyType; 26 import static dagger.internal.codegen.binding.MapKeys.getMapKey; 27 import static dagger.internal.codegen.binding.MapKeys.mapKeyType; 28 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 29 import static dagger.internal.codegen.extension.Optionals.firstPresent; 30 import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType; 31 import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType; 32 import static java.util.Arrays.asList; 33 import static javax.lang.model.element.ElementKind.METHOD; 34 35 import com.google.auto.common.MoreTypes; 36 import com.google.common.collect.ImmutableSet; 37 import dagger.Binds; 38 import dagger.BindsOptionalOf; 39 import dagger.internal.codegen.base.ContributionType; 40 import dagger.internal.codegen.base.FrameworkTypes; 41 import dagger.internal.codegen.base.MapType; 42 import dagger.internal.codegen.base.OptionalType; 43 import dagger.internal.codegen.base.RequestKinds; 44 import dagger.internal.codegen.base.SetType; 45 import dagger.internal.codegen.base.SimpleAnnotationMirror; 46 import dagger.internal.codegen.langmodel.DaggerElements; 47 import dagger.internal.codegen.langmodel.DaggerTypes; 48 import dagger.model.Key; 49 import dagger.model.Key.MultibindingContributionIdentifier; 50 import dagger.model.RequestKind; 51 import dagger.multibindings.Multibinds; 52 import dagger.producers.Produced; 53 import dagger.producers.Producer; 54 import dagger.producers.Production; 55 import dagger.producers.internal.ProductionImplementation; 56 import dagger.producers.monitoring.ProductionComponentMonitor; 57 import java.util.Map; 58 import java.util.Optional; 59 import java.util.Set; 60 import java.util.concurrent.Executor; 61 import java.util.stream.Stream; 62 import javax.inject.Inject; 63 import javax.inject.Provider; 64 import javax.lang.model.element.AnnotationMirror; 65 import javax.lang.model.element.ExecutableElement; 66 import javax.lang.model.element.TypeElement; 67 import javax.lang.model.type.DeclaredType; 68 import javax.lang.model.type.ExecutableType; 69 import javax.lang.model.type.PrimitiveType; 70 import javax.lang.model.type.TypeMirror; 71 72 /** A factory for {@link Key}s. */ 73 public final class KeyFactory { 74 private final DaggerTypes types; 75 private final DaggerElements elements; 76 private final InjectionAnnotations injectionAnnotations; 77 78 @Inject KeyFactory( DaggerTypes types, DaggerElements elements, InjectionAnnotations injectionAnnotations)79 KeyFactory( 80 DaggerTypes types, DaggerElements elements, InjectionAnnotations injectionAnnotations) { 81 this.types = checkNotNull(types); 82 this.elements = checkNotNull(elements); 83 this.injectionAnnotations = injectionAnnotations; 84 } 85 boxPrimitives(TypeMirror type)86 private TypeMirror boxPrimitives(TypeMirror type) { 87 return type.getKind().isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type; 88 } 89 setOf(TypeMirror elementType)90 private DeclaredType setOf(TypeMirror elementType) { 91 return types.getDeclaredType(elements.getTypeElement(Set.class), boxPrimitives(elementType)); 92 } 93 mapOf(TypeMirror keyType, TypeMirror valueType)94 private DeclaredType mapOf(TypeMirror keyType, TypeMirror valueType) { 95 return types.getDeclaredType( 96 elements.getTypeElement(Map.class), boxPrimitives(keyType), boxPrimitives(valueType)); 97 } 98 99 /** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */ mapOfFrameworkType( TypeMirror keyType, TypeElement frameworkType, TypeMirror valueType)100 private TypeMirror mapOfFrameworkType( 101 TypeMirror keyType, TypeElement frameworkType, TypeMirror valueType) { 102 return mapOf(keyType, types.getDeclaredType(frameworkType, boxPrimitives(valueType))); 103 } 104 forComponentMethod(ExecutableElement componentMethod)105 Key forComponentMethod(ExecutableElement componentMethod) { 106 checkArgument(componentMethod.getKind().equals(METHOD)); 107 return forMethod(componentMethod, componentMethod.getReturnType()); 108 } 109 forProductionComponentMethod(ExecutableElement componentMethod)110 Key forProductionComponentMethod(ExecutableElement componentMethod) { 111 checkArgument(componentMethod.getKind().equals(METHOD)); 112 TypeMirror returnType = componentMethod.getReturnType(); 113 TypeMirror keyType = 114 isFutureType(returnType) 115 ? getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments()) 116 : returnType; 117 return forMethod(componentMethod, keyType); 118 } 119 forSubcomponentCreatorMethod( ExecutableElement subcomponentCreatorMethod, DeclaredType declaredContainer)120 Key forSubcomponentCreatorMethod( 121 ExecutableElement subcomponentCreatorMethod, DeclaredType declaredContainer) { 122 checkArgument(subcomponentCreatorMethod.getKind().equals(METHOD)); 123 ExecutableType resolvedMethod = 124 asExecutable(types.asMemberOf(declaredContainer, subcomponentCreatorMethod)); 125 return Key.builder(resolvedMethod.getReturnType()).build(); 126 } 127 forSubcomponentCreator(TypeMirror creatorType)128 public Key forSubcomponentCreator(TypeMirror creatorType) { 129 return Key.builder(creatorType).build(); 130 } 131 forProvidesMethod(ExecutableElement method, TypeElement contributingModule)132 public Key forProvidesMethod(ExecutableElement method, TypeElement contributingModule) { 133 return forBindingMethod( 134 method, contributingModule, Optional.of(elements.getTypeElement(Provider.class))); 135 } 136 forProducesMethod(ExecutableElement method, TypeElement contributingModule)137 public Key forProducesMethod(ExecutableElement method, TypeElement contributingModule) { 138 return forBindingMethod( 139 method, contributingModule, Optional.of(elements.getTypeElement(Producer.class))); 140 } 141 142 /** Returns the key bound by a {@link Binds} method. */ forBindsMethod(ExecutableElement method, TypeElement contributingModule)143 Key forBindsMethod(ExecutableElement method, TypeElement contributingModule) { 144 checkArgument(isAnnotationPresent(method, Binds.class)); 145 return forBindingMethod(method, contributingModule, Optional.empty()); 146 } 147 148 /** Returns the base key bound by a {@link BindsOptionalOf} method. */ forBindsOptionalOfMethod(ExecutableElement method, TypeElement contributingModule)149 Key forBindsOptionalOfMethod(ExecutableElement method, TypeElement contributingModule) { 150 checkArgument(isAnnotationPresent(method, BindsOptionalOf.class)); 151 return forBindingMethod(method, contributingModule, Optional.empty()); 152 } 153 forBindingMethod( ExecutableElement method, TypeElement contributingModule, Optional<TypeElement> frameworkType)154 private Key forBindingMethod( 155 ExecutableElement method, 156 TypeElement contributingModule, 157 Optional<TypeElement> frameworkType) { 158 checkArgument(method.getKind().equals(METHOD)); 159 ExecutableType methodType = 160 MoreTypes.asExecutable( 161 types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), method)); 162 ContributionType contributionType = ContributionType.fromBindingElement(method); 163 TypeMirror returnType = methodType.getReturnType(); 164 if (frameworkType.isPresent() 165 && frameworkType.get().equals(elements.getTypeElement(Producer.class)) 166 && isType(returnType)) { 167 if (isFutureType(methodType.getReturnType())) { 168 returnType = getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments()); 169 } else if (contributionType.equals(ContributionType.SET_VALUES) 170 && SetType.isSet(returnType)) { 171 SetType setType = SetType.from(returnType); 172 if (isFutureType(setType.elementType())) { 173 returnType = 174 types.getDeclaredType( 175 elements.getTypeElement(Set.class), unwrapType(setType.elementType())); 176 } 177 } 178 } 179 TypeMirror keyType = bindingMethodKeyType(returnType, method, contributionType, frameworkType); 180 Key key = forMethod(method, keyType); 181 return contributionType.equals(ContributionType.UNIQUE) 182 ? key 183 : key.toBuilder() 184 .multibindingContributionIdentifier( 185 new MultibindingContributionIdentifier(method, contributingModule)) 186 .build(); 187 } 188 189 /** 190 * Returns the key for a {@link Multibinds @Multibinds} method. 191 * 192 * <p>The key's type is either {@code Set<T>} or {@code Map<K, Provider<V>>}. The latter works 193 * even for maps used by {@code Producer}s. 194 */ forMultibindsMethod(ExecutableType executableType, ExecutableElement method)195 Key forMultibindsMethod(ExecutableType executableType, ExecutableElement method) { 196 checkArgument(method.getKind().equals(METHOD), "%s must be a method", method); 197 TypeMirror returnType = executableType.getReturnType(); 198 TypeMirror keyType = 199 MapType.isMap(returnType) 200 ? mapOfFrameworkType( 201 MapType.from(returnType).keyType(), 202 elements.getTypeElement(Provider.class), 203 MapType.from(returnType).valueType()) 204 : returnType; 205 return forMethod(method, keyType); 206 } 207 bindingMethodKeyType( TypeMirror returnType, ExecutableElement method, ContributionType contributionType, Optional<TypeElement> frameworkType)208 private TypeMirror bindingMethodKeyType( 209 TypeMirror returnType, 210 ExecutableElement method, 211 ContributionType contributionType, 212 Optional<TypeElement> frameworkType) { 213 switch (contributionType) { 214 case UNIQUE: 215 return returnType; 216 case SET: 217 return setOf(returnType); 218 case MAP: 219 TypeMirror mapKeyType = mapKeyType(getMapKey(method).get(), types); 220 return frameworkType.isPresent() 221 ? mapOfFrameworkType(mapKeyType, frameworkType.get(), returnType) 222 : mapOf(mapKeyType, returnType); 223 case SET_VALUES: 224 // TODO(gak): do we want to allow people to use "covariant return" here? 225 checkArgument(SetType.isSet(returnType)); 226 return returnType; 227 } 228 throw new AssertionError(); 229 } 230 231 /** 232 * Returns the key for a binding associated with a {@link DelegateDeclaration}. 233 * 234 * <p>If {@code delegateDeclaration} is {@code @IntoMap}, transforms the {@code Map<K, V>} key 235 * from {@link DelegateDeclaration#key()} to {@code Map<K, FrameworkType<V>>}. If {@code 236 * delegateDeclaration} is not a map contribution, its key is returned. 237 */ forDelegateBinding(DelegateDeclaration delegateDeclaration, Class<?> frameworkType)238 Key forDelegateBinding(DelegateDeclaration delegateDeclaration, Class<?> frameworkType) { 239 return delegateDeclaration.contributionType().equals(ContributionType.MAP) 240 ? wrapMapValue(delegateDeclaration.key(), frameworkType) 241 : delegateDeclaration.key(); 242 } 243 forMethod(ExecutableElement method, TypeMirror keyType)244 private Key forMethod(ExecutableElement method, TypeMirror keyType) { 245 return forQualifiedType(injectionAnnotations.getQualifier(method), keyType); 246 } 247 forInjectConstructorWithResolvedType(TypeMirror type)248 public Key forInjectConstructorWithResolvedType(TypeMirror type) { 249 return Key.builder(type).build(); 250 } 251 252 // TODO(ronshapiro): Remove these conveniences which are simple wrappers around Key.Builder forType(TypeMirror type)253 Key forType(TypeMirror type) { 254 return Key.builder(type).build(); 255 } 256 forMembersInjectedType(TypeMirror type)257 public Key forMembersInjectedType(TypeMirror type) { 258 return Key.builder(type).build(); 259 } 260 forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type)261 Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) { 262 return Key.builder(boxPrimitives(type)).qualifier(qualifier).build(); 263 } 264 forProductionExecutor()265 public Key forProductionExecutor() { 266 return Key.builder(elements.getTypeElement(Executor.class).asType()) 267 .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(Production.class))) 268 .build(); 269 } 270 forProductionImplementationExecutor()271 public Key forProductionImplementationExecutor() { 272 return Key.builder(elements.getTypeElement(Executor.class).asType()) 273 .qualifier(SimpleAnnotationMirror.of(elements.getTypeElement(ProductionImplementation.class))) 274 .build(); 275 } 276 forProductionComponentMonitor()277 public Key forProductionComponentMonitor() { 278 return Key.builder(elements.getTypeElement(ProductionComponentMonitor.class).asType()).build(); 279 } 280 281 /** 282 * If {@code requestKey} is for a {@code Map<K, V>} or {@code Map<K, Produced<V>>}, returns keys 283 * for {@code Map<K, Provider<V>>} and {@code Map<K, Producer<V>>} (if Dagger-Producers is on 284 * the classpath). 285 */ implicitFrameworkMapKeys(Key requestKey)286 ImmutableSet<Key> implicitFrameworkMapKeys(Key requestKey) { 287 return Stream.of(implicitMapProviderKeyFrom(requestKey), implicitMapProducerKeyFrom(requestKey)) 288 .filter(Optional::isPresent) 289 .map(Optional::get) 290 .collect(toImmutableSet()); 291 } 292 293 /** 294 * Optionally extract a {@link Key} for the underlying provision binding(s) if such a valid key 295 * can be inferred from the given key. Specifically, if the key represents a {@link Map}{@code 296 * <K, V>} or {@code Map<K, Producer<V>>}, a key of {@code Map<K, Provider<V>>} will be 297 * returned. 298 */ implicitMapProviderKeyFrom(Key possibleMapKey)299 Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) { 300 return firstPresent( 301 rewrapMapKey(possibleMapKey, Produced.class, Provider.class), 302 wrapMapKey(possibleMapKey, Provider.class)); 303 } 304 305 /** 306 * Optionally extract a {@link Key} for the underlying production binding(s) if such a 307 * valid key can be inferred from the given key. Specifically, if the key represents a 308 * {@link Map}{@code <K, V>} or {@code Map<K, Produced<V>>}, a key of 309 * {@code Map<K, Producer<V>>} will be returned. 310 */ implicitMapProducerKeyFrom(Key possibleMapKey)311 Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) { 312 return firstPresent( 313 rewrapMapKey(possibleMapKey, Produced.class, Producer.class), 314 wrapMapKey(possibleMapKey, Producer.class)); 315 } 316 317 /** 318 * If {@code key}'s type is {@code Map<K, Provider<V>>}, {@code Map<K, Producer<V>>}, or {@code 319 * Map<K, Produced<V>>}, returns a key with the same qualifier and {@link 320 * Key#multibindingContributionIdentifier()} whose type is simply {@code Map<K, V>}. 321 * 322 * <p>Otherwise, returns {@code key}. 323 */ unwrapMapValueType(Key key)324 public Key unwrapMapValueType(Key key) { 325 if (MapType.isMap(key)) { 326 MapType mapType = MapType.from(key); 327 if (!mapType.isRawType()) { 328 for (Class<?> frameworkClass : asList(Provider.class, Producer.class, Produced.class)) { 329 if (mapType.valuesAreTypeOf(frameworkClass)) { 330 return key.toBuilder() 331 .type(mapOf(mapType.keyType(), mapType.unwrappedValueType(frameworkClass))) 332 .build(); 333 } 334 } 335 } 336 } 337 return key; 338 } 339 340 /** 341 * Converts a {@link Key} of type {@code Map<K, V>} to {@code Map<K, Provider<V>>}. 342 */ wrapMapValue(Key key, Class<?> newWrappingClass)343 private Key wrapMapValue(Key key, Class<?> newWrappingClass) { 344 checkArgument( 345 FrameworkTypes.isFrameworkType(elements.getTypeElement(newWrappingClass).asType())); 346 return wrapMapKey(key, newWrappingClass).get(); 347 } 348 349 /** 350 * If {@code key}'s type is {@code Map<K, CurrentWrappingClass<Bar>>}, returns a key with type 351 * {@code Map<K, NewWrappingClass<Bar>>} with the same qualifier. Otherwise returns {@link 352 * Optional#empty()}. 353 * 354 * <p>Returns {@link Optional#empty()} if {@code newWrappingClass} is not in the classpath. 355 * 356 * @throws IllegalArgumentException if {@code newWrappingClass} is the same as {@code 357 * currentWrappingClass} 358 */ rewrapMapKey( Key possibleMapKey, Class<?> currentWrappingClass, Class<?> newWrappingClass)359 public Optional<Key> rewrapMapKey( 360 Key possibleMapKey, Class<?> currentWrappingClass, Class<?> newWrappingClass) { 361 checkArgument(!currentWrappingClass.equals(newWrappingClass)); 362 if (MapType.isMap(possibleMapKey)) { 363 MapType mapType = MapType.from(possibleMapKey); 364 if (!mapType.isRawType() && mapType.valuesAreTypeOf(currentWrappingClass)) { 365 TypeElement wrappingElement = elements.getTypeElement(newWrappingClass); 366 if (wrappingElement == null) { 367 // This target might not be compiled with Producers, so wrappingClass might not have an 368 // associated element. 369 return Optional.empty(); 370 } 371 DeclaredType wrappedValueType = 372 types.getDeclaredType( 373 wrappingElement, mapType.unwrappedValueType(currentWrappingClass)); 374 return Optional.of( 375 possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build()); 376 } 377 } 378 return Optional.empty(); 379 } 380 381 /** 382 * If {@code key}'s type is {@code Map<K, Foo>} and {@code Foo} is not {@code WrappingClass 383 * <Bar>}, returns a key with type {@code Map<K, WrappingClass<Foo>>} with the same qualifier. 384 * Otherwise returns {@link Optional#empty()}. 385 * 386 * <p>Returns {@link Optional#empty()} if {@code WrappingClass} is not in the classpath. 387 */ wrapMapKey(Key possibleMapKey, Class<?> wrappingClass)388 private Optional<Key> wrapMapKey(Key possibleMapKey, Class<?> wrappingClass) { 389 if (MapType.isMap(possibleMapKey)) { 390 MapType mapType = MapType.from(possibleMapKey); 391 if (!mapType.isRawType() && !mapType.valuesAreTypeOf(wrappingClass)) { 392 TypeElement wrappingElement = elements.getTypeElement(wrappingClass); 393 if (wrappingElement == null) { 394 // This target might not be compiled with Producers, so wrappingClass might not have an 395 // associated element. 396 return Optional.empty(); 397 } 398 DeclaredType wrappedValueType = types.getDeclaredType(wrappingElement, mapType.valueType()); 399 return Optional.of( 400 possibleMapKey.toBuilder().type(mapOf(mapType.keyType(), wrappedValueType)).build()); 401 } 402 } 403 return Optional.empty(); 404 } 405 406 /** 407 * If {@code key}'s type is {@code Set<WrappingClass<Bar>>}, returns a key with type {@code Set 408 * <Bar>} with the same qualifier. Otherwise returns {@link Optional#empty()}. 409 */ unwrapSetKey(Key key, Class<?> wrappingClass)410 Optional<Key> unwrapSetKey(Key key, Class<?> wrappingClass) { 411 if (SetType.isSet(key)) { 412 SetType setType = SetType.from(key); 413 if (!setType.isRawType() && setType.elementsAreTypeOf(wrappingClass)) { 414 return Optional.of( 415 key.toBuilder().type(setOf(setType.unwrappedElementType(wrappingClass))).build()); 416 } 417 } 418 return Optional.empty(); 419 } 420 421 /** 422 * If {@code key}'s type is {@code Optional<T>} for some {@code T}, returns a key with the same 423 * qualifier whose type is {@linkplain RequestKinds#extractKeyType(RequestKind, TypeMirror)} 424 * extracted} from {@code T}. 425 */ unwrapOptional(Key key)426 Optional<Key> unwrapOptional(Key key) { 427 if (!OptionalType.isOptional(key)) { 428 return Optional.empty(); 429 } 430 431 TypeMirror optionalValueType = OptionalType.from(key).valueType(); 432 return Optional.of(key.toBuilder().type(extractKeyType(optionalValueType)).build()); 433 } 434 } 435