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.processingstep; 18 19 import static dagger.internal.codegen.extension.DaggerCollectors.toOptional; 20 import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet; 21 22 import androidx.room.compiler.processing.XElement; 23 import androidx.room.compiler.processing.XMessager; 24 import androidx.room.compiler.processing.XMethodElement; 25 import androidx.room.compiler.processing.XProcessingEnv; 26 import androidx.room.compiler.processing.XTypeElement; 27 import com.google.auto.common.BasicAnnotationProcessor.ProcessingStep; 28 import com.google.common.collect.ImmutableSet; 29 import com.google.common.collect.Sets; 30 import com.squareup.javapoet.ClassName; 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.ProductionBinding; 36 import dagger.internal.codegen.binding.ProvisionBinding; 37 import dagger.internal.codegen.javapoet.TypeNames; 38 import dagger.internal.codegen.validation.ModuleValidator; 39 import dagger.internal.codegen.validation.ValidationReport; 40 import dagger.internal.codegen.writing.InaccessibleMapKeyProxyGenerator; 41 import dagger.internal.codegen.writing.ModuleGenerator; 42 import java.util.Map; 43 import java.util.Set; 44 import javax.inject.Inject; 45 46 /** 47 * A {@link ProcessingStep} that validates module classes and generates factories for binding 48 * methods. 49 */ 50 final class ModuleProcessingStep extends TypeCheckingProcessingStep<XTypeElement> { 51 private final XMessager messager; 52 private final ModuleValidator moduleValidator; 53 private final BindingFactory bindingFactory; 54 private final SourceFileGenerator<ProvisionBinding> factoryGenerator; 55 private final SourceFileGenerator<ProductionBinding> producerFactoryGenerator; 56 private final SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator; 57 private final InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator; 58 private final DelegateDeclaration.Factory delegateDeclarationFactory; 59 private final Set<XTypeElement> processedModuleElements = Sets.newLinkedHashSet(); 60 61 @Inject ModuleProcessingStep( XMessager messager, ModuleValidator moduleValidator, BindingFactory bindingFactory, SourceFileGenerator<ProvisionBinding> factoryGenerator, SourceFileGenerator<ProductionBinding> producerFactoryGenerator, @ModuleGenerator SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator, InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator, DelegateDeclaration.Factory delegateDeclarationFactory)62 ModuleProcessingStep( 63 XMessager messager, 64 ModuleValidator moduleValidator, 65 BindingFactory bindingFactory, 66 SourceFileGenerator<ProvisionBinding> factoryGenerator, 67 SourceFileGenerator<ProductionBinding> producerFactoryGenerator, 68 @ModuleGenerator SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator, 69 InaccessibleMapKeyProxyGenerator inaccessibleMapKeyProxyGenerator, 70 DelegateDeclaration.Factory delegateDeclarationFactory) { 71 this.messager = messager; 72 this.moduleValidator = moduleValidator; 73 this.bindingFactory = bindingFactory; 74 this.factoryGenerator = factoryGenerator; 75 this.producerFactoryGenerator = producerFactoryGenerator; 76 this.moduleConstructorProxyGenerator = moduleConstructorProxyGenerator; 77 this.inaccessibleMapKeyProxyGenerator = inaccessibleMapKeyProxyGenerator; 78 this.delegateDeclarationFactory = delegateDeclarationFactory; 79 } 80 81 @Override annotationClassNames()82 public ImmutableSet<ClassName> annotationClassNames() { 83 return ImmutableSet.of(TypeNames.MODULE, TypeNames.PRODUCER_MODULE); 84 } 85 86 @Override process( XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation)87 public ImmutableSet<XElement> process( 88 XProcessingEnv env, Map<String, ? extends Set<? extends XElement>> elementsByAnnotation) { 89 moduleValidator.addKnownModules( 90 elementsByAnnotation.values().stream() 91 .flatMap(Set::stream) 92 // This cast is safe because @Module has @Target(ElementType.TYPE) 93 .map(XTypeElement.class::cast) 94 .collect(toImmutableSet())); 95 return super.process(env, elementsByAnnotation); 96 } 97 98 @Override process(XTypeElement module, ImmutableSet<ClassName> annotations)99 protected void process(XTypeElement module, ImmutableSet<ClassName> annotations) { 100 if (processedModuleElements.contains(module)) { 101 return; 102 } 103 // For backwards compatibility, we allow a companion object to be annotated with @Module even 104 // though it's no longer required. However, we skip processing the companion object itself 105 // because it will now be processed when processing the companion object's enclosing class. 106 if (module.isCompanionObject()) { 107 // TODO(danysantiago): Be strict about annotating companion objects with @Module, 108 // i.e. tell user to annotate parent instead. 109 return; 110 } 111 ValidationReport report = moduleValidator.validate(module); 112 report.printMessagesTo(messager); 113 if (report.isClean()) { 114 generateForMethodsIn(module); 115 module.getEnclosedTypeElements().stream() 116 .filter(XTypeElement::isCompanionObject) 117 .collect(toOptional()) 118 .ifPresent(this::generateForMethodsIn); 119 } 120 processedModuleElements.add(module); 121 } 122 generateForMethodsIn(XTypeElement module)123 private void generateForMethodsIn(XTypeElement module) { 124 for (XMethodElement method : module.getDeclaredMethods()) { 125 if (method.hasAnnotation(TypeNames.PROVIDES)) { 126 generate(factoryGenerator, bindingFactory.providesMethodBinding(method, module)); 127 } else if (method.hasAnnotation(TypeNames.PRODUCES)) { 128 generate(producerFactoryGenerator, bindingFactory.producesMethodBinding(method, module)); 129 } else if (method.hasAnnotation(TypeNames.BINDS)) { 130 inaccessibleMapKeyProxyGenerator.generate(bindsMethodBinding(module, method), messager); 131 } 132 } 133 // We should never need to generate a constructor proxy for a companion object since we never 134 // need to call a companion object's constructor. 135 if (!module.isCompanionObject()) { 136 moduleConstructorProxyGenerator.generate(module, messager); 137 } 138 } 139 generate( SourceFileGenerator<B> generator, B binding)140 private <B extends ContributionBinding> void generate( 141 SourceFileGenerator<B> generator, B binding) { 142 generator.generate(binding, messager); 143 inaccessibleMapKeyProxyGenerator.generate(binding, messager); 144 } 145 bindsMethodBinding(XTypeElement module, XMethodElement method)146 private ContributionBinding bindsMethodBinding(XTypeElement module, XMethodElement method) { 147 return bindingFactory.unresolvedDelegateBinding( 148 delegateDeclarationFactory.create(method, module)); 149 } 150 } 151