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 net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING; 20 21 import androidx.room.compiler.processing.XProcessingEnv; 22 import androidx.room.compiler.processing.XProcessingEnvConfig; 23 import androidx.room.compiler.processing.XProcessingStep; 24 import androidx.room.compiler.processing.XRoundEnv; 25 import androidx.room.compiler.processing.compat.XConverters; 26 import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor; 27 import com.google.auto.service.AutoService; 28 import com.google.common.annotations.VisibleForTesting; 29 import com.google.common.collect.ImmutableList; 30 import com.google.common.collect.ImmutableSet; 31 import com.google.errorprone.annotations.CheckReturnValue; 32 import dagger.BindsInstance; 33 import dagger.Component; 34 import dagger.Module; 35 import dagger.Provides; 36 import dagger.internal.codegen.base.ClearableCache; 37 import dagger.internal.codegen.base.SourceFileGenerationException; 38 import dagger.internal.codegen.base.SourceFileGenerator; 39 import dagger.internal.codegen.binding.InjectBindingRegistry; 40 import dagger.internal.codegen.binding.MembersInjectionBinding; 41 import dagger.internal.codegen.binding.ProvisionBinding; 42 import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModule; 43 import dagger.internal.codegen.compileroption.CompilerOptions; 44 import dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions; 45 import dagger.internal.codegen.componentgenerator.ComponentGeneratorModule; 46 import dagger.internal.codegen.validation.BindingMethodProcessingStep; 47 import dagger.internal.codegen.validation.BindingMethodValidatorsModule; 48 import dagger.internal.codegen.validation.BindsInstanceProcessingStep; 49 import dagger.internal.codegen.validation.ExternalBindingGraphPlugins; 50 import dagger.internal.codegen.validation.InjectBindingRegistryModule; 51 import dagger.internal.codegen.validation.MonitoringModuleProcessingStep; 52 import dagger.internal.codegen.validation.MultibindingAnnotationsProcessingStep; 53 import dagger.internal.codegen.validation.ValidationBindingGraphPlugins; 54 import dagger.spi.BindingGraphPlugin; 55 import java.util.Arrays; 56 import java.util.Map; 57 import java.util.Optional; 58 import java.util.Set; 59 import javax.annotation.processing.Processor; 60 import javax.inject.Inject; 61 import javax.inject.Singleton; 62 import javax.lang.model.SourceVersion; 63 import net.ltgt.gradle.incap.IncrementalAnnotationProcessor; 64 65 /** 66 * The annotation processor responsible for generating the classes that drive the Dagger 2.0 67 * implementation. 68 * 69 * <p>TODO(gak): give this some better documentation 70 */ 71 @IncrementalAnnotationProcessor(ISOLATING) 72 @AutoService(Processor.class) 73 public class ComponentProcessor extends JavacBasicAnnotationProcessor { envConfig(Map<String, String> options)74 private static XProcessingEnvConfig envConfig(Map<String, String> options) { 75 return new XProcessingEnvConfig.Builder().disableAnnotatedElementValidation(true).build(); 76 } 77 78 private final Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins; 79 80 @Inject InjectBindingRegistry injectBindingRegistry; 81 @Inject SourceFileGenerator<ProvisionBinding> factoryGenerator; 82 @Inject SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator; 83 @Inject ImmutableList<XProcessingStep> processingSteps; 84 @Inject ValidationBindingGraphPlugins validationBindingGraphPlugins; 85 @Inject ExternalBindingGraphPlugins externalBindingGraphPlugins; 86 @Inject Set<ClearableCache> clearableCaches; 87 ComponentProcessor()88 public ComponentProcessor() { 89 super(ComponentProcessor::envConfig); 90 this.testingPlugins = Optional.empty(); 91 } 92 ComponentProcessor(Iterable<BindingGraphPlugin> testingPlugins)93 private ComponentProcessor(Iterable<BindingGraphPlugin> testingPlugins) { 94 super(ComponentProcessor::envConfig); 95 this.testingPlugins = Optional.of(ImmutableSet.copyOf(testingPlugins)); 96 } 97 98 /** 99 * Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading 100 * them from a {@link java.util.ServiceLoader}. 101 */ 102 @VisibleForTesting forTesting(BindingGraphPlugin... testingPlugins)103 public static ComponentProcessor forTesting(BindingGraphPlugin... testingPlugins) { 104 return forTesting(Arrays.asList(testingPlugins)); 105 } 106 107 /** 108 * Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading 109 * them from a {@link java.util.ServiceLoader}. 110 */ 111 @VisibleForTesting forTesting(Iterable<BindingGraphPlugin> testingPlugins)112 public static ComponentProcessor forTesting(Iterable<BindingGraphPlugin> testingPlugins) { 113 return new ComponentProcessor(testingPlugins); 114 } 115 116 @Override initialize(XProcessingEnv env)117 public void initialize(XProcessingEnv env) { 118 ProcessorComponent.factory() 119 .create(env, testingPlugins.orElseGet(this::loadExternalPlugins)) 120 .inject(this); 121 } 122 123 @Override getSupportedSourceVersion()124 public SourceVersion getSupportedSourceVersion() { 125 return SourceVersion.latestSupported(); 126 } 127 128 @Override getSupportedOptions()129 public ImmutableSet<String> getSupportedOptions() { 130 return ImmutableSet.<String>builder() 131 .addAll(ProcessingEnvironmentCompilerOptions.supportedOptions()) 132 .addAll(validationBindingGraphPlugins.allSupportedOptions()) 133 .addAll(externalBindingGraphPlugins.allSupportedOptions()) 134 .build(); 135 } 136 137 @Override processingSteps()138 public Iterable<XProcessingStep> processingSteps() { 139 validationBindingGraphPlugins.initializePlugins(); 140 externalBindingGraphPlugins.initializePlugins(); 141 142 return processingSteps; 143 } 144 loadExternalPlugins()145 private ImmutableSet<BindingGraphPlugin> loadExternalPlugins() { 146 return ServiceLoaders.load(processingEnv, BindingGraphPlugin.class); 147 } 148 149 @Singleton 150 @Component( 151 modules = { 152 BindingGraphValidationModule.class, 153 BindingMethodValidatorsModule.class, 154 ComponentGeneratorModule.class, 155 InjectBindingRegistryModule.class, 156 ProcessingEnvironmentModule.class, 157 ProcessingRoundCacheModule.class, 158 ProcessingStepsModule.class, 159 SourceFileGeneratorsModule.class, 160 }) 161 interface ProcessorComponent { inject(ComponentProcessor processor)162 void inject(ComponentProcessor processor); 163 factory()164 static Factory factory() { 165 return DaggerComponentProcessor_ProcessorComponent.factory(); 166 } 167 168 @Component.Factory 169 interface Factory { 170 @CheckReturnValue create( @indsInstance XProcessingEnv xProcessingEnv, @BindsInstance ImmutableSet<BindingGraphPlugin> externalPlugins)171 ProcessorComponent create( 172 @BindsInstance XProcessingEnv xProcessingEnv, 173 @BindsInstance ImmutableSet<BindingGraphPlugin> externalPlugins); 174 } 175 } 176 177 @Module 178 interface ProcessingStepsModule { 179 @Provides processingSteps( MapKeyProcessingStep mapKeyProcessingStep, InjectProcessingStep injectProcessingStep, AssistedInjectProcessingStep assistedInjectProcessingStep, AssistedFactoryProcessingStep assistedFactoryProcessingStep, AssistedProcessingStep assistedProcessingStep, MonitoringModuleProcessingStep monitoringModuleProcessingStep, MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep, BindsInstanceProcessingStep bindsInstanceProcessingStep, ModuleProcessingStep moduleProcessingStep, ComponentProcessingStep componentProcessingStep, ComponentHjarProcessingStep componentHjarProcessingStep, BindingMethodProcessingStep bindingMethodProcessingStep, CompilerOptions compilerOptions)180 static ImmutableList<XProcessingStep> processingSteps( 181 MapKeyProcessingStep mapKeyProcessingStep, 182 InjectProcessingStep injectProcessingStep, 183 AssistedInjectProcessingStep assistedInjectProcessingStep, 184 AssistedFactoryProcessingStep assistedFactoryProcessingStep, 185 AssistedProcessingStep assistedProcessingStep, 186 MonitoringModuleProcessingStep monitoringModuleProcessingStep, 187 MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep, 188 BindsInstanceProcessingStep bindsInstanceProcessingStep, 189 ModuleProcessingStep moduleProcessingStep, 190 ComponentProcessingStep componentProcessingStep, 191 ComponentHjarProcessingStep componentHjarProcessingStep, 192 BindingMethodProcessingStep bindingMethodProcessingStep, 193 CompilerOptions compilerOptions) { 194 return ImmutableList.of( 195 mapKeyProcessingStep, 196 injectProcessingStep, 197 assistedInjectProcessingStep, 198 assistedFactoryProcessingStep, 199 assistedProcessingStep, 200 monitoringModuleProcessingStep, 201 multibindingAnnotationsProcessingStep, 202 bindsInstanceProcessingStep, 203 moduleProcessingStep, 204 compilerOptions.headerCompilation() 205 ? componentHjarProcessingStep 206 : componentProcessingStep, 207 bindingMethodProcessingStep); 208 } 209 } 210 211 @Override postRound(XProcessingEnv env, XRoundEnv roundEnv)212 public void postRound(XProcessingEnv env, XRoundEnv roundEnv) { 213 // TODO(bcorso): Add a way to determine if processing is over without converting to Javac here. 214 if (!XConverters.toJavac(roundEnv).processingOver()) { 215 try { 216 injectBindingRegistry.generateSourcesForRequiredBindings( 217 factoryGenerator, membersInjectorGenerator); 218 } catch (SourceFileGenerationException e) { 219 e.printMessageTo(env.getMessager()); 220 } 221 } 222 clearableCaches.forEach(ClearableCache::clearCache); 223 } 224 } 225