diff options
author | Android Build Coastguard Worker <android-build-coastguard-worker@google.com> | 2022-02-11 19:55:07 +0000 |
---|---|---|
committer | Gerrit Code Review <noreply-gerritcodereview@google.com> | 2022-02-11 19:55:07 +0000 |
commit | 711a2ff538884d269fe3a31db2f840ca2aae2da9 (patch) | |
tree | c9599cae94bced2ebf7ef7465d6c0dfe78c1878c | |
parent | e6648bf1055fd88d069bd6bdcde68e4897de1a43 (diff) | |
parent | 2c5196bad0c5f793890ed0510cf016bdaa47acc6 (diff) | |
download | support-snap-temp-L35000000953028468.tar.gz |
Merge "Add API for disabling XProcessing built-in validation" into snap-temp-L35000000953028468snap-temp-L35000000953028468
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", |