dagger.hilt.processor.internal.root.RootProcessingStep Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of hilt-compiler Show documentation
Show all versions of hilt-compiler Show documentation
A fast dependency injector for Android and Java.
/*
* Copyright (C) 2019 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.hilt.processor.internal.root;
import static com.google.common.base.Preconditions.checkState;
import static dagger.hilt.processor.internal.HiltCompilerOptions.isCrossCompilationRootValidationDisabled;
import static dagger.hilt.processor.internal.HiltCompilerOptions.isSharedTestComponentsEnabled;
import static dagger.hilt.processor.internal.HiltCompilerOptions.useAggregatingRootProcessor;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static java.util.Arrays.stream;
import androidx.room.compiler.processing.XElement;
import androidx.room.compiler.processing.XFiler.Mode;
import androidx.room.compiler.processing.XProcessingEnv;
import androidx.room.compiler.processing.XRoundEnv;
import androidx.room.compiler.processing.XTypeElement;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.BadInputException;
import dagger.hilt.processor.internal.BaseProcessingStep;
import dagger.hilt.processor.internal.aggregateddeps.AggregatedDepsMetadata;
import dagger.hilt.processor.internal.aliasof.AliasOfPropagatedDataMetadata;
import dagger.hilt.processor.internal.definecomponent.DefineComponentClassesMetadata;
import dagger.hilt.processor.internal.earlyentrypoint.AggregatedEarlyEntryPointMetadata;
import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputs;
import dagger.hilt.processor.internal.root.ir.AggregatedDepsIr;
import dagger.hilt.processor.internal.root.ir.AggregatedEarlyEntryPointIr;
import dagger.hilt.processor.internal.root.ir.AggregatedRootIr;
import dagger.hilt.processor.internal.root.ir.AggregatedRootIrValidator;
import dagger.hilt.processor.internal.root.ir.AggregatedUninstallModulesIr;
import dagger.hilt.processor.internal.root.ir.AliasOfPropagatedDataIr;
import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIr;
import dagger.hilt.processor.internal.root.ir.ComponentTreeDepsIrCreator;
import dagger.hilt.processor.internal.root.ir.DefineComponentClassesIr;
import dagger.hilt.processor.internal.root.ir.InvalidRootsException;
import dagger.hilt.processor.internal.root.ir.ProcessedRootSentinelIr;
import dagger.hilt.processor.internal.uninstallmodules.AggregatedUninstallModulesMetadata;
import dagger.internal.codegen.xprocessing.XElements;
import java.util.Set;
/** Processor that outputs dagger components based on transitive build deps. */
public final class RootProcessingStep extends BaseProcessingStep {
private boolean processed;
// TODO(b/297889547) do not run preProcess and postProcess if supported annotation isn't present
// in the environment.
private boolean hasElementsToProcess = false;
private GeneratesRootInputs generatesRootInputs;
public RootProcessingStep(XProcessingEnv env) {
super(env);
generatesRootInputs = new GeneratesRootInputs(processingEnv());
}
private Mode getMode() {
return useAggregatingRootProcessor(processingEnv()) ? Mode.Aggregating : Mode.Isolating;
}
@Override
protected ImmutableSet annotationClassNames() {
return stream(RootType.values()).map(RootType::className).collect(toImmutableSet());
}
@Override
public void processEach(ClassName annotation, XElement element) throws Exception {
hasElementsToProcess = true;
XTypeElement rootElement = XElements.asTypeElement(element);
// TODO(bcorso): Move this logic into a separate isolating processor to avoid regenerating it
// for unrelated changes in Gradle.
RootType rootType = RootType.of(rootElement);
if (rootType.isTestRoot()) {
new TestInjectorGenerator(processingEnv(), TestRootMetadata.of(processingEnv(), rootElement))
.generate();
}
XTypeElement originatingRootElement =
Root.create(rootElement, processingEnv()).originatingRootElement();
new AggregatedRootGenerator(
rootElement, originatingRootElement, processingEnv().requireTypeElement(annotation))
.generate();
}
@Override
protected void postProcess(XProcessingEnv env, XRoundEnv roundEnv) throws Exception {
if (!hasElementsToProcess) {
return;
}
if (!useAggregatingRootProcessor(processingEnv())) {
return;
}
ImmutableSet newElements =
generatesRootInputs.getElementsToWaitFor(roundEnv).stream().collect(toImmutableSet());
if (processed) {
checkState(
newElements.isEmpty(),
"Found extra modules after compilation: %s\n"
+ "(If you are adding an annotation processor that generates root input for hilt, "
+ "the annotation must be annotated with @dagger.hilt.GeneratesRootInput.\n)",
newElements.stream().map(XElements::toStableString).collect(toImmutableList()));
} else if (newElements.isEmpty()) {
processed = true;
ImmutableSet rootsToProcess = rootsToProcess();
if (rootsToProcess.isEmpty()) {
return;
}
// Generate an @ComponentTreeDeps for each unique component tree.
ComponentTreeDepsGenerator componentTreeDepsGenerator =
new ComponentTreeDepsGenerator(processingEnv(), getMode());
for (ComponentTreeDepsMetadata metadata : componentTreeDepsMetadatas(rootsToProcess)) {
componentTreeDepsGenerator.generate(metadata);
}
// Generate a sentinel for all processed roots.
for (AggregatedRootIr ir : rootsToProcess) {
XTypeElement rootElement = processingEnv().requireTypeElement(ir.getRoot().canonicalName());
new ProcessedRootSentinelGenerator(rootElement, getMode()).generate();
}
}
}
private ImmutableSet rootsToProcess() {
ImmutableSet processedRoots =
ProcessedRootSentinelMetadata.from(processingEnv()).stream()
.map(ProcessedRootSentinelMetadata::toIr)
.collect(toImmutableSet());
ImmutableSet aggregatedRoots =
AggregatedRootMetadata.from(processingEnv()).stream()
.map(AggregatedRootMetadata::toIr)
.collect(toImmutableSet());
boolean isCrossCompilationRootValidationDisabled =
isCrossCompilationRootValidationDisabled(
aggregatedRoots.stream()
.map(ir -> processingEnv().requireTypeElement(ir.getRoot().canonicalName()))
.collect(toImmutableSet()),
processingEnv());
try {
return ImmutableSet.copyOf(
AggregatedRootIrValidator.rootsToProcess(
isCrossCompilationRootValidationDisabled, processedRoots, aggregatedRoots));
} catch (InvalidRootsException ex) {
throw new BadInputException(ex.getMessage());
}
}
private ImmutableSet componentTreeDepsMetadatas(
ImmutableSet aggregatedRoots) {
ImmutableSet defineComponentDeps =
DefineComponentClassesMetadata.from(processingEnv()).stream()
.map(DefineComponentClassesMetadata::toIr)
.collect(toImmutableSet());
ImmutableSet aliasOfDeps =
AliasOfPropagatedDataMetadata.from(processingEnv()).stream()
.map(AliasOfPropagatedDataMetadata::toIr)
.collect(toImmutableSet());
ImmutableSet aggregatedDeps =
AggregatedDepsMetadata.from(processingEnv()).stream()
.map(AggregatedDepsMetadata::toIr)
.collect(toImmutableSet());
ImmutableSet aggregatedUninstallModulesDeps =
AggregatedUninstallModulesMetadata.from(processingEnv()).stream()
.map(AggregatedUninstallModulesMetadata::toIr)
.collect(toImmutableSet());
ImmutableSet aggregatedEarlyEntryPointDeps =
AggregatedEarlyEntryPointMetadata.from(processingEnv()).stream()
.map(AggregatedEarlyEntryPointMetadata::toIr)
.collect(toImmutableSet());
// We should be guaranteed that there are no mixed roots, so check if this is prod or test.
boolean isTest = aggregatedRoots.stream().anyMatch(AggregatedRootIr::isTestRoot);
Set componentTreeDeps =
ComponentTreeDepsIrCreator.components(
isTest,
isSharedTestComponentsEnabled(processingEnv()),
aggregatedRoots,
defineComponentDeps,
aliasOfDeps,
aggregatedDeps,
aggregatedUninstallModulesDeps,
aggregatedEarlyEntryPointDeps);
return componentTreeDeps.stream()
.map(it -> ComponentTreeDepsMetadata.from(it, processingEnv()))
.collect(toImmutableSet());
}
}