• 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.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