• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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