Merge "Add BasicAnnotationProcessor-like APIs for XProcessing" into androidx-main
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
new file mode 100644
index 0000000..733e5f9
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XBasicAnnotationProcessor.kt
@@ -0,0 +1,37 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing
+
+/**
+ * Common interface for basic annotation processors.
+ *
+ * A processor should not implement this interface directly and instead should extend
+ * [androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor] or
+ * [androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor].
+ */
+interface XBasicAnnotationProcessor {
+
+    /**
+     * The list of processing steps to execute.
+     */
+    fun processingSteps(): Iterable<XProcessingStep>
+
+    /**
+     * Called at the end of a processing round after all [processingSteps] have been executed.
+     */
+    fun postRound(env: XProcessingEnv, round: XRoundEnv) { }
+}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt
index b3bac7f..96f3994 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XProcessingStep.kt
@@ -16,16 +16,6 @@
 
 package androidx.room.compiler.processing
 
-import androidx.room.compiler.processing.javac.JavacElement
-import androidx.room.compiler.processing.javac.JavacProcessingEnv
-import androidx.room.compiler.processing.ksp.KspElement
-import androidx.room.compiler.processing.ksp.KspProcessingEnv
-import com.google.auto.common.BasicAnnotationProcessor
-import com.google.common.collect.ImmutableSetMultimap
-import com.google.devtools.ksp.symbol.KSAnnotated
-import javax.annotation.processing.ProcessingEnvironment
-import javax.lang.model.element.Element
-
 /**
  * Processing step to simplify processing a set of annotations.
  */
@@ -47,59 +37,4 @@
      * The set of annotation qualified names processed by this step.
      */
     fun annotations(): Set<String>
-
-    companion object {
-
-        /**
-         * Wraps current [XProcessingStep] into an Auto Common
-         * [BasicAnnotationProcessor.ProcessingStep].
-         */
-        @JvmStatic
-        fun XProcessingStep.asAutoCommonProcessor(
-            env: ProcessingEnvironment
-        ): BasicAnnotationProcessor.Step {
-            return JavacProcessingStepDelegate(
-                env = env,
-                delegate = this
-            )
-        }
-
-        @JvmStatic
-        fun XProcessingStep.executeInKsp(env: XProcessingEnv): List<KSAnnotated> {
-            check(env is KspProcessingEnv)
-            val round = XRoundEnv.create(env)
-            val args = annotations().associateWith { annotation ->
-                round.getElementsAnnotatedWith(annotation)
-            }
-            return process(env, args)
-                .map { (it as KspElement).declaration }
-        }
-    }
-}
-
-internal class JavacProcessingStepDelegate(
-    val env: ProcessingEnvironment,
-    val delegate: XProcessingStep
-) : BasicAnnotationProcessor.Step {
-    override fun annotations(): Set<String> = delegate.annotations()
-
-    @Suppress("UnstableApiUsage")
-    override fun process(
-        elementsByAnnotation: ImmutableSetMultimap<String, Element>
-    ): Set<Element> {
-        val converted = mutableMapOf<String, Set<XElement>>()
-        // create a new x processing environment for each step to ensure it can freely cache
-        // whatever it wants and we don't keep elements references across rounds.
-        val xEnv = JavacProcessingEnv(env)
-        annotations().forEach { annotation ->
-            val elements = elementsByAnnotation[annotation].mapNotNull { element ->
-                xEnv.wrapAnnotatedElement(element, annotation)
-            }.toSet()
-            converted[annotation] = elements
-        }
-        val result = delegate.process(xEnv, converted)
-        return result.map {
-            (it as JavacElement).element
-        }.toSet()
-    }
 }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
index 4d5e1ee..c3cadc6 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/compat/XConverters.kt
@@ -19,15 +19,18 @@
 import androidx.room.compiler.processing.XElement
 import androidx.room.compiler.processing.XExecutableElement
 import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.XRoundEnv
 import androidx.room.compiler.processing.XType
 import androidx.room.compiler.processing.XTypeElement
 import androidx.room.compiler.processing.XVariableElement
 import androidx.room.compiler.processing.javac.JavacElement
 import androidx.room.compiler.processing.javac.JavacExecutableElement
 import androidx.room.compiler.processing.javac.JavacProcessingEnv
+import androidx.room.compiler.processing.javac.JavacRoundEnv
 import androidx.room.compiler.processing.javac.JavacType
 import androidx.room.compiler.processing.javac.JavacTypeElement
 import androidx.room.compiler.processing.javac.JavacVariableElement
+import javax.annotation.processing.RoundEnvironment
 import javax.lang.model.element.Element
 import javax.lang.model.element.ExecutableElement
 import javax.lang.model.element.TypeElement
@@ -38,6 +41,9 @@
 object XConverters {
 
     @JvmStatic
+    fun XRoundEnv.toJavac(): RoundEnvironment = (this as JavacRoundEnv).delegate
+
+    @JvmStatic
     fun XElement.toJavac(): Element = (this as JavacElement).element
 
     @JvmStatic
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
new file mode 100644
index 0000000..f8926ad
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacBasicAnnotationProcessor.kt
@@ -0,0 +1,73 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.javac
+
+import androidx.room.compiler.processing.XBasicAnnotationProcessor
+import androidx.room.compiler.processing.XElement
+import androidx.room.compiler.processing.XRoundEnv
+import com.google.auto.common.BasicAnnotationProcessor
+import com.google.common.collect.ImmutableSetMultimap
+import javax.annotation.processing.RoundEnvironment
+import javax.lang.model.element.Element
+
+/**
+ * Javac implementation of a [XBasicAnnotationProcessor] with built-in support for validating and
+ * deferring elements via auto-common's [BasicAnnotationProcessor].
+ */
+abstract class JavacBasicAnnotationProcessor :
+    BasicAnnotationProcessor(), XBasicAnnotationProcessor {
+
+    final override fun steps(): Iterable<Step> {
+        // Execute all processing steps in a single auto-common Step. This is done to share the
+        // XProcessingEnv and its cached across steps in the same round.
+        val steps = processingSteps()
+        val parentStep = object : Step {
+            override fun annotations() = steps.flatMap { it.annotations() }.toSet()
+
+            override fun process(
+                elementsByAnnotation: ImmutableSetMultimap<String, Element>
+            ): Set<Element> {
+                val xEnv = JavacProcessingEnv(processingEnv)
+                val convertedElementsByAnnotation = mutableMapOf<String, Set<XElement>>()
+                annotations().forEach { annotation ->
+                    convertedElementsByAnnotation[annotation] =
+                        elementsByAnnotation[annotation].mapNotNull { element ->
+                            xEnv.wrapAnnotatedElement(element, annotation)
+                        }.toSet()
+                }
+                val results = steps.flatMap { step ->
+                    step.process(
+                        env = xEnv,
+                        elementsByAnnotation = step.annotations().associateWith {
+                            convertedElementsByAnnotation[it] ?: emptySet()
+                        }
+                    )
+                }
+                return results.map { (it as JavacElement).element }.toSet()
+            }
+        }
+        return listOf(parentStep)
+    }
+
+    final override fun postRound(roundEnv: RoundEnvironment) {
+        // Due to BasicAnnotationProcessor taking over AbstractProcessor#process() we can't
+        // share the same XProcessingEnv from the steps, but that might be ok...
+        val xEnv = JavacProcessingEnv(processingEnv)
+        val xRound = XRoundEnv.create(xEnv, roundEnv)
+        postRound(xEnv, xRound)
+    }
+}
\ No newline at end of file
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
new file mode 100644
index 0000000..9551d6d
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspBasicAnnotationProcessor.kt
@@ -0,0 +1,59 @@
+/*
+ * Copyright 2021 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package androidx.room.compiler.processing.ksp
+
+import androidx.room.compiler.processing.XBasicAnnotationProcessor
+import androidx.room.compiler.processing.XElement
+import androidx.room.compiler.processing.XProcessingEnv
+import androidx.room.compiler.processing.XRoundEnv
+import com.google.devtools.ksp.processing.Resolver
+import com.google.devtools.ksp.processing.SymbolProcessor
+import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
+import com.google.devtools.ksp.symbol.KSAnnotated
+import com.google.devtools.ksp.validate
+
+/**
+ * KSP implementation of a [XBasicAnnotationProcessor] with built-in support for validating and
+ * deferring symbols.
+ */
+abstract class KspBasicAnnotationProcessor(
+    val symbolProcessorEnvironment: SymbolProcessorEnvironment
+) : SymbolProcessor, XBasicAnnotationProcessor {
+
+    final override fun process(resolver: Resolver): List<KSAnnotated> {
+        val processingEnv = XProcessingEnv.create(
+            symbolProcessorEnvironment.options,
+            resolver,
+            symbolProcessorEnvironment.codeGenerator,
+            symbolProcessorEnvironment.logger
+        )
+        val round = XRoundEnv.create(processingEnv)
+        val deferredElements = processingSteps().flatMap { step ->
+            val invalidElements = mutableSetOf<XElement>()
+            val elementsByAnnotation = step.annotations().associateWith { annotation ->
+                val annotatedElements = round.getElementsAnnotatedWith(annotation)
+                annotatedElements
+                    .filter { (it as KspElement).declaration.validate() }
+                    .also { invalidElements.addAll(annotatedElements - it) }
+                    .toSet()
+            }
+            invalidElements + step.process(processingEnv, elementsByAnnotation)
+        }
+        postRound(processingEnv, round)
+        return deferredElements.map { (it as KspElement).declaration }
+    }
+}
\ No newline at end of file
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 004ace1..b0af4d3 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
@@ -16,20 +16,18 @@
 
 package androidx.room.compiler.processing
 
-import androidx.room.compiler.processing.XProcessingStep.Companion.asAutoCommonProcessor
-import androidx.room.compiler.processing.XProcessingStep.Companion.executeInKsp
+import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor
+import androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor
+import androidx.room.compiler.processing.ksp.KspElement
 import androidx.room.compiler.processing.testcode.MainAnnotation
 import androidx.room.compiler.processing.testcode.OtherAnnotation
 import androidx.room.compiler.processing.util.CompilationTestCapabilities
-import com.google.auto.common.BasicAnnotationProcessor
 import com.google.common.truth.Truth.assertAbout
 import com.google.common.truth.Truth.assertThat
-import com.google.devtools.ksp.processing.Resolver
 import com.google.devtools.ksp.processing.SymbolProcessor
 import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
 import com.google.devtools.ksp.processing.SymbolProcessorProvider
 import com.google.devtools.ksp.symbol.ClassKind
-import com.google.devtools.ksp.symbol.KSAnnotated
 import com.google.devtools.ksp.symbol.KSClassDeclaration
 import com.google.testing.compile.JavaFileObjects
 import com.google.testing.compile.JavaSourcesSubjectFactory
@@ -79,12 +77,8 @@
                 )
             }
         }
-        val mainProcessor = object : BasicAnnotationProcessor() {
-            override fun steps(): Iterable<Step> {
-                return listOf(
-                    processingStep.asAutoCommonProcessor(processingEnv)
-                )
-            }
+        val mainProcessor = object : JavacBasicAnnotationProcessor() {
+            override fun processingSteps() = listOf(processingStep)
         }
         val main = JavaFileObjects.forSourceString(
             "foo.bar.Main",
@@ -187,19 +181,8 @@
         ).that(
             listOf(main)
         ).processedWith(
-            object : BasicAnnotationProcessor() {
-                override fun steps(): Iterable<Step> {
-                    return listOf(
-                        processingStep.asAutoCommonProcessor(processingEnv)
-                    )
-                }
-
-                override fun getSupportedOptions(): Set<String> {
-                    return setOf(
-                        MainAnnotation::class.qualifiedName!!,
-                        OtherAnnotation::class.qualifiedName!!
-                    )
-                }
+            object : JavacBasicAnnotationProcessor() {
+                override fun processingSteps() = listOf(processingStep)
             }
         ).compilesWithoutError()
         assertThat(otherAnnotatedElements).containsExactly(
@@ -267,19 +250,8 @@
         ).that(
             listOf(main)
         ).processedWith(
-            object : BasicAnnotationProcessor() {
-                override fun steps(): Iterable<Step> {
-                    return listOf(
-                        processingStep.asAutoCommonProcessor(processingEnv)
-                    )
-                }
-
-                override fun getSupportedOptions(): Set<String> {
-                    return setOf(
-                        MainAnnotation::class.qualifiedName!!,
-                        OtherAnnotation::class.qualifiedName!!
-                    )
-                }
+            object : JavacBasicAnnotationProcessor() {
+                override fun processingSteps() = listOf(processingStep)
             }
         ).compilesWithoutError()
         assertThat(elementPerRound).hasSize(2)
@@ -298,6 +270,7 @@
     @Test
     fun kspReturnsUnprocessed() {
         CompilationTestCapabilities.assumeKspIsEnabled()
+        var returned: Set<XElement>? = null
         val processingStep = object : XProcessingStep {
             override fun process(
                 env: XProcessingEnv,
@@ -306,26 +279,17 @@
                 return elementsByAnnotation.values
                     .flatten()
                     .toSet()
+                    .also { returned = it }
             }
 
             override fun annotations(): Set<String> {
                 return setOf(OtherAnnotation::class.qualifiedName!!)
             }
         }
-        var returned: List<KSAnnotated>? = null
         val processorProvider = object : SymbolProcessorProvider {
             override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
-                return object : SymbolProcessor {
-                    override fun process(resolver: Resolver): List<KSAnnotated> {
-                        val env = XProcessingEnv.create(
-                            emptyMap(),
-                            resolver,
-                            environment.codeGenerator,
-                            environment.logger
-                        )
-                        return processingStep.executeInKsp(env)
-                            .also { returned = it }
-                    }
+                return object : KspBasicAnnotationProcessor(environment) {
+                    override fun processingSteps() = listOf(processingStep)
                 }
             }
         }
@@ -352,8 +316,137 @@
             isNotNull()
             isNotEmpty()
         }
-        val element = returned!!.first() as KSClassDeclaration
+        val element =
+            returned!!.map { (it as KspElement).declaration }.first() as KSClassDeclaration
         assertThat(element.classKind).isEqualTo(ClassKind.CLASS)
         assertThat(element.qualifiedName!!.asString()).isEqualTo("foo.bar.Other")
     }
+
+    @Test
+    fun javacAnnotatedElementsByStep() {
+        val main = JavaFileObjects.forSourceString(
+            "foo.bar.Main",
+            """
+            package foo.bar;
+            import androidx.room.compiler.processing.testcode.*;
+            @MainAnnotation(
+                typeList = {},
+                singleType = Object.class,
+                intMethod = 3,
+                singleOtherAnnotation = @OtherAnnotation("y")
+            )
+            class Main {
+            }
+            """.trimIndent()
+        )
+        val other = JavaFileObjects.forSourceString(
+            "foo.bar.Other",
+            """
+            package foo.bar;
+            import androidx.room.compiler.processing.testcode.*;
+            @OtherAnnotation("x")
+            class Other {
+            }
+            """.trimIndent()
+        )
+        val elementsByStep = mutableMapOf<XProcessingStep, Collection<String>>()
+        val mainStep = object : XProcessingStep {
+            override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
+            override fun process(
+                env: XProcessingEnv,
+                elementsByAnnotation: Map<String, Set<XElement>>
+            ): Set<XElement> {
+                elementsByStep[this] = elementsByAnnotation.values.flatten()
+                    .map { (it as XTypeElement).qualifiedName }
+                return emptySet()
+            }
+        }
+        val otherStep = object : XProcessingStep {
+            override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
+            override fun process(
+                env: XProcessingEnv,
+                elementsByAnnotation: Map<String, Set<XElement>>
+            ): Set<XElement> {
+                elementsByStep[this] = elementsByAnnotation.values.flatten()
+                    .map { (it as XTypeElement).qualifiedName }
+                return emptySet()
+            }
+        }
+        assertAbout(
+            JavaSourcesSubjectFactory.javaSources()
+        ).that(
+            listOf(main, other)
+        ).processedWith(
+            object : JavacBasicAnnotationProcessor() {
+                override fun processingSteps() = listOf(mainStep, otherStep)
+            }
+        ).compilesWithoutError()
+        assertThat(elementsByStep[mainStep])
+            .containsExactly("foo.bar.Main")
+        assertThat(elementsByStep[otherStep])
+            .containsExactly("foo.bar.Other")
+    }
+
+    @Test
+    fun kspAnnotatedElementsByStep() {
+        val main = SourceFile.kotlin(
+            "Classes.kt",
+            """
+            package foo.bar
+            import androidx.room.compiler.processing.testcode.*
+            @MainAnnotation(
+                typeList = [],
+                singleType = Any::class,
+                intMethod = 3,
+                singleOtherAnnotation = OtherAnnotation("y")
+            )
+            class Main {
+            }
+            @OtherAnnotation("y")
+            class Other {
+            }
+            """.trimIndent()
+        )
+        val elementsByStep = mutableMapOf<XProcessingStep, Collection<String>>()
+        val mainStep = object : XProcessingStep {
+            override fun annotations() = setOf(MainAnnotation::class.qualifiedName!!)
+            override fun process(
+                env: XProcessingEnv,
+                elementsByAnnotation: Map<String, Set<XElement>>
+            ): Set<XElement> {
+                elementsByStep[this] = elementsByAnnotation.values.flatten()
+                    .map { (it as XTypeElement).qualifiedName }
+                return emptySet()
+            }
+        }
+        val otherStep = object : XProcessingStep {
+            override fun annotations() = setOf(OtherAnnotation::class.qualifiedName!!)
+            override fun process(
+                env: XProcessingEnv,
+                elementsByAnnotation: Map<String, Set<XElement>>
+            ): Set<XElement> {
+                elementsByStep[this] = elementsByAnnotation.values.flatten()
+                    .map { (it as XTypeElement).qualifiedName }
+                return emptySet()
+            }
+        }
+        val processorProvider = object : SymbolProcessorProvider {
+            override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
+                return object : KspBasicAnnotationProcessor(environment) {
+                    override fun processingSteps() = listOf(mainStep, otherStep)
+                }
+            }
+        }
+        KotlinCompilation().apply {
+            workingDir = temporaryFolder.root
+            inheritClassPath = true
+            symbolProcessorProviders = listOf(processorProvider)
+            sources = listOf(main)
+            verbose = false
+        }.compile()
+        assertThat(elementsByStep[mainStep])
+            .containsExactly("foo.bar.Main")
+        assertThat(elementsByStep[otherStep])
+            .containsExactly("foo.bar.Other")
+    }
 }
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
index fa1656b9..7437810 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/RoomKspProcessor.kt
@@ -16,44 +16,25 @@
 
 package androidx.room
 
-import androidx.room.compiler.processing.XProcessingEnv
-import androidx.room.compiler.processing.XProcessingStep.Companion.executeInKsp
-import com.google.devtools.ksp.processing.CodeGenerator
-import com.google.devtools.ksp.processing.KSPLogger
-import com.google.devtools.ksp.processing.Resolver
+import androidx.room.compiler.processing.ksp.KspBasicAnnotationProcessor
 import com.google.devtools.ksp.processing.SymbolProcessor
 import com.google.devtools.ksp.processing.SymbolProcessorEnvironment
 import com.google.devtools.ksp.processing.SymbolProcessorProvider
-import com.google.devtools.ksp.symbol.KSAnnotated
 
 /**
  * Entry point for processing using KSP.
  */
 class RoomKspProcessor(
-    private val options: Map<String, String>,
-    private val codeGenerator: CodeGenerator,
-    private val logger: KSPLogger
-) : SymbolProcessor {
-    override fun process(resolver: Resolver): List<KSAnnotated> {
-        val processingEnv = XProcessingEnv.create(
-            options,
-            resolver,
-            codeGenerator,
-            logger
-        )
+    environment: SymbolProcessorEnvironment
+) : KspBasicAnnotationProcessor(environment) {
 
-        return DatabaseProcessingStep().executeInKsp(
-            processingEnv
-        )
-    }
+    override fun processingSteps() = listOf(
+        DatabaseProcessingStep()
+    )
 
     class Provider : SymbolProcessorProvider {
         override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor {
-            return RoomKspProcessor(
-                options = environment.options,
-                codeGenerator = environment.codeGenerator,
-                logger = environment.logger
-            )
+            return RoomKspProcessor(environment)
         }
     }
 }
\ No newline at end of file
diff --git a/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt b/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
index 8119102..8f6c8ac 100644
--- a/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
+++ b/room/room-compiler/src/main/kotlin/androidx/room/RoomProcessor.kt
@@ -17,12 +17,11 @@
 package androidx.room
 
 import androidx.room.compiler.processing.XProcessingEnv
-import androidx.room.compiler.processing.XProcessingStep.Companion.asAutoCommonProcessor
+import androidx.room.compiler.processing.javac.JavacBasicAnnotationProcessor
 import androidx.room.processor.Context
 import androidx.room.processor.ProcessorErrors
 import androidx.room.util.SimpleJavaVersion
 import androidx.room.vo.Warning
-import com.google.auto.common.BasicAnnotationProcessor
 import javax.lang.model.SourceVersion
 
 /**
@@ -34,20 +33,18 @@
 /**
  * The annotation processor for Room.
  */
-class RoomProcessor : BasicAnnotationProcessor() {
+class RoomProcessor : JavacBasicAnnotationProcessor() {
 
     /** Helper variable to avoid reporting the warning twice. */
     private var jdkVersionHasBugReported = false
 
-    override fun steps(): MutableIterable<Step> {
-        return mutableListOf(
-            DatabaseProcessingStep().asAutoCommonProcessor(processingEnv)
-        )
-    }
+    override fun processingSteps() = listOf(
+        DatabaseProcessingStep()
+    )
 
     override fun getSupportedOptions(): MutableSet<String> {
         val supportedOptions = Context.ARG_OPTIONS.toMutableSet()
-        // x processing is a cheap wrapper so it is fine to re-create.
+        // XProcessingEnv is a cheap wrapper so it is fine to re-create.
         val xProcessing = XProcessingEnv.create(processingEnv)
         if (Context.BooleanProcessorOptions.INCREMENTAL.getValue(xProcessing)) {
             if (methodParametersVisibleInClassFiles()) {