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 androidx.room.compiler.processing.XProcessingEnv; 20 import androidx.room.compiler.processing.XProcessingEnvConfig; 21 import androidx.room.compiler.processing.XProcessingStep; 22 import androidx.room.compiler.processing.XRoundEnv; 23 import androidx.room.compiler.processing.XTypeElement; 24 import com.google.common.collect.ImmutableList; 25 import com.google.common.collect.ImmutableSet; 26 import com.google.errorprone.annotations.CheckReturnValue; 27 import dagger.Binds; 28 import dagger.BindsInstance; 29 import dagger.Component; 30 import dagger.Module; 31 import dagger.Provides; 32 import dagger.internal.codegen.base.ClearableCache; 33 import dagger.internal.codegen.base.SourceFileGenerationException; 34 import dagger.internal.codegen.base.SourceFileGenerator; 35 import dagger.internal.codegen.base.SourceFileHjarGenerator; 36 import dagger.internal.codegen.binding.ComponentDescriptor; 37 import dagger.internal.codegen.binding.ContributionBinding; 38 import dagger.internal.codegen.binding.InjectBindingRegistry; 39 import dagger.internal.codegen.binding.MembersInjectionBinding; 40 import dagger.internal.codegen.binding.ModuleDescriptor; 41 import dagger.internal.codegen.binding.MonitoringModules; 42 import dagger.internal.codegen.binding.ProductionBinding; 43 import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModule; 44 import dagger.internal.codegen.compileroption.CompilerOptions; 45 import dagger.internal.codegen.componentgenerator.ComponentGeneratorModule; 46 import dagger.internal.codegen.kotlin.KotlinMetadataFactory; 47 import dagger.internal.codegen.processingstep.ProcessingStepsModule; 48 import dagger.internal.codegen.validation.AnyBindingMethodValidator; 49 import dagger.internal.codegen.validation.BindingMethodValidatorsModule; 50 import dagger.internal.codegen.validation.ComponentCreatorValidator; 51 import dagger.internal.codegen.validation.ComponentValidator; 52 import dagger.internal.codegen.validation.External; 53 import dagger.internal.codegen.validation.ExternalBindingGraphPlugins; 54 import dagger.internal.codegen.validation.InjectBindingRegistryModule; 55 import dagger.internal.codegen.validation.InjectValidator; 56 import dagger.internal.codegen.validation.ValidationBindingGraphPlugins; 57 import dagger.internal.codegen.writing.FactoryGenerator; 58 import dagger.internal.codegen.writing.MembersInjectorGenerator; 59 import dagger.internal.codegen.writing.ModuleGenerator; 60 import dagger.internal.codegen.writing.ModuleProxies.ModuleConstructorProxyGenerator; 61 import dagger.internal.codegen.writing.ProducerFactoryGenerator; 62 import dagger.multibindings.IntoSet; 63 import dagger.spi.model.BindingGraphPlugin; 64 import java.util.Optional; 65 import java.util.Set; 66 import javax.inject.Inject; 67 import javax.inject.Singleton; 68 import javax.tools.Diagnostic.Kind; 69 70 /** An implementation of Dagger's component processor that is shared between Javac and KSP. */ 71 final class DelegateComponentProcessor { 72 static final XProcessingEnvConfig PROCESSING_ENV_CONFIG = 73 new XProcessingEnvConfig.Builder().disableAnnotatedElementValidation(true).build(); 74 75 @Inject InjectBindingRegistry injectBindingRegistry; 76 @Inject SourceFileGenerator<ContributionBinding> factoryGenerator; 77 @Inject SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator; 78 @Inject ImmutableList<XProcessingStep> processingSteps; 79 @Inject ValidationBindingGraphPlugins validationBindingGraphPlugins; 80 @Inject ExternalBindingGraphPlugins externalBindingGraphPlugins; 81 @Inject Set<ClearableCache> clearableCaches; 82 initialize( XProcessingEnv env, Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins, Optional<ImmutableSet<dagger.spi.BindingGraphPlugin>> legacyTestingPlugins)83 public void initialize( 84 XProcessingEnv env, 85 Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins, 86 Optional<ImmutableSet<dagger.spi.BindingGraphPlugin>> legacyTestingPlugins) { 87 ImmutableSet<BindingGraphPlugin> plugins = 88 testingPlugins.orElseGet(() -> ServiceLoaders.loadServices(env, BindingGraphPlugin.class)); 89 ImmutableSet<dagger.spi.BindingGraphPlugin> legacyPlugins = 90 legacyTestingPlugins.orElseGet( 91 () -> ServiceLoaders.loadServices(env, dagger.spi.BindingGraphPlugin.class)); 92 if (env.getBackend() != XProcessingEnv.Backend.JAVAC) { 93 legacyPlugins.forEach( 94 legacyPlugin -> 95 env.getMessager() 96 .printMessage( 97 Kind.ERROR, 98 "Cannot use legacy dagger.spi.BindingGraphPlugin while compiling with KSP: " 99 + legacyPlugin.pluginName() 100 + ". Either compile with KAPT or migrate the plugin to implement " 101 + "dagger.spi.model.BindingGraphPlugin.")); 102 // Even though we've reported an error, processing will still continue for the remainder of 103 // the processing round to try to catch other errors. We set the javac plugins to empty to 104 // skip processing since it would just result in ClassCastExceptions in KSP. 105 legacyPlugins = ImmutableSet.of(); 106 } 107 DaggerDelegateComponentProcessor_Injector.factory() 108 .create(env, plugins, legacyPlugins) 109 .inject(this); 110 validationBindingGraphPlugins.initializePlugins(); 111 externalBindingGraphPlugins.initializePlugins(); 112 } 113 processingSteps()114 public Iterable<XProcessingStep> processingSteps() { 115 116 return processingSteps; 117 } 118 onProcessingRoundBegin()119 public void onProcessingRoundBegin() { 120 externalBindingGraphPlugins.onProcessingRoundBegin(); 121 } 122 postRound(XProcessingEnv env, XRoundEnv roundEnv)123 public void postRound(XProcessingEnv env, XRoundEnv roundEnv) { 124 if (!roundEnv.isProcessingOver()) { 125 try { 126 injectBindingRegistry.generateSourcesForRequiredBindings( 127 factoryGenerator, membersInjectorGenerator); 128 } catch (SourceFileGenerationException e) { 129 e.printMessageTo(env.getMessager()); 130 } 131 } else { 132 validationBindingGraphPlugins.endPlugins(); 133 externalBindingGraphPlugins.endPlugins(); 134 } 135 clearableCaches.forEach(ClearableCache::clearCache); 136 } 137 138 @Singleton 139 @Component( 140 modules = { 141 BindingGraphValidationModule.class, 142 BindingMethodValidatorsModule.class, 143 ComponentGeneratorModule.class, 144 InjectBindingRegistryModule.class, 145 ProcessingEnvironmentModule.class, 146 ProcessingRoundCacheModule.class, 147 ProcessingStepsModule.class, 148 SourceFileGeneratorsModule.class, 149 }) 150 interface Injector { inject(DelegateComponentProcessor processor)151 void inject(DelegateComponentProcessor processor); 152 153 @Component.Factory 154 interface Factory { 155 @CheckReturnValue create( @indsInstance XProcessingEnv processingEnv, @BindsInstance @External ImmutableSet<BindingGraphPlugin> externalPlugins, @BindsInstance @External ImmutableSet<dagger.spi.BindingGraphPlugin> legacyExternalPlugins)156 Injector create( 157 @BindsInstance XProcessingEnv processingEnv, 158 @BindsInstance @External ImmutableSet<BindingGraphPlugin> externalPlugins, 159 @BindsInstance @External 160 ImmutableSet<dagger.spi.BindingGraphPlugin> legacyExternalPlugins); 161 } 162 } 163 164 @Module 165 interface ProcessingRoundCacheModule { 166 @Binds 167 @IntoSet anyBindingMethodValidator(AnyBindingMethodValidator cache)168 ClearableCache anyBindingMethodValidator(AnyBindingMethodValidator cache); 169 170 @Binds 171 @IntoSet injectValidator(InjectValidator cache)172 ClearableCache injectValidator(InjectValidator cache); 173 174 @Binds 175 @IntoSet moduleDescriptorFactory(ModuleDescriptor.Factory cache)176 ClearableCache moduleDescriptorFactory(ModuleDescriptor.Factory cache); 177 178 @Binds 179 @IntoSet componentDescriptorFactory(ComponentDescriptor.Factory cache)180 ClearableCache componentDescriptorFactory(ComponentDescriptor.Factory cache); 181 182 @Binds 183 @IntoSet monitoringModules(MonitoringModules cache)184 ClearableCache monitoringModules(MonitoringModules cache); 185 186 @Binds 187 @IntoSet componentValidator(ComponentValidator cache)188 ClearableCache componentValidator(ComponentValidator cache); 189 190 @Binds 191 @IntoSet componentCreatorValidator(ComponentCreatorValidator cache)192 ClearableCache componentCreatorValidator(ComponentCreatorValidator cache); 193 194 @Binds 195 @IntoSet kotlinMetadata(KotlinMetadataFactory cache)196 ClearableCache kotlinMetadata(KotlinMetadataFactory cache); 197 } 198 199 @Module 200 interface SourceFileGeneratorsModule { 201 @Provides factoryGenerator( FactoryGenerator generator, CompilerOptions compilerOptions, XProcessingEnv processingEnv)202 static SourceFileGenerator<ContributionBinding> factoryGenerator( 203 FactoryGenerator generator, 204 CompilerOptions compilerOptions, 205 XProcessingEnv processingEnv) { 206 return hjarWrapper(generator, compilerOptions, processingEnv); 207 } 208 209 @Provides producerFactoryGenerator( ProducerFactoryGenerator generator, CompilerOptions compilerOptions, XProcessingEnv processingEnv)210 static SourceFileGenerator<ProductionBinding> producerFactoryGenerator( 211 ProducerFactoryGenerator generator, 212 CompilerOptions compilerOptions, 213 XProcessingEnv processingEnv) { 214 return hjarWrapper(generator, compilerOptions, processingEnv); 215 } 216 217 @Provides membersInjectorGenerator( MembersInjectorGenerator generator, CompilerOptions compilerOptions, XProcessingEnv processingEnv)218 static SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator( 219 MembersInjectorGenerator generator, 220 CompilerOptions compilerOptions, 221 XProcessingEnv processingEnv) { 222 return hjarWrapper(generator, compilerOptions, processingEnv); 223 } 224 225 @Provides 226 @ModuleGenerator moduleConstructorProxyGenerator( ModuleConstructorProxyGenerator generator, CompilerOptions compilerOptions, XProcessingEnv processingEnv)227 static SourceFileGenerator<XTypeElement> moduleConstructorProxyGenerator( 228 ModuleConstructorProxyGenerator generator, 229 CompilerOptions compilerOptions, 230 XProcessingEnv processingEnv) { 231 return hjarWrapper(generator, compilerOptions, processingEnv); 232 } 233 } 234 hjarWrapper( SourceFileGenerator<T> generator, CompilerOptions compilerOptions, XProcessingEnv processingEnv)235 private static <T> SourceFileGenerator<T> hjarWrapper( 236 SourceFileGenerator<T> generator, 237 CompilerOptions compilerOptions, 238 XProcessingEnv processingEnv) { 239 return compilerOptions.headerCompilation() 240 ? SourceFileHjarGenerator.wrap(generator, processingEnv) 241 : generator; 242 } 243 } 244