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.auto.common.MoreTypes.isType; 22 import static com.google.common.base.Preconditions.checkArgument; 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.ProducerAnnotations.productionImplementationQualifier; 26 import static dagger.internal.codegen.base.ProducerAnnotations.productionQualifier; 27 import static dagger.internal.codegen.base.RequestKinds.extractKeyType; 28 import static dagger.internal.codegen.binding.MapKeys.getMapKey; 29 import static dagger.internal.codegen.binding.MapKeys.mapKeyType; 30 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 31 import static dagger.internal.codegen.extension.Optionals.firstPresent; 32 import static dagger.internal.codegen.langmodel.DaggerElements.isAnnotationPresent; 33 import static dagger.internal.codegen.langmodel.DaggerTypes.isFutureType; 34 import static dagger.internal.codegen.langmodel.DaggerTypes.unwrapType; 35 import static dagger.internal.codegen.xprocessing.XTypes.isDeclared; 36 import static java.util.Arrays.asList; 37 import static javax.lang.model.element.ElementKind.METHOD; 38 39 import androidx.room.compiler.processing.XAnnotation; 40 import androidx.room.compiler.processing.XMethodElement; 41 import androidx.room.compiler.processing.XMethodType; 42 import androidx.room.compiler.processing.XProcessingEnv; 43 import androidx.room.compiler.processing.XType; 44 import androidx.room.compiler.processing.XTypeElement; 45 import com.google.auto.common.MoreTypes; 46 import com.google.common.collect.ImmutableSet; 47 import com.squareup.javapoet.ClassName; 48 import dagger.Binds; 49 import dagger.BindsOptionalOf; 50 import dagger.internal.codegen.base.ContributionType; 51 import dagger.internal.codegen.base.FrameworkTypes; 52 import dagger.internal.codegen.base.MapType; 53 import dagger.internal.codegen.base.OptionalType; 54 import dagger.internal.codegen.base.RequestKinds; 55 import dagger.internal.codegen.base.SetType; 56 import dagger.internal.codegen.javapoet.TypeNames; 57 import dagger.internal.codegen.langmodel.DaggerElements; 58 import dagger.internal.codegen.langmodel.DaggerTypes; 59 import dagger.multibindings.Multibinds; 60 import dagger.spi.model.DaggerAnnotation; 61 import dagger.spi.model.DaggerType; 62 import dagger.spi.model.Key; 63 import dagger.spi.model.Key.MultibindingContributionIdentifier; 64 import dagger.spi.model.RequestKind; 65 import java.util.Map; 66 import java.util.Optional; 67 import java.util.stream.Stream; 68 import javax.inject.Inject; 69 import javax.lang.model.element.AnnotationMirror; 70 import javax.lang.model.element.ExecutableElement; 71 import javax.lang.model.element.TypeElement; 72 import javax.lang.model.type.DeclaredType; 73 import javax.lang.model.type.ExecutableType; 74 import javax.lang.model.type.PrimitiveType; 75 import javax.lang.model.type.TypeMirror; 76 77 /** A factory for {@link Key}s. */ 78 public final class KeyFactory { 79 private final XProcessingEnv processingEnv; 80 private final DaggerTypes types; 81 private final DaggerElements elements; 82 private final InjectionAnnotations injectionAnnotations; 83 84 @Inject KeyFactory( XProcessingEnv processingEnv, DaggerTypes types, DaggerElements elements, InjectionAnnotations injectionAnnotations)85 KeyFactory( 86 XProcessingEnv processingEnv, 87 DaggerTypes types, 88 DaggerElements elements, 89 InjectionAnnotations injectionAnnotations) { 90 this.processingEnv = processingEnv; 91 this.types = types; 92 this.elements = elements; 93 this.injectionAnnotations = injectionAnnotations; 94 } 95 boxPrimitives(TypeMirror type)96 private TypeMirror boxPrimitives(TypeMirror type) { 97 return type.getKind().isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type; 98 } 99 setOf(TypeMirror elementType)100 private DeclaredType setOf(TypeMirror elementType) { 101 return types.getDeclaredType( 102 elements.getTypeElement(TypeNames.SET), boxPrimitives(elementType)); 103 } 104 mapOf(XType keyType, XType valueType)105 private DeclaredType mapOf(XType keyType, XType valueType) { 106 return mapOf(toJavac(keyType), toJavac(valueType)); 107 } 108 mapOf(TypeMirror keyType, TypeMirror valueType)109 private DeclaredType mapOf(TypeMirror keyType, TypeMirror valueType) { 110 return types.getDeclaredType( 111 elements.getTypeElement(TypeNames.MAP), boxPrimitives(keyType), boxPrimitives(valueType)); 112 } 113 114 /** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */ mapOfFrameworkType( XType keyType, ClassName frameworkClassName, XType valueType)115 private TypeMirror mapOfFrameworkType( 116 XType keyType, ClassName frameworkClassName, XType valueType) { 117 return mapOfFrameworkType(toJavac(keyType), frameworkClassName, toJavac(valueType)); 118 } 119 120 /** Returns {@code Map<KeyType, FrameworkType<ValueType>>}. */ mapOfFrameworkType( TypeMirror keyType, ClassName frameworkClassName, TypeMirror valueType)121 private TypeMirror mapOfFrameworkType( 122 TypeMirror keyType, ClassName frameworkClassName, TypeMirror valueType) { 123 return mapOf( 124 keyType, 125 types.getDeclaredType( 126 elements.getTypeElement(frameworkClassName), boxPrimitives(valueType))); 127 } 128 forComponentMethod(XMethodElement componentMethod)129 Key forComponentMethod(XMethodElement componentMethod) { 130 return forMethod(componentMethod, componentMethod.getReturnType()); 131 } 132 forProductionComponentMethod(XMethodElement componentMethod)133 Key forProductionComponentMethod(XMethodElement componentMethod) { 134 XType returnType = componentMethod.getReturnType(); 135 XType keyType = 136 isFutureType(returnType) ? getOnlyElement(returnType.getTypeArguments()) : returnType; 137 return forMethod(componentMethod, keyType); 138 } 139 forSubcomponentCreatorMethod( XMethodElement subcomponentCreatorMethod, XType declaredContainer)140 Key forSubcomponentCreatorMethod( 141 XMethodElement subcomponentCreatorMethod, XType declaredContainer) { 142 checkArgument(isDeclared(declaredContainer)); 143 XMethodType resolvedMethod = subcomponentCreatorMethod.asMemberOf(declaredContainer); 144 return Key.builder(DaggerType.from(resolvedMethod.getReturnType())).build(); 145 } 146 forSubcomponentCreator(XType creatorType)147 public Key forSubcomponentCreator(XType creatorType) { 148 return Key.builder(DaggerType.from(creatorType)).build(); 149 } 150 forProvidesMethod(XMethodElement method, XTypeElement contributingModule)151 public Key forProvidesMethod(XMethodElement method, XTypeElement contributingModule) { 152 return forProvidesMethod(toJavac(method), toJavac(contributingModule)); 153 } 154 forProvidesMethod(ExecutableElement method, TypeElement contributingModule)155 public Key forProvidesMethod(ExecutableElement method, TypeElement contributingModule) { 156 return forBindingMethod(method, contributingModule, Optional.of(TypeNames.PROVIDER)); 157 } 158 forProducesMethod(XMethodElement method, XTypeElement contributingModule)159 public Key forProducesMethod(XMethodElement method, XTypeElement contributingModule) { 160 return forProducesMethod(toJavac(method), toJavac(contributingModule)); 161 } 162 forProducesMethod(ExecutableElement method, TypeElement contributingModule)163 public Key forProducesMethod(ExecutableElement method, TypeElement contributingModule) { 164 return forBindingMethod(method, contributingModule, Optional.of(TypeNames.PRODUCER)); 165 } 166 167 /** Returns the key bound by a {@link Binds} method. */ forBindsMethod(XMethodElement method, XTypeElement contributingModule)168 Key forBindsMethod(XMethodElement method, XTypeElement contributingModule) { 169 return forBindsMethod(toJavac(method), toJavac(contributingModule)); 170 } 171 172 /** Returns the key bound by a {@link Binds} method. */ forBindsMethod(ExecutableElement method, TypeElement contributingModule)173 Key forBindsMethod(ExecutableElement method, TypeElement contributingModule) { 174 checkArgument(isAnnotationPresent(method, TypeNames.BINDS)); 175 return forBindingMethod(method, contributingModule, Optional.empty()); 176 } 177 178 /** Returns the base key bound by a {@link BindsOptionalOf} method. */ forBindsOptionalOfMethod(XMethodElement method, XTypeElement contributingModule)179 Key forBindsOptionalOfMethod(XMethodElement method, XTypeElement contributingModule) { 180 checkArgument(method.hasAnnotation(TypeNames.BINDS_OPTIONAL_OF)); 181 return forBindingMethod(method, contributingModule, Optional.empty()); 182 } 183 forBindingMethod( XMethodElement method, XTypeElement contributingModule, Optional<ClassName> frameworkClassName)184 private Key forBindingMethod( 185 XMethodElement method, 186 XTypeElement contributingModule, 187 Optional<ClassName> frameworkClassName) { 188 return forBindingMethod(toJavac(method), toJavac(contributingModule), frameworkClassName); 189 } 190 forBindingMethod( ExecutableElement method, TypeElement contributingModule, Optional<ClassName> frameworkClassName)191 private Key forBindingMethod( 192 ExecutableElement method, 193 TypeElement contributingModule, 194 Optional<ClassName> frameworkClassName) { 195 checkArgument(method.getKind().equals(METHOD)); 196 ExecutableType methodType = 197 MoreTypes.asExecutable( 198 types.asMemberOf(MoreTypes.asDeclared(contributingModule.asType()), method)); 199 ContributionType contributionType = ContributionType.fromBindingElement(method); 200 TypeMirror returnType = methodType.getReturnType(); 201 if (frameworkClassName.isPresent() 202 && frameworkClassName.get().equals(TypeNames.PRODUCER) 203 && isType(returnType)) { 204 if (isFutureType(methodType.getReturnType())) { 205 returnType = getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments()); 206 } else if (contributionType.equals(ContributionType.SET_VALUES) 207 && SetType.isSet(returnType)) { 208 SetType setType = SetType.from(toXProcessing(returnType, processingEnv)); 209 if (isFutureType(setType.elementType())) { 210 returnType = 211 types.getDeclaredType( 212 elements.getTypeElement(TypeNames.SET), 213 toJavac(unwrapType(setType.elementType()))); 214 } 215 } 216 } 217 TypeMirror keyType = 218 bindingMethodKeyType(returnType, method, contributionType, frameworkClassName); 219 Key key = forMethod(method, keyType); 220 return contributionType.equals(ContributionType.UNIQUE) 221 ? key 222 : key.toBuilder() 223 .multibindingContributionIdentifier( 224 new MultibindingContributionIdentifier(method, contributingModule)) 225 .build(); 226 } 227 228 /** 229 * Returns the key for a {@link Multibinds @Multibinds} method. 230 * 231 * <p>The key's type is either {@code Set<T>} or {@code Map<K, Provider<V>>}. The latter works 232 * even for maps used by {@code Producer}s. 233 */ forMultibindsMethod(XMethodElement method, XMethodType methodType)234 Key forMultibindsMethod(XMethodElement method, XMethodType methodType) { 235 XType returnType = method.getReturnType(); 236 TypeMirror keyType = 237 MapType.isMap(returnType) 238 ? mapOfFrameworkType( 239 MapType.from(returnType).keyType(), 240 TypeNames.PROVIDER, 241 MapType.from(returnType).valueType()) 242 : toJavac(returnType); 243 return forMethod(toJavac(method), keyType); 244 } 245 bindingMethodKeyType( TypeMirror returnType, ExecutableElement method, ContributionType contributionType, Optional<ClassName> frameworkClassName)246 private TypeMirror bindingMethodKeyType( 247 TypeMirror returnType, 248 ExecutableElement method, 249 ContributionType contributionType, 250 Optional<ClassName> frameworkClassName) { 251 switch (contributionType) { 252 case UNIQUE: 253 return returnType; 254 case SET: 255 return setOf(returnType); 256 case MAP: 257 Optional<AnnotationMirror> mapKey = getMapKey(method); 258 // TODO(bcorso): We've added a special checkState here since a number of people have run 259 // into this particular case, but technically it shouldn't be necessary if we are properly 260 // doing superficial validation and deferring on unresolvable types. We should revisit 261 // whether this is necessary once we're able to properly defer this case. 262 checkState( 263 mapKey.isPresent(), 264 "Missing map key annotation for method: %s#%s. That method was annotated with: %s. If a" 265 + " map key annotation is included in that list, it means Dagger wasn't able to" 266 + " detect that it was a map key because the dependency is missing from the" 267 + " classpath of the current build. To fix, add a dependency for the map key to the" 268 + " current build. For more details, see" 269 + " https://github.com/google/dagger/issues/3133#issuecomment-1002790894.", 270 method.getEnclosingElement(), 271 method, 272 method.getAnnotationMirrors()); 273 TypeMirror mapKeyType = mapKeyType(toXProcessing(mapKey.get(), processingEnv)); 274 return frameworkClassName.isPresent() 275 ? mapOfFrameworkType(mapKeyType, frameworkClassName.get(), returnType) 276 : mapOf(mapKeyType, returnType); 277 case SET_VALUES: 278 // TODO(gak): do we want to allow people to use "covariant return" here? 279 checkArgument(SetType.isSet(returnType)); 280 return returnType; 281 } 282 throw new AssertionError(); 283 } 284 285 /** 286 * Returns the key for a binding associated with a {@link DelegateDeclaration}. 287 * 288 * <p>If {@code delegateDeclaration} is {@code @IntoMap}, transforms the {@code Map<K, V>} key 289 * from {@link DelegateDeclaration#key()} to {@code Map<K, FrameworkType<V>>}. If {@code 290 * delegateDeclaration} is not a map contribution, its key is returned. 291 */ forDelegateBinding(DelegateDeclaration delegateDeclaration, ClassName frameworkType)292 Key forDelegateBinding(DelegateDeclaration delegateDeclaration, ClassName frameworkType) { 293 return delegateDeclaration.contributionType().equals(ContributionType.MAP) 294 ? wrapMapValue(delegateDeclaration.key(), frameworkType) 295 : delegateDeclaration.key(); 296 } 297 forMethod(XMethodElement method, XType keyType)298 private Key forMethod(XMethodElement method, XType keyType) { 299 return forMethod(toJavac(method), toJavac(keyType)); 300 } 301 forMethod(ExecutableElement method, TypeMirror keyType)302 private Key forMethod(ExecutableElement method, TypeMirror keyType) { 303 return forQualifiedType(injectionAnnotations.getQualifier(method), keyType); 304 } 305 forInjectConstructorWithResolvedType(XType type)306 public Key forInjectConstructorWithResolvedType(XType type) { 307 return forInjectConstructorWithResolvedType(toJavac(type)); 308 } 309 forInjectConstructorWithResolvedType(TypeMirror type)310 public Key forInjectConstructorWithResolvedType(TypeMirror type) { 311 return Key.builder(fromJava(type)).build(); 312 } 313 314 // TODO(ronshapiro): Remove these conveniences which are simple wrappers around Key.Builder forType(XType type)315 Key forType(XType type) { 316 return Key.builder(DaggerType.from(type)).build(); 317 } 318 forMembersInjectedType(TypeMirror type)319 public Key forMembersInjectedType(TypeMirror type) { 320 return forMembersInjectedType(toXProcessing(type, processingEnv)); 321 } 322 forMembersInjectedType(XType type)323 public Key forMembersInjectedType(XType type) { 324 return Key.builder(DaggerType.from(type)).build(); 325 } 326 forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type)327 Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) { 328 return forQualifiedType( 329 qualifier.map(annotation -> toXProcessing(annotation, processingEnv)), 330 toXProcessing(type, processingEnv)); 331 } 332 forQualifiedType(Optional<XAnnotation> qualifier, XType type)333 Key forQualifiedType(Optional<XAnnotation> qualifier, XType type) { 334 return Key.builder(DaggerType.from(type.boxed())) 335 .qualifier(qualifier.map(DaggerAnnotation::from)) 336 .build(); 337 } 338 forProductionExecutor()339 public Key forProductionExecutor() { 340 return Key.builder(fromJava(elements.getTypeElement(TypeNames.EXECUTOR).asType())) 341 .qualifier(fromJava(toJavac(productionQualifier(processingEnv)))) 342 .build(); 343 } 344 forProductionImplementationExecutor()345 public Key forProductionImplementationExecutor() { 346 return Key.builder(fromJava(elements.getTypeElement(TypeNames.EXECUTOR).asType())) 347 .qualifier(fromJava(toJavac(productionImplementationQualifier(processingEnv)))) 348 .build(); 349 } 350 forProductionComponentMonitor()351 public Key forProductionComponentMonitor() { 352 return Key.builder( 353 fromJava(elements.getTypeElement(TypeNames.PRODUCTION_COMPONENT_MONITOR).asType())) 354 .build(); 355 } 356 357 /** 358 * If {@code requestKey} is for a {@code Map<K, V>} or {@code Map<K, Produced<V>>}, returns keys 359 * for {@code Map<K, Provider<V>>} and {@code Map<K, Producer<V>>} (if Dagger-Producers is on 360 * the classpath). 361 */ implicitFrameworkMapKeys(Key requestKey)362 ImmutableSet<Key> implicitFrameworkMapKeys(Key requestKey) { 363 return Stream.of(implicitMapProviderKeyFrom(requestKey), implicitMapProducerKeyFrom(requestKey)) 364 .filter(Optional::isPresent) 365 .map(Optional::get) 366 .collect(toImmutableSet()); 367 } 368 369 /** 370 * Optionally extract a {@link Key} for the underlying provision binding(s) if such a valid key 371 * can be inferred from the given key. Specifically, if the key represents a {@link Map}{@code 372 * <K, V>} or {@code Map<K, Producer<V>>}, a key of {@code Map<K, Provider<V>>} will be 373 * returned. 374 */ implicitMapProviderKeyFrom(Key possibleMapKey)375 Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) { 376 return firstPresent( 377 rewrapMapKey(possibleMapKey, TypeNames.PRODUCED, TypeNames.PROVIDER), 378 wrapMapKey(possibleMapKey, TypeNames.PROVIDER)); 379 } 380 381 /** 382 * Optionally extract a {@link Key} for the underlying production binding(s) if such a 383 * valid key can be inferred from the given key. Specifically, if the key represents a 384 * {@link Map}{@code <K, V>} or {@code Map<K, Produced<V>>}, a key of 385 * {@code Map<K, Producer<V>>} will be returned. 386 */ implicitMapProducerKeyFrom(Key possibleMapKey)387 Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) { 388 return firstPresent( 389 rewrapMapKey(possibleMapKey, TypeNames.PRODUCED, TypeNames.PRODUCER), 390 wrapMapKey(possibleMapKey, TypeNames.PRODUCER)); 391 } 392 393 /** 394 * If {@code key}'s type is {@code Map<K, Provider<V>>}, {@code Map<K, Producer<V>>}, or {@code 395 * Map<K, Produced<V>>}, returns a key with the same qualifier and {@link 396 * Key#multibindingContributionIdentifier()} whose type is simply {@code Map<K, V>}. 397 * 398 * <p>Otherwise, returns {@code key}. 399 */ unwrapMapValueType(Key key)400 public Key unwrapMapValueType(Key key) { 401 if (MapType.isMap(key)) { 402 MapType mapType = MapType.from(key); 403 if (!mapType.isRawType()) { 404 for (ClassName frameworkClass : 405 asList(TypeNames.PROVIDER, TypeNames.PRODUCER, TypeNames.PRODUCED)) { 406 if (mapType.valuesAreTypeOf(frameworkClass)) { 407 return key.toBuilder() 408 .type( 409 fromJava(mapOf(mapType.keyType(), mapType.unwrappedValueType(frameworkClass)))) 410 .build(); 411 } 412 } 413 } 414 } 415 return key; 416 } 417 418 /** Converts a {@link Key} of type {@code Map<K, V>} to {@code Map<K, Provider<V>>}. */ wrapMapValue(Key key, ClassName newWrappingClassName)419 private Key wrapMapValue(Key key, ClassName newWrappingClassName) { 420 checkArgument( 421 FrameworkTypes.isFrameworkType(elements.getTypeElement(newWrappingClassName).asType())); 422 return wrapMapKey(key, newWrappingClassName).get(); 423 } 424 425 /** 426 * If {@code key}'s type is {@code Map<K, CurrentWrappingClass<Bar>>}, returns a key with type 427 * {@code Map<K, NewWrappingClass<Bar>>} with the same qualifier. Otherwise returns {@link 428 * Optional#empty()}. 429 * 430 * <p>Returns {@link Optional#empty()} if {@code newWrappingClass} is not in the classpath. 431 * 432 * @throws IllegalArgumentException if {@code newWrappingClass} is the same as {@code 433 * currentWrappingClass} 434 */ rewrapMapKey( Key possibleMapKey, ClassName currentWrappingClassName, ClassName newWrappingClassName)435 public Optional<Key> rewrapMapKey( 436 Key possibleMapKey, ClassName currentWrappingClassName, ClassName newWrappingClassName) { 437 checkArgument(!currentWrappingClassName.equals(newWrappingClassName)); 438 if (MapType.isMap(possibleMapKey)) { 439 MapType mapType = MapType.from(possibleMapKey); 440 if (!mapType.isRawType() && mapType.valuesAreTypeOf(currentWrappingClassName)) { 441 TypeElement wrappingElement = elements.getTypeElement(newWrappingClassName); 442 if (wrappingElement == null) { 443 // This target might not be compiled with Producers, so wrappingClass might not have an 444 // associated element. 445 return Optional.empty(); 446 } 447 DeclaredType wrappedValueType = 448 types.getDeclaredType( 449 wrappingElement, toJavac(mapType.unwrappedValueType(currentWrappingClassName))); 450 return Optional.of( 451 possibleMapKey.toBuilder() 452 .type(fromJava(mapOf(toJavac(mapType.keyType()), wrappedValueType))) 453 .build()); 454 } 455 } 456 return Optional.empty(); 457 } 458 459 /** 460 * If {@code key}'s type is {@code Map<K, Foo>} and {@code Foo} is not {@code WrappingClass 461 * <Bar>}, returns a key with type {@code Map<K, WrappingClass<Foo>>} with the same qualifier. 462 * Otherwise returns {@link Optional#empty()}. 463 * 464 * <p>Returns {@link Optional#empty()} if {@code WrappingClass} is not in the classpath. 465 */ wrapMapKey(Key possibleMapKey, ClassName wrappingClassName)466 private Optional<Key> wrapMapKey(Key possibleMapKey, ClassName wrappingClassName) { 467 if (MapType.isMap(possibleMapKey)) { 468 MapType mapType = MapType.from(possibleMapKey); 469 if (!mapType.isRawType() && !mapType.valuesAreTypeOf(wrappingClassName)) { 470 TypeElement wrappingElement = elements.getTypeElement(wrappingClassName); 471 if (wrappingElement == null) { 472 // This target might not be compiled with Producers, so wrappingClass might not have an 473 // associated element. 474 return Optional.empty(); 475 } 476 DeclaredType wrappedValueType = 477 types.getDeclaredType(wrappingElement, toJavac(mapType.valueType())); 478 return Optional.of( 479 possibleMapKey.toBuilder() 480 .type(fromJava(mapOf(toJavac(mapType.keyType()), wrappedValueType))) 481 .build()); 482 } 483 } 484 return Optional.empty(); 485 } 486 487 /** 488 * If {@code key}'s type is {@code Set<WrappingClass<Bar>>}, returns a key with type {@code Set 489 * <Bar>} with the same qualifier. Otherwise returns {@link Optional#empty()}. 490 */ unwrapSetKey(Key key, ClassName wrappingClassName)491 Optional<Key> unwrapSetKey(Key key, ClassName wrappingClassName) { 492 if (SetType.isSet(key)) { 493 SetType setType = SetType.from(key); 494 if (!setType.isRawType() && setType.elementsAreTypeOf(wrappingClassName)) { 495 return Optional.of( 496 key.toBuilder() 497 .type(fromJava(setOf(toJavac(setType.unwrappedElementType(wrappingClassName))))) 498 .build()); 499 } 500 } 501 return Optional.empty(); 502 } 503 504 /** 505 * If {@code key}'s type is {@code Optional<T>} for some {@code T}, returns a key with the same 506 * qualifier whose type is {@linkplain RequestKinds#extractKeyType(RequestKind, TypeMirror)} 507 * extracted} from {@code T}. 508 */ unwrapOptional(Key key)509 Optional<Key> unwrapOptional(Key key) { 510 if (!OptionalType.isOptional(key)) { 511 return Optional.empty(); 512 } 513 514 XType optionalValueType = OptionalType.from(key).valueType(); 515 return Optional.of( 516 key.toBuilder().type(DaggerType.from(extractKeyType(optionalValueType))).build()); 517 } 518 fromJava(AnnotationMirror annotation)519 private DaggerAnnotation fromJava(AnnotationMirror annotation) { 520 return DaggerAnnotation.from(toXProcessing(annotation, processingEnv)); 521 } 522 fromJava(TypeMirror typeMirror)523 private DaggerType fromJava(TypeMirror typeMirror) { 524 return DaggerType.from(toXProcessing(typeMirror, processingEnv)); 525 } 526 } 527