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 {
getModuleElement()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