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.Optional;
     22 import com.google.common.base.Predicate;
     23 import com.google.common.collect.FluentIterable;
     24 import com.google.common.collect.ImmutableList;
     25 import com.google.common.collect.ImmutableMap;
     26 import com.google.common.collect.ImmutableSet;
     27 import com.google.common.util.concurrent.ListenableFuture;
     28 import dagger.Component;
     29 import dagger.Lazy;
     30 import dagger.MembersInjector;
     31 import dagger.Module;
     32 import dagger.Subcomponent;
     33 import dagger.producers.ProductionComponent;
     34 import java.lang.annotation.Annotation;
     35 import java.util.EnumSet;
     36 import java.util.LinkedHashSet;
     37 import java.util.List;
     38 import java.util.Map;
     39 import java.util.Set;
     40 import java.util.concurrent.Executor;
     41 import javax.inject.Provider;
     42 import javax.lang.model.element.AnnotationMirror;
     43 import javax.lang.model.element.ExecutableElement;
     44 import javax.lang.model.element.TypeElement;
     45 import javax.lang.model.type.DeclaredType;
     46 import javax.lang.model.type.ExecutableType;
     47 import javax.lang.model.type.TypeMirror;
     48 import javax.lang.model.util.ElementFilter;
     49 import javax.lang.model.util.Elements;
     50 import javax.lang.model.util.Types;
     51 
     52 import static com.google.auto.common.MoreElements.getAnnotationMirror;
     53 import static com.google.auto.common.MoreElements.isAnnotationPresent;
     54 import static com.google.common.base.Preconditions.checkArgument;
     55 import static com.google.common.base.Verify.verify;
     56 import static com.google.common.collect.Iterables.getOnlyElement;
     57 import static dagger.internal.codegen.ConfigurationAnnotations.enclosedBuilders;
     58 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentDependencies;
     59 import static dagger.internal.codegen.ConfigurationAnnotations.getComponentModules;
     60 import static dagger.internal.codegen.ConfigurationAnnotations.isComponent;
     61 import static javax.lang.model.type.TypeKind.DECLARED;
     62 import static javax.lang.model.type.TypeKind.VOID;
     63 
     64 /**
     65  * The logical representation of a {@link Component} or {@link ProductionComponent} definition.
     66  *
     67  * @author Gregory Kick
     68  * @since 2.0
     69  */
     70 @AutoValue
     71 abstract class ComponentDescriptor {
     72   ComponentDescriptor() {}
     73 
     74   enum Kind {
     75     COMPONENT(Component.class, Component.Builder.class, true),
     76     SUBCOMPONENT(Subcomponent.class, Subcomponent.Builder.class, false),
     77     PRODUCTION_COMPONENT(ProductionComponent.class, ProductionComponent.Builder.class, true);
     78 
     79     private final Class<? extends Annotation> annotationType;
     80     private final Class<? extends Annotation> builderType;
     81     private final boolean isTopLevel;
     82 
     83     /**
     84      * Returns the kind of an annotated element if it is annotated with one of the
     85      * {@linkplain #annotationType() annotation types}.
     86      *
     87      * @throws IllegalArgumentException if the element is annotated with more than one of the
     88      *     annotation types
     89      */
     90     static Optional<Kind> forAnnotatedElement(TypeElement element) {
     91       Set<Kind> kinds = EnumSet.noneOf(Kind.class);
     92       for (Kind kind : values()) {
     93         if (MoreElements.isAnnotationPresent(element, kind.annotationType())) {
     94           kinds.add(kind);
     95         }
     96       }
     97       checkArgument(
     98           kinds.size() <= 1, "%s cannot be annotated with more than one of %s", element, kinds);
     99       return Optional.fromNullable(getOnlyElement(kinds, null));
    100     }
    101 
    102     Kind(
    103         Class<? extends Annotation> annotationType,
    104         Class<? extends Annotation> builderType,
    105         boolean isTopLevel) {
    106       this.annotationType = annotationType;
    107       this.builderType = builderType;
    108       this.isTopLevel = isTopLevel;
    109     }
    110 
    111     Class<? extends Annotation> annotationType() {
    112       return annotationType;
    113     }
    114 
    115     Class<? extends Annotation> builderAnnotationType() {
    116       return builderType;
    117     }
    118 
    119     boolean isTopLevel() {
    120       return isTopLevel;
    121     }
    122   }
    123 
    124   abstract Kind kind();
    125 
    126   abstract AnnotationMirror componentAnnotation();
    127 
    128   /**
    129    * The type (interface or abstract class) that defines the component. This is the element to which
    130    * the {@link Component} annotation was applied.
    131    */
    132   abstract TypeElement componentDefinitionType();
    133 
    134   /**
    135    * The set of component dependencies listed in {@link Component#dependencies}.
    136    */
    137   abstract ImmutableSet<TypeElement> dependencies();
    138 
    139   /**
    140    * The set of {@link ModuleDescriptor modules} declared directly in {@link Component#modules}.
    141    * Use {@link #transitiveModules} to get the full set of modules available upon traversing
    142    * {@link Module#includes}.
    143    */
    144   abstract ImmutableSet<ModuleDescriptor> modules();
    145 
    146   /**
    147    * Returns the set of {@link ModuleDescriptor modules} declared in {@link Component#modules} and
    148    * those reachable by traversing {@link Module#includes}.
    149    *
    150    * <p>Note that for subcomponents this <em>will not</em> include descriptors for any modules that
    151    * are declared in parent components.
    152    */
    153   ImmutableSet<ModuleDescriptor> transitiveModules() {
    154     Set<ModuleDescriptor> transitiveModules = new LinkedHashSet<>();
    155     for (ModuleDescriptor module : modules()) {
    156       addTransitiveModules(transitiveModules, module);
    157     }
    158     return ImmutableSet.copyOf(transitiveModules);
    159   }
    160 
    161   ImmutableSet<TypeElement> transitiveModuleTypes() {
    162     return FluentIterable.from(transitiveModules())
    163         .transform(ModuleDescriptor.getModuleElement())
    164         .toSet();
    165   }
    166 
    167   private static Set<ModuleDescriptor> addTransitiveModules(
    168       Set<ModuleDescriptor> transitiveModules, ModuleDescriptor module) {
    169     if (transitiveModules.add(module)) {
    170       for (ModuleDescriptor includedModule : module.includedModules()) {
    171         addTransitiveModules(transitiveModules, includedModule);
    172       }
    173     }
    174     return transitiveModules;
    175   }
    176 
    177   /**
    178    * An index of the type to which this component holds a reference (the type listed in
    179    * {@link Component#dependencies} or {@link ProductionComponent#dependencies} as opposed to the
    180    * enclosing type) for each method from a component dependency that can be used for binding.
    181    */
    182   abstract ImmutableMap<ExecutableElement, TypeElement> dependencyMethodIndex();
    183 
    184   /**
    185    * The element representing {@link Executor}, if it should be a dependency of this component.
    186    */
    187   abstract Optional<TypeElement> executorDependency();
    188 
    189   /**
    190    * The scope of the component.
    191    */
    192   abstract Scope scope();
    193 
    194   abstract ImmutableMap<ComponentMethodDescriptor, ComponentDescriptor> subcomponents();
    195 
    196   abstract ImmutableSet<ComponentMethodDescriptor> componentMethods();
    197 
    198   // TODO(gak): Consider making this non-optional and revising the
    199   // interaction between the spec & generation
    200   abstract Optional<BuilderSpec> builderSpec();
    201 
    202   @AutoValue
    203   static abstract class ComponentMethodDescriptor {
    204     abstract ComponentMethodKind kind();
    205     abstract Optional<DependencyRequest> dependencyRequest();
    206     abstract ExecutableElement methodElement();
    207 
    208     /**
    209      * A predicate that passes for {@link ComponentMethodDescriptor}s of a given kind.
    210      */
    211     static Predicate<ComponentMethodDescriptor> isOfKind(final ComponentMethodKind kind) {
    212       return new Predicate<ComponentMethodDescriptor>() {
    213         @Override
    214         public boolean apply(ComponentMethodDescriptor descriptor) {
    215           return kind.equals(descriptor.kind());
    216         }
    217       };
    218     }
    219   }
    220 
    221   enum ComponentMethodKind {
    222     PROVISON,
    223     PRODUCTION,
    224     MEMBERS_INJECTION,
    225     SUBCOMPONENT,
    226     SUBCOMPONENT_BUILDER,
    227   }
    228 
    229   @AutoValue
    230   static abstract class BuilderSpec {
    231     abstract TypeElement builderDefinitionType();
    232     abstract Map<TypeElement, ExecutableElement> methodMap();
    233     abstract ExecutableElement buildMethod();
    234     abstract TypeMirror componentType();
    235   }
    236 
    237   static final class Factory {
    238     private final Elements elements;
    239     private final Types types;
    240     private final DependencyRequest.Factory dependencyRequestFactory;
    241     private final ModuleDescriptor.Factory moduleDescriptorFactory;
    242 
    243     Factory(
    244         Elements elements,
    245         Types types,
    246         DependencyRequest.Factory dependencyRequestFactory,
    247         ModuleDescriptor.Factory moduleDescriptorFactory) {
    248       this.elements = elements;
    249       this.types = types;
    250       this.dependencyRequestFactory = dependencyRequestFactory;
    251       this.moduleDescriptorFactory = moduleDescriptorFactory;
    252     }
    253 
    254     /**
    255      * Returns a component descriptor for a type annotated with either {@link Component @Component}
    256      * or {@link ProductionComponent @ProductionComponent}.
    257      */
    258     ComponentDescriptor forComponent(TypeElement componentDefinitionType) {
    259       Optional<Kind> kind = Kind.forAnnotatedElement(componentDefinitionType);
    260       checkArgument(
    261           kind.isPresent() && kind.get().isTopLevel(),
    262           "%s must be annotated with @Component or @ProductionComponent",
    263           componentDefinitionType);
    264       return create(componentDefinitionType, kind.get());
    265     }
    266 
    267     private ComponentDescriptor create(TypeElement componentDefinitionType, Kind kind) {
    268       DeclaredType declaredComponentType = MoreTypes.asDeclared(componentDefinitionType.asType());
    269       AnnotationMirror componentMirror =
    270           getAnnotationMirror(componentDefinitionType, kind.annotationType())
    271               .or(getAnnotationMirror(componentDefinitionType, Subcomponent.class))
    272               .get();
    273       ImmutableSet<TypeElement> componentDependencyTypes =
    274           isComponent(componentDefinitionType)
    275               ? MoreTypes.asTypeElements(getComponentDependencies(componentMirror))
    276               : ImmutableSet.<TypeElement>of();
    277 
    278       ImmutableMap.Builder<ExecutableElement, TypeElement> dependencyMethodIndex =
    279           ImmutableMap.builder();
    280 
    281       for (TypeElement componentDependency : componentDependencyTypes) {
    282         List<ExecutableElement> dependencyMethods =
    283             ElementFilter.methodsIn(elements.getAllMembers(componentDependency));
    284         for (ExecutableElement dependencyMethod : dependencyMethods) {
    285           if (isComponentContributionMethod(elements, dependencyMethod)) {
    286             dependencyMethodIndex.put(dependencyMethod, componentDependency);
    287           }
    288         }
    289       }
    290 
    291       Optional<TypeElement> executorDependency =
    292           kind.equals(Kind.PRODUCTION_COMPONENT)
    293               ? Optional.of(elements.getTypeElement(Executor.class.getCanonicalName()))
    294               : Optional.<TypeElement>absent();
    295 
    296       ImmutableSet.Builder<ModuleDescriptor> modules = ImmutableSet.builder();
    297       for (TypeMirror moduleIncludesType : getComponentModules(componentMirror)) {
    298         modules.add(moduleDescriptorFactory.create(MoreTypes.asTypeElement(moduleIncludesType)));
    299       }
    300       if (kind.equals(Kind.PRODUCTION_COMPONENT)) {
    301         modules.add(descriptorForMonitoringModule(componentDefinitionType));
    302       }
    303 
    304       ImmutableSet<ExecutableElement> unimplementedMethods =
    305           Util.getUnimplementedMethods(elements, componentDefinitionType);
    306 
    307       ImmutableSet.Builder<ComponentMethodDescriptor> componentMethodsBuilder =
    308           ImmutableSet.builder();
    309 
    310       ImmutableMap.Builder<ComponentMethodDescriptor, ComponentDescriptor> subcomponentDescriptors =
    311           ImmutableMap.builder();
    312       for (ExecutableElement componentMethod : unimplementedMethods) {
    313         ExecutableType resolvedMethod =
    314             MoreTypes.asExecutable(types.asMemberOf(declaredComponentType, componentMethod));
    315         ComponentMethodDescriptor componentMethodDescriptor =
    316             getDescriptorForComponentMethod(componentDefinitionType, kind, componentMethod);
    317         componentMethodsBuilder.add(componentMethodDescriptor);
    318         switch (componentMethodDescriptor.kind()) {
    319           case SUBCOMPONENT:
    320             subcomponentDescriptors.put(
    321                 componentMethodDescriptor,
    322                 create(
    323                     MoreElements.asType(MoreTypes.asElement(resolvedMethod.getReturnType())),
    324                     Kind.SUBCOMPONENT));
    325             break;
    326           case SUBCOMPONENT_BUILDER:
    327             subcomponentDescriptors.put(
    328                 componentMethodDescriptor,
    329                 create(
    330                     MoreElements.asType(
    331                         MoreTypes.asElement(resolvedMethod.getReturnType()).getEnclosingElement()),
    332                     Kind.SUBCOMPONENT));
    333             break;
    334           default: // nothing special to do for other methods.
    335         }
    336 
    337       }
    338 
    339       ImmutableList<DeclaredType> enclosedBuilders = kind.builderAnnotationType() == null
    340           ? ImmutableList.<DeclaredType>of()
    341           : enclosedBuilders(componentDefinitionType, kind.builderAnnotationType());
    342       Optional<DeclaredType> builderType =
    343           Optional.fromNullable(getOnlyElement(enclosedBuilders, null));
    344 
    345       Scope scope = Scope.scopeOf(componentDefinitionType);
    346       return new AutoValue_ComponentDescriptor(
    347           kind,
    348           componentMirror,
    349           componentDefinitionType,
    350           componentDependencyTypes,
    351           modules.build(),
    352           dependencyMethodIndex.build(),
    353           executorDependency,
    354           scope,
    355           subcomponentDescriptors.build(),
    356           componentMethodsBuilder.build(),
    357           createBuilderSpec(builderType));
    358     }
    359 
    360     private ComponentMethodDescriptor getDescriptorForComponentMethod(TypeElement componentElement,
    361         Kind componentKind,
    362         ExecutableElement componentMethod) {
    363       ExecutableType resolvedComponentMethod = MoreTypes.asExecutable(types.asMemberOf(
    364           MoreTypes.asDeclared(componentElement.asType()), componentMethod));
    365       TypeMirror returnType = resolvedComponentMethod.getReturnType();
    366       if (returnType.getKind().equals(DECLARED)) {
    367         if (MoreTypes.isTypeOf(Provider.class, returnType)
    368             || MoreTypes.isTypeOf(Lazy.class, returnType)) {
    369           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
    370               ComponentMethodKind.PROVISON,
    371               Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
    372                   resolvedComponentMethod)),
    373               componentMethod);
    374         } else if (MoreTypes.isTypeOf(MembersInjector.class, returnType)) {
    375           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
    376               ComponentMethodKind.MEMBERS_INJECTION,
    377               Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
    378                   componentMethod,
    379                   resolvedComponentMethod)),
    380               componentMethod);
    381         } else if (isAnnotationPresent(MoreTypes.asElement(returnType), Subcomponent.class)) {
    382           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
    383               ComponentMethodKind.SUBCOMPONENT,
    384               Optional.<DependencyRequest>absent(),
    385               componentMethod);
    386         } else if (isAnnotationPresent(MoreTypes.asElement(returnType),
    387             Subcomponent.Builder.class)) {
    388           return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
    389               ComponentMethodKind.SUBCOMPONENT_BUILDER,
    390               Optional.<DependencyRequest>absent(),
    391               componentMethod);
    392         }
    393       }
    394 
    395       // a typical provision method
    396       if (componentMethod.getParameters().isEmpty()
    397           && !componentMethod.getReturnType().getKind().equals(VOID)) {
    398         switch (componentKind) {
    399           case COMPONENT:
    400           case SUBCOMPONENT:
    401             return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
    402                 ComponentMethodKind.PROVISON,
    403                 Optional.of(dependencyRequestFactory.forComponentProvisionMethod(componentMethod,
    404                     resolvedComponentMethod)),
    405                 componentMethod);
    406           case PRODUCTION_COMPONENT:
    407             return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
    408                 ComponentMethodKind.PRODUCTION,
    409                 Optional.of(dependencyRequestFactory.forComponentProductionMethod(componentMethod,
    410                     resolvedComponentMethod)),
    411                 componentMethod);
    412           default:
    413             throw new AssertionError();
    414         }
    415       }
    416 
    417       List<? extends TypeMirror> parameterTypes = resolvedComponentMethod.getParameterTypes();
    418       if (parameterTypes.size() == 1
    419           && (returnType.getKind().equals(VOID)
    420               || MoreTypes.equivalence().equivalent(returnType, parameterTypes.get(0)))) {
    421         return new AutoValue_ComponentDescriptor_ComponentMethodDescriptor(
    422             ComponentMethodKind.MEMBERS_INJECTION,
    423             Optional.of(dependencyRequestFactory.forComponentMembersInjectionMethod(
    424                 componentMethod,
    425                 resolvedComponentMethod)),
    426             componentMethod);
    427       }
    428 
    429       throw new IllegalArgumentException("not a valid component method: " + componentMethod);
    430     }
    431 
    432     private Optional<BuilderSpec> createBuilderSpec(Optional<DeclaredType> builderType) {
    433       if (!builderType.isPresent()) {
    434         return Optional.absent();
    435       }
    436       TypeElement element = MoreTypes.asTypeElement(builderType.get());
    437       ImmutableSet<ExecutableElement> methods = Util.getUnimplementedMethods(elements, element);
    438       ImmutableMap.Builder<TypeElement, ExecutableElement> map = ImmutableMap.builder();
    439       ExecutableElement buildMethod = null;
    440       for (ExecutableElement method : methods) {
    441         if (method.getParameters().isEmpty()) {
    442           buildMethod = method;
    443         } else {
    444           ExecutableType resolved =
    445               MoreTypes.asExecutable(types.asMemberOf(builderType.get(), method));
    446           map.put(MoreTypes.asTypeElement(getOnlyElement(resolved.getParameterTypes())), method);
    447         }
    448       }
    449       verify(buildMethod != null); // validation should have ensured this.
    450       return Optional.<BuilderSpec>of(new AutoValue_ComponentDescriptor_BuilderSpec(element,
    451           map.build(), buildMethod, element.getEnclosingElement().asType()));
    452     }
    453 
    454     /**
    455      * Returns a descriptor for a generated module that handles monitoring for production
    456      * components. This module is generated in the {@link MonitoringModuleProcessingStep}.
    457      *
    458      * @throws TypeNotPresentException if the module has not been generated yet. This will cause the
    459      *     processor to retry in a later processing round.
    460      */
    461     private ModuleDescriptor descriptorForMonitoringModule(TypeElement componentDefinitionType) {
    462       String generatedMonitorModuleName =
    463           SourceFiles.generatedMonitoringModuleName(componentDefinitionType).canonicalName();
    464       TypeElement monitoringModule = elements.getTypeElement(generatedMonitorModuleName);
    465       if (monitoringModule == null) {
    466         throw new TypeNotPresentException(generatedMonitorModuleName, null);
    467       }
    468       return moduleDescriptorFactory.create(monitoringModule);
    469     }
    470   }
    471 
    472   static boolean isComponentContributionMethod(Elements elements, ExecutableElement method) {
    473     return method.getParameters().isEmpty()
    474         && !method.getReturnType().getKind().equals(VOID)
    475         && !elements.getTypeElement(Object.class.getCanonicalName())
    476             .equals(method.getEnclosingElement());
    477   }
    478 
    479   static boolean isComponentProductionMethod(Elements elements, ExecutableElement method) {
    480     return isComponentContributionMethod(elements, method)
    481         && MoreTypes.isTypeOf(ListenableFuture.class, method.getReturnType());
    482   }
    483 }
    484