1 /* 2 * Copyright (C) 2014 The Dagger Authors. 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 17 package dagger.internal.codegen; 18 19 import static com.google.auto.common.MoreElements.isAnnotationPresent; 20 import static javax.lang.model.util.ElementFilter.methodsIn; 21 import static javax.lang.model.util.ElementFilter.typesIn; 22 23 import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep; 24 import com.google.auto.common.MoreElements; 25 import com.google.common.collect.ImmutableSet; 26 import com.google.common.collect.SetMultimap; 27 import com.google.common.collect.Sets; 28 import dagger.Binds; 29 import dagger.Module; 30 import dagger.Provides; 31 import dagger.internal.codegen.base.SourceFileGenerator; 32 import dagger.internal.codegen.binding.BindingFactory; 33 import dagger.internal.codegen.binding.ContributionBinding; 34 import dagger.internal.codegen.binding.DelegateDeclaration; 35 import dagger.internal.codegen.binding.DelegateDeclaration.Factory; 36 import dagger.internal.codegen.binding.ProductionBinding; 37 import dagger.internal.codegen.binding.ProvisionBinding; 38 import dagger.internal.codegen.kotlin.KotlinMetadataUtil; 39 import dagger.internal.codegen.validation.ModuleValidator; 40 import dagger.internal.codegen.validation.TypeCheckingProcessingStep; 41 import dagger.internal.codegen.validation.ValidationReport; 42 import dagger.internal.codegen.writing.InaccessibleMapKeyProxyGenerator; 43 import dagger.internal.codegen.writing.ModuleGenerator; 44 import dagger.producers.ProducerModule; 45 import dagger.producers.Produces; 46 import java.lang.annotation.Annotation; 47 import java.util.List; 48 import java.util.Set; 49 import javax.annotation.processing.Messager; 50 import javax.inject.Inject; 51 import javax.lang.model.element.Element; 52 import javax.lang.model.element.ExecutableElement; 53 import javax.lang.model.element.TypeElement; 54 55 /** 56 * A {@link ProcessingStep} that validates module classes and generates factories for binding 57 * methods. 58 */ 59 final class ModuleProcessingStep extends TypeCheckingProcessingStep<TypeElement> { 60 private final Messager messager; 61 private final ModuleValidator moduleValidator; 62 private final BindingFactory bindingFactory; 63 private final SourceFileGenerator<ProvisionBinding> factoryGenerator; 64 private final SourceFileGenerator<ProductionBinding> producerFactoryGenerator; 65 private final SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator; 66 private final InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator; 67 private final DelegateDeclaration.Factory delegateDeclarationFactory; 68 private final KotlinMetadataUtil metadataUtil; 69 private final Set<TypeElement> processedModuleElements = Sets.newLinkedHashSet(); 70 71 @Inject ModuleProcessingStep( Messager messager, ModuleValidator moduleValidator, BindingFactory bindingFactory, SourceFileGenerator<ProvisionBinding> factoryGenerator, SourceFileGenerator<ProductionBinding> producerFactoryGenerator, @ModuleGenerator SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator, InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator, Factory delegateDeclarationFactory, KotlinMetadataUtil metadataUtil)72 ModuleProcessingStep( 73 Messager messager, 74 ModuleValidator moduleValidator, 75 BindingFactory bindingFactory, 76 SourceFileGenerator<ProvisionBinding> factoryGenerator, 77 SourceFileGenerator<ProductionBinding> producerFactoryGenerator, 78 @ModuleGenerator SourceFileGenerator<TypeElement> moduleConstructorProxyGenerator, 79 InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator, 80 Factory delegateDeclarationFactory, 81 KotlinMetadataUtil metadataUtil) { 82 super(MoreElements::asType); 83 this.messager = messager; 84 this.moduleValidator = moduleValidator; 85 this.bindingFactory = bindingFactory; 86 this.factoryGenerator = factoryGenerator; 87 this.producerFactoryGenerator = producerFactoryGenerator; 88 this.moduleConstructorProxyGenerator = moduleConstructorProxyGenerator; 89 this.inaccessibleMapKeyProxyGenerator = inaccessibleMapKeyProxyGenerator; 90 this.delegateDeclarationFactory = delegateDeclarationFactory; 91 this.metadataUtil = metadataUtil; 92 } 93 94 @Override annotations()95 public Set<? extends Class<? extends Annotation>> annotations() { 96 return ImmutableSet.of(Module.class, ProducerModule.class); 97 } 98 99 @Override process( SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation)100 public ImmutableSet<Element> process( 101 SetMultimap<Class<? extends Annotation>, Element> elementsByAnnotation) { 102 List<TypeElement> modules = typesIn(elementsByAnnotation.values()); 103 moduleValidator.addKnownModules(modules); 104 return super.process(elementsByAnnotation); 105 } 106 107 @Override process( TypeElement module, ImmutableSet<Class<? extends Annotation>> annotations)108 protected void process( 109 TypeElement module, ImmutableSet<Class<? extends Annotation>> annotations) { 110 if (processedModuleElements.contains(module)) { 111 return; 112 } 113 // For backwards compatibility, we allow a companion object to be annotated with @Module even 114 // though it's no longer required. However, we skip processing the companion object itself 115 // because it will now be processed when processing the companion object's enclosing class. 116 if (metadataUtil.isCompanionObjectClass(module)) { 117 // TODO(danysantiago): Be strict about annotating companion objects with @Module, 118 // i.e. tell user to annotate parent instead. 119 return; 120 } 121 ValidationReport<TypeElement> report = moduleValidator.validate(module); 122 report.printMessagesTo(messager); 123 if (report.isClean()) { 124 generateForMethodsIn(module); 125 if (metadataUtil.hasEnclosedCompanionObject(module)) { 126 generateForMethodsIn(metadataUtil.getEnclosedCompanionObject(module)); 127 } 128 } 129 processedModuleElements.add(module); 130 } 131 generateForMethodsIn(TypeElement module)132 private void generateForMethodsIn(TypeElement module) { 133 for (ExecutableElement method : methodsIn(module.getEnclosedElements())) { 134 if (isAnnotationPresent(method, Provides.class)) { 135 generate(factoryGenerator, bindingFactory.providesMethodBinding(method, module)); 136 } else if (isAnnotationPresent(method, Produces.class)) { 137 generate(producerFactoryGenerator, bindingFactory.producesMethodBinding(method, module)); 138 } else if (isAnnotationPresent(method, Binds.class)) { 139 inaccessibleMapKeyProxyGenerator.generate(bindsMethodBinding(module, method), messager); 140 } 141 } 142 moduleConstructorProxyGenerator.generate(module, messager); 143 } 144 generate( SourceFileGenerator<B> generator, B binding)145 private <B extends ContributionBinding> void generate( 146 SourceFileGenerator<B> generator, B binding) { 147 generator.generate(binding, messager); 148 inaccessibleMapKeyProxyGenerator.generate(binding, messager); 149 } 150 bindsMethodBinding(TypeElement module, ExecutableElement method)151 private ContributionBinding bindsMethodBinding(TypeElement module, ExecutableElement method) { 152 return bindingFactory.unresolvedDelegateBinding( 153 delegateDeclarationFactory.create(method, module)); 154 } 155 } 156