/*
* Copyright (C) 2014 The Dagger Authors.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package dagger.internal.codegen;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.ISOLATING;
import com.google.auto.common.BasicAnnotationProcessor;
import com.google.auto.service.AutoService;
import com.google.common.annotations.VisibleForTesting;
import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.google.common.collect.Sets;
import com.google.errorprone.annotations.CheckReturnValue;
import dagger.BindsInstance;
import dagger.Component;
import dagger.Module;
import dagger.Provides;
import dagger.internal.codegen.SpiModule.TestingPlugins;
import dagger.internal.codegen.base.ClearableCache;
import dagger.internal.codegen.base.SourceFileGenerationException;
import dagger.internal.codegen.base.SourceFileGenerator;
import dagger.internal.codegen.binding.InjectBindingRegistry;
import dagger.internal.codegen.binding.MembersInjectionBinding;
import dagger.internal.codegen.binding.ProvisionBinding;
import dagger.internal.codegen.bindinggraphvalidation.BindingGraphValidationModule;
import dagger.internal.codegen.compileroption.CompilerOptions;
import dagger.internal.codegen.compileroption.ProcessingEnvironmentCompilerOptions;
import dagger.internal.codegen.componentgenerator.ComponentGeneratorModule;
import dagger.internal.codegen.validation.BindingGraphPlugins;
import dagger.internal.codegen.validation.BindingMethodProcessingStep;
import dagger.internal.codegen.validation.BindingMethodValidatorsModule;
import dagger.internal.codegen.validation.BindsInstanceProcessingStep;
import dagger.internal.codegen.validation.InjectBindingRegistryModule;
import dagger.internal.codegen.validation.MonitoringModuleProcessingStep;
import dagger.internal.codegen.validation.MultibindingAnnotationsProcessingStep;
import dagger.spi.BindingGraphPlugin;
import java.util.Arrays;
import java.util.Optional;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
import javax.annotation.processing.RoundEnvironment;
import javax.inject.Inject;
import javax.inject.Singleton;
import javax.lang.model.SourceVersion;
import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
/**
* The annotation processor responsible for generating the classes that drive the Dagger 2.0
* implementation.
*
*
TODO(gak): give this some better documentation
*/
@IncrementalAnnotationProcessor(ISOLATING)
@AutoService(Processor.class)
public class ComponentProcessor extends BasicAnnotationProcessor {
private final Optional> testingPlugins;
@Inject InjectBindingRegistry injectBindingRegistry;
@Inject SourceFileGenerator factoryGenerator;
@Inject SourceFileGenerator membersInjectorGenerator;
@Inject ImmutableList processingSteps;
@Inject BindingGraphPlugins bindingGraphPlugins;
@Inject Set clearableCaches;
public ComponentProcessor() {
this.testingPlugins = Optional.empty();
}
private ComponentProcessor(Iterable testingPlugins) {
this.testingPlugins = Optional.of(ImmutableSet.copyOf(testingPlugins));
}
/**
* Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading
* them from a {@link java.util.ServiceLoader}.
*/
@VisibleForTesting
public static ComponentProcessor forTesting(BindingGraphPlugin... testingPlugins) {
return forTesting(Arrays.asList(testingPlugins));
}
/**
* Creates a component processor that uses given {@link BindingGraphPlugin}s instead of loading
* them from a {@link java.util.ServiceLoader}.
*/
@VisibleForTesting
public static ComponentProcessor forTesting(Iterable testingPlugins) {
return new ComponentProcessor(testingPlugins);
}
@Override
public SourceVersion getSupportedSourceVersion() {
return SourceVersion.latestSupported();
}
@Override
public Set getSupportedOptions() {
return Sets.union(
ProcessingEnvironmentCompilerOptions.supportedOptions(),
bindingGraphPlugins.allSupportedOptions())
.immutableCopy();
}
@Override
protected Iterable extends ProcessingStep> initSteps() {
ProcessorComponent.factory().create(processingEnv, testingPlugins).inject(this);
bindingGraphPlugins.initializePlugins();
return processingSteps;
}
@Singleton
@Component(
modules = {
BindingGraphValidationModule.class,
BindingMethodValidatorsModule.class,
ComponentGeneratorModule.class,
InjectBindingRegistryModule.class,
ProcessingEnvironmentModule.class,
ProcessingRoundCacheModule.class,
ProcessingStepsModule.class,
SourceFileGeneratorsModule.class,
SpiModule.class
})
interface ProcessorComponent {
void inject(ComponentProcessor processor);
static Factory factory() {
return DaggerComponentProcessor_ProcessorComponent.factory();
}
@Component.Factory
interface Factory {
@CheckReturnValue
ProcessorComponent create(
@BindsInstance ProcessingEnvironment processingEnv,
@BindsInstance @TestingPlugins Optional> testingPlugins);
}
}
@Module
interface ProcessingStepsModule {
@Provides
static ImmutableList processingSteps(
MapKeyProcessingStep mapKeyProcessingStep,
InjectProcessingStep injectProcessingStep,
AssistedInjectProcessingStep assistedInjectProcessingStep,
AssistedFactoryProcessingStep assistedFactoryProcessingStep,
AssistedProcessingStep assistedProcessingStep,
MonitoringModuleProcessingStep monitoringModuleProcessingStep,
MultibindingAnnotationsProcessingStep multibindingAnnotationsProcessingStep,
BindsInstanceProcessingStep bindsInstanceProcessingStep,
ModuleProcessingStep moduleProcessingStep,
ComponentProcessingStep componentProcessingStep,
ComponentHjarProcessingStep componentHjarProcessingStep,
BindingMethodProcessingStep bindingMethodProcessingStep,
CompilerOptions compilerOptions) {
return ImmutableList.of(
mapKeyProcessingStep,
injectProcessingStep,
assistedInjectProcessingStep,
assistedFactoryProcessingStep,
assistedProcessingStep,
monitoringModuleProcessingStep,
multibindingAnnotationsProcessingStep,
bindsInstanceProcessingStep,
moduleProcessingStep,
compilerOptions.headerCompilation()
? componentHjarProcessingStep
: componentProcessingStep,
bindingMethodProcessingStep);
}
}
@Override
protected void postRound(RoundEnvironment roundEnv) {
if (!roundEnv.processingOver()) {
try {
injectBindingRegistry.generateSourcesForRequiredBindings(
factoryGenerator, membersInjectorGenerator);
} catch (SourceFileGenerationException e) {
e.printMessageTo(processingEnv.getMessager());
}
}
clearableCaches.forEach(ClearableCache::clearCache);
}
}