aboutsummaryrefslogtreecommitdiff
path: root/java/dagger/hilt/processor/internal/root/RootProcessor.java
diff options
context:
space:
mode:
Diffstat (limited to 'java/dagger/hilt/processor/internal/root/RootProcessor.java')
-rw-r--r--java/dagger/hilt/processor/internal/root/RootProcessor.java207
1 files changed, 42 insertions, 165 deletions
diff --git a/java/dagger/hilt/processor/internal/root/RootProcessor.java b/java/dagger/hilt/processor/internal/root/RootProcessor.java
index 1ee4446d4..8f8c94874 100644
--- a/java/dagger/hilt/processor/internal/root/RootProcessor.java
+++ b/java/dagger/hilt/processor/internal/root/RootProcessor.java
@@ -17,11 +17,8 @@
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.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
-import static java.util.Comparator.comparing;
import static javax.lang.model.element.Modifier.PUBLIC;
import static net.ltgt.gradle.incap.IncrementalAnnotationProcessorType.AGGREGATING;
@@ -31,17 +28,16 @@ import com.google.common.collect.ImmutableList;
import com.google.common.collect.ImmutableSet;
import com.squareup.javapoet.ClassName;
import dagger.hilt.processor.internal.BaseProcessor;
-import dagger.hilt.processor.internal.ClassNames;
-import dagger.hilt.processor.internal.ComponentDescriptor;
-import dagger.hilt.processor.internal.ComponentNames;
+import dagger.hilt.processor.internal.ComponentTree;
import dagger.hilt.processor.internal.ProcessorErrors;
import dagger.hilt.processor.internal.aggregateddeps.ComponentDependencies;
import dagger.hilt.processor.internal.definecomponent.DefineComponents;
import dagger.hilt.processor.internal.generatesrootinput.GeneratesRootInputs;
import java.io.IOException;
+import java.util.ArrayList;
import java.util.Arrays;
-import java.util.Comparator;
import java.util.HashSet;
+import java.util.List;
import java.util.Set;
import javax.annotation.processing.ProcessingEnvironment;
import javax.annotation.processing.Processor;
@@ -54,10 +50,9 @@ import net.ltgt.gradle.incap.IncrementalAnnotationProcessor;
@IncrementalAnnotationProcessor(AGGREGATING)
@AutoService(Processor.class)
public final class RootProcessor extends BaseProcessor {
- private static final Comparator<TypeElement> QUALIFIED_NAME_COMPARATOR =
- comparing(TypeElement::getQualifiedName, (n1, n2) -> n1.toString().compareTo(n2.toString()));
-
+ private final List<ClassName> rootNames = new ArrayList<>();
private final Set<ClassName> processed = new HashSet<>();
+ private boolean isTestEnv;
// TODO(bcorso): Consider using a Dagger component to create/scope these objects
private final DefineComponents defineComponents = DefineComponents.create();
private GeneratesRootInputs generatesRootInputs;
@@ -81,13 +76,25 @@ public final class RootProcessor extends BaseProcessor {
@Override
public void processEach(TypeElement annotation, Element element) throws Exception {
TypeElement rootElement = MoreElements.asType(element);
- RootType rootType = RootType.of(rootElement);
- if (rootType.isTestRoot()) {
+ boolean isTestRoot = RootType.of(getProcessingEnv(), rootElement).isTestRoot();
+ checkState(
+ rootNames.isEmpty() || isTestEnv == isTestRoot,
+ "Cannot mix test roots with non-test roots:"
+ + "\n\tNon-Test Roots: %s"
+ + "\n\tTest Roots: %s",
+ isTestRoot ? rootNames : rootElement,
+ isTestRoot ? rootElement : rootNames);
+ isTestEnv = isTestRoot;
+
+ rootNames.add(ClassName.get(rootElement));
+ if (isTestEnv) {
new TestInjectorGenerator(
- getProcessingEnv(), TestRootMetadata.of(getProcessingEnv(), rootElement))
- .generate();
+ getProcessingEnv(),
+ TestRootMetadata.of(getProcessingEnv(), rootElement)).generate();
+ } else {
+ ProcessorErrors.checkState(
+ rootNames.size() <= 1, element, "More than one root found: %s", rootNames);
}
- new AggregatedRootGenerator(rootElement, annotation, getProcessingEnv()).generate();
}
@Override
@@ -107,22 +114,14 @@ public final class RootProcessor extends BaseProcessor {
return;
}
- ImmutableSet<Root> allRoots =
- AggregatedRootMetadata.from(getElementUtils()).stream()
- .map(metadata -> Root.create(metadata.rootElement(), getProcessingEnv()))
- .collect(toImmutableSet());
-
- ImmutableSet<Root> processedRoots =
- ProcessedRootSentinelMetadata.from(getElementUtils()).stream()
- .flatMap(metadata -> metadata.rootElements().stream())
+ ImmutableList<Root> rootsToProcess =
+ rootNames.stream()
+ .filter(rootName -> !processed.contains(rootName))
+ // We create a new root element each round to avoid the jdk8 bug where
+ // TypeElement.equals does not work for elements across processing rounds.
+ .map(rootName -> getElementUtils().getTypeElement(rootName.toString()))
.map(rootElement -> Root.create(rootElement, getProcessingEnv()))
- .collect(toImmutableSet());
-
- ImmutableSet<Root> rootsToProcess =
- allRoots.stream()
- .filter(root -> !processedRoots.contains(root))
- .filter(root -> !processed.contains(rootName(root)))
- .collect(toImmutableSet());
+ .collect(toImmutableList());
if (rootsToProcess.isEmpty()) {
// Skip further processing since there's no roots that need processing.
@@ -133,163 +132,40 @@ public final class RootProcessor extends BaseProcessor {
// all roots. We should consider if it's worth trying to continue processing for other
// roots. At the moment, I think it's rare that if one root failed the others would not.
try {
- validateRoots(allRoots, rootsToProcess);
-
- boolean isTestEnv = rootsToProcess.stream().anyMatch(Root::isTestRoot);
- ComponentNames componentNames =
- isTestEnv && isSharedTestComponentsEnabled(getProcessingEnv())
- ? ComponentNames.withRenamingIntoPackage(
- ClassNames.DEFAULT_ROOT.packageName(),
- rootsToProcess.stream().map(Root::element).collect(toImmutableList()))
- : ComponentNames.withoutRenaming();
-
- ImmutableSet<ComponentDescriptor> componentDescriptors =
- defineComponents.getComponentDescriptors(getElementUtils());
- ComponentTree tree = ComponentTree.from(componentDescriptors);
- ComponentDependencies deps =
- ComponentDependencies.from(componentDescriptors, getElementUtils());
+ ComponentTree tree = defineComponents.getComponentTree(getElementUtils());
+ ComponentDependencies deps = ComponentDependencies.from(
+ tree.getComponentDescriptors(), getElementUtils());
ImmutableList<RootMetadata> rootMetadatas =
rootsToProcess.stream()
.map(root -> RootMetadata.create(root, tree, deps, getProcessingEnv()))
.collect(toImmutableList());
for (RootMetadata rootMetadata : rootMetadatas) {
- if (!rootMetadata.canShareTestComponents()) {
- generateComponents(rootMetadata, componentNames);
- }
+ setProcessingState(rootMetadata.root());
+ generateComponents(rootMetadata);
}
if (isTestEnv) {
- ImmutableList<RootMetadata> rootsThatCanShareComponents =
- rootMetadatas.stream()
- .filter(RootMetadata::canShareTestComponents)
- .collect(toImmutableList());
- generateTestComponentData(rootMetadatas, componentNames);
- if (deps.hasEarlyEntryPoints() || !rootsThatCanShareComponents.isEmpty()) {
- Root defaultRoot = Root.createDefaultRoot(getProcessingEnv());
- generateComponents(
- RootMetadata.createForDefaultRoot(
- defaultRoot, rootsThatCanShareComponents, tree, deps, getProcessingEnv()),
- componentNames);
- EarlySingletonComponentCreatorGenerator.generate(getProcessingEnv());
- }
+ generateTestComponentData(rootMetadatas);
}
} catch (Exception e) {
for (Root root : rootsToProcess) {
- processed.add(rootName(root));
+ processed.add(root.classname());
}
throw e;
- } finally {
- rootsToProcess.forEach(this::setProcessingState);
- // Calculate the roots processed in this round. We do this in the finally-block rather than in
- // the try-block because the catch-block can change the processing state.
- ImmutableSet<Root> rootsProcessedInRound =
- rootsToProcess.stream()
- // Only add a sentinel for processed roots. Skip preprocessed roots since those will
- // will be processed in the next round.
- .filter(root -> processed.contains(rootName(root)))
- .collect(toImmutableSet());
- for (Root root : rootsProcessedInRound) {
- new ProcessedRootSentinelGenerator(rootElement(root), getProcessingEnv()).generate();
- }
- }
- }
-
- private void validateRoots(ImmutableSet<Root> allRoots, ImmutableSet<Root> rootsToProcess) {
-
- ImmutableSet<TypeElement> rootElementsToProcess =
- rootsToProcess.stream()
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- ImmutableSet<TypeElement> appRootElementsToProcess =
- rootsToProcess.stream()
- .filter(root -> !root.isTestRoot())
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- // Perform validation between roots in this compilation unit.
- if (!appRootElementsToProcess.isEmpty()) {
- ImmutableSet<TypeElement> testRootElementsToProcess =
- rootsToProcess.stream()
- .filter(Root::isTestRoot)
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- ProcessorErrors.checkState(
- testRootElementsToProcess.isEmpty(),
- "Cannot process test roots and app roots in the same compilation unit:"
- + "\n\tApp root in this compilation unit: %s"
- + "\n\tTest roots in this compilation unit: %s",
- appRootElementsToProcess,
- testRootElementsToProcess);
-
- ProcessorErrors.checkState(
- appRootElementsToProcess.size() == 1,
- "Cannot process multiple app roots in the same compilation unit: %s",
- appRootElementsToProcess);
- }
-
- // Perform validation across roots previous compilation units.
- if (!isCrossCompilationRootValidationDisabled(rootElementsToProcess, getProcessingEnv())) {
- ImmutableSet<TypeElement> processedTestRootElements =
- allRoots.stream()
- .filter(Root::isTestRoot)
- .filter(root -> !rootsToProcess.contains(root))
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- // TODO(b/185742783): Add an explanation or link to docs to explain why we're forbidding this.
- ProcessorErrors.checkState(
- processedTestRootElements.isEmpty(),
- "Cannot process new roots when there are test roots from a previous compilation unit:"
- + "\n\tTest roots from previous compilation unit: %s"
- + "\n\tAll roots from this compilation unit: %s",
- processedTestRootElements,
- rootElementsToProcess);
-
- ImmutableSet<TypeElement> processedAppRootElements =
- allRoots.stream()
- .filter(root -> !root.isTestRoot())
- .filter(root -> !rootsToProcess.contains(root))
- .map(Root::element)
- .sorted(QUALIFIED_NAME_COMPARATOR)
- .collect(toImmutableSet());
-
- ProcessorErrors.checkState(
- processedAppRootElements.isEmpty() || appRootElementsToProcess.isEmpty(),
- "Cannot process app roots in this compilation unit since there are app roots in a "
- + "previous compilation unit:"
- + "\n\tApp roots in previous compilation unit: %s"
- + "\n\tApp roots in this compilation unit: %s",
- processedAppRootElements,
- appRootElementsToProcess);
}
}
private void setProcessingState(Root root) {
- processed.add(rootName(root));
+ processed.add(root.classname());
}
- private ClassName rootName(Root root) {
- return ClassName.get(rootElement(root));
+ private void generateComponents(RootMetadata rootMetadata) throws IOException {
+ RootGenerator.generate(rootMetadata, getProcessingEnv());
}
- private TypeElement rootElement(Root root) {
- return root.element();
- }
-
- private void generateComponents(RootMetadata rootMetadata, ComponentNames componentNames)
+ private void generateTestComponentData(ImmutableList<RootMetadata> rootMetadatas)
throws IOException {
- RootGenerator.generate(rootMetadata, componentNames, getProcessingEnv());
- }
-
- private void generateTestComponentData(
- ImmutableList<RootMetadata> rootMetadatas, ComponentNames componentNames) throws IOException {
for (RootMetadata rootMetadata : rootMetadatas) {
// TODO(bcorso): Consider moving this check earlier into processEach.
TypeElement testElement = rootMetadata.testRootMetadata().testElement();
@@ -298,7 +174,8 @@ public final class RootProcessor extends BaseProcessor {
testElement,
"Hilt tests must be public, but found: %s",
testElement);
- new TestComponentDataGenerator(getProcessingEnv(), rootMetadata, componentNames).generate();
+ new TestComponentDataGenerator(getProcessingEnv(), rootMetadata).generate();
}
+ new TestComponentDataSupplierGenerator(getProcessingEnv(), rootMetadatas).generate();
}
}