Home | History | Annotate | Download | only in codegen
      1 /*
      2  * Copyright (C) 2014 Google, Inc.
      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 package dagger.internal.codegen;
     17 
     18 import com.google.auto.common.AnnotationMirrors;
     19 import com.google.auto.common.MoreElements;
     20 import com.google.auto.common.MoreTypes;
     21 import com.google.auto.value.AutoValue;
     22 import com.google.common.base.Equivalence;
     23 import com.google.common.base.MoreObjects;
     24 import com.google.common.base.Optional;
     25 import com.google.common.collect.Iterables;
     26 import com.google.common.util.concurrent.ListenableFuture;
     27 import dagger.Provides;
     28 import dagger.producers.Produced;
     29 import dagger.producers.Producer;
     30 import dagger.producers.Produces;
     31 import java.util.Map;
     32 import java.util.Set;
     33 import javax.inject.Provider;
     34 import javax.inject.Qualifier;
     35 import javax.lang.model.element.AnnotationMirror;
     36 import javax.lang.model.element.ElementKind;
     37 import javax.lang.model.element.ExecutableElement;
     38 import javax.lang.model.element.Modifier;
     39 import javax.lang.model.element.TypeElement;
     40 import javax.lang.model.type.DeclaredType;
     41 import javax.lang.model.type.ExecutableType;
     42 import javax.lang.model.type.PrimitiveType;
     43 import javax.lang.model.type.TypeKind;
     44 import javax.lang.model.type.TypeMirror;
     45 import javax.lang.model.util.Elements;
     46 import javax.lang.model.util.SimpleTypeVisitor6;
     47 import javax.lang.model.util.Types;
     48 
     49 import static com.google.auto.common.MoreTypes.asExecutable;
     50 import static com.google.common.base.Preconditions.checkArgument;
     51 import static com.google.common.base.Preconditions.checkNotNull;
     52 import static dagger.internal.codegen.InjectionAnnotations.getQualifier;
     53 import static dagger.internal.codegen.MapKeys.getMapKey;
     54 import static dagger.internal.codegen.MapKeys.getUnwrappedMapKeyType;
     55 import static dagger.internal.codegen.Util.unwrapOptionalEquivalence;
     56 import static dagger.internal.codegen.Util.wrapOptionalInEquivalence;
     57 import static javax.lang.model.element.ElementKind.METHOD;
     58 
     59 /**
     60  * Represents a unique combination of {@linkplain TypeMirror type} and
     61  * {@linkplain Qualifier qualifier} to which binding can occur.
     62  *
     63  * @author Gregory Kick
     64  */
     65 @AutoValue
     66 abstract class Key {
     67   /**
     68    * A {@link javax.inject.Qualifier} annotation that provides a unique namespace prefix
     69    * for the type of this key.
     70    *
     71    * Despite documentation in {@link AnnotationMirror}, equals and hashCode aren't implemented
     72    * to represent logical equality, so {@link AnnotationMirrors#equivalence()}
     73    * provides this facility.
     74    */
     75   abstract Optional<Equivalence.Wrapper<AnnotationMirror>> wrappedQualifier();
     76 
     77   /**
     78    * The type represented by this key.
     79    *
     80    * As documented in {@link TypeMirror}, equals and hashCode aren't implemented to represent
     81    * logical equality, so {@link MoreTypes#equivalence()} wraps this type.
     82    */
     83   abstract Equivalence.Wrapper<TypeMirror> wrappedType();
     84 
     85   Optional<AnnotationMirror> qualifier() {
     86     return unwrapOptionalEquivalence(wrappedQualifier());
     87   }
     88 
     89   TypeMirror type() {
     90     return wrappedType().get();
     91   }
     92 
     93   private static TypeMirror normalize(Types types, TypeMirror type) {
     94     TypeKind kind = type.getKind();
     95     return kind.isPrimitive() ? types.boxedClass((PrimitiveType) type).asType() : type;
     96   }
     97 
     98   Key withType(Types types, TypeMirror newType) {
     99     return new AutoValue_Key(wrappedQualifier(),
    100         MoreTypes.equivalence().wrap(normalize(types, newType)));
    101   }
    102 
    103   boolean isValidMembersInjectionKey() {
    104     return !qualifier().isPresent();
    105   }
    106 
    107   /**
    108    * Returns true if the key is valid as an implicit key (that is, if it's valid for a just-in-time
    109    * binding by discovering an {@code @Inject} constructor).
    110    */
    111   boolean isValidImplicitProvisionKey(final Types types) {
    112     // Qualifiers disqualify implicit provisioning.
    113     if (qualifier().isPresent()) {
    114       return false;
    115     }
    116 
    117     return type().accept(new SimpleTypeVisitor6<Boolean, Void>() {
    118       @Override protected Boolean defaultAction(TypeMirror e, Void p) {
    119         return false; // Only declared types are allowed.
    120       }
    121 
    122       @Override public Boolean visitDeclared(DeclaredType type, Void ignored) {
    123         // Non-classes or abstract classes aren't allowed.
    124         TypeElement element = MoreElements.asType(type.asElement());
    125         if (!element.getKind().equals(ElementKind.CLASS)
    126             || element.getModifiers().contains(Modifier.ABSTRACT)) {
    127           return false;
    128         }
    129 
    130         // If the key has type arguments, validate that each type argument is declared.
    131         // Otherwise the type argument may be a wildcard (or other type), and we can't
    132         // resolve that to actual types.
    133         for (TypeMirror arg : type.getTypeArguments()) {
    134           if (arg.getKind() != TypeKind.DECLARED) {
    135             return false;
    136           }
    137         }
    138 
    139         // Also validate that the key is not the erasure of a generic type.
    140         // If it is, that means the user referred to Foo<T> as just 'Foo',
    141         // which we don't allow.  (This is a judgement call -- we *could*
    142         // allow it and instantiate the type bounds... but we don't.)
    143         return MoreTypes.asDeclared(element.asType()).getTypeArguments().isEmpty()
    144             || !types.isSameType(types.erasure(element.asType()), type());
    145       }
    146     }, null);
    147   }
    148 
    149   @Override
    150   public String toString() {
    151     return MoreObjects.toStringHelper(Key.class)
    152         .omitNullValues()
    153         .add("qualifier", qualifier().orNull())
    154         .add("type", type())
    155         .toString();
    156   }
    157 
    158   static final class Factory {
    159     private final Types types;
    160     private final Elements elements;
    161 
    162     Factory(Types types, Elements elements) {
    163       this.types = checkNotNull(types);
    164       this.elements = checkNotNull(elements);
    165     }
    166 
    167     private TypeElement getSetElement() {
    168       return elements.getTypeElement(Set.class.getCanonicalName());
    169     }
    170 
    171     private TypeElement getMapElement() {
    172       return elements.getTypeElement(Map.class.getCanonicalName());
    173     }
    174 
    175     private TypeElement getProviderElement() {
    176       return elements.getTypeElement(Provider.class.getCanonicalName());
    177     }
    178 
    179     private TypeElement getProducerElement() {
    180       return elements.getTypeElement(Producer.class.getCanonicalName());
    181     }
    182 
    183     private TypeElement getClassElement(Class<?> cls) {
    184       return elements.getTypeElement(cls.getCanonicalName());
    185     }
    186 
    187     Key forComponentMethod(ExecutableElement componentMethod) {
    188       checkNotNull(componentMethod);
    189       checkArgument(componentMethod.getKind().equals(METHOD));
    190       TypeMirror returnType = normalize(types, componentMethod.getReturnType());
    191       return forMethod(componentMethod, returnType);
    192     }
    193 
    194     Key forProductionComponentMethod(ExecutableElement componentMethod) {
    195       checkNotNull(componentMethod);
    196       checkArgument(componentMethod.getKind().equals(METHOD));
    197       TypeMirror returnType = normalize(types, componentMethod.getReturnType());
    198       TypeMirror keyType = returnType;
    199       if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
    200         keyType = Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
    201       }
    202       return forMethod(componentMethod, keyType);
    203     }
    204 
    205     Key forSubcomponentBuilderMethod(
    206         ExecutableElement subcomponentBuilderMethod, DeclaredType declaredContainer) {
    207       checkNotNull(subcomponentBuilderMethod);
    208       checkArgument(subcomponentBuilderMethod.getKind().equals(METHOD));
    209       ExecutableType resolvedMethod =
    210           asExecutable(types.asMemberOf(declaredContainer, subcomponentBuilderMethod));
    211       TypeMirror returnType = normalize(types, resolvedMethod.getReturnType());
    212       return forMethod(subcomponentBuilderMethod, returnType);
    213     }
    214 
    215     Key forProvidesMethod(ExecutableType executableType, ExecutableElement method) {
    216       checkNotNull(method);
    217       checkArgument(method.getKind().equals(METHOD));
    218       Provides providesAnnotation = method.getAnnotation(Provides.class);
    219       checkArgument(providesAnnotation != null);
    220       TypeMirror returnType = normalize(types, executableType.getReturnType());
    221       TypeMirror keyType =
    222           providesOrProducesKeyType(
    223               returnType,
    224               method,
    225               Optional.of(providesAnnotation.type()),
    226               Optional.<Produces.Type>absent());
    227       return forMethod(method, keyType);
    228     }
    229 
    230     // TODO(user): Reconcile this method with forProvidesMethod when Provides.Type and
    231     // Produces.Type are no longer different.
    232     Key forProducesMethod(ExecutableType executableType, ExecutableElement method) {
    233       checkNotNull(method);
    234       checkArgument(method.getKind().equals(METHOD));
    235       Produces producesAnnotation = method.getAnnotation(Produces.class);
    236       checkArgument(producesAnnotation != null);
    237       TypeMirror returnType = normalize(types, executableType.getReturnType());
    238       TypeMirror unfuturedType = returnType;
    239       if (MoreTypes.isTypeOf(ListenableFuture.class, returnType)) {
    240         unfuturedType =
    241             Iterables.getOnlyElement(MoreTypes.asDeclared(returnType).getTypeArguments());
    242       }
    243       TypeMirror keyType =
    244           providesOrProducesKeyType(
    245               unfuturedType,
    246               method,
    247               Optional.<Provides.Type>absent(),
    248               Optional.of(producesAnnotation.type()));
    249       return forMethod(method, keyType);
    250     }
    251 
    252     private TypeMirror providesOrProducesKeyType(
    253         TypeMirror returnType,
    254         ExecutableElement method,
    255         Optional<Provides.Type> providesType,
    256         Optional<Produces.Type> producesType) {
    257       switch (providesType.isPresent()
    258           ? providesType.get()
    259           : Provides.Type.valueOf(producesType.get().name())) {
    260         case UNIQUE:
    261           return returnType;
    262         case SET:
    263           return types.getDeclaredType(getSetElement(), returnType);
    264         case MAP:
    265           return mapOfFactoryType(
    266               method,
    267               returnType,
    268               providesType.isPresent() ? getProviderElement() : getProducerElement());
    269         case SET_VALUES:
    270           // TODO(gak): do we want to allow people to use "covariant return" here?
    271           checkArgument(MoreTypes.isType(returnType) && MoreTypes.isTypeOf(Set.class, returnType));
    272           return returnType;
    273         default:
    274           throw new AssertionError();
    275       }
    276     }
    277 
    278     private TypeMirror mapOfFactoryType(
    279         ExecutableElement method, TypeMirror valueType, TypeElement factoryType) {
    280       TypeMirror mapKeyType = mapKeyType(method);
    281       TypeMirror mapValueFactoryType = types.getDeclaredType(factoryType, valueType);
    282       return types.getDeclaredType(getMapElement(), mapKeyType, mapValueFactoryType);
    283     }
    284 
    285     private TypeMirror mapKeyType(ExecutableElement method) {
    286       AnnotationMirror mapKeyAnnotation = getMapKey(method).get();
    287       return MapKeys.unwrapValue(mapKeyAnnotation).isPresent()
    288           ? getUnwrappedMapKeyType(mapKeyAnnotation.getAnnotationType(), types)
    289           : mapKeyAnnotation.getAnnotationType();
    290     }
    291 
    292     private Key forMethod(ExecutableElement method, TypeMirror keyType) {
    293       return new AutoValue_Key(
    294           wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), getQualifier(method)),
    295           MoreTypes.equivalence().wrap(keyType));
    296     }
    297 
    298     Key forInjectConstructorWithResolvedType(TypeMirror type) {
    299       return new AutoValue_Key(
    300           Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
    301           MoreTypes.equivalence().wrap(type));
    302     }
    303 
    304     Key forComponent(TypeMirror type) {
    305       return new AutoValue_Key(
    306           Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
    307           MoreTypes.equivalence().wrap(normalize(types, type)));
    308     }
    309 
    310     Key forMembersInjectedType(TypeMirror type) {
    311       return new AutoValue_Key(
    312           Optional.<Equivalence.Wrapper<AnnotationMirror>>absent(),
    313           MoreTypes.equivalence().wrap(normalize(types, type)));
    314     }
    315 
    316     Key forQualifiedType(Optional<AnnotationMirror> qualifier, TypeMirror type) {
    317       return new AutoValue_Key(
    318           wrapOptionalInEquivalence(AnnotationMirrors.equivalence(), qualifier),
    319           MoreTypes.equivalence().wrap(normalize(types, type)));
    320     }
    321 
    322     /**
    323      * Optionally extract a {@link Key} for the underlying provision binding(s) if such a
    324      * valid key can be inferred from the given key.  Specifically, if the key represents a
    325      * {@link Map}{@code <K, V>}, a key of {@code Map<K, Provider<V>>} will be returned.
    326      */
    327     Optional<Key> implicitMapProviderKeyFrom(Key possibleMapKey) {
    328       return maybeWrapMapValue(possibleMapKey, Provider.class);
    329     }
    330 
    331     /**
    332      * Optionally extract a {@link Key} for the underlying production binding(s) if such a
    333      * valid key can be inferred from the given key.  Specifically, if the key represents a
    334      * {@link Map}{@code <K, V>}, a key of {@code Map<K, Producer<V>>} will be returned.
    335      */
    336     Optional<Key> implicitMapProducerKeyFrom(Key possibleMapKey) {
    337       return maybeWrapMapValue(possibleMapKey, Producer.class);
    338     }
    339 
    340     /**
    341      * Returns a key of {@link Map}{@code <K, WrappingClass<V>>} if the input key represents a
    342      * {@code Map<K, V>}.
    343      */
    344     private Optional<Key> maybeWrapMapValue(Key possibleMapKey, Class<?> wrappingClass) {
    345       if (MoreTypes.isTypeOf(Map.class, possibleMapKey.type())) {
    346         DeclaredType declaredMapType = MoreTypes.asDeclared(possibleMapKey.type());
    347         TypeMirror mapValueType = Util.getValueTypeOfMap(declaredMapType);
    348         if (!MoreTypes.isTypeOf(wrappingClass, mapValueType)) {
    349           TypeMirror keyType = Util.getKeyTypeOfMap(declaredMapType);
    350           TypeElement wrappingElement = getClassElement(wrappingClass);
    351           if (wrappingElement == null) {
    352             // This target might not be compiled with Producers, so wrappingClass might not have an
    353             // associated element.
    354             return Optional.absent();
    355           }
    356           DeclaredType wrappedType = types.getDeclaredType(wrappingElement, mapValueType);
    357           TypeMirror mapType = types.getDeclaredType(getMapElement(), keyType, wrappedType);
    358           return Optional.<Key>of(new AutoValue_Key(
    359               possibleMapKey.wrappedQualifier(),
    360               MoreTypes.equivalence().wrap(mapType)));
    361         }
    362       }
    363       return Optional.absent();
    364     }
    365 
    366     /**
    367      * Optionally extract a {@link Key} for a {@code Set<T>} if the given key is for
    368      * {@code Set<Produced<T>>}.
    369      */
    370     Optional<Key> implicitSetKeyFromProduced(Key possibleSetOfProducedKey) {
    371       if (MoreTypes.isTypeOf(Set.class, possibleSetOfProducedKey.type())) {
    372         TypeMirror argType =
    373             MoreTypes.asDeclared(possibleSetOfProducedKey.type()).getTypeArguments().get(0);
    374         if (MoreTypes.isTypeOf(Produced.class, argType)) {
    375           TypeMirror producedArgType = MoreTypes.asDeclared(argType).getTypeArguments().get(0);
    376           TypeMirror setType = types.getDeclaredType(getSetElement(), producedArgType);
    377           return Optional.of(possibleSetOfProducedKey.withType(types, setType));
    378         }
    379       }
    380       return Optional.absent();
    381     }
    382   }
    383 }
    384