Merge "Make XType extend XAnnotated to support type annotations" into androidx-main
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
index b1a65c0..9ad98bf 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XType.kt
@@ -29,7 +29,7 @@
  * @see javax.lang.model.type.TypeMirror
  * @see [XArrayType]
  */
-interface XType {
+interface XType : XAnnotated {
     /**
      * The Javapoet [TypeName] representation of the type
      */
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
new file mode 100644
index 0000000..ac2d325
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotation.kt
@@ -0,0 +1,56 @@
+/*
+ * Copyright 2023 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.InternalXAnnotation
+import androidx.room.compiler.processing.XAnnotationBox
+import androidx.room.compiler.processing.XAnnotationValue
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.javac.kotlin.KmAnnotationContainer
+
+internal class JavacKmAnnotation(
+    private val env: JavacProcessingEnv,
+    private val kmAnnotation: KmAnnotationContainer
+) : InternalXAnnotation() {
+    override fun <T : Annotation> asAnnotationBox(annotationClass: Class<T>): XAnnotationBox<T> {
+        throw UnsupportedOperationException("No plan to support XAnnotationBox.")
+    }
+
+    override val name: String
+        get() = typeElement.name
+
+    override val qualifiedName: String
+        get() = typeElement.qualifiedName
+
+    override val typeElement: JavacTypeElement by lazy {
+        requireNotNull(env.findTypeElement(kmAnnotation.className))
+    }
+
+    override val type: XType
+        get() = typeElement.type
+
+    override val annotationValues: List<XAnnotationValue> by lazy {
+        val methods = typeElement.getDeclaredMethods()
+        methods.map { method ->
+            JavacKmAnnotationValue(
+                method = method,
+                kmAnnotationArgumentContainer =
+                    kmAnnotation.getArguments(env).getValue(method.jvmName)
+            )
+        }
+    }
+}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotationValue.kt
new file mode 100644
index 0000000..c100d0b
--- /dev/null
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacKmAnnotationValue.kt
@@ -0,0 +1,33 @@
+/*
+ * Copyright 2023 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.InternalXAnnotationValue
+import androidx.room.compiler.processing.XMethodElement
+import androidx.room.compiler.processing.XType
+import androidx.room.compiler.processing.javac.kotlin.KmAnnotationArgumentContainer
+
+internal class JavacKmAnnotationValue(
+    private val method: XMethodElement,
+    override val valueType: XType = method.returnType,
+    private val kmAnnotationArgumentContainer: KmAnnotationArgumentContainer
+) : InternalXAnnotationValue() {
+    override val name: String = method.jvmName
+    override val value: Any? by lazy {
+        kmAnnotationArgumentContainer.getValue(method)
+    }
+}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
index 3dd55ea..89420be 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacType.kt
@@ -17,6 +17,9 @@
 package androidx.room.compiler.processing.javac
 
 import androidx.room.compiler.codegen.XTypeName
+import androidx.room.compiler.processing.InternalXAnnotated
+import androidx.room.compiler.processing.XAnnotation
+import androidx.room.compiler.processing.XAnnotationBox
 import androidx.room.compiler.processing.XEquality
 import androidx.room.compiler.processing.XNullability
 import androidx.room.compiler.processing.XRawType
@@ -25,6 +28,8 @@
 import androidx.room.compiler.processing.javac.kotlin.KmTypeContainer
 import androidx.room.compiler.processing.ksp.ERROR_JTYPE_NAME
 import androidx.room.compiler.processing.safeTypeName
+import androidx.room.compiler.processing.unwrapRepeatedAnnotationsFromContainer
+import com.google.auto.common.MoreElements
 import com.google.auto.common.MoreTypes
 import javax.lang.model.type.TypeKind
 import javax.lang.model.type.TypeMirror
@@ -34,7 +39,8 @@
     internal val env: JavacProcessingEnv,
     open val typeMirror: TypeMirror,
     internal val maybeNullability: XNullability?,
-) : XType, XEquality {
+) : XType, XEquality, InternalXAnnotated {
+
     // Kotlin type information about the type if this type is driven from Kotlin code.
     abstract val kotlinType: KmTypeContainer?
 
@@ -85,6 +91,37 @@
 
     override fun asTypeName() = xTypeName
 
+    override fun <T : Annotation> getAnnotations(
+        annotation: KClass<T>,
+        containerAnnotation: KClass<out Annotation>?
+    ): List<XAnnotationBox<T>> {
+        throw UnsupportedOperationException("No plan to support XAnnotationBox.")
+    }
+
+    override fun hasAnnotation(
+        annotation: KClass<out Annotation>,
+        containerAnnotation: KClass<out Annotation>?
+    ): Boolean {
+        val annotationClassName: String = annotation.java.canonicalName!!
+        return getAllAnnotations().any { it.qualifiedName == annotationClassName }
+    }
+
+    override fun getAllAnnotations(): List<XAnnotation> {
+        return kotlinType?.annotations?.map {
+            JavacKmAnnotation(env, it)
+        } ?: typeMirror.annotationMirrors.map { mirror -> JavacAnnotation(env, mirror) }
+                .flatMap { annotation ->
+                    annotation.unwrapRepeatedAnnotationsFromContainer() ?: listOf(annotation)
+                }
+    }
+
+    override fun hasAnnotationWithPackage(pkg: String): Boolean {
+        return getAllAnnotations().any {
+            val element = (it.typeElement as JavacTypeElement).element
+            MoreElements.getPackage(element).toString() == pkg
+        }
+    }
+
     override fun equals(other: Any?): Boolean {
         return XEquality.equals(this, other)
     }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
index 5b09016..1029947 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacTypeElement.kt
@@ -37,6 +37,7 @@
 import com.squareup.kotlinpoet.javapoet.JClassName
 import javax.lang.model.element.ElementKind
 import javax.lang.model.element.TypeElement
+import javax.lang.model.type.DeclaredType
 import javax.lang.model.type.TypeKind
 import javax.lang.model.util.ElementFilter
 
@@ -218,11 +219,15 @@
     }
 
     override val superInterfaces by lazy {
+        val superTypesFromKotlinMetadata = kotlinMetadata?.superTypes
+            ?.associateBy { it.className } ?: emptyMap()
         element.interfaces.map {
+            check(it is DeclaredType)
+            val interfaceName = ClassName.get(MoreElements.asType(it.asElement()))
             val element = MoreTypes.asTypeElement(it)
             env.wrap<JavacType>(
                 typeMirror = it,
-                kotlinType = KmClassContainer.createFor(env, element)?.type,
+                kotlinType = superTypesFromKotlinMetadata[interfaceName.canonicalName()],
                 elementNullability = element.nullability
             )
         }
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
index fdf221a..9e8131c 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/kotlin/KotlinClassMetadataUtils.kt
@@ -16,7 +16,12 @@
 
 package androidx.room.compiler.processing.javac.kotlin
 
+import androidx.room.compiler.processing.XArrayType
+import androidx.room.compiler.processing.XEnumTypeElement
+import androidx.room.compiler.processing.XMethodElement
 import androidx.room.compiler.processing.XNullability
+import androidx.room.compiler.processing.javac.JavacKmAnnotation
+import androidx.room.compiler.processing.javac.JavacKmAnnotationValue
 import androidx.room.compiler.processing.javac.JavacProcessingEnv
 import androidx.room.compiler.processing.util.sanitizeAsJavaParameterName
 import javax.lang.model.element.Element
@@ -25,7 +30,10 @@
 import javax.tools.Diagnostic
 import kotlinx.metadata.Flag
 import kotlinx.metadata.Flags
+import kotlinx.metadata.KmAnnotation
+import kotlinx.metadata.KmAnnotationArgument
 import kotlinx.metadata.KmClass
+import kotlinx.metadata.KmClassifier
 import kotlinx.metadata.KmConstructor
 import kotlinx.metadata.KmFunction
 import kotlinx.metadata.KmProperty
@@ -50,10 +58,14 @@
 
     val type: KmTypeContainer by lazy {
         KmTypeContainer(
-            kmType = KmType(flags),
+            kmType = KmType(flags).apply {
+                classifier = KmClassifier.Class(kmClass.name)
+            },
             typeArguments = kmClass.typeParameters.map { kmTypeParameter ->
                 KmTypeContainer(
-                    kmType = KmType(kmTypeParameter.flags),
+                    kmType = KmType(kmTypeParameter.flags).apply {
+                        classifier = KmClassifier.Class(kmTypeParameter.name)
+                    },
                     typeArguments = emptyList(),
                     upperBounds = kmTypeParameter.upperBounds.map { it.asContainer() }
                 )
@@ -65,6 +77,10 @@
         kmClass.supertypes.firstOrNull()?.asContainer()
     }
 
+    val superTypes: List<KmTypeContainer> by lazy {
+        kmClass.supertypes.map { it.asContainer() }
+    }
+
     val typeParameters: List<KmTypeParameterContainer> by lazy {
         kmClass.typeParameters.map { it.asContainer() }
     }
@@ -265,6 +281,16 @@
 ) : KmFlags {
     override val flags: Flags
         get() = kmType.flags
+
+    val className: String? = kmType.classifier.let {
+        when (it) {
+            is KmClassifier.Class -> it.name.replace('/', '.')
+            else -> null
+        }
+    }
+
+    val annotations = kmType.annotations.map { it.asContainer() }
+
     fun isExtensionType() =
         kmType.annotations.any { it.className == "kotlin/ExtensionFunctionType" }
     fun isNullable() = Flag.Type.IS_NULLABLE(flags)
@@ -278,6 +304,49 @@
     )
 }
 
+internal class KmAnnotationContainer(private val kmAnnotation: KmAnnotation) {
+    val className = kmAnnotation.className.replace('/', '.')
+    fun getArguments(env: JavacProcessingEnv): Map<String, KmAnnotationArgumentContainer> {
+        return kmAnnotation.arguments.mapValues { (_, arg) ->
+            arg.asContainer(env)
+        }
+    }
+}
+
+internal class KmAnnotationArgumentContainer(
+    private val env: JavacProcessingEnv,
+    private val kmAnnotationArgument: KmAnnotationArgument
+) {
+    fun getValue(method: XMethodElement): Any? {
+        return kmAnnotationArgument.let {
+            when (it) {
+                is KmAnnotationArgument.LiteralValue<*> -> it.value
+                is KmAnnotationArgument.ArrayValue -> {
+                    it.elements.map {
+                        val valueType = (method.returnType as XArrayType).componentType
+                        JavacKmAnnotationValue(method, valueType, it.asContainer(env))
+                    }
+                }
+                is KmAnnotationArgument.EnumValue -> {
+                    val enumTypeElement = env.findTypeElement(
+                        it.enumClassName.replace('/', '.')) as XEnumTypeElement
+                    enumTypeElement.entries.associateBy { it.name }[it.enumEntryName]
+                }
+                is KmAnnotationArgument.AnnotationValue -> {
+                    val kmAnnotation = KmAnnotation(
+                        it.annotation.className,
+                        it.annotation.arguments
+                    ).asContainer()
+                    JavacKmAnnotation(env, kmAnnotation)
+                }
+                is KmAnnotationArgument.KClassValue -> {
+                    env.requireType(it.className.replace('/', '.'))
+                }
+            }
+        }
+    }
+}
+
 internal val KmTypeContainer.nullability: XNullability
     get() = if (isNullable()) {
         XNullability.NULLABLE
@@ -346,13 +415,14 @@
                 // it here since it is not valid name
                 name = "set-?".sanitizeAsJavaParameterName(0)
             ).apply { type = this@asContainer.returnType }
+            val returnType = KmType(0).apply { classifier = KmClassifier.Class("Unit") }
             KmPropertyFunctionContainerImpl(
                 flags = this.setterFlags,
                 name = JvmAbi.computeSetterName(this.name),
                 jvmName = it.name,
                 descriptor = it.asString(),
                 parameters = listOf(param.asContainer()),
-                returnType = KmType(0).asContainer(),
+                returnType = returnType.asContainer(),
             )
         },
     )
@@ -373,4 +443,9 @@
     KmValueParameterContainer(
         kmValueParameter = this,
         type = this.type.asContainer()
-    )
\ No newline at end of file
+    )
+
+private fun KmAnnotation.asContainer() = KmAnnotationContainer(this)
+
+private fun KmAnnotationArgument.asContainer(env: JavacProcessingEnv) =
+    KmAnnotationArgumentContainer(env, this)
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotated.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotated.kt
index 1080617..4039290 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotated.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotated.kt
@@ -72,7 +72,7 @@
 
     override fun hasAnnotationWithPackage(pkg: String): Boolean {
         return annotations().any {
-            it.annotationType.resolve().declaration.qualifiedName?.getQualifier() == pkg
+            it.annotationType.resolve().declaration.packageName.asString() == pkg
         }
     }
 
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
index 51a0c6e..4e48afc 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotation.kt
@@ -28,7 +28,9 @@
     val ksAnnotated: KSAnnotation
 ) : InternalXAnnotation() {
 
-    val ksType: KSType by lazy { ksAnnotated.annotationType.resolve() }
+    val ksType: KSType by lazy {
+        ksAnnotated.annotationType.resolve()
+    }
 
     override val name: String
         get() = ksAnnotated.shortName.asString()
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
index b0d03e1..d6b75dd 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspType.kt
@@ -24,6 +24,7 @@
 import androidx.room.compiler.processing.tryBox
 import androidx.room.compiler.processing.tryUnbox
 import com.google.devtools.ksp.KspExperimental
+import com.google.devtools.ksp.symbol.KSAnnotation
 import com.google.devtools.ksp.symbol.KSClassDeclaration
 import com.google.devtools.ksp.symbol.KSType
 import com.google.devtools.ksp.symbol.KSTypeArgument
@@ -46,13 +47,13 @@
  * Similarly, we may not be able to get a [KSType] (e.g. if it resolves to error).
  */
 internal abstract class KspType(
-    val env: KspProcessingEnv,
+    env: KspProcessingEnv,
     val ksType: KSType,
     /**
      * Type resolver to convert KSType into its JVM representation.
      */
     protected val jvmTypeResolver: KspJvmTypeResolver?
-) : XType, XEquality {
+) : KspAnnotated(env), XType, XEquality {
     override val rawType by lazy {
         KspRawType(this)
     }
@@ -213,6 +214,8 @@
         }
     }
 
+    override fun annotations(): Sequence<KSAnnotation> = ksType.annotations
+
     override fun isNone(): Boolean {
         // even void is converted to Unit so we don't have none type in KSP
         // see: KspTypeTest.noneType
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
index d96e81d..2b79b8b 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationTest.kt
@@ -1106,6 +1106,158 @@
         }
     }
 
+    @Test
+    fun typeAnnotations() {
+        val kotlinSource = Source.kotlin(
+            "foo.bar.Subject.kt",
+            """
+            package foo.bar
+
+            interface MyInterface
+            open class Base
+
+            @Target(AnnotationTarget.TYPE)
+            annotation class A
+
+            class Subject(i: @A MyInterface) : @A Base(), @A MyInterface {
+                val p: @A MyInterface = TODO()
+                fun f(a: @A MyInterface): @A MyInterface = TODO()
+            }
+            """.trimIndent()
+        )
+        val javaSource = Source.java(
+            "foo.bar.Subject.java",
+            """
+            package foo.bar;
+            import java.lang.annotation.ElementType;
+            import java.lang.annotation.Target;
+            import java.lang.annotation.Repeatable;
+
+            interface MyInterface {}
+            class Base {}
+
+            @Target(ElementType.TYPE_USE)
+            @interface A {}
+
+            class Subject extends @A Base implements @A MyInterface {
+                Subject(@A MyInterface i) {}
+                @A MyInterface p;
+                @A MyInterface f(@A MyInterface a) {
+                    throw new RuntimeException();
+                }
+            }
+            """.trimIndent()
+        )
+
+        listOf(javaSource, kotlinSource).forEach { source ->
+            runTest(
+                sources = listOf(source)
+            ) { invocation ->
+                // We can't see type annotations from precompiled Java classes. Skipping it for now:
+                // https://github.com/google/ksp/issues/1296
+                if (source == javaSource && preCompiled) {
+                    return@runTest
+                }
+                val subject = invocation.processingEnv.requireTypeElement("foo.bar.Subject")
+                // There's an issue in KSP that prevents us from getting type annotations in
+                // places other than supertypes: https://github.com/google/ksp/issues/1325
+                val annotations = if (invocation.isKsp) {
+                    listOf(
+                        subject.superClass!!.getAllAnnotations().first(),
+                        subject.superInterfaces.first().getAllAnnotations().first(),
+                    )
+                } else {
+                    listOf(
+                        subject.superClass!!.getAllAnnotations().first(),
+                        subject.superInterfaces.first().getAllAnnotations().first(),
+                        subject.getDeclaredField("p").type.getAllAnnotations().first(),
+                        subject.getConstructors().first().parameters.first().type
+                            .getAllAnnotations().first(),
+                        subject.getMethodByJvmName("f").returnType
+                            .getAllAnnotations().first(),
+                        subject.getMethodByJvmName("f").parameters.first().type
+                            .getAllAnnotations().first()
+                    )
+                }
+                annotations.forEach { annotation ->
+                    assertThat(annotation.qualifiedName).isEqualTo("foo.bar.A")
+                }
+                assertThat(subject.superClass!!.hasAnnotationWithPackage("foo.bar")).isTrue()
+                subject.superInterfaces.forEach {
+                    assertThat(it.hasAnnotationWithPackage("foo.bar")).isTrue()
+                }
+            }
+        }
+    }
+
+    @Test
+    fun repeatedTypeAnnotations() {
+        val kotlinSource = Source.kotlin(
+            "foo.bar.Subject.kt",
+            """
+            package foo.bar
+
+            @Target(AnnotationTarget.TYPE)
+            @Repeatable
+            annotation class A(val value: Int)
+
+            open class Base
+
+            class Subject : @A(0) @A(1) Base()
+            """.trimIndent()
+        )
+        val javaSource = Source.java(
+            "foo.bar.Subject.java",
+            """
+            package foo.bar;
+            import java.lang.annotation.ElementType;
+            import java.lang.annotation.Target;
+            import java.lang.annotation.Repeatable;
+
+            class Base {}
+
+            @Repeatable(AContainer.class)
+            @Target(ElementType.TYPE_USE)
+            @interface A {
+                int value();
+            }
+
+            @Target(ElementType.TYPE_USE)
+            @interface AContainer {
+                A[] value();
+            }
+
+            class Subject extends @A(0) @A(1) Base {}
+            """.trimIndent()
+        )
+
+        listOf(javaSource, kotlinSource).forEach { source ->
+            runTest(
+                sources = listOf(source)
+            ) { invocation ->
+                // We can't see type annotations from precompiled Java classes. Skipping it for now:
+                // https://github.com/google/ksp/issues/1296
+                if (source == javaSource && preCompiled) {
+                    return@runTest
+                }
+                val subject = invocation.processingEnv.requireTypeElement("foo.bar.Subject")
+                val base = subject.superClass!!
+                assertThat(base.getAllAnnotations()[0].name)
+                    .isEqualTo("A")
+                assertThat(base.getAllAnnotations()[0].qualifiedName)
+                    .isEqualTo("foo.bar.A")
+                assertThat(base.getAllAnnotations()[0].annotationValues.first().asInt())
+                    .isEqualTo(0)
+                assertThat(base.getAllAnnotations()[1].name)
+                    .isEqualTo("A")
+                assertThat(base.getAllAnnotations()[1].qualifiedName)
+                    .isEqualTo("foo.bar.A")
+                assertThat(base.getAllAnnotations()[1].annotationValues.first().asInt())
+                    .isEqualTo(1)
+            }
+        }
+    }
+
     // helper function to read what we need
     private fun XAnnotated.getSuppressValues(): List<String>? {
         return this.findAnnotation<TestSuppressWarnings>()
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
index 3d05e0b..0ca863f 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XAnnotationValueTest.kt
@@ -57,6 +57,7 @@
 class XAnnotationValueTest(
     private val isPreCompiled: Boolean,
     private val sourceKind: SourceKind,
+    private val isTypeAnnotation: Boolean,
 ) {
     private fun runTest(
         javaSource: Source.JavaSource,
@@ -104,34 +105,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     boolean booleanParam();
                     boolean[] booleanArrayParam();
                     boolean[] booleanVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     booleanParam = true,
                     booleanArrayParam = {true, false, true},
                     booleanVarArgsParam = {false, true, false}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    booleanParam = true,
+                    booleanArrayParam = {true, false, true},
+                    booleanVarArgsParam = {false, true, false}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val booleanParam: Boolean,
                     val booleanArrayParam: BooleanArray,
                     vararg val booleanVarArgsParam: Boolean,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     booleanParam = true,
                     booleanArrayParam = [true, false, true],
                     booleanVarArgsParam = [false, true, false],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    booleanParam = true,
+                    booleanArrayParam = [true, false, true],
+                    booleanVarArgsParam = [false, true, false],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -161,11 +180,7 @@
                     checkSingleValue(value, expectedValues[i])
                 }
             }
-
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -194,34 +209,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     int intParam();
                     int[] intArrayParam();
                     int[] intVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     intParam = (short) 1,
                     intArrayParam = {(byte) 3, (short) 5, 7},
                     intVarArgsParam = {(byte) 9, (short) 11, 13}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    intParam = (short) 1,
+                    intArrayParam = {(byte) 3, (short) 5, 7},
+                    intVarArgsParam = {(byte) 9, (short) 11, 13}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val intParam: Int,
                     val intArrayParam: IntArray,
                     vararg val intVarArgsParam: Int,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     intParam = 1,
                     intArrayParam = [3, 5, 7],
                     intVarArgsParam = [9, 11, 13],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    intParam = 1,
+                    intArrayParam = [3, 5, 7],
+                    intVarArgsParam = [9, 11, 13],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -252,10 +285,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -284,34 +314,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     short shortParam();
                     short[] shortArrayParam();
                     short[] shortVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     shortParam = (byte) 1,
                     shortArrayParam = {(byte) 3, (short) 5, 7},
                     shortVarArgsParam = {(byte) 9, (short) 11, 13}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    shortParam = (byte) 1,
+                    shortArrayParam = {(byte) 3, (short) 5, 7},
+                    shortVarArgsParam = {(byte) 9, (short) 11, 13}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val shortParam: Short,
                     val shortArrayParam: ShortArray,
                     vararg val shortVarArgsParam: Short,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     shortParam = 1,
                     shortArrayParam = [3, 5, 7],
                     shortVarArgsParam = [9, 11, 13],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    shortParam = 1,
+                    shortArrayParam = [3, 5, 7],
+                    shortVarArgsParam = [9, 11, 13],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -342,10 +390,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -374,34 +419,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     long longParam();
                     long[] longArrayParam();
                     long[] longVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     longParam = (byte) 1,
                     longArrayParam = {(short) 3, (int) 5, 7L},
                     longVarArgsParam = {(short) 9, (int) 11, 13L}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    longParam = (byte) 1,
+                    longArrayParam = {(short) 3, (int) 5, 7L},
+                    longVarArgsParam = {(short) 9, (int) 11, 13L}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val longParam: Long,
                     val longArrayParam: LongArray,
                     vararg val longVarArgsParam: Long,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     longParam = 1L,
                     longArrayParam = [3L, 5L, 7L],
                     longVarArgsParam = [9L, 11L, 13L],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    longParam = 1L,
+                    longArrayParam = [3L, 5L, 7L],
+                    longVarArgsParam = [9L, 11L, 13L],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -432,10 +495,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -464,34 +524,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     float floatParam();
                     float[] floatArrayParam();
                     float[] floatVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     floatParam = (byte) 1,
                     floatArrayParam = {(short) 3, 5.1F, 7.1F},
                     floatVarArgsParam = {9, 11.1F, 13.1F}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    floatParam = (byte) 1,
+                    floatArrayParam = {(short) 3, 5.1F, 7.1F},
+                    floatVarArgsParam = {9, 11.1F, 13.1F}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val floatParam: Float,
                     val floatArrayParam: FloatArray,
                     vararg val floatVarArgsParam: Float,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     floatParam = 1F,
                     floatArrayParam = [3F, 5.1F, 7.1F],
                     floatVarArgsParam = [9F, 11.1F, 13.1F],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    floatParam = 1F,
+                    floatArrayParam = [3F, 5.1F, 7.1F],
+                    floatVarArgsParam = [9F, 11.1F, 13.1F],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -522,10 +600,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -554,34 +629,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     double doubleParam();
                     double[] doubleArrayParam();
                     double[] doubleVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     doubleParam = (byte) 1,
                     doubleArrayParam = {(short) 3, 5.1F, 7.1},
                     doubleVarArgsParam = {9, 11.1F, 13.1}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    doubleParam = (byte) 1,
+                    doubleArrayParam = {(short) 3, 5.1F, 7.1},
+                    doubleVarArgsParam = {9, 11.1F, 13.1}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val doubleParam: Double,
                     val doubleArrayParam: DoubleArray,
                     vararg val doubleVarArgsParam: Double,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     doubleParam = 1.0,
                     doubleArrayParam = [3.0, 5.1, 7.1],
                     doubleVarArgsParam = [9.0, 11.1, 13.1],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    doubleParam = 1.0,
+                    doubleArrayParam = [3.0, 5.1, 7.1],
+                    doubleVarArgsParam = [9.0, 11.1, 13.1],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -612,9 +705,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
+            val annotation = getAnnotation(invocation)
             annotation.getAnnotationValue("doubleParam").value
             annotation.getAnnotationValue("doubleArrayParam").value
             annotation.getAnnotationValue("doubleVarArgsParam").value
@@ -676,34 +767,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     byte byteParam();
                     byte[] byteArrayParam();
                     byte[] byteVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     byteParam = (byte) 1,
                     byteArrayParam = {(byte) 3, (byte) 5, (byte) 7},
                     byteVarArgsParam = {(byte) 9, (byte) 11, (byte) 13}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    byteParam = (byte) 1,
+                    byteArrayParam = {(byte) 3, (byte) 5, (byte) 7},
+                    byteVarArgsParam = {(byte) 9, (byte) 11, (byte) 13}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val byteParam: Byte,
                     val byteArrayParam: ByteArray,
                     vararg val byteVarArgsParam: Byte,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     byteParam = 1,
                     byteArrayParam = [3, 5, 7],
                     byteVarArgsParam = [9, 11, 13],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    byteParam = 1,
+                    byteArrayParam = [3, 5, 7],
+                    byteVarArgsParam = [9, 11, 13],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -734,10 +843,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -766,34 +872,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     char charParam();
                     char[] charArrayParam();
                     char[] charVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     charParam = '1',
                     charArrayParam = {'2', '3', '4'},
                     charVarArgsParam = {'5', '6', '7'}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    charParam = '1',
+                    charArrayParam = {'2', '3', '4'},
+                    charVarArgsParam = {'5', '6', '7'}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val charParam: Char,
                     val charArrayParam: CharArray,
                     vararg val charVarArgsParam: Char,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     charParam = '1',
                     charArrayParam = ['2', '3', '4'],
                     charVarArgsParam = ['5', '6', '7'],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    charParam = '1',
+                    charArrayParam = ['2', '3', '4'],
+                    charVarArgsParam = ['5', '6', '7'],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -824,10 +948,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -856,34 +977,52 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     String stringParam();
                     String[] stringArrayParam();
                     String[] stringVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     stringParam = "1",
                     stringArrayParam = {"3", "5", "7"},
                     stringVarArgsParam = {"9", "11", "13"}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    stringParam = "1",
+                    stringArrayParam = {"3", "5", "7"},
+                    stringVarArgsParam = {"9", "11", "13"}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
                 "test.MyClass.kt",
                 """
                 package test
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val stringParam: String,
                     val stringArrayParam: Array<String>,
                     vararg val stringVarArgsParam: String,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     stringParam = "1",
                     stringArrayParam = ["3", "5", "7"],
                     stringVarArgsParam = ["9", "11", "13"],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    stringParam = "1",
+                    stringArrayParam = ["3", "5", "7"],
+                    stringVarArgsParam = ["9", "11", "13"],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -925,10 +1064,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -957,18 +1093,28 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
                 enum MyEnum {V1, V2, V3}
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     MyEnum enumParam();
                     MyEnum[] enumArrayParam();
                     MyEnum[] enumVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     enumParam = MyEnum.V1,
                     enumArrayParam = {MyEnum.V1, MyEnum.V2, MyEnum.V3},
                     enumVarArgsParam = {MyEnum.V3, MyEnum.V2, MyEnum.V1}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    enumParam = MyEnum.V1,
+                    enumArrayParam = {MyEnum.V1, MyEnum.V2, MyEnum.V3},
+                    enumVarArgsParam = {MyEnum.V3, MyEnum.V2, MyEnum.V1}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
@@ -976,17 +1122,25 @@
                 """
                 package test
                 enum class MyEnum {V1, V2, V3}
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val enumParam: MyEnum,
                     val enumArrayParam: Array<MyEnum>,
                     vararg val enumVarArgsParam: MyEnum,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     enumParam = MyEnum.V1,
                     enumArrayParam = [MyEnum.V1, MyEnum.V2, MyEnum.V3],
                     enumVarArgsParam = [MyEnum.V3, MyEnum.V2, MyEnum.V1],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    enumParam = MyEnum.V1,
+                    enumArrayParam = [MyEnum.V1, MyEnum.V2, MyEnum.V3],
+                    enumVarArgsParam = [MyEnum.V3, MyEnum.V2, MyEnum.V1],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -1031,10 +1185,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
                     @test.MyAnnotation(
@@ -1062,20 +1213,30 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
                 class C1 {}
                 class C2 {}
                 class C3 {}
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     Class<?> typeParam();
                     Class<?>[] typeArrayParam();
                     Class<?>[] typeVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     typeParam = C1.class,
                     typeArrayParam = {C1.class, C2.class, C3.class},
                     typeVarArgsParam = {C3.class, C2.class, C1.class}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    typeParam = C1.class,
+                    typeArrayParam = {C1.class, C2.class, C3.class},
+                    typeVarArgsParam = {C3.class, C2.class, C1.class}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
@@ -1085,17 +1246,25 @@
                 class C1
                 class C2
                 class C3
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val typeParam: kotlin.reflect.KClass<*>,
                     val typeArrayParam: Array<kotlin.reflect.KClass<*>>,
                     vararg val typeVarArgsParam: kotlin.reflect.KClass<*>,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     typeParam = C1::class,
                     typeArrayParam = [C1::class, C2::class, C3::class],
                     typeVarArgsParam = [C3::class, C2::class, C1::class],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    typeParam = C1::class,
+                    typeArrayParam = [C1::class, C2::class, C3::class],
+                    typeVarArgsParam = [C3::class, C2::class, C1::class],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -1154,10 +1323,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -1186,20 +1352,30 @@
                 "test.MyClass",
                 """
                 package test;
+                import java.lang.annotation.ElementType;
+                import java.lang.annotation.Target;
                 @interface A {
                     String value();
                 }
+                @Target({ElementType.TYPE, ElementType.TYPE_USE})
                 @interface MyAnnotation {
                     A annotationParam();
                     A[] annotationArrayParam();
                     A[] annotationVarArgsParam(); // There's no varargs in java so use array
                 }
+                interface MyInterface {}
                 @MyAnnotation(
                     annotationParam = @A("1"),
                     annotationArrayParam = {@A("3"), @A("5"), @A("7")},
                     annotationVarArgsParam = {@A("9"), @A("11"), @A("13")}
                 )
-                class MyClass {}
+                class MyClass implements
+                @MyAnnotation(
+                    annotationParam = @A("1"),
+                    annotationArrayParam = {@A("3"), @A("5"), @A("7")},
+                    annotationVarArgsParam = {@A("9"), @A("11"), @A("13")}
+                )
+                MyInterface {}
                 """.trimIndent()
             ) as Source.JavaSource,
             kotlinSource = Source.kotlin(
@@ -1207,17 +1383,25 @@
                 """
                 package test
                 annotation class A(val value: String)
+                @Target(AnnotationTarget.CLASS, AnnotationTarget.TYPE)
                 annotation class MyAnnotation(
                     val annotationParam: A,
                     val annotationArrayParam: Array<A>,
                     vararg val annotationVarArgsParam: A,
                 )
+                interface MyInterface
                 @MyAnnotation(
                     annotationParam = A("1"),
                     annotationArrayParam = [A("3"), A("5"), A("7")],
                     annotationVarArgsParam = [A("9"), A("11"), A("13")],
                 )
-                class MyClass
+                class MyClass :
+                @MyAnnotation(
+                    annotationParam = A("1"),
+                    annotationArrayParam = [A("3"), A("5"), A("7")],
+                    annotationVarArgsParam = [A("9"), A("11"), A("13")],
+                )
+                MyInterface
                 """.trimIndent()
             ) as Source.KotlinSource
         ) { invocation ->
@@ -1263,10 +1447,7 @@
                 }
             }
 
-            val annotation = invocation.processingEnv.requireTypeElement("test.MyClass")
-                .getAllAnnotations()
-                .single { it.qualifiedName == "test.MyAnnotation" }
-
+            val annotation = getAnnotation(invocation)
             // Compare the AnnotationSpec string ignoring whitespace
             assertThat(annotation.toAnnotationSpec().toString().removeWhiteSpace())
                 .isEqualTo("""
@@ -1292,17 +1473,36 @@
         return this.replace("\\s+".toRegex(), "")
     }
 
+    private fun getAnnotation(invocation: XTestInvocation): XAnnotation {
+        val typeElement = invocation.processingEnv.requireTypeElement("test.MyClass")
+        return if (isTypeAnnotation) {
+            typeElement.superInterfaces.first().getAllAnnotations()
+                .single { it.qualifiedName == "test.MyAnnotation" }
+        } else {
+            typeElement.getAllAnnotations().single { it.qualifiedName == "test.MyAnnotation" }
+        }
+    }
+
     enum class SourceKind { JAVA, KOTLIN }
 
     companion object {
         @JvmStatic
-        @Parameterized.Parameters(name = "isPreCompiled_{0}_sourceKind_{1}")
+        @Parameterized.Parameters(name = "isPreCompiled_{0}_sourceKind_{1}_isTypeAnnotation_{2}")
         fun params(): List<Array<Any>> {
             val isPreCompiledValues = arrayOf(false, true)
             val sourceKindValues = arrayOf(SourceKind.JAVA, SourceKind.KOTLIN)
+            val isTypeAnnotation = arrayOf(false, true)
             return isPreCompiledValues.flatMap { isPreCompiled ->
-                sourceKindValues.map { sourceKind ->
-                    arrayOf(isPreCompiled, sourceKind)
+                sourceKindValues.flatMap { sourceKind ->
+                    isTypeAnnotation.mapNotNull { isTypeAnnotation ->
+                        // We can't see type annotations from precompiled Java classes. Skipping it
+                        // for now: https://github.com/google/ksp/issues/1296
+                        if (isPreCompiled && sourceKind == SourceKind.JAVA && isTypeAnnotation) {
+                            null
+                        } else {
+                            arrayOf(isPreCompiled, sourceKind, isTypeAnnotation)
+                        }
+                    }
                 }
             }
         }
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
index e44db5b..9036fa2 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeElementTest.kt
@@ -19,6 +19,7 @@
 import androidx.room.compiler.codegen.XClassName
 import androidx.room.compiler.codegen.XTypeName
 import androidx.room.compiler.codegen.asClassName
+import androidx.room.compiler.processing.javac.JavacType
 import androidx.room.compiler.processing.ksp.jvmDescriptor
 import androidx.room.compiler.processing.util.Source
 import androidx.room.compiler.processing.util.XTestInvocation
@@ -255,6 +256,9 @@
                     assertThat(superInterface.typeArguments[0].asTypeName().kotlin)
                         .isEqualTo(KClassName("kotlin", "String"))
                 }
+                if (! invocation.isKsp) {
+                    assertThat((superInterface as JavacType).kotlinType).isNotNull()
+                }
             }
         }
     }
diff --git a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
index 835cdfd..724c037 100644
--- a/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
+++ b/room/room-compiler-processing/src/test/java/androidx/room/compiler/processing/XTypeTest.kt
@@ -24,6 +24,7 @@
 import androidx.room.compiler.processing.util.XTestInvocation
 import androidx.room.compiler.processing.util.asJClassName
 import androidx.room.compiler.processing.util.asKClassName
+import androidx.room.compiler.processing.util.compileFiles
 import androidx.room.compiler.processing.util.dumpToString
 import androidx.room.compiler.processing.util.getDeclaredField
 import androidx.room.compiler.processing.util.getDeclaredMethodByJvmName
@@ -1525,4 +1526,115 @@
             it.assertCompilationResult { hasErrorContaining("Unresolved reference: MissingType") }
         }
     }
+
+    @Test
+    fun hasAnnotationWithPackage() {
+        val kotlinSrc = Source.kotlin(
+            "KotlinClass.kt",
+            """
+            package foo.bar
+            interface KotlinInterface
+            open class KotlinBase
+            @Target(AnnotationTarget.TYPE)
+            annotation class KotlinAnnotation {
+                @Target(AnnotationTarget.TYPE)
+                annotation class KotlinNestedAnnotation
+            }
+            class KotlinClass : @KotlinAnnotation.KotlinNestedAnnotation KotlinBase(),
+                    @KotlinAnnotation KotlinInterface {
+                inner class KotlinInner : @KotlinAnnotation KotlinInterface
+                class KotlinNested : @KotlinAnnotation KotlinInterface
+            }
+            """.trimIndent()
+        )
+        // KSP can't read nested annotations in Java sources if the filename does not match
+        // the outer class.
+        val javaAnnotationSource = Source.java(
+            "foo.bar.JavaAnnotation",
+            """
+            package foo.bar;
+            import java.lang.annotation.ElementType;
+            import java.lang.annotation.Target;
+            @Target(ElementType.TYPE_USE)
+            @interface JavaAnnotation {
+                @Target(ElementType.TYPE_USE)
+                @interface JavaNestedAnnotation {}
+            }
+            """.trimIndent()
+        )
+        val javaSrc = Source.java(
+            "foo.bar.JavaClass",
+            """
+            package foo.bar;
+            interface JavaInterface {}
+            class JavaBase {}
+            class JavaClass extends @JavaAnnotation.JavaNestedAnnotation JavaBase
+                implements @JavaAnnotation JavaInterface {}
+            """.trimIndent()
+        )
+        fun checkKotlin(invocation: XTestInvocation) {
+            val kotlinTypeElement = invocation.processingEnv.requireTypeElement(
+                "foo.bar.KotlinClass")
+            kotlinTypeElement.superInterfaces.single().let {
+                assertThat(it.getAllAnnotations().single().typeElement.packageName)
+                        .isEqualTo("foo.bar")
+                assertThat(it.getAllAnnotations().single().typeElement.qualifiedName)
+                    .isEqualTo("foo.bar.KotlinAnnotation")
+
+                assertThat(it.hasAnnotationWithPackage("foo.bar.KotlinAnnotation")).isFalse()
+                assertThat(it.hasAnnotationWithPackage("foo.bar")).isTrue()
+                assertThat(it.hasAnnotationWithPackage("foo")).isFalse()
+            }
+            kotlinTypeElement.superClass!!.let {
+                assertThat(it.getAllAnnotations().single().typeElement.packageName)
+                    .isEqualTo("foo.bar")
+                assertThat(it.getAllAnnotations().single().typeElement.qualifiedName)
+                    .isEqualTo("foo.bar.KotlinAnnotation.KotlinNestedAnnotation")
+
+                assertThat(it.getAllAnnotations().single().typeElement.packageName)
+                    .isEqualTo("foo.bar")
+                assertThat(it.getAllAnnotations().single().typeElement.qualifiedName)
+                    .isEqualTo("foo.bar.KotlinAnnotation.KotlinNestedAnnotation")
+            }
+        }
+        fun checkJava(invocation: XTestInvocation) {
+            val javaTypeElement = invocation.processingEnv.requireTypeElement(
+                "foo.bar.JavaClass")
+            javaTypeElement.superInterfaces.first().let {
+                assertThat(it.getAllAnnotations().single().typeElement.packageName)
+                    .isEqualTo("foo.bar")
+                assertThat(it.getAllAnnotations().single().typeElement.qualifiedName)
+                    .isEqualTo("foo.bar.JavaAnnotation")
+
+                assertThat(it.hasAnnotationWithPackage("foo.bar.JavaClass")).isFalse()
+                assertThat(it.hasAnnotationWithPackage("foo.bar")).isTrue()
+                assertThat(it.hasAnnotationWithPackage("foo")).isFalse()
+            }
+            javaTypeElement.superClass!!.let {
+                assertThat(it.getAllAnnotations().single().typeElement.packageName)
+                    .isEqualTo("foo.bar")
+                assertThat(it.getAllAnnotations().single().typeElement.qualifiedName)
+                    .isEqualTo("foo.bar.JavaAnnotation.JavaNestedAnnotation")
+
+                assertThat(it.hasAnnotationWithPackage("foo.bar.JavaClass")).isFalse()
+                assertThat(it.hasAnnotationWithPackage("foo.bar")).isTrue()
+                assertThat(it.hasAnnotationWithPackage("foo")).isFalse()
+            }
+        }
+        runProcessorTest(
+            sources = listOf(kotlinSrc, javaAnnotationSource, javaSrc),
+            handler = {
+                checkKotlin(it)
+                checkJava(it)
+            }
+        )
+        runProcessorTest(
+            classpath = compileFiles(listOf(kotlinSrc)),
+            handler = {
+                // We can't see type annotations from precompiled Java classes. Skipping it
+                // for now: https://github.com/google/ksp/issues/1296
+                checkKotlin(it)
+            }
+        )
+    }
 }