• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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