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.MoreElements;
     19 import com.google.auto.common.MoreTypes;
     20 import com.google.auto.value.AutoValue;
     21 import com.google.common.base.Function;
     22 import com.google.common.base.Optional;
     23 import com.google.common.collect.FluentIterable;
     24 import com.google.common.collect.ImmutableSet;
     25 import com.google.common.collect.Iterables;
     26 import com.google.common.util.concurrent.ListenableFuture;
     27 import dagger.Lazy;
     28 import dagger.MembersInjector;
     29 import dagger.Provides;
     30 import dagger.producers.Produced;
     31 import dagger.producers.Producer;
     32 import dagger.producers.internal.AbstractProducer;
     33 import java.util.List;
     34 import javax.inject.Inject;
     35 import javax.inject.Provider;
     36 import javax.lang.model.element.AnnotationMirror;
     37 import javax.lang.model.element.Element;
     38 import javax.lang.model.element.ExecutableElement;
     39 import javax.lang.model.element.TypeElement;
     40 import javax.lang.model.element.VariableElement;
     41 import javax.lang.model.type.DeclaredType;
     42 import javax.lang.model.type.ExecutableType;
     43 import javax.lang.model.type.TypeKind;
     44 import javax.lang.model.type.TypeMirror;
     45 import javax.lang.model.util.Elements;
     46 
     47 import static com.google.auto.common.MoreTypes.isTypeOf;
     48 import static com.google.common.base.Preconditions.checkArgument;
     49 import static com.google.common.base.Preconditions.checkNotNull;
     50 import static com.google.common.base.Preconditions.checkState;
     51 import static javax.lang.model.type.TypeKind.DECLARED;
     52 import static javax.lang.model.util.ElementFilter.constructorsIn;
     53 
     54 /**
     55  * Represents a request for a key at an injection point. Parameters to {@link Inject} constructors
     56  * or {@link Provides} methods are examples of key requests.
     57  *
     58  * @author Gregory Kick
     59  * @since 2.0
     60  */
     61 // TODO(gak): Set bindings and the permutations thereof need to be addressed
     62 @AutoValue
     63 abstract class DependencyRequest {
     64   static final Function<DependencyRequest, BindingKey> BINDING_KEY_FUNCTION =
     65       new Function<DependencyRequest, BindingKey>() {
     66         @Override public BindingKey apply(DependencyRequest request) {
     67           return request.bindingKey();
     68         }
     69       };
     70 
     71   enum Kind {
     72     /** A default request for an instance.  E.g.: {@code Blah} */
     73     INSTANCE,
     74     /** A request for a {@link Provider}.  E.g.: {@code Provider<Blah>} */
     75     PROVIDER,
     76     /** A request for a {@link Lazy}.  E.g.: {@code Lazy<Blah>} */
     77     LAZY,
     78     /** A request for a {@link MembersInjector}.  E.g.: {@code MembersInjector<Blah>} */
     79     MEMBERS_INJECTOR,
     80     /** A request for a {@link Producer}.  E.g.: {@code Producer<Blah>} */
     81     PRODUCER,
     82     /** A request for a {@link Produced}.  E.g.: {@code Produced<Blah>} */
     83     PRODUCED,
     84     /**
     85      * A request for a {@link ListenableFuture}.  E.g.: {@code ListenableFuture<Blah>}.
     86      * These can only be requested by component interfaces.
     87      */
     88     FUTURE,
     89   }
     90 
     91   abstract Kind kind();
     92   abstract Key key();
     93 
     94   BindingKey bindingKey() {
     95     switch (kind()) {
     96       case INSTANCE:
     97       case LAZY:
     98       case PROVIDER:
     99       case PRODUCER:
    100       case PRODUCED:
    101       case FUTURE:
    102         return BindingKey.create(BindingKey.Kind.CONTRIBUTION, key());
    103       case MEMBERS_INJECTOR:
    104         return BindingKey.create(BindingKey.Kind.MEMBERS_INJECTION, key());
    105       default:
    106         throw new AssertionError();
    107     }
    108   }
    109 
    110   abstract Element requestElement();
    111 
    112   /**
    113    * Returns the possibly resolved type that contained the requesting element. For members injection
    114    * requests, this is the type itself.
    115    */
    116   abstract DeclaredType enclosingType();
    117 
    118   /** Returns true if this request allows null objects. */
    119   abstract boolean isNullable();
    120 
    121   /**
    122    * An optional name for this request when it's referred to in generated code. If absent, it will
    123    * use a name derived from {@link #requestElement}.
    124    */
    125   abstract Optional<String> overriddenVariableName();
    126 
    127   /**
    128    * Factory for {@link DependencyRequest}s.
    129    *
    130    * <p>Any factory method may throw {@link TypeNotPresentException} if a type is not available,
    131    * which may mean that the type will be generated in a later round of processing.
    132    */
    133   static final class Factory {
    134     private final Elements elements;
    135     private final Key.Factory keyFactory;
    136 
    137     Factory(Elements elements, Key.Factory keyFactory) {
    138       this.elements = elements;
    139       this.keyFactory = keyFactory;
    140     }
    141 
    142     ImmutableSet<DependencyRequest> forRequiredResolvedVariables(DeclaredType container,
    143         List<? extends VariableElement> variables, List<? extends TypeMirror> resolvedTypes) {
    144       checkState(resolvedTypes.size() == variables.size());
    145       ImmutableSet.Builder<DependencyRequest> builder = ImmutableSet.builder();
    146       for (int i = 0; i < variables.size(); i++) {
    147         builder.add(forRequiredResolvedVariable(container, variables.get(i), resolvedTypes.get(i)));
    148       }
    149       return builder.build();
    150     }
    151 
    152     ImmutableSet<DependencyRequest> forRequiredVariables(
    153         List<? extends VariableElement> variables) {
    154       return FluentIterable.from(variables)
    155           .transform(
    156               new Function<VariableElement, DependencyRequest>() {
    157                 @Override
    158                 public DependencyRequest apply(VariableElement input) {
    159                   return forRequiredVariable(input);
    160                 }
    161               })
    162           .toSet();
    163     }
    164 
    165     /**
    166      * Creates a implicit {@link DependencyRequest} for {@code mapOfFactoryKey}, which will be used
    167      * to satisfy the {@code mapOfValueRequest}.
    168      *
    169      * @param mapOfValueRequest a request for {@code Map<K, V>}
    170      * @param mapOfFactoryKey a key equivalent to {@code mapOfValueRequest}'s key, whose type is
    171      *     {@code Map<K, Provider<V>>} or {@code Map<K, Producer<V>>}
    172      */
    173     DependencyRequest forImplicitMapBinding(
    174         DependencyRequest mapOfValueRequest, Key mapOfFactoryKey) {
    175       checkNotNull(mapOfValueRequest);
    176       return new AutoValue_DependencyRequest(
    177           Kind.PROVIDER,
    178           mapOfFactoryKey,
    179           mapOfValueRequest.requestElement(),
    180           mapOfValueRequest.enclosingType(),
    181           false /* doesn't allow null */,
    182           Optional.<String>absent());
    183     }
    184 
    185     DependencyRequest forRequiredVariable(VariableElement variableElement) {
    186       return forRequiredVariable(variableElement, Optional.<String>absent());
    187     }
    188 
    189     DependencyRequest forRequiredVariable(VariableElement variableElement, Optional<String> name) {
    190       checkNotNull(variableElement);
    191       TypeMirror type = variableElement.asType();
    192       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
    193       return newDependencyRequest(
    194           variableElement, type, qualifier, getEnclosingType(variableElement), name);
    195     }
    196 
    197     DependencyRequest forRequiredResolvedVariable(DeclaredType container,
    198         VariableElement variableElement,
    199         TypeMirror resolvedType) {
    200       checkNotNull(variableElement);
    201       checkNotNull(resolvedType);
    202       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(variableElement);
    203       return newDependencyRequest(
    204           variableElement, resolvedType, qualifier, container, Optional.<String>absent());
    205     }
    206 
    207     DependencyRequest forComponentProvisionMethod(ExecutableElement provisionMethod,
    208         ExecutableType provisionMethodType) {
    209       checkNotNull(provisionMethod);
    210       checkNotNull(provisionMethodType);
    211       checkArgument(
    212           provisionMethod.getParameters().isEmpty(),
    213           "Component provision methods must be empty: %s",
    214           provisionMethod);
    215       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(provisionMethod);
    216       return newDependencyRequest(
    217           provisionMethod,
    218           provisionMethodType.getReturnType(),
    219           qualifier,
    220           getEnclosingType(provisionMethod),
    221           Optional.<String>absent());
    222     }
    223 
    224     DependencyRequest forComponentProductionMethod(ExecutableElement productionMethod,
    225         ExecutableType productionMethodType) {
    226       checkNotNull(productionMethod);
    227       checkNotNull(productionMethodType);
    228       checkArgument(productionMethod.getParameters().isEmpty(),
    229           "Component production methods must be empty: %s", productionMethod);
    230       TypeMirror type = productionMethodType.getReturnType();
    231       Optional<AnnotationMirror> qualifier = InjectionAnnotations.getQualifier(productionMethod);
    232       DeclaredType container = getEnclosingType(productionMethod);
    233       // Only a component production method can be a request for a ListenableFuture, so we
    234       // special-case it here.
    235       if (isTypeOf(ListenableFuture.class, type)) {
    236         return new AutoValue_DependencyRequest(
    237             Kind.FUTURE,
    238             keyFactory.forQualifiedType(
    239                 qualifier, Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments())),
    240             productionMethod,
    241             container,
    242             false /* doesn't allow null */,
    243             Optional.<String>absent());
    244       } else {
    245         return newDependencyRequest(
    246             productionMethod, type, qualifier, container, Optional.<String>absent());
    247       }
    248     }
    249 
    250     DependencyRequest forComponentMembersInjectionMethod(ExecutableElement membersInjectionMethod,
    251         ExecutableType membersInjectionMethodType) {
    252       checkNotNull(membersInjectionMethod);
    253       checkNotNull(membersInjectionMethodType);
    254       Optional<AnnotationMirror> qualifier =
    255           InjectionAnnotations.getQualifier(membersInjectionMethod);
    256       checkArgument(!qualifier.isPresent());
    257       TypeMirror returnType = membersInjectionMethodType.getReturnType();
    258       if (returnType.getKind().equals(DECLARED)
    259           && MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
    260         return new AutoValue_DependencyRequest(
    261             Kind.MEMBERS_INJECTOR,
    262             keyFactory.forMembersInjectedType(
    263                 Iterables.getOnlyElement(((DeclaredType) returnType).getTypeArguments())),
    264             membersInjectionMethod,
    265             getEnclosingType(membersInjectionMethod),
    266             false /* doesn't allow null */,
    267             Optional.<String>absent());
    268       } else {
    269         return new AutoValue_DependencyRequest(
    270             Kind.MEMBERS_INJECTOR,
    271             keyFactory.forMembersInjectedType(
    272                 Iterables.getOnlyElement(membersInjectionMethodType.getParameterTypes())),
    273             membersInjectionMethod,
    274             getEnclosingType(membersInjectionMethod),
    275             false /* doesn't allow null */,
    276             Optional.<String>absent());
    277       }
    278     }
    279 
    280     DependencyRequest forMembersInjectedType(DeclaredType type) {
    281       return new AutoValue_DependencyRequest(
    282           Kind.MEMBERS_INJECTOR,
    283           keyFactory.forMembersInjectedType(type),
    284           type.asElement(),
    285           type,
    286           false /* doesn't allow null */,
    287           Optional.<String>absent());
    288     }
    289 
    290     DependencyRequest forProductionComponentMonitorProvider() {
    291       TypeElement element = elements.getTypeElement(AbstractProducer.class.getCanonicalName());
    292       for (ExecutableElement constructor : constructorsIn(element.getEnclosedElements())) {
    293         if (constructor.getParameters().size() == 2) {
    294           // the 2-arg constructor has the appropriate dependency as its first arg
    295           return forRequiredVariable(constructor.getParameters().get(0), Optional.of("monitor"));
    296         }
    297       }
    298       throw new AssertionError("expected 2-arg constructor in AbstractProducer");
    299     }
    300 
    301     private DependencyRequest newDependencyRequest(
    302         Element requestElement,
    303         TypeMirror type,
    304         Optional<AnnotationMirror> qualifier,
    305         DeclaredType container,
    306         Optional<String> name) {
    307       KindAndType kindAndType = extractKindAndType(type);
    308       if (kindAndType.kind().equals(Kind.MEMBERS_INJECTOR)) {
    309         checkArgument(!qualifier.isPresent());
    310       }
    311       // Only instance types can be non-null -- all other requests are wrapped
    312       // inside something (e.g, Provider, Lazy, etc..).
    313       // TODO(sameb): should Produced/Producer always require non-nullable?
    314       boolean allowsNull = !kindAndType.kind().equals(Kind.INSTANCE)
    315           || ConfigurationAnnotations.getNullableType(requestElement).isPresent();
    316       return new AutoValue_DependencyRequest(
    317           kindAndType.kind(),
    318           keyFactory.forQualifiedType(qualifier, kindAndType.type()),
    319           requestElement,
    320           container,
    321           allowsNull,
    322           name);
    323     }
    324 
    325     @AutoValue
    326     static abstract class KindAndType {
    327       abstract Kind kind();
    328       abstract TypeMirror type();
    329     }
    330 
    331     /**
    332      * Extracts the correct requesting type & kind out a request type. For example, if a user
    333      * requests {@code Provider<Foo>}, this will return ({@link Kind#PROVIDER}, {@code Foo}).
    334      *
    335      * @throws TypeNotPresentException if {@code type}'s kind is {@link TypeKind#ERROR}, which may
    336      *     mean that the type will be generated in a later round of processing
    337      */
    338     static KindAndType extractKindAndType(TypeMirror type) {
    339       if (type.getKind().equals(TypeKind.ERROR)) {
    340         throw new TypeNotPresentException(type.toString(), null);
    341       }
    342 
    343       // We must check TYPEVAR explicitly before the below checks because calling
    344       // isTypeOf(..) on a TYPEVAR throws an exception (because it can't be
    345       // represented as a Class).
    346       if (type.getKind().equals(TypeKind.TYPEVAR)) {
    347         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
    348       } else if (isTypeOf(Provider.class, type)) {
    349         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PROVIDER,
    350             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
    351       } else if (isTypeOf(Lazy.class, type)) {
    352         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.LAZY,
    353             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
    354       } else if (isTypeOf(MembersInjector.class, type)) {
    355         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.MEMBERS_INJECTOR,
    356             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
    357       } else if (isTypeOf(Producer.class, type)) {
    358         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCER,
    359             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
    360       } else if (isTypeOf(Produced.class, type)) {
    361         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.PRODUCED,
    362             Iterables.getOnlyElement(((DeclaredType) type).getTypeArguments()));
    363       } else {
    364         return new AutoValue_DependencyRequest_Factory_KindAndType(Kind.INSTANCE, type);
    365       }
    366     }
    367 
    368     static DeclaredType getEnclosingType(Element element) {
    369       while (!MoreElements.isType(element)) {
    370         element = element.getEnclosingElement();
    371       }
    372       return MoreTypes.asDeclared(element.asType());
    373     }
    374   }
    375 }
    376