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