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 */ 16package dagger.internal.codegen; 17 18import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep; 19import com.google.auto.common.MoreElements; 20import com.google.auto.common.SuperficialValidation; 21import com.google.common.base.Function; 22import com.google.common.collect.FluentIterable; 23import com.google.common.collect.ImmutableSet; 24import com.google.common.collect.SetMultimap; 25import com.google.common.collect.Sets; 26import dagger.producers.ProducerModule; 27import dagger.producers.Produces; 28import java.lang.annotation.Annotation; 29import java.util.List; 30import java.util.Set; 31import javax.annotation.processing.Messager; 32import javax.lang.model.element.Element; 33import javax.lang.model.element.ExecutableElement; 34import javax.lang.model.element.TypeElement; 35import javax.lang.model.util.ElementFilter; 36 37import static com.google.auto.common.MoreElements.isAnnotationPresent; 38import static javax.lang.model.element.ElementKind.METHOD; 39 40/** 41 * An annotation processor for generating Dagger implementation code based on the 42 * {@link ProducerModule} (and {@link Produces}) annotation. 43 * 44 * @author Jesse Beder 45 * @since 2.0 46 */ 47final class ProducerModuleProcessingStep implements ProcessingStep { 48 private final Messager messager; 49 private final ModuleValidator moduleValidator; 50 private final ProducesMethodValidator producesMethodValidator; 51 private final ProductionBinding.Factory productionBindingFactory; 52 private final ProducerFactoryGenerator factoryGenerator; 53 private final Set<Element> processedModuleElements = Sets.newLinkedHashSet(); 54 55 ProducerModuleProcessingStep( 56 Messager messager, 57 ModuleValidator moduleValidator, 58 ProducesMethodValidator producesMethodValidator, 59 ProductionBinding.Factory productionBindingFactory, 60 ProducerFactoryGenerator factoryGenerator) { 61 this.messager = messager; 62 this.moduleValidator = moduleValidator; 63 this.producesMethodValidator = producesMethodValidator; 64 this.productionBindingFactory = productionBindingFactory; 65 this.factoryGenerator = factoryGenerator; 66 } 67 68 @Override 69 public Set<Class<? extends Annotation>> annotations() { 70 return ImmutableSet.of(Produces.class, ProducerModule.class); 71 } 72 73 @Override 74 public Set<Element> process( 75 SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) { 76 // first, check and collect all produces methods 77 ImmutableSet.Builder<ExecutableElement> validProducesMethodsBuilder = ImmutableSet.builder(); 78 for (Element producesElement : elementsByAnnotation.get(Produces.class)) { 79 if (producesElement.getKind().equals(METHOD)) { 80 ExecutableElement producesMethodElement = (ExecutableElement) producesElement; 81 ValidationReport<ExecutableElement> methodReport = 82 producesMethodValidator.validate(producesMethodElement); 83 methodReport.printMessagesTo(messager); 84 if (methodReport.isClean()) { 85 validProducesMethodsBuilder.add(producesMethodElement); 86 } 87 } 88 } 89 ImmutableSet<ExecutableElement> validProducesMethods = validProducesMethodsBuilder.build(); 90 91 // process each module 92 for (Element moduleElement : 93 Sets.difference(elementsByAnnotation.get(ProducerModule.class), 94 processedModuleElements)) { 95 if (SuperficialValidation.validateElement(moduleElement)) { 96 ValidationReport<TypeElement> report = 97 moduleValidator.validate(MoreElements.asType(moduleElement)); 98 report.printMessagesTo(messager); 99 100 if (report.isClean()) { 101 ImmutableSet.Builder<ExecutableElement> moduleProducesMethodsBuilder = 102 ImmutableSet.builder(); 103 List<ExecutableElement> moduleMethods = 104 ElementFilter.methodsIn(moduleElement.getEnclosedElements()); 105 for (ExecutableElement methodElement : moduleMethods) { 106 if (isAnnotationPresent(methodElement, Produces.class)) { 107 moduleProducesMethodsBuilder.add(methodElement); 108 } 109 } 110 ImmutableSet<ExecutableElement> moduleProducesMethods = 111 moduleProducesMethodsBuilder.build(); 112 113 if (Sets.difference(moduleProducesMethods, validProducesMethods).isEmpty()) { 114 // all of the produces methods in this module are valid! 115 // time to generate some factories! 116 ImmutableSet<ProductionBinding> bindings = FluentIterable.from(moduleProducesMethods) 117 .transform(new Function<ExecutableElement, ProductionBinding>() { 118 @Override 119 public ProductionBinding apply(ExecutableElement producesMethod) { 120 return productionBindingFactory.forProducesMethod(producesMethod, 121 producesMethod.getEnclosingElement().asType()); 122 } 123 }) 124 .toSet(); 125 126 try { 127 for (ProductionBinding binding : bindings) { 128 factoryGenerator.generate(binding); 129 } 130 } catch (SourceFileGenerationException e) { 131 e.printMessageTo(messager); 132 } 133 } 134 } 135 136 processedModuleElements.add(moduleElement); 137 } 138 } 139 return ImmutableSet.of(); 140 } 141} 142