diff options
Diffstat (limited to 'java/dagger/hilt/processor/internal/root/RootProcessor.java')
-rw-r--r-- | java/dagger/hilt/processor/internal/root/RootProcessor.java | 207 |
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(); } } |