Merge "Wrap XAnnotationValue.value list items in XAnnotationValue." into androidx-main
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
index 1787f38..7a4dc1b 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotation.kt
@@ -47,40 +47,92 @@
*/
val type: XType
- /**
- * All values declared in the annotation class.
- */
+ /** All values declared in the annotation class. */
val annotationValues: List<XAnnotationValue>
- /**
- * Returns the value of the given [methodName] as a type reference.
- */
- fun getAsType(methodName: String): XType = get(methodName)
+ /** Returns the value of the given [methodName] as a type reference. */
+ fun getAsType(methodName: String): XType = getAnnotationValue(methodName).asType()
- /**
- * Returns the value of the given [methodName] as a list of type references.
- */
- fun getAsTypeList(methodName: String): List<XType> = get(methodName)
+ /** Returns the value of the given [methodName] as a list of type references. */
+ fun getAsTypeList(methodName: String): List<XType> = getAnnotationValue(methodName).asTypeList()
- /**
- * Returns the value of the given [methodName] as another [XAnnotation].
- */
- fun getAsAnnotation(methodName: String): XAnnotation = get(methodName)
+ /** Returns the value of the given [methodName] as another [XAnnotation]. */
+ fun getAsAnnotation(methodName: String): XAnnotation =
+ getAnnotationValue(methodName).asAnnotation()
- /**
- * Returns the value of the given [methodName] as a list of [XAnnotation].
- */
- fun getAsAnnotationList(methodName: String): List<XAnnotation> = get(methodName)
+ /** Returns the value of the given [methodName] as a list of [XAnnotation]. */
+ fun getAsAnnotationList(methodName: String): List<XAnnotation> =
+ getAnnotationValue(methodName).asAnnotationList()
- /**
- * Returns the value of the given [methodName] as a [XEnumEntry].
- */
- fun getAsEnum(methodName: String): XEnumEntry = get(methodName)
+ /** Returns the value of the given [methodName] as a [XEnumEntry]. */
+ fun getAsEnum(methodName: String): XEnumEntry = getAnnotationValue(methodName).asEnum()
- /**
- * Returns the value of the given [methodName] as a list of [XEnumEntry].
- */
- fun getAsEnumList(methodName: String): List<XEnumEntry> = get(methodName)
+ /** Returns the value of the given [methodName] as a list of [XEnumEntry]. */
+ fun getAsEnumList(methodName: String): List<XEnumEntry> =
+ getAnnotationValue(methodName).asEnumList()
+
+ /** Returns the value of the given [methodName] as a [Boolean]. */
+ fun getAsBoolean(methodName: String): Boolean = getAnnotationValue(methodName).asBoolean()
+
+ /** Returns the value of the given [methodName] as a list of [Boolean]. */
+ fun getAsBooleanList(methodName: String): List<Boolean> =
+ getAnnotationValue(methodName).asBooleanList()
+
+ /** Returns the value of the given [methodName] as a [String]. */
+ fun getAsString(methodName: String): String = getAnnotationValue(methodName).asString()
+
+ /** Returns the value of the given [methodName] as a list of [String]. */
+ fun getAsStringList(methodName: String): List<String> =
+ getAnnotationValue(methodName).asStringList()
+
+ /** Returns the value of the given [methodName] as a [Int]. */
+ fun getAsInt(methodName: String): Int = getAnnotationValue(methodName).asInt()
+
+ /** Returns the value of the given [methodName] as a list of [Int]. */
+ fun getAsIntList(methodName: String): List<Int> = getAnnotationValue(methodName).asIntList()
+
+ /** Returns the value of the given [methodName] as a [Long]. */
+ fun getAsLong(methodName: String): Long = getAnnotationValue(methodName).asLong()
+
+ /** Returns the value of the given [methodName] as a list of [Long]. */
+ fun getAsLongList(methodName: String): List<Long> = getAnnotationValue(methodName).asLongList()
+
+ /** Returns the value of the given [methodName] as a [Short]. */
+ fun getAsShort(methodName: String): Short = getAnnotationValue(methodName).asShort()
+
+ /** Returns the value of the given [methodName] as a list of [Short]. */
+ fun getAsShortList(methodName: String): List<Short> =
+ getAnnotationValue(methodName).asShortList()
+
+ /** Returns the value of the given [methodName] as a [Float]. */
+ fun getAsFloat(methodName: String): Float = getAnnotationValue(methodName).asFloat()
+
+ /** Returns the value of the given [methodName] as a list of [Float]. */
+ fun getAsFloatList(methodName: String): List<Float> =
+ getAnnotationValue(methodName).asFloatList()
+
+ /** Returns the value of the given [methodName] as a [Double]. */
+ fun getAsDouble(methodName: String): Double = getAnnotationValue(methodName).asDouble()
+
+ /** Returns the value of the given [methodName] as a list of [Double]. */
+ fun getAsDoubleList(methodName: String): List<Double> =
+ getAnnotationValue(methodName).asDoubleList()
+
+ /** Returns the value of the given [methodName] as a [Byte]. */
+ fun getAsByte(methodName: String): Byte = getAnnotationValue(methodName).asByte()
+
+ /** Returns the value of the given [methodName] as a list of [Byte]. */
+ fun getAsByteList(methodName: String): List<Byte> = getAnnotationValue(methodName).asByteList()
+
+ /** Returns the value of the given [methodName] as a list of [Byte]. */
+ fun getAsAnnotationValueList(methodName: String): List<XAnnotationValue> =
+ getAnnotationValue(methodName).asAnnotationValueList()
+
+ /**Returns the value of the given [methodName] as a [XAnnotationValue]. */
+ fun getAnnotationValue(methodName: String): XAnnotationValue {
+ return annotationValues.firstOrNull { it.name == methodName }
+ ?: error("No property named $methodName was found in annotation $name")
+ }
}
/**
@@ -95,15 +147,9 @@
*
* For convenience, wrapper functions are provided for these types, eg [XAnnotation.getAsType]
*/
-inline fun <reified T> XAnnotation.get(methodName: String): T {
- val argument = annotationValues.firstOrNull { it.name == methodName }
- ?: error("No property named $methodName was found in annotation $name")
-
- return argument.value as? T ?: error(
- "Value of $methodName of type ${argument.value?.javaClass} " +
- "cannot be cast to ${T::class.java}"
- )
-}
+// TODO: Consider deprecating this method for getAs*() methods
+@Suppress("DEPRECATION")
+inline fun <reified T> XAnnotation.get(methodName: String): T = get(methodName, T::class.java)
/**
* Returns the value of the given [methodName], throwing an exception if the method is not
@@ -119,16 +165,23 @@
*
* For convenience, wrapper functions are provided for these types, eg [XAnnotation.getAsType]
*/
+@Deprecated("Use one of the getAs*() methods instead, e.g. getAsBoolean().")
fun <T> XAnnotation.get(methodName: String, clazz: Class<T>): T {
- val argument = annotationValues.firstOrNull { it.name == methodName }
- ?: error("No property named $methodName was found in annotation $name")
+ val argument = getAnnotationValue(methodName)
- if (!clazz.isInstance(argument.value)) {
- error("Value of $methodName of type ${argument.value?.javaClass} cannot be cast to $clazz")
+ val value = if (argument.value is List<*>) {
+ // If the argument is for a list, unwrap each item in the list
+ (argument.value as List<*>).map { (it as XAnnotationValue).value }
+ } else {
+ argument.value
+ }
+
+ if (!clazz.isInstance(value)) {
+ error("Value of $methodName of type ${value?.javaClass} cannot be cast to $clazz")
}
@Suppress("UNCHECKED_CAST")
- return argument.value as T
+ return value as T
}
/**
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt
index c3c6d34..ffd039b 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/XAnnotationValue.kt
@@ -34,7 +34,77 @@
* - XEnumEntry
* - XAnnotation
* - XType
- * - List of any of the above
+ * - List of [XAnnotationValue]
*/
val value: Any?
-}
+
+ /** Returns the value as a [XType]. */
+ fun asType(): XType = value as XType
+
+ /** Returns the value as a list of [XType]. */
+ fun asTypeList(): List<XType> = asAnnotationValueList().map { it.asType() }
+
+ /** Returns the value as another [XAnnotation]. */
+ fun asAnnotation(): XAnnotation = value as XAnnotation
+
+ /** Returns the value as a list of [XAnnotation]. */
+ fun asAnnotationList(): List<XAnnotation> = asAnnotationValueList().map { it.asAnnotation() }
+
+ /** Returns the value as a [XEnumEntry]. */
+ fun asEnum(): XEnumEntry = value as XEnumEntry
+
+ /** Returns the value as a list of [XEnumEntry]. */
+ fun asEnumList(): List<XEnumEntry> = asAnnotationValueList().map { it.asEnum() }
+
+ /** Returns the value as a [Boolean]. */
+ fun asBoolean(): Boolean = value as Boolean
+
+ /** Returns the value as a list of [Boolean]. */
+ fun asBooleanList(): List<Boolean> = asAnnotationValueList().map { it.asBoolean() }
+
+ /** Returns the value as a [String]. */
+ fun asString(): String = value as String
+
+ /** Returns the value as a list of [String]. */
+ fun asStringList(): List<String> = asAnnotationValueList().map { it.asString() }
+
+ /** Returns the value as a [Int]. */
+ fun asInt(): Int = value as Int
+
+ /** Returns the value as a list of [Int]. */
+ fun asIntList(): List<Int> = asAnnotationValueList().map { it.asInt() }
+
+ /** Returns the value as a [Long]. */
+ fun asLong(): Long = value as Long
+
+ /** Returns the value as a list of [Long]. */
+ fun asLongList(): List<Long> = asAnnotationValueList().map { it.asLong() }
+
+ /** Returns the value as a [Short]. */
+ fun asShort(): Short = value as Short
+
+ /** Returns the value as a list of [Short]. */
+ fun asShortList(): List<Short> = asAnnotationValueList().map { it.asShort() }
+
+ /** Returns the value as a [Float]. */
+ fun asFloat(): Float = value as Float
+
+ /** Returns the value as a list of [Float]. */
+ fun asFloatList(): List<Float> = asAnnotationValueList().map { it.value as Float }
+
+ /** Returns the value as a [Double]. */
+ fun asDouble(): Double = value as Double
+
+ /** Returns the value as a list of [Double]. */
+ fun asDoubleList(): List<Double> = asAnnotationValueList().map { it.asDouble() }
+
+ /** Returns the value as a [Byte]. */
+ fun asByte(): Byte = value as Byte
+
+ /** Returns the value as a list of [Byte]. */
+ fun asByteList(): List<Byte> = asAnnotationValueList().map { it.asByte() }
+
+ /**Returns the value a list of [XAnnotationValue]. */
+ @Suppress("UNCHECKED_CAST") // Values in a list are always wrapped in XAnnotationValue
+ fun asAnnotationValueList(): List<XAnnotationValue> = value as List<XAnnotationValue>
+}
\ No newline at end of file
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
index 8767264..7a3d2b2 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/javac/JavacAnnotationValue.kt
@@ -30,55 +30,60 @@
internal class JavacAnnotationValue(
val env: JavacProcessingEnv,
- val element: ExecutableElement,
- val annotationValue: AnnotationValue
+ val method: ExecutableElement,
+ val annotationValue: AnnotationValue,
+ private val valueProvider: () -> Any? = {
+ UNWRAP_VISITOR.visit(annotationValue, VisitorData(env, method))
+ }
) : XAnnotationValue {
override val name: String
- get() = element.simpleName.toString()
+ get() = method.simpleName.toString()
- override val value: Any? by lazy { UNWRAP_VISITOR.visit(annotationValue, env) }
+ override val value: Any? by lazy { valueProvider.invoke() }
}
-private val UNWRAP_VISITOR = object : AbstractAnnotationValueVisitor8<Any?, JavacProcessingEnv>() {
- override fun visitBoolean(b: Boolean, env: JavacProcessingEnv) = b
- override fun visitByte(b: Byte, env: JavacProcessingEnv) = b
- override fun visitChar(c: Char, env: JavacProcessingEnv) = c
- override fun visitDouble(d: Double, env: JavacProcessingEnv) = d
- override fun visitFloat(f: Float, env: JavacProcessingEnv) = f
- override fun visitInt(i: Int, env: JavacProcessingEnv) = i
- override fun visitLong(i: Long, env: JavacProcessingEnv) = i
- override fun visitShort(s: Short, env: JavacProcessingEnv) = s
+private data class VisitorData(val env: JavacProcessingEnv, val method: ExecutableElement)
- override fun visitString(s: String?, env: JavacProcessingEnv) =
+private val UNWRAP_VISITOR = object : AbstractAnnotationValueVisitor8<Any?, VisitorData>() {
+ override fun visitBoolean(b: Boolean, data: VisitorData) = b
+ override fun visitByte(b: Byte, data: VisitorData) = b
+ override fun visitChar(c: Char, data: VisitorData) = c
+ override fun visitDouble(d: Double, data: VisitorData) = d
+ override fun visitFloat(f: Float, data: VisitorData) = f
+ override fun visitInt(i: Int, data: VisitorData) = i
+ override fun visitLong(i: Long, data: VisitorData) = i
+ override fun visitShort(s: Short, data: VisitorData) = s
+
+ override fun visitString(s: String?, data: VisitorData) =
if (s == "<error>") {
throw TypeNotPresentException(s, null)
} else {
s
}
- override fun visitType(t: TypeMirror, env: JavacProcessingEnv): JavacType {
+ override fun visitType(t: TypeMirror, data: VisitorData): JavacType {
if (t.kind == TypeKind.ERROR) {
throw TypeNotPresentException(t.toString(), null)
}
- return env.wrap(t, kotlinType = null, XNullability.NONNULL)
+ return data.env.wrap(t, kotlinType = null, XNullability.NONNULL)
}
- override fun visitEnumConstant(c: VariableElement, env: JavacProcessingEnv): JavacEnumEntry {
+ override fun visitEnumConstant(c: VariableElement, data: VisitorData): JavacEnumEntry {
val type = c.asType()
if (type.kind == TypeKind.ERROR) {
throw TypeNotPresentException(type.toString(), null)
}
val enumTypeElement = MoreTypes.asTypeElement(type)
return JavacEnumEntry(
- env = env,
+ env = data.env,
entryElement = c,
- enumTypeElement = JavacTypeElement.create(env, enumTypeElement) as XEnumTypeElement
+ enumTypeElement = JavacTypeElement.create(data.env, enumTypeElement) as XEnumTypeElement
)
}
- override fun visitAnnotation(a: AnnotationMirror, env: JavacProcessingEnv) =
- JavacAnnotation(env, a)
+ override fun visitAnnotation(a: AnnotationMirror, data: VisitorData) =
+ JavacAnnotation(data.env, a)
- override fun visitArray(vals: MutableList<out AnnotationValue>, env: JavacProcessingEnv) =
- vals.map { it.accept(this, env) }
+ override fun visitArray(vals: MutableList<out AnnotationValue>, data: VisitorData) =
+ vals.map { JavacAnnotationValue(data.env, data.method, it) { it.accept(this, data) } }
}
\ No newline at end of file
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 122b1b7..bb707eb 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
@@ -20,10 +20,7 @@
import androidx.room.compiler.processing.XAnnotationBox
import androidx.room.compiler.processing.XType
import androidx.room.compiler.processing.XAnnotationValue
-import androidx.room.compiler.processing.isArray
-import com.google.devtools.ksp.getConstructors
import com.google.devtools.ksp.symbol.KSAnnotation
-import com.google.devtools.ksp.symbol.KSClassDeclaration
import com.google.devtools.ksp.symbol.KSType
internal class KspAnnotation(
@@ -44,18 +41,7 @@
}
override val annotationValues: List<XAnnotationValue> by lazy {
- ksAnnotated.arguments.map { arg ->
- KspAnnotationValue(
- env, arg,
- isListType = {
- (ksType.declaration as KSClassDeclaration).getConstructors()
- .singleOrNull()
- ?.parameters
- ?.firstOrNull { it.name == arg.name }
- ?.let { env.wrap(it.type).isArray() } == true
- }
- )
- }
+ ksAnnotated.arguments.map { KspAnnotationValue(env, this, it) }
}
override fun <T : Annotation> asAnnotationBox(annotationClass: Class<T>): XAnnotationBox<T> {
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationValue.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationValue.kt
index 7fd29c2..9959811 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationValue.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspAnnotationValue.kt
@@ -17,7 +17,9 @@
package androidx.room.compiler.processing.ksp
import androidx.room.compiler.processing.XAnnotationValue
+import androidx.room.compiler.processing.isArray
import com.google.devtools.ksp.getClassDeclarationByName
+import com.google.devtools.ksp.getConstructors
import com.google.devtools.ksp.symbol.ClassKind
import com.google.devtools.ksp.symbol.KSAnnotation
import com.google.devtools.ksp.symbol.KSClassDeclaration
@@ -26,64 +28,80 @@
internal class KspAnnotationValue(
val env: KspProcessingEnv,
+ private val owner: KspAnnotation,
val valueArgument: KSValueArgument,
- val isListType: () -> Boolean,
+ private val valueProvider: () -> Any? = { owner.unwrap(valueArgument) },
) : XAnnotationValue {
override val name: String
get() = valueArgument.name?.asString()
?: error("Value argument $this does not have a name.")
- override val value: Any? by lazy { valueArgument.unwrap() }
+ override val value: Any? by lazy { valueProvider.invoke() }
+}
- private fun KSValueArgument.unwrap(): Any? {
- fun unwrap(value: Any?): Any? {
- return when (value) {
- is KSType -> {
- val declaration = value.declaration
- // Wrap enum entries in enum specific type elements
- if (declaration is KSClassDeclaration &&
- declaration.classKind == ClassKind.ENUM_ENTRY
- ) {
- KspEnumEntry.create(env, declaration)
- } else {
- // And otherwise represent class types as generic XType
- env.wrap(value, allowPrimitives = true)
- }
+internal fun KspAnnotation.unwrap(valueArgument: KSValueArgument): Any? {
+ fun unwrap(value: Any?): Any? {
+ return when (value) {
+ is KSType -> {
+ val declaration = value.declaration
+ // Wrap enum entries in enum specific type elements
+ if (declaration is KSClassDeclaration &&
+ declaration.classKind == ClassKind.ENUM_ENTRY
+ ) {
+ KspEnumEntry.create(env, declaration)
+ } else {
+ // And otherwise represent class types as generic XType
+ env.wrap(value, allowPrimitives = true)
}
- is KSAnnotation -> KspAnnotation(env, value)
- // The List implementation further wraps each value as a AnnotationValue.
- // We don't use arrays because we don't have a reified type to instantiate the array
- // with, and using "Any" prevents the array from being cast to the correct
- // type later on.
- is List<*> -> value.map { unwrap(it) }
- // TODO: https://github.com/google/ksp/issues/429
- // If the enum value is from compiled code KSP gives us the actual value an not
- // the KSType, so we wrap it as KspEnumEntry for consistency.
- is Enum<*> -> {
- val declaration =
- env.resolver.getClassDeclarationByName(value::class.java.canonicalName)
- ?: error("Cannot find KSClassDeclaration for Enum '$value'.")
- val valueDeclaration = declaration.declarations
- .filterIsInstance<KSClassDeclaration>()
- .filter { it.classKind == ClassKind.ENUM_ENTRY }
- .firstOrNull() { it.simpleName.getShortName() == value.name }
- ?: error("Cannot find ENUM_ENTRY '$value' in '$declaration'.")
- KspEnumEntry.create(env, valueDeclaration)
- }
- else -> value
}
- }
- return unwrap(value).let { result ->
- // TODO: 5/24/21 KSP does not wrap a single item in a list, even though the
- // return type should be Class<?>[] (only in sources).
- // https://github.com/google/ksp/issues/172
- // https://github.com/google/ksp/issues/214
- if (result !is List<*> && isListType()) {
- listOf(result)
- } else {
- result
+ is KSAnnotation -> KspAnnotation(env, value)
+ // The List implementation further wraps each value as a AnnotationValue.
+ // We don't use arrays because we don't have a reified type to instantiate the array
+ // with, and using "Any" prevents the array from being cast to the correct
+ // type later on.
+ is List<*> -> value.map { unwrap(it) }
+ // TODO: https://github.com/google/ksp/issues/429
+ // If the enum value is from compiled code KSP gives us the actual value an not
+ // the KSType, so we wrap it as KspEnumEntry for consistency.
+ is Enum<*> -> {
+ val declaration =
+ env.resolver.getClassDeclarationByName(value::class.java.canonicalName)
+ ?: error("Cannot find KSClassDeclaration for Enum '$value'.")
+ val valueDeclaration = declaration.declarations
+ .filterIsInstance<KSClassDeclaration>()
+ .filter { it.classKind == ClassKind.ENUM_ENTRY }
+ .firstOrNull() { it.simpleName.getShortName() == value.name }
+ ?: error("Cannot find ENUM_ENTRY '$value' in '$declaration'.")
+ KspEnumEntry.create(env, valueDeclaration)
}
+ else -> value
}
}
+ return unwrap(valueArgument.value).let { result ->
+ when {
+ result is List<*> -> {
+ // For lists, wrap each item in a KSPAnnotationValue. This models things similar to
+ // javac, and allows us to report errors on each individual item rather than just
+ // the list itself.
+ result.map { KspAnnotationValue(env, this, valueArgument) { it } }
+ }
+ isArrayType(valueArgument) -> {
+ // TODO: 5/24/21 KSP does not wrap a single item in a list, even though the
+ // return type should be Class<?>[] (only in sources).
+ // https://github.com/google/ksp/issues/172
+ // https://github.com/google/ksp/issues/214
+ listOf(KspAnnotationValue(env, this, valueArgument) { result })
+ }
+ else -> result
+ }
+ }
+}
+
+private fun KspAnnotation.isArrayType(arg: KSValueArgument): Boolean {
+ return (ksType.declaration as KSClassDeclaration).getConstructors()
+ .singleOrNull()
+ ?.parameters
+ ?.firstOrNull { it.name == arg.name }
+ ?.let { env.wrap(it.type).isArray() } == true
}
diff --git a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMessager.kt b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMessager.kt
index c03ee6a..d5d6147 100644
--- a/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMessager.kt
+++ b/room/room-compiler-processing/src/main/java/androidx/room/compiler/processing/ksp/KspMessager.kt
@@ -51,6 +51,11 @@
// pick first node with a location, if possible
it.location != NonExistLocation
} ?: nodes.firstOrNull() // fallback to the first non-null argument
+
+ // TODO: 10/8/21 Consider checking if the KspAnnotationValue is for an item in a value's
+ // list and adding that information to the error message if so (currently, we have to
+ // report an error on the list itself, so the information about the particular item is
+ // lost). https://github.com/google/ksp/issues/656
if (ksNode == null || ksNode.location == NonExistLocation) {
internalPrintMessage(kind, "$msg - ${element.fallbackLocationText}", ksNode)
} else {
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 6fd9043..de97611 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
@@ -163,10 +163,10 @@
val element = invocation.processingEnv.requireTypeElement("foo.bar.Baz")
val annotation = element.requireAnnotation<TestSuppressWarnings>()
- val argument = annotation.annotationValues.single()
+ val argument = annotation.getAnnotationValue("value")
assertThat(argument.name).isEqualTo("value")
assertThat(
- argument.value
+ argument.asStringList()
).isEqualTo(
listOf("warning1", "warning 2")
)
@@ -192,10 +192,10 @@
val annotation =
element.requireAnnotation(ClassName.get(TestSuppressWarnings::class.java))
- val argument = annotation.annotationValues.single()
+ val argument = annotation.getAnnotationValue("value")
assertThat(argument.name).isEqualTo("value")
assertThat(
- argument.value
+ argument.asStringList()
).isEqualTo(
listOf("warning1", "warning 2")
)
@@ -857,10 +857,12 @@
val annotation =
element.requireAnnotation(ClassName.get(JavaAnnotationWithDefaults::class.java))
- // Even though not necessary for calling from Kotlin, use the version that passes
- // in a Class to test it.
- assertThat(annotation.get("stringVal", String::class.java)).isEqualTo("test")
- assertThat(annotation.get("intVal", Int::class.javaObjectType)).isEqualTo(3)
+ assertThat(annotation.get<String>("stringVal")).isEqualTo("test")
+ assertThat(annotation.get<Int>("intVal")).isEqualTo(3)
+
+ // Also test reading theses values through getAs*() methods
+ assertThat(annotation.getAsString("stringVal")).isEqualTo("test")
+ assertThat(annotation.getAsInt("intVal")).isEqualTo(3)
}
}