Home | History | Annotate | Download | only in codegen
      1 package dagger.internal.codegen;
      2 
      3 import com.google.auto.common.MoreTypes;
      4 import com.google.auto.value.AutoValue;
      5 import com.google.common.base.Function;
      6 import com.google.common.base.Optional;
      7 import com.google.common.collect.ImmutableSet;
      8 import dagger.Module;
      9 import dagger.Provides;
     10 import dagger.producers.ProducerModule;
     11 import dagger.producers.Produces;
     12 import java.util.LinkedHashSet;
     13 import java.util.Set;
     14 import javax.lang.model.element.AnnotationMirror;
     15 import javax.lang.model.element.ExecutableElement;
     16 import javax.lang.model.element.TypeElement;
     17 import javax.lang.model.type.TypeMirror;
     18 import javax.lang.model.util.Elements;
     19 
     20 import static com.google.auto.common.MoreElements.getAnnotationMirror;
     21 import static com.google.auto.common.MoreElements.isAnnotationPresent;
     22 import static com.google.common.base.Verify.verify;
     23 import static dagger.internal.codegen.ConfigurationAnnotations.getModuleIncludes;
     24 import static dagger.internal.codegen.Util.componentCanMakeNewInstances;
     25 import static javax.lang.model.type.TypeKind.DECLARED;
     26 import static javax.lang.model.type.TypeKind.NONE;
     27 import static javax.lang.model.util.ElementFilter.methodsIn;
     28 
     29 @AutoValue
     30 abstract class ModuleDescriptor {
     31   static final Function<ModuleDescriptor, TypeElement> getModuleElement() {
     32     return new Function<ModuleDescriptor, TypeElement>() {
     33       @Override public TypeElement apply(ModuleDescriptor input) {
     34         return input.moduleElement();
     35       }
     36     };
     37   }
     38 
     39   abstract AnnotationMirror moduleAnnotation();
     40 
     41   abstract TypeElement moduleElement();
     42 
     43   abstract ImmutableSet<ModuleDescriptor> includedModules();
     44 
     45   abstract ImmutableSet<ContributionBinding> bindings();
     46 
     47   enum DefaultCreationStrategy {
     48     PASSED,
     49     CONSTRUCTED,
     50   }
     51 
     52   abstract DefaultCreationStrategy defaultCreationStrategy();
     53 
     54   static final class Factory {
     55     private final Elements elements;
     56     private final ProvisionBinding.Factory provisionBindingFactory;
     57     private final ProductionBinding.Factory productionBindingFactory;
     58 
     59     Factory(
     60         Elements elements,
     61         ProvisionBinding.Factory provisionBindingFactory,
     62         ProductionBinding.Factory productionBindingFactory) {
     63       this.elements = elements;
     64       this.provisionBindingFactory = provisionBindingFactory;
     65       this.productionBindingFactory = productionBindingFactory;
     66     }
     67 
     68     ModuleDescriptor create(TypeElement moduleElement) {
     69       AnnotationMirror moduleAnnotation = getModuleAnnotation(moduleElement).get();
     70 
     71       ImmutableSet.Builder<ContributionBinding> bindings = ImmutableSet.builder();
     72       for (ExecutableElement moduleMethod : methodsIn(elements.getAllMembers(moduleElement))) {
     73         if (isAnnotationPresent(moduleMethod, Provides.class)) {
     74           bindings.add(
     75               provisionBindingFactory.forProvidesMethod(moduleMethod, moduleElement.asType()));
     76         }
     77         if (isAnnotationPresent(moduleMethod, Produces.class)) {
     78           bindings.add(
     79               productionBindingFactory.forProducesMethod(moduleMethod, moduleElement.asType()));
     80         }
     81       }
     82 
     83       DefaultCreationStrategy defaultCreationStrategy =
     84           (componentCanMakeNewInstances(moduleElement)
     85               && moduleElement.getTypeParameters().isEmpty())
     86                   ? ModuleDescriptor.DefaultCreationStrategy.CONSTRUCTED
     87                   : ModuleDescriptor.DefaultCreationStrategy.PASSED;
     88 
     89       return new AutoValue_ModuleDescriptor(
     90           moduleAnnotation,
     91           moduleElement,
     92           ImmutableSet.copyOf(
     93               collectIncludedModules(new LinkedHashSet<ModuleDescriptor>(), moduleElement)),
     94           bindings.build(),
     95           defaultCreationStrategy);
     96     }
     97 
     98     private static Optional<AnnotationMirror> getModuleAnnotation(TypeElement moduleElement) {
     99       return getAnnotationMirror(moduleElement, Module.class)
    100           .or(getAnnotationMirror(moduleElement, ProducerModule.class));
    101     }
    102 
    103     private Set<ModuleDescriptor> collectIncludedModules(
    104         Set<ModuleDescriptor> includedModules, TypeElement moduleElement) {
    105       TypeMirror superclass = moduleElement.getSuperclass();
    106       if (!superclass.getKind().equals(NONE)) {
    107         verify(superclass.getKind().equals(DECLARED));
    108         TypeElement superclassElement = MoreTypes.asTypeElement(superclass);
    109         if (!superclassElement.getQualifiedName().contentEquals(Object.class.getCanonicalName())) {
    110           collectIncludedModules(includedModules, superclassElement);
    111         }
    112       }
    113       Optional<AnnotationMirror> moduleAnnotation = getModuleAnnotation(moduleElement);
    114       if (moduleAnnotation.isPresent()) {
    115         for (TypeMirror moduleIncludesType : getModuleIncludes(moduleAnnotation.get())) {
    116           includedModules.add(create(MoreTypes.asTypeElement(moduleIncludesType)));
    117         }
    118       }
    119       return includedModules;
    120     }
    121   }
    122 }
    123