diff --git a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
index cdec4269a51..c94f6a977ab 100644
--- a/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
+++ b/java/dagger/hilt/android/processor/internal/androidentrypoint/AndroidEntryPointMetadata.java
@@ -16,7 +16,7 @@
package dagger.hilt.android.processor.internal.androidentrypoint;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.BooleanOption.DISABLE_ANDROID_SUPERCLASS_VALIDATION;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.isAndroidSuperclassValidationDisabled;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import com.google.auto.common.MoreElements;
@@ -245,7 +245,7 @@ private static AndroidEntryPointMetadata of(
final TypeElement baseElement;
final ClassName generatedClassName;
boolean requiresBytecodeInjection =
- DISABLE_ANDROID_SUPERCLASS_VALIDATION.get(env)
+ isAndroidSuperclassValidationDisabled(androidEntryPointElement, env)
&& MoreTypes.isTypeOf(Void.class, androidEntryPointClassValue.asType());
if (requiresBytecodeInjection) {
baseElement = MoreElements.asType(env.getTypeUtils().asElement(androidEntryPointElement.getSuperclass()));
diff --git a/java/dagger/hilt/processor/internal/BUILD b/java/dagger/hilt/processor/internal/BUILD
index 93dba0fb70b..978655dea55 100644
--- a/java/dagger/hilt/processor/internal/BUILD
+++ b/java/dagger/hilt/processor/internal/BUILD
@@ -154,6 +154,11 @@ java_library(
java_library(
name = "compiler_options",
srcs = ["HiltCompilerOptions.java"],
+ deps = [
+ ":processor_errors",
+ "//java/dagger/internal/guava:collect",
+ "@google_bazel_common//third_party/java/javapoet",
+ ],
)
filegroup(
diff --git a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
index 7cf82ee3f8a..0d248239bd9 100644
--- a/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
+++ b/java/dagger/hilt/processor/internal/HiltCompilerOptions.java
@@ -16,36 +16,74 @@
package dagger.hilt.processor.internal;
+import com.google.common.collect.ImmutableSet;
import java.util.Arrays;
import java.util.Set;
import java.util.stream.Collectors;
import javax.annotation.processing.ProcessingEnvironment;
+import javax.lang.model.element.TypeElement;
/** Hilt annotation processor options. */
// TODO(danysantiago): Consider consolidating with Dagger compiler options logic.
public final class HiltCompilerOptions {
+ /**
+ * Returns {@code true} if the superclass validation is disabled for
+ * {@link dagger.hilt.android.AndroidEntryPoint}-annotated classes.
+ *
+ * This flag is for internal use only! The superclass validation checks that the super class is a
+ * generated {@code Hilt_} class. This flag is disabled by the Hilt Gradle plugin to enable
+ * bytecode transformation to change the superclass.
+ */
+ public static boolean isAndroidSuperclassValidationDisabled(
+ TypeElement element, ProcessingEnvironment env) {
+ BooleanOption option = BooleanOption.DISABLE_ANDROID_SUPERCLASS_VALIDATION;
+ return option.get(env);
+ }
+
+ /**
+ * Returns {@code true} if cross-compilation root validation is disabled.
+ *
+ *
This flag should rarely be needed, but may be used for legacy/migration purposes if
+ * tests require the use of {@link dagger.hilt.android.HiltAndroidApp} rather than
+ * {@link dagger.hilt.android.testing.HiltAndroidTest}.
+ *
+ *
Note that Hilt still does validation within a single compilation unit. In particular,
+ * a compilation unit that contains a {@code HiltAndroidApp} usage cannot have other
+ * {@code HiltAndroidApp} or {@code HiltAndroidTest} usages in the same compilation unit.
+ */
+ public static boolean isCrossCompilationRootValidationDisabled(
+ ImmutableSet rootElements, ProcessingEnvironment env) {
+ BooleanOption option = BooleanOption.DISABLE_CROSS_COMPILATION_ROOT_VALIDATION;
+ return option.get(env);
+ }
+
+ /** Returns {@code true} if the check for {@link dagger.hilt.InstallIn} is disabled. */
+ public static boolean isModuleInstallInCheckDisabled(ProcessingEnvironment env) {
+ return BooleanOption.DISABLE_MODULES_HAVE_INSTALL_IN_CHECK.get(env);
+ }
+
+ /**
+ * Returns {@code true} of unit tests should try to share generated components, rather than using
+ * separate generated components per Hilt test root.
+ *
+ *
Tests that provide their own test bindings (e.g. using {@link
+ * dagger.hilt.android.testing.BindValue} or a test {@link dagger.Module}) cannot use the shared
+ * component. In these cases, a component will be generated for the test.
+ */
+ public static boolean isSharedTestComponentsEnabled(ProcessingEnvironment env) {
+ return BooleanOption.SHARE_TEST_COMPONENTS.get(env);
+ }
+
/** Processor options which can have true or false values. */
- public enum BooleanOption {
- /**
- * Flag that disables validating the superclass of @AndroidEntryPoint are Hilt_ generated,
- * classes. This flag is to be used internally by the Gradle plugin, enabling the bytecode
- * transformation to change the superclass.
- */
+ private enum BooleanOption {
DISABLE_ANDROID_SUPERCLASS_VALIDATION(
"android.internal.disableAndroidSuperclassValidation", false),
- /** Flag that disables check on modules to be annotated with @InstallIn. */
+ DISABLE_CROSS_COMPILATION_ROOT_VALIDATION("disableCrossCompilationRootValidation", false),
+
DISABLE_MODULES_HAVE_INSTALL_IN_CHECK("disableModulesHaveInstallInCheck", false),
- /**
- * Flag that enables unit tests to share a single generated Component, rather than using a
- * separate generated Component per Hilt test root.
- *
- *
Tests that provide their own test bindings (e.g. using {@link
- * dagger.hilt.android.testing.BindValue} or a test {@link dagger.Module}) cannot use the shared
- * component. In these cases, a component will be generated for the test.
- */
SHARE_TEST_COMPONENTS("shareTestComponents", false);
private final String name;
@@ -56,7 +94,7 @@ public enum BooleanOption {
this.defaultValue = defaultValue;
}
- public boolean get(ProcessingEnvironment env) {
+ boolean get(ProcessingEnvironment env) {
String value = env.getOptions().get(getQualifiedName());
if (value == null) {
return defaultValue;
@@ -65,7 +103,7 @@ public boolean get(ProcessingEnvironment env) {
return Boolean.parseBoolean(value);
}
- public String getQualifiedName() {
+ String getQualifiedName() {
return "dagger.hilt." + name;
}
}
@@ -75,6 +113,4 @@ public static Set getProcessorOptions() {
.map(BooleanOption::getQualifiedName)
.collect(Collectors.toSet());
}
-
- private HiltCompilerOptions() {}
}
diff --git a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
index c45b373cbb5..151401e6082 100644
--- a/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
+++ b/java/dagger/hilt/processor/internal/aggregateddeps/AggregatedDepsProcessor.java
@@ -20,7 +20,7 @@
import static com.google.auto.common.MoreElements.asType;
import static com.google.auto.common.MoreElements.getPackage;
import static com.google.common.collect.Iterables.getOnlyElement;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.BooleanOption.DISABLE_MODULES_HAVE_INSTALL_IN_CHECK;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.isModuleInstallInCheckDisabled;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableList;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static javax.lang.model.element.ElementKind.CLASS;
@@ -398,7 +398,7 @@ private static boolean isValidKind(Element element) {
}
private boolean installInCheckDisabled(Element element) {
- return DISABLE_MODULES_HAVE_INSTALL_IN_CHECK.get(getProcessingEnv())
+ return isModuleInstallInCheckDisabled(getProcessingEnv())
|| Processors.hasAnnotation(element, ClassNames.DISABLE_INSTALL_IN_CHECK);
}
diff --git a/java/dagger/hilt/processor/internal/root/RootMetadata.java b/java/dagger/hilt/processor/internal/root/RootMetadata.java
index 1a115034ff1..b39b590efc6 100644
--- a/java/dagger/hilt/processor/internal/root/RootMetadata.java
+++ b/java/dagger/hilt/processor/internal/root/RootMetadata.java
@@ -18,7 +18,7 @@
import static com.google.common.base.Preconditions.checkState;
import static com.google.common.base.Suppliers.memoize;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.BooleanOption.SHARE_TEST_COMPONENTS;
+import static dagger.hilt.processor.internal.HiltCompilerOptions.isSharedTestComponentsEnabled;
import static dagger.internal.codegen.extension.DaggerStreams.toImmutableSet;
import static javax.lang.model.element.Modifier.ABSTRACT;
import static javax.lang.model.element.Modifier.PRIVATE;
@@ -133,7 +133,7 @@ public ImmutableSet modules(ClassName componentName) {
// TODO(groakley): Allow more tests to share modules, e.g. tests that uninstall the same module.
// In that case, this might instead return which shared dep grouping should be used.
public boolean canShareTestComponents() {
- return SHARE_TEST_COMPONENTS.get(env)
+ return isSharedTestComponentsEnabled(env)
&& root.isTestRoot()
&& !deps.includesTestDeps(root.classname());
}
diff --git a/java/dagger/hilt/processor/internal/root/RootProcessor.java b/java/dagger/hilt/processor/internal/root/RootProcessor.java
index 3ef8963641d..1ee4446d48c 100644
--- a/java/dagger/hilt/processor/internal/root/RootProcessor.java
+++ b/java/dagger/hilt/processor/internal/root/RootProcessor.java
@@ -17,7 +17,8 @@
package dagger.hilt.processor.internal.root;
import static com.google.common.base.Preconditions.checkState;
-import static dagger.hilt.processor.internal.HiltCompilerOptions.BooleanOption.SHARE_TEST_COMPONENTS;
+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;
@@ -136,7 +137,7 @@ public void postRoundProcess(RoundEnvironment roundEnv) throws Exception {
boolean isTestEnv = rootsToProcess.stream().anyMatch(Root::isTestRoot);
ComponentNames componentNames =
- isTestEnv && SHARE_TEST_COMPONENTS.get(getProcessingEnv())
+ isTestEnv && isSharedTestComponentsEnabled(getProcessingEnv())
? ComponentNames.withRenamingIntoPackage(
ClassNames.DEFAULT_ROOT.packageName(),
rootsToProcess.stream().map(Root::element).collect(toImmutableList()))
@@ -202,23 +203,6 @@ private void validateRoots(ImmutableSet allRoots, ImmutableSet roots
.sorted(QUALIFIED_NAME_COMPARATOR)
.collect(toImmutableSet());
- ImmutableSet 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 appRootElementsToProcess =
rootsToProcess.stream()
.filter(root -> !root.isTestRoot())
@@ -226,6 +210,7 @@ private void validateRoots(ImmutableSet allRoots, ImmutableSet roots
.sorted(QUALIFIED_NAME_COMPARATOR)
.collect(toImmutableSet());
+ // Perform validation between roots in this compilation unit.
if (!appRootElementsToProcess.isEmpty()) {
ImmutableSet testRootElementsToProcess =
rootsToProcess.stream()
@@ -242,6 +227,31 @@ private void validateRoots(ImmutableSet allRoots, ImmutableSet roots
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 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 processedAppRootElements =
allRoots.stream()
.filter(root -> !root.isTestRoot())
@@ -251,18 +261,13 @@ private void validateRoots(ImmutableSet allRoots, ImmutableSet roots
.collect(toImmutableSet());
ProcessorErrors.checkState(
- processedAppRootElements.isEmpty(),
+ 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);
-
- ProcessorErrors.checkState(
- appRootElementsToProcess.size() == 1,
- "Cannot process multiple app roots in the same compilation unit: %s",
- appRootElementsToProcess);
}
}
diff --git a/javatests/dagger/hilt/processor/internal/root/BUILD b/javatests/dagger/hilt/processor/internal/root/BUILD
index 084ad23ba5c..0dba875c760 100644
--- a/javatests/dagger/hilt/processor/internal/root/BUILD
+++ b/javatests/dagger/hilt/processor/internal/root/BUILD
@@ -40,6 +40,7 @@ compiler_test(
"@maven//:androidx_test_core",
],
deps = [
+ "//java/dagger/internal/guava:collect",
"//javatests/dagger/hilt/android/processor:android_compilers",
"@google_bazel_common//third_party/java/compile_testing",
"@google_bazel_common//third_party/java/junit",
@@ -70,6 +71,7 @@ compiler_test(
"@maven//:androidx_test_core",
],
deps = [
+ "//java/dagger/internal/guava:collect",
"//javatests/dagger/hilt/android/processor:android_compilers",
"@google_bazel_common//third_party/java/compile_testing",
"@google_bazel_common//third_party/java/junit",
@@ -90,6 +92,7 @@ compiler_test(
"@maven//:androidx_test_core",
],
deps = [
+ "//java/dagger/internal/guava:collect",
"//javatests/dagger/hilt/android/processor:android_compilers",
"@google_bazel_common//third_party/java/compile_testing",
"@google_bazel_common//third_party/java/junit",
diff --git a/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java b/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
index 72b32f10835..adf6d9b2de1 100644
--- a/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
+++ b/javatests/dagger/hilt/processor/internal/root/MyAppPreviousCompilationTest.java
@@ -17,17 +17,41 @@
package dagger.hilt.processor.internal.root;
import static com.google.testing.compile.CompilationSubject.assertThat;
-import static dagger.hilt.android.processor.AndroidCompilers.compiler;
+import com.google.common.collect.ImmutableCollection;
+import com.google.common.collect.ImmutableList;
import com.google.testing.compile.Compilation;
+import com.google.testing.compile.Compiler;
import com.google.testing.compile.JavaFileObjects;
+import dagger.hilt.android.processor.AndroidCompilers;
import javax.tools.JavaFileObject;
import org.junit.Test;
import org.junit.runner.RunWith;
-import org.junit.runners.JUnit4;
+import org.junit.runners.Parameterized;
+import org.junit.runners.Parameterized.Parameters;
-@RunWith(JUnit4.class)
+@RunWith(Parameterized.class)
public final class MyAppPreviousCompilationTest {
+
+ @Parameters(name = "{0}")
+ public static ImmutableCollection