Add preRound() to XBasicAnnotationProcessor

Test: XProcessingStepTest

Change-Id: Id90dc97d4e1ef51325d0588207bc336d98dd354a
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 1181a10..bb7e7dc 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
@@ -55,6 +55,11 @@
     fun initialize(env: XProcessingEnv) { }
 
     /**
+     * Called at the beginning of a processing round before all [processingSteps] execute.
+     */
+    fun preRound(env: XProcessingEnv, round: XRoundEnv) { }
+
+    /**
      * The list of processing steps to execute.
      */
     fun processingSteps(): Iterable<XProcessingStep>
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 62c5c4e..715e356 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
@@ -59,6 +59,7 @@
     ): Boolean {
         val xRoundEnv = JavacRoundEnv(xEnv, roundEnv)
         if (roundEnv.processingOver()) {
+            preRound(xEnv, xRoundEnv)
             val missingElements = commonDelegate.processLastRound()
             postRound(xEnv, xRoundEnv)
             if (!xProcessingEnv.config.disableAnnotatedElementValidation &&
@@ -68,6 +69,7 @@
                 commonDelegate.reportMissingElements(missingElements)
             }
         } else {
+            preRound(xEnv, xRoundEnv)
             commonDelegate.processRound(xRoundEnv)
             postRound(xEnv, xRoundEnv)
             xEnv.clearCache()
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 9a24b90..dd842c2 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
@@ -58,6 +58,7 @@
             initialized = true
         }
         val xRoundEnv = KspRoundEnv(xEnv, false)
+        preRound(xEnv, xRoundEnv)
         commonDelegate.processRound(xRoundEnv)
         postRound(xEnv, xRoundEnv)
         xEnv.clearCache() // Reset cache after every round to avoid leaking elements across rounds
@@ -71,6 +72,7 @@
 
     final override fun finish() {
         val xRoundEnv = KspRoundEnv(xEnv, true)
+        preRound(xEnv, xRoundEnv)
         val missingElements = commonDelegate.processLastRound()
         postRound(xEnv, xRoundEnv)
         if (!xProcessingEnv.config.disableAnnotatedElementValidation && !logger.hasError) {
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 c096cec..ff20504 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
@@ -754,6 +754,7 @@
                 return deferredElements
             }
         }
+        val invokedPreRound = mutableListOf<Boolean>()
         val invokedPostRound = mutableListOf<Boolean>()
         assertAbout(
             JavaSourcesSubjectFactory.javaSources()
@@ -764,6 +765,10 @@
                 override fun initialize(env: XProcessingEnv) {
                     invokedLifecycles.add("initialize")
                 }
+                override fun preRound(env: XProcessingEnv, round: XRoundEnv) {
+                    invokedLifecycles.add("preRound")
+                    invokedPreRound.add(round.isProcessingOver)
+                }
                 override fun processingSteps(): List<XProcessingStep> {
                     invokedLifecycles.add("processingSteps")
                     return listOf(mainStep)
@@ -785,14 +790,21 @@
         assertThat(invokedLifecycles).containsExactly(
             "initialize",
             "processingSteps",
+            "preRound", // 1st round
             "process", // 1st round
             "postRound", // 1st round
+            "preRound", // 2nd round
             "process", // 2nd round
             "postRound", // 2nd round
+            "preRound", // final round
             "processOver", // final round
             "postRound", // final round
         ).inOrder()
 
+        // Assert preRound() is invoked exactly 3 times, and the last round env reported
+        // that processing was over.
+        assertThat(invokedPreRound).containsExactly(false, false, true)
+
         // Assert postRound() is invoked exactly 3 times, and the last round env reported
         // that processing was over.
         assertThat(invokedPostRound).containsExactly(false, false, true)
@@ -1055,6 +1067,7 @@
                 return deferredElements
             }
         }
+        val invokedPreRound = mutableListOf<Boolean>()
         val invokedPostRound = mutableListOf<Boolean>()
         val processorProvider = object : SymbolProcessorProvider {
             override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
@@ -1063,6 +1076,11 @@
                         invokedLifecycles.add("initialize")
                     }
 
+                    override fun preRound(env: XProcessingEnv, round: XRoundEnv) {
+                        invokedLifecycles.add("preRound")
+                        invokedPreRound.add(round.isProcessingOver)
+                    }
+
                     override fun processingSteps(): List<XProcessingStep> {
                         invokedLifecycles.add("processingSteps")
                         return listOf(mainStep)
@@ -1090,15 +1108,22 @@
         // Assert processOver() was only called once
         assertThat(invokedLifecycles).containsExactly(
             "initialize",
+            "preRound", // 1st round
             "processingSteps",
             "process", // 1st round
             "postRound", // 1st round
+            "preRound", // 2nd round
             "process", // 2nd round
             "postRound", // 2nd round
+            "preRound", // final round
             "processOver", // final round
             "postRound", // final round
         ).inOrder()
 
+        // Assert preRound() is invoked exactly 3 times, and the last round env reported
+        // that processing was over.
+        assertThat(invokedPreRound).containsExactly(false, false, true)
+
         // Assert postRound() is invoked exactly 3 times, and the last round env reported
         // that processing was over.
         assertThat(invokedPostRound).containsExactly(false, false, true)