aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndroid Build Coastguard Worker <android-build-coastguard-worker@google.com>2022-02-11 19:55:07 +0000
committerGerrit Code Review <noreply-gerritcodereview@google.com>2022-02-11 19:55:07 +0000
commit711a2ff538884d269fe3a31db2f840ca2aae2da9 (patch)
treec9599cae94bced2ebf7ef7465d6c0dfe78c1878c
parente6648bf1055fd88d069bd6bdcde68e4897de1a43 (diff)
parent2c5196bad0c5f793890ed0510cf016bdaa47acc6 (diff)
downloadsupport-snap-temp-L35000000953028468.tar.gz
Merge "Add API for disabling XProcessing built-in validation" into snap-temp-L35000000953028468snap-temp-L35000000953028468
-rw-r--r--room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt26
-rw-r--r--room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt42
-rw-r--r--room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt4
-rw-r--r--room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt2
-rw-r--r--room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt104
5 files changed, 156 insertions, 22 deletions
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt
index e3b1bc0ecfa..381902f4f5c 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt
@@ -26,16 +26,19 @@ import javax.tools.Diagnostic
* [androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor].
*
* The XProcessing Javac and KSP implementations of this interface will automatically validate and
- * defer annotated elements for the steps. If no valid annotated element is found for a
- * [XProcessingStep] then its [XProcessingStep.process] function will not be invoked, except for
- * the last round in which [XProcessingStep.processOver] is invoked regardless if the annotated
- * elements are valid or not. If there were invalid annotated elements until the last round, then
- * the XProcessing implementations will report an error for each invalid element.
+ * defer annotated elements for the steps, unless disabled via
+ * [XProcessingEnvConfig.disableAnnotatedElementValidation]. If validation is enable and no valid
+ * annotated element is found for a [XProcessingStep] then its [XProcessingStep.process] function
+ * will not be invoked, except for the last round in which [XProcessingStep.processOver] is invoked
+ * regardless if the annotated elements are valid or not. If there were invalid annotated elements
+ * until the last round, then the XProcessing implementations will report an error for each invalid
+ * element. If validation is disabled, no error is reported if there are invalid elements found in
+ * the ast round.
*
* Be aware that even though the similarity in name, the Javac implementation of this interface
- * is not 1:1 with [com.google.auto.common.BasicAnnotationProcessor]. Specifically, validation is
- * done for each annotated element as opposed to the enclosing type element of the annotated
- * elements for the [XProcessingStep].
+ * is not 1:1 with [com.google.auto.common.BasicAnnotationProcessor]. Specifically, when validation
+ * is enabled it is done for each annotated element as opposed to the enclosing type element of the
+ * annotated elements for the [XProcessingStep].
*/
interface XBasicAnnotationProcessor {
@@ -95,7 +98,12 @@ internal class CommonProcessorDelegate(
// Split between valid and invalid elements. Unlike auto-common, validation is only
// done in the annotated element from the round and not in the closest enclosing
// type element.
- val (validElements, invalidElements) = annotatedElements.partition { it.validate() }
+ val (validElements, invalidElements) =
+ if (env.config.disableAnnotatedElementValidation) {
+ annotatedElements to emptySet<XElement>()
+ } else {
+ annotatedElements.partition { it.validate() }
+ }
deferredElements.addAll(invalidElements)
(validElements + stepDeferredElementsByAnnotation.getValue(annotation)).let {
if (it.isNotEmpty()) {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt
index 6677e68cdc0..e6b21cb2cdf 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingEnvConfig.kt
@@ -32,9 +32,28 @@ package androidx.room.compiler.processing
@Suppress("SyntheticAccessor", "DataClassPrivateConstructor")
data class XProcessingEnvConfig private constructor(
/**
- * @see [Builder.excludeMethodsWithInvalidJvmSourceNames] for docs.
+ * When set to `true`, XProcessingEnv will hide all methods that have invalid source names
+ * in Java (i.e. cannot be called from generated Java sources).
+ *
+ * Doing this resolution is expensive (requires type resolution) hence it is set to `false`
+ * by default.
+ *
+ * Note that, due to KAPT stubs, this is not 100% consistent between KAPT and KSP when set
+ * to `false`. Since KAPT generates stubs, it automatically removes methods that have
+ * invalid JVM names.
*/
- val excludeMethodsWithInvalidJvmSourceNames: Boolean = false
+ val excludeMethodsWithInvalidJvmSourceNames: Boolean = false,
+
+ /**
+ * When set to `true`, [XBasicAnnotationProcessor] will not validate annotated elements
+ * in the round before passing them to the various [XProcessingStep]s. Enabling this
+ * options essentially disabled the built-in element deferring mechanism offered by
+ * XProcessing.
+ *
+ * This option can be useful for processor with a custom and more precise validation as
+ * the built-in validation can be too broad.
+ */
+ val disableAnnotatedElementValidation: Boolean = false,
) {
fun toBuilder() = Builder(this)
@@ -44,15 +63,7 @@ data class XProcessingEnvConfig private constructor(
private var instance = baseline
/**
- * When set to `true`, XProcessingEnv will hide all methods that have invalid source names
- * in Java (i.e. cannot be called from generated Java sources).
- *
- * Doing this resolution is expensive (requires type resolution) hence it is set to `false`
- * by default.
- *
- * Note that, due to KAPT stubs, this is not 100% consistent between KAPT and KSP when set
- * to `false`. Since KAPT generates stubs, it automatically removes methods that have
- * invalid JVM names.
+ * @see XProcessingEnvConfig.excludeMethodsWithInvalidJvmSourceNames for docs.
*/
fun excludeMethodsWithInvalidJvmSourceNames(value: Boolean) = apply {
instance = instance.copy(
@@ -60,6 +71,15 @@ data class XProcessingEnvConfig private constructor(
)
}
+ /**
+ * @see XProcessingEnvConfig.disableAnnotatedElementValidation for docs.
+ */
+ fun disableAnnotatedElementValidation(value: Boolean) = apply {
+ instance = instance.copy(
+ disableAnnotatedElementValidation = value
+ )
+ }
+
fun build(): XProcessingEnvConfig {
return instance
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt
index a5dcac21a53..62c5c4ed026 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt
@@ -61,7 +61,9 @@ abstract class JavacBasicAnnotationProcessor @JvmOverloads constructor(
if (roundEnv.processingOver()) {
val missingElements = commonDelegate.processLastRound()
postRound(xEnv, xRoundEnv)
- if (!roundEnv.errorRaised()) {
+ if (!xProcessingEnv.config.disableAnnotatedElementValidation &&
+ !roundEnv.errorRaised()
+ ) {
// Report missing elements if no error was raised to avoid being noisy.
commonDelegate.reportMissingElements(missingElements)
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt
index 0c0cc26f0c9..dade4701c17 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt
@@ -75,7 +75,7 @@ abstract class KspBasicAnnotationProcessor @JvmOverloads constructor(
val xRoundEnv = KspRoundEnv(xEnv, true)
val missingElements = commonDelegate.processLastRound()
postRound(xEnv, xRoundEnv)
- if (!logger.hasError) {
+ if (!xProcessingEnv.config.disableAnnotatedElementValidation && !logger.hasError) {
// Report missing elements if no error was raised to avoid being noisy.
commonDelegate.reportMissingElements(missingElements)
}
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
index e20331185dc..67383e7bbf3 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XProcessingStepTest.kt
@@ -1192,6 +1192,110 @@ class XProcessingStepTest {
}
@Test
+ fun javacDisableValidatingAnnotatedElements() {
+ val processingStep = object : XProcessingStep {
+ var round = 0
+ override fun process(
+ env: XProcessingEnv,
+ elementsByAnnotation: Map<String, Set<XElement>>
+ ): Set<XElement> {
+ if (round++ == 0) {
+ val className = ClassName.get("foo.bar", "ToBeGenerated")
+ val spec = TypeSpec.classBuilder(className).build()
+ JavaFile.builder(className.packageName(), spec)
+ .build()
+ .writeTo(env.filer)
+ }
+ return elementsByAnnotation.values.flatten().toSet()
+ }
+ override fun annotations(): Set<String> {
+ return setOf(OtherAnnotation::class.qualifiedName!!)
+ }
+ }
+ val main = Source.java(
+ "foo.bar.Other",
+ """
+ package foo.bar;
+ import androidx.room.compiler.processing.testcode.*;
+ @OtherAnnotation("y")
+ class Other extends ToBeGenerated {
+ }
+ """.trimIndent()
+ )
+ assertAbout(
+ JavaSourcesSubjectFactory.javaSources()
+ ).that(
+ listOf(main.toJFO())
+ ).processedWith(
+ object : JavacBasicAnnotationProcessor(
+ configureEnv = {
+ XProcessingEnvConfig.DEFAULT.copy(disableAnnotatedElementValidation = true)
+ }
+ ) {
+ override fun processingSteps() = listOf(processingStep)
+ }
+ ).compilesWithoutError()
+ }
+
+ @Test
+ fun kspDisableValidatingAnnotatedElements() {
+ CompilationTestCapabilities.assumeKspIsEnabled()
+ val processingStep = object : XProcessingStep {
+ var round = 0
+ override fun process(
+ env: XProcessingEnv,
+ elementsByAnnotation: Map<String, Set<XElement>>
+ ): Set<XElement> {
+ if (round++ == 0) {
+ val className = ClassName.get("foo.bar", "ToBeGenerated")
+ val spec = TypeSpec.classBuilder(className).build()
+ JavaFile.builder(className.packageName(), spec)
+ .build()
+ .writeTo(env.filer)
+ }
+ return elementsByAnnotation.values.flatten().toSet()
+ }
+
+ override fun annotations(): Set<String> {
+ return setOf(OtherAnnotation::class.qualifiedName!!)
+ }
+ }
+ val processorProvider = SymbolProcessorProvider { environment ->
+ object : KspBasicAnnotationProcessor(
+ symbolProcessorEnvironment = environment,
+ config = XProcessingEnvConfig.DEFAULT.copy(
+ disableAnnotatedElementValidation = true
+ )
+ ) {
+ override fun processingSteps() = listOf(processingStep)
+ }
+ }
+ val main = Source.kotlin(
+ "Other.kt",
+ """
+ package foo.bar
+ import androidx.room.compiler.processing.testcode.*
+ @OtherAnnotation("y")
+ internal class Other : ToBeGenerated() {
+ }
+ """.trimIndent()
+ )
+
+ val result = compile(
+ workingDir = temporaryFolder.root,
+ arguments = TestCompilationArguments(
+ sources = listOf(main),
+ symbolProcessorProviders = listOf(processorProvider)
+ )
+ )
+ assertThat(result.success).isTrue()
+ // no error due to invalid elements in last round because validation is skipped
+ assertThat(
+ result.diagnostics[Diagnostic.Kind.ERROR]?.map { it.msg } ?: emptyList<String>()
+ ).isEmpty()
+ }
+
+ @Test
fun javacVariousDeferredElements() {
val main = Source.java(
"foo.bar.Main",