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.BasicAnnotationProcessor;
19 import com.google.auto.service.AutoService;
20 import com.google.common.base.Ascii;
21 import com.google.common.collect.ImmutableList;
22 import com.google.common.collect.ImmutableSet;
23 import dagger.Module;
24 import dagger.Provides;
25 import dagger.producers.ProducerModule;
26 import dagger.producers.Produces;
27 import java.lang.annotation.Annotation;
28 import java.util.EnumSet;
29 import java.util.Map;
30 import java.util.Set;
31 import javax.annotation.processing.Filer;
32 import javax.annotation.processing.Messager;
33 import javax.annotation.processing.ProcessingEnvironment;
34 import javax.annotation.processing.Processor;
35 import javax.lang.model.SourceVersion;
36 import javax.lang.model.util.Elements;
37 import javax.lang.model.util.Types;
38 import javax.tools.Diagnostic;
39 
40 import static javax.tools.Diagnostic.Kind.ERROR;
41 
42 /**
43  * The annotation processor responsible for generating the classes that drive the Dagger 2.0
44  * implementation.
45  *
46  * TODO(gak): give this some better documentation
47  *
48  * @author Gregory Kick
49  * @since 2.0
50  */
51 @AutoService(Processor.class)
52 public final class ComponentProcessor extends BasicAnnotationProcessor {
53   private InjectBindingRegistry injectBindingRegistry;
54   private FactoryGenerator factoryGenerator;
55   private MembersInjectorGenerator membersInjectorGenerator;
56 
57   @Override
getSupportedSourceVersion()58   public SourceVersion getSupportedSourceVersion() {
59     return SourceVersion.latestSupported();
60   }
61 
62   @Override
getSupportedOptions()63   public Set<String> getSupportedOptions() {
64     return ImmutableSet.of(
65         DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY,
66         NULLABLE_VALIDATION_KEY,
67         PRIVATE_MEMBER_VALIDATION_TYPE_KEY,
68         STATIC_MEMBER_VALIDATION_TYPE_KEY
69     );
70   }
71 
72   @Override
initSteps()73   protected Iterable<ProcessingStep> initSteps() {
74     Messager messager = processingEnv.getMessager();
75     Types types = processingEnv.getTypeUtils();
76     Elements elements = processingEnv.getElementUtils();
77     Filer filer = processingEnv.getFiler();
78 
79     Diagnostic.Kind nullableDiagnosticType =
80         nullableValidationType(processingEnv).diagnosticKind().get();
81 
82     MethodSignatureFormatter methodSignatureFormatter = new MethodSignatureFormatter(types);
83     ContributionBindingFormatter contributionBindingFormatter =
84         new ContributionBindingFormatter(methodSignatureFormatter);
85     DependencyRequestFormatter dependencyRequestFormatter = new DependencyRequestFormatter(types);
86     KeyFormatter keyFormatter = new KeyFormatter();
87 
88     InjectConstructorValidator injectConstructorValidator = new InjectConstructorValidator();
89     InjectFieldValidator injectFieldValidator = new InjectFieldValidator(
90         privateMemberValidationType(processingEnv).diagnosticKind().get(),
91         staticMemberValidationType(processingEnv).diagnosticKind().get());
92     InjectMethodValidator injectMethodValidator = new InjectMethodValidator(
93         privateMemberValidationType(processingEnv).diagnosticKind().get(),
94         staticMemberValidationType(processingEnv).diagnosticKind().get());
95     ModuleValidator moduleValidator =
96         new ModuleValidator(
97             types,
98             elements,
99             methodSignatureFormatter,
100             Module.class,
101             ImmutableList.<Class<? extends Annotation>>of(Module.class),
102             Provides.class);
103     ProvidesMethodValidator providesMethodValidator = new ProvidesMethodValidator(elements);
104     BuilderValidator componentBuilderValidator =
105         new BuilderValidator(elements, types, ComponentDescriptor.Kind.COMPONENT);
106     BuilderValidator subcomponentBuilderValidator =
107         new BuilderValidator(elements, types, ComponentDescriptor.Kind.SUBCOMPONENT);
108     ComponentValidator subcomponentValidator = ComponentValidator.createForSubcomponent(elements,
109         types, moduleValidator, subcomponentBuilderValidator);
110     ComponentValidator componentValidator = ComponentValidator.createForComponent(elements, types,
111         moduleValidator, subcomponentValidator, subcomponentBuilderValidator);
112     MapKeyValidator mapKeyValidator = new MapKeyValidator();
113     ModuleValidator producerModuleValidator =
114         new ModuleValidator(
115             types,
116             elements,
117             methodSignatureFormatter,
118             ProducerModule.class,
119             ImmutableList.of(Module.class, ProducerModule.class),
120             Produces.class);
121     ProducesMethodValidator producesMethodValidator = new ProducesMethodValidator(elements);
122     ProductionComponentValidator productionComponentValidator = new ProductionComponentValidator();
123     BuilderValidator productionComponentBuilderValidator =
124         new BuilderValidator(elements, types, ComponentDescriptor.Kind.PRODUCTION_COMPONENT);
125 
126     Key.Factory keyFactory = new Key.Factory(types, elements);
127 
128     this.factoryGenerator =
129         new FactoryGenerator(filer, DependencyRequestMapper.FOR_PROVIDER, nullableDiagnosticType);
130     this.membersInjectorGenerator =
131         new MembersInjectorGenerator(filer, DependencyRequestMapper.FOR_PROVIDER);
132     ComponentGenerator componentGenerator =
133         new ComponentGenerator(filer, elements, types, keyFactory, nullableDiagnosticType);
134     ProducerFactoryGenerator producerFactoryGenerator =
135         new ProducerFactoryGenerator(filer, DependencyRequestMapper.FOR_PRODUCER);
136     MonitoringModuleGenerator monitoringModuleGenerator = new MonitoringModuleGenerator(filer);
137 
138     DependencyRequest.Factory dependencyRequestFactory =
139         new DependencyRequest.Factory(elements, keyFactory);
140     ProvisionBinding.Factory provisionBindingFactory =
141         new ProvisionBinding.Factory(elements, types, keyFactory, dependencyRequestFactory);
142     ProductionBinding.Factory productionBindingFactory =
143         new ProductionBinding.Factory(types, keyFactory, dependencyRequestFactory);
144 
145     MembersInjectionBinding.Factory membersInjectionBindingFactory =
146         new MembersInjectionBinding.Factory(elements, types, keyFactory, dependencyRequestFactory);
147 
148     this.injectBindingRegistry = new InjectBindingRegistry(
149         elements, types, messager, provisionBindingFactory, membersInjectionBindingFactory);
150 
151     ModuleDescriptor.Factory moduleDescriptorFactory = new ModuleDescriptor.Factory(
152         elements, provisionBindingFactory, productionBindingFactory);
153 
154     ComponentDescriptor.Factory componentDescriptorFactory = new ComponentDescriptor.Factory(
155         elements, types, dependencyRequestFactory, moduleDescriptorFactory);
156 
157     BindingGraph.Factory bindingGraphFactory =
158         new BindingGraph.Factory(
159             elements,
160             injectBindingRegistry,
161             keyFactory,
162             provisionBindingFactory,
163             productionBindingFactory);
164 
165     MapKeyGenerator mapKeyGenerator = new MapKeyGenerator(filer);
166     ComponentHierarchyValidator componentHierarchyValidator = new ComponentHierarchyValidator();
167     BindingGraphValidator bindingGraphValidator =
168         new BindingGraphValidator(
169             types,
170             injectBindingRegistry,
171             scopeValidationType(processingEnv),
172             nullableDiagnosticType,
173             contributionBindingFormatter,
174             methodSignatureFormatter,
175             dependencyRequestFormatter,
176             keyFormatter);
177 
178     return ImmutableList.<ProcessingStep>of(
179         new MapKeyProcessingStep(messager, types, mapKeyValidator, mapKeyGenerator),
180         new InjectProcessingStep(
181             messager,
182             injectConstructorValidator,
183             injectFieldValidator,
184             injectMethodValidator,
185             provisionBindingFactory,
186             membersInjectionBindingFactory,
187             injectBindingRegistry),
188         new MonitoringModuleProcessingStep(messager, monitoringModuleGenerator),
189         new ModuleProcessingStep(
190             messager,
191             moduleValidator,
192             providesMethodValidator,
193             provisionBindingFactory,
194             factoryGenerator),
195         new ComponentProcessingStep(
196             messager,
197             componentValidator,
198             subcomponentValidator,
199             componentBuilderValidator,
200             subcomponentBuilderValidator,
201             componentHierarchyValidator,
202             bindingGraphValidator,
203             componentDescriptorFactory,
204             bindingGraphFactory,
205             componentGenerator),
206         new ProducerModuleProcessingStep(
207             messager,
208             producerModuleValidator,
209             producesMethodValidator,
210             productionBindingFactory,
211             producerFactoryGenerator),
212         new ProductionComponentProcessingStep(
213             messager,
214             productionComponentValidator,
215             productionComponentBuilderValidator,
216             componentHierarchyValidator,
217             bindingGraphValidator,
218             componentDescriptorFactory,
219             bindingGraphFactory,
220             componentGenerator));
221   }
222 
223   @Override
postProcess()224   protected void postProcess() {
225     try {
226       injectBindingRegistry.generateSourcesForRequiredBindings(
227           factoryGenerator, membersInjectorGenerator);
228     } catch (SourceFileGenerationException e) {
229       e.printMessageTo(processingEnv.getMessager());
230     }
231   }
232 
233   private static final String DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY =
234       "dagger.disableInterComponentScopeValidation";
235 
236   private static final String NULLABLE_VALIDATION_KEY = "dagger.nullableValidation";
237 
238   private static final String PRIVATE_MEMBER_VALIDATION_TYPE_KEY =
239       "dagger.privateMemberValidation";
240 
241   private static final String STATIC_MEMBER_VALIDATION_TYPE_KEY =
242       "dagger.staticMemberValidation";
243 
scopeValidationType(ProcessingEnvironment processingEnv)244   private static ValidationType scopeValidationType(ProcessingEnvironment processingEnv) {
245     return valueOf(processingEnv,
246         DISABLE_INTER_COMPONENT_SCOPE_VALIDATION_KEY,
247         ValidationType.ERROR,
248         EnumSet.allOf(ValidationType.class));
249   }
250 
nullableValidationType(ProcessingEnvironment processingEnv)251   private static ValidationType nullableValidationType(ProcessingEnvironment processingEnv) {
252     return valueOf(processingEnv,
253         NULLABLE_VALIDATION_KEY,
254         ValidationType.ERROR,
255         EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
256   }
257 
privateMemberValidationType(ProcessingEnvironment processingEnv)258   private static ValidationType privateMemberValidationType(ProcessingEnvironment processingEnv) {
259     return valueOf(processingEnv,
260         PRIVATE_MEMBER_VALIDATION_TYPE_KEY,
261         ValidationType.ERROR,
262         EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
263   }
264 
staticMemberValidationType(ProcessingEnvironment processingEnv)265   private static ValidationType staticMemberValidationType(ProcessingEnvironment processingEnv) {
266     return valueOf(processingEnv,
267         STATIC_MEMBER_VALIDATION_TYPE_KEY,
268         ValidationType.ERROR,
269         EnumSet.of(ValidationType.ERROR, ValidationType.WARNING));
270   }
271 
valueOf(ProcessingEnvironment processingEnv, String key, T defaultValue, Set<T> validValues)272   private static <T extends Enum<T>> T valueOf(ProcessingEnvironment processingEnv, String key,
273       T defaultValue, Set<T> validValues) {
274     Map<String, String> options = processingEnv.getOptions();
275     if (options.containsKey(key)) {
276       try {
277         T type = Enum.valueOf(
278             defaultValue.getDeclaringClass(),
279             Ascii.toUpperCase(options.get(key)));
280         if (!validValues.contains(type)) {
281           throw new IllegalArgumentException(); // let handler below print out good msg.
282         }
283         return type;
284       } catch (IllegalArgumentException e) {
285         processingEnv.getMessager().printMessage(ERROR, "Processor option -A"
286             + key + " may only have the values " + validValues
287             + " (case insensitive), found: " + options.get(key));
288       }
289     }
290     return defaultValue;
291   }
292 }
293