• 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 static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.DYNAMIC;
20 
21 import com.google.auto.common.BasicAnnotationProcessor;
22 import com.google.auto.service.AutoService;
23 import com.google.common.annotations.VisibleForTesting;
24 import com.google.common.collect.ImmutableList;
25 import com.google.common.collect.ImmutableSet;
26 import com.google.common.collect.Iterables;
27 import com.google.errorprone.annotations.CanIgnoreReturnValue;
28 import com.google.errorprone.annotations.CheckReturnValue;
29 import dagger.BindsInstance;
30 import dagger.Component;
31 import dagger.Module;
32 import dagger.Provides;
33 import dagger.internal.codegen.SpiModule.TestingPlugins;
34 import dagger.spi.BindingGraphPlugin;
35 import java.util.Arrays;
36 import java.util.Optional;
37 import java.util.Set;
38 import javax.annotation.processing.Processor;
39 import javax.annotation.processing.RoundEnvironment;
40 import javax.inject.Inject;
41 import javax.inject.Singleton;
42 import javax.lang.model.SourceVersion;
43 import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
44 
45 /**
46  * The annotation processor responsible for generating the classes that drive the Dagger 2.0
47  * implementation.
48  *
49  * <p>TODO(gak): give this some better documentation
50  */
51 @IncrementalAnnotationProcessor(DYNAMIC)
52 @AutoService(Processor.class)
53 public class ComponentProcessor extends BasicAnnotationProcessor {
54   private final Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins;
55 
56   @Inject InjectBindingRegistry injectBindingRegistry;
57   @Inject SourceFileGenerator<ProvisionBinding> factoryGenerator;
58   @Inject SourceFileGenerator<MembersInjectionBinding> membersInjectorGenerator;
59   @Inject ImmutableList<ProcessingStep> processingSteps;
60   @Inject BindingGraphPlugins bindingGraphPlugins;
61   @Inject CompilerOptions compilerOptions;
62   @Inject DaggerStatisticsCollector statisticsCollector;
63   @Inject Set<ClearableCache> clearableCaches;
64 
ComponentProcessor()65   public ComponentProcessor() {
66     this.testingPlugins = Optional.empty();
67   }
68 
ComponentProcessor(Iterable<BindingGraphPlugin> testingPlugins)69   private ComponentProcessor(Iterable<BindingGraphPlugin> testingPlugins) {
70     this.testingPlugins = Optional.of(ImmutableSet.copyOf(testingPlugins));
71   }
72 
73   /**
74    * Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading
75    * them from a {@link java.util.ServiceLoader}.
76    */
77   @VisibleForTesting
forTesting(BindingGraphPlugin... testingPlugins)78   public static ComponentProcessor forTesting(BindingGraphPlugin... testingPlugins) {
79     return forTesting(Arrays.asList(testingPlugins));
80   }
81 
82   /**
83    * Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading
84    * them from a {@link java.util.ServiceLoader}.
85    */
86   @VisibleForTesting
forTesting(Iterable<BindingGraphPlugin> testingPlugins)87   public static ComponentProcessor forTesting(Iterable<BindingGraphPlugin> testingPlugins) {
88     return new ComponentProcessor(testingPlugins);
89   }
90 
91   @Override
getSupportedSourceVersion()92   public SourceVersion getSupportedSourceVersion() {
93     return SourceVersion.latestSupported();
94   }
95 
96   @Override
getSupportedOptions()97   public Set<String> getSupportedOptions() {
98     ImmutableSet.Builder<String> options = ImmutableSet.builder();
99     options.addAll(ProcessingEnvironmentCompilerOptions.supportedOptions());
100     options.addAll(bindingGraphPlugins.allSupportedOptions());
101     if (compilerOptions.useGradleIncrementalProcessing()) {
102       options.add("org.gradle.annotation.processing.isolating");
103     }
104     return options.build();
105   }
106 
107   @Override
initSteps()108   protected Iterable<? extends ProcessingStep> initSteps() {
109     ProcessorComponent.builder()
110         .processingEnvironmentModule(new ProcessingEnvironmentModule(processingEnv))
111         .testingPlugins(testingPlugins)
112         .build()
113         .inject(this);
114 
115     statisticsCollector.processingStarted();
116     bindingGraphPlugins.initializePlugins();
117     return Iterables.transform(
118         processingSteps,
119         step -> new DaggerStatisticsCollectingProcessingStep(step, statisticsCollector));
120   }
121 
122   @Singleton
123   @Component(
124       modules = {
125         BindingGraphValidationModule.class,
126         BindingMethodValidatorsModule.class,
127         InjectBindingRegistryModule.class,
128         ProcessingEnvironmentModule.class,
129         ProcessingRoundCacheModule.class,
130         ProcessingStepsModule.class,
131         SourceFileGeneratorsModule.class,
132         SpiModule.class,
133         SystemComponentsModule.class,
134         TopLevelImplementationComponent.InstallationModule.class,
135       })
136   interface ProcessorComponent {
inject(ComponentProcessor processor)137     void inject(ComponentProcessor processor);
138 
builder()139     static Builder builder() {
140       return DaggerComponentProcessor_ProcessorComponent.builder();
141     }
142 
143     @CanIgnoreReturnValue
144     @Component.Builder
145     interface Builder {
processingEnvironmentModule(ProcessingEnvironmentModule module)146       Builder processingEnvironmentModule(ProcessingEnvironmentModule module);
147 
148       @BindsInstance
testingPlugins( @estingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins)149       Builder testingPlugins(
150           @TestingPlugins Optional<ImmutableSet<BindingGraphPlugin>> testingPlugins);
151 
build()152       @CheckReturnValue ProcessorComponent build();
153     }
154   }
155 
156   @Module
157   interface ProcessingStepsModule {
158     @Provides
processingSteps( MapKeyProcessingStep mapKeyProcessingStep, InjectProcessingStep injectProcessingStep, MonitoringModuleProcessingStep monitoringModuleProcessingStep, MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep, BindsInstanceProcessingStep bindsInstanceProcessingStep, ModuleProcessingStep moduleProcessingStep, ComponentProcessingStep componentProcessingStep, ComponentHjarProcessingStep componentHjarProcessingStep, BindingMethodProcessingStep bindingMethodProcessingStep, CompilerOptions compilerOptions)159     static ImmutableList<ProcessingStep> processingSteps(
160         MapKeyProcessingStep mapKeyProcessingStep,
161         InjectProcessingStep injectProcessingStep,
162         MonitoringModuleProcessingStep monitoringModuleProcessingStep,
163         MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep,
164         BindsInstanceProcessingStep bindsInstanceProcessingStep,
165         ModuleProcessingStep moduleProcessingStep,
166         ComponentProcessingStep componentProcessingStep,
167         ComponentHjarProcessingStep componentHjarProcessingStep,
168         BindingMethodProcessingStep bindingMethodProcessingStep,
169         CompilerOptions compilerOptions) {
170       return ImmutableList.of(
171           mapKeyProcessingStep,
172           injectProcessingStep,
173           monitoringModuleProcessingStep,
174           multibindingAnnotationsProcessingStep,
175           bindsInstanceProcessingStep,
176           moduleProcessingStep,
177           compilerOptions.headerCompilation()
178                   // Ahead Of Time subcomponents use the regular hjar filtering in
179                   // HjarSourceFileGenerator since they must retain protected implementation methods
180                   // between subcomponents
181                   && !compilerOptions.aheadOfTimeSubcomponents()
182               ? componentHjarProcessingStep
183               : componentProcessingStep,
184           bindingMethodProcessingStep);
185     }
186   }
187 
188   @Override
postRound(RoundEnvironment roundEnv)189   protected void postRound(RoundEnvironment roundEnv) {
190     statisticsCollector.roundFinished();
191     if (roundEnv.processingOver()) {
192       statisticsCollector.processingStopped();
193     } else {
194       try {
195         injectBindingRegistry.generateSourcesForRequiredBindings(
196             factoryGenerator, membersInjectorGenerator);
197       } catch (SourceFileGenerationException e) {
198         e.printMessageTo(processingEnv.getMessager());
199       }
200     }
201     clearableCaches.forEach(ClearableCache::clearCache);
202   }
203 }
204