From 801d0590635e7ac6339cf8ef350266917ffa3f64 Mon Sep 17 00:00:00 2001 From: Yong-yuan-X <2463436064@qq.com> Date: Tue, 30 Jun 2026 21:46:04 +0800 Subject: [PATCH 1/3] Add regression test for annotation array value type --- .../ksp/test/AAConfiguredUnitTestSuite.kt | 6 +++ .../devtools/ksp/test/KSPUnitTestSuite.kt | 3 ++ .../ksp/test/PsiConfiguredUnitTestSuite.kt | 6 +++ .../testData/annotationArrayValueType.kt | 34 +++++++++++++ .../AnnotationArrayValueTypeProcessor.kt | 48 +++++++++++++++++++ 5 files changed, 97 insertions(+) create mode 100644 kotlin-analysis-api/testData/annotationArrayValueType.kt create mode 100644 test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/AAConfiguredUnitTestSuite.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/AAConfiguredUnitTestSuite.kt index 402889a526..b471136b07 100644 --- a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/AAConfiguredUnitTestSuite.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/AAConfiguredUnitTestSuite.kt @@ -28,6 +28,12 @@ class AAConfiguredUnitTestSuite : KSPUnitTestSuite(experimentalPsiResolution = f runTest("$AA_PATH/getSymbolsWithAnnotation/aliasedAnnotation.kt") } + @TestMetadata("annotationArrayValueType.kt") + @Test + override fun testAnnotationArrayValueType() { + runFailingTest("$AA_PATH/annotationArrayValueType.kt") + } + @TestMetadata("allUseSiteTargetAppliedToAnnotationList.kt") @Test override fun testAllUseSiteTargetAppliedToAnnotationList() { diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPUnitTestSuite.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPUnitTestSuite.kt index e4ac7ae95f..2534b42c26 100644 --- a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPUnitTestSuite.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/KSPUnitTestSuite.kt @@ -152,6 +152,9 @@ abstract class KSPUnitTestSuite( runTest("$AA_PATH/annotationWithArrayValue.kt") } + @Bug("https://github.com/google/ksp/issues/3008", BugState.OPEN) + abstract fun testAnnotationArrayValueType() + @TestMetadata("annotationWithDefault.kt") @Test fun testAnnotationWithDefault() { diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/PsiConfiguredUnitTestSuite.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/PsiConfiguredUnitTestSuite.kt index 6b9d875dd9..2be0ea332e 100644 --- a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/PsiConfiguredUnitTestSuite.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/test/PsiConfiguredUnitTestSuite.kt @@ -28,6 +28,12 @@ class PsiConfiguredUnitTestSuite : KSPUnitTestSuite(experimentalPsiResolution = runFailingTest("$AA_PATH/getSymbolsWithAnnotation/aliasedAnnotation.kt") } + @TestMetadata("annotationArrayValueType.kt") + @Test + override fun testAnnotationArrayValueType() { + runFailingTest("$AA_PATH/annotationArrayValueType.kt") + } + @TestMetadata("allUseSiteTargetAppliedToAnnotationList.kt") @Test override fun testAllUseSiteTargetAppliedToAnnotationList() { diff --git a/kotlin-analysis-api/testData/annotationArrayValueType.kt b/kotlin-analysis-api/testData/annotationArrayValueType.kt new file mode 100644 index 0000000000..90ccc05ac8 --- /dev/null +++ b/kotlin-analysis-api/testData/annotationArrayValueType.kt @@ -0,0 +1,34 @@ +/* + * Copyright 2026 Google LLC + * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors. + * + * 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. + */ +// TEST PROCESSOR: AnnotationArrayValueTypeProcessor +// EXPECTED: +// args is Array<*>: true +// args size: 2 +// END +// FILE: JavaAnnotation.java +public @interface JavaAnnotation { + NestedAnnotation[] args(); +} + +// FILE: NestedAnnotation.java +public @interface NestedAnnotation { + String value(); +} + +// FILE: JavaAnnotated.java +@JavaAnnotation(args = {@NestedAnnotation(value = "one"), @NestedAnnotation(value = "two")}) +class JavaAnnotated {} diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt new file mode 100644 index 0000000000..bbdeb33973 --- /dev/null +++ b/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt @@ -0,0 +1,48 @@ +/* + * Copyright 2026 Google LLC + * Copyright 2010-2026 JetBrains s.r.o. and Kotlin Programming Language contributors. + * + * 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 com.google.devtools.ksp.processor + +import com.google.devtools.ksp.getClassDeclarationByName +import com.google.devtools.ksp.processing.Resolver +import com.google.devtools.ksp.symbol.KSAnnotated + +class AnnotationArrayValueTypeProcessor : AbstractTestProcessor() { + private val results = mutableListOf() + + override fun process(resolver: Resolver): List { + val annotated = resolver.getClassDeclarationByName("JavaAnnotated")!! + val annotation = annotated.annotations.single { it.shortName.asString() == "JavaAnnotation" } + val argument = annotation.arguments.single() + val value = argument.value + results.add("${argument.name?.asString()} is Array<*>: ${value is Array<*>}") + results.add("${argument.name?.asString()} size: ${value.sizeOrNull()}") + return emptyList() + } + + override fun toResult(): List { + return results + } + + private fun Any?.sizeOrNull(): Int? { + return when (this) { + is Array<*> -> size + is Collection<*> -> size + else -> null + } + } +} From aa88c923688b69c6e1ef8dde442b0bfa417cc8d7 Mon Sep 17 00:00:00 2001 From: Yong-yuan-X <2463436064@qq.com> Date: Fri, 3 Jul 2026 11:54:43 +0800 Subject: [PATCH 2/3] Add Kotlin annotation array value test --- .../AnnotationArrayValueTypeProcessor.kt | 18 ++++++++++++------ .../testData/annotationArrayValueType.kt | 10 ++++++++-- 2 files changed, 20 insertions(+), 8 deletions(-) rename {test-utils/src/main => kotlin-analysis-api/src/test}/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt (75%) diff --git a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt similarity index 75% rename from test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt rename to kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt index bbdeb33973..1f3474c6ba 100644 --- a/test-utils/src/main/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt @@ -25,12 +25,8 @@ class AnnotationArrayValueTypeProcessor : AbstractTestProcessor() { private val results = mutableListOf() override fun process(resolver: Resolver): List { - val annotated = resolver.getClassDeclarationByName("JavaAnnotated")!! - val annotation = annotated.annotations.single { it.shortName.asString() == "JavaAnnotation" } - val argument = annotation.arguments.single() - val value = argument.value - results.add("${argument.name?.asString()} is Array<*>: ${value is Array<*>}") - results.add("${argument.name?.asString()} size: ${value.sizeOrNull()}") + logAnnotationArrayValue(resolver, "JavaAnnotated") + logAnnotationArrayValue(resolver, "KotlinAnnotated") return emptyList() } @@ -38,6 +34,16 @@ class AnnotationArrayValueTypeProcessor : AbstractTestProcessor() { return results } + private fun logAnnotationArrayValue(resolver: Resolver, className: String) { + val annotated = resolver.getClassDeclarationByName(className)!! + val annotation = annotated.annotations.single { it.shortName.asString() == "JavaAnnotation" } + val argument = annotation.arguments.single() + val value = argument.value + val argumentName = argument.name?.asString() + results.add("$className $argumentName is Array<*>: ${value is Array<*>}") + results.add("$className $argumentName size: ${value.sizeOrNull()}") + } + private fun Any?.sizeOrNull(): Int? { return when (this) { is Array<*> -> size diff --git a/kotlin-analysis-api/testData/annotationArrayValueType.kt b/kotlin-analysis-api/testData/annotationArrayValueType.kt index 90ccc05ac8..b3c5360ce0 100644 --- a/kotlin-analysis-api/testData/annotationArrayValueType.kt +++ b/kotlin-analysis-api/testData/annotationArrayValueType.kt @@ -16,8 +16,10 @@ */ // TEST PROCESSOR: AnnotationArrayValueTypeProcessor // EXPECTED: -// args is Array<*>: true -// args size: 2 +// JavaAnnotated args is Array<*>: true +// JavaAnnotated args size: 2 +// KotlinAnnotated args is Array<*>: true +// KotlinAnnotated args size: 2 // END // FILE: JavaAnnotation.java public @interface JavaAnnotation { @@ -32,3 +34,7 @@ public @interface NestedAnnotation { // FILE: JavaAnnotated.java @JavaAnnotation(args = {@NestedAnnotation(value = "one"), @NestedAnnotation(value = "two")}) class JavaAnnotated {} + +// FILE: KotlinAnnotated.kt +@JavaAnnotation(args = [NestedAnnotation(value = "one"), NestedAnnotation(value = "two")]) +class KotlinAnnotated From e908b15458a5bb92945c3fba058485009b877b8d Mon Sep 17 00:00:00 2001 From: Yong-yuan-X <2463436064@qq.com> Date: Fri, 3 Jul 2026 18:38:09 +0800 Subject: [PATCH 3/3] Expand annotation array value coverage --- .../AnnotationArrayValueTypeProcessor.kt | 20 ++++++++++--------- .../testData/annotationArrayValueType.kt | 18 +++++++++++++---- 2 files changed, 25 insertions(+), 13 deletions(-) diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt index 1f3474c6ba..43b7c19c26 100644 --- a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/AnnotationArrayValueTypeProcessor.kt @@ -25,8 +25,8 @@ class AnnotationArrayValueTypeProcessor : AbstractTestProcessor() { private val results = mutableListOf() override fun process(resolver: Resolver): List { - logAnnotationArrayValue(resolver, "JavaAnnotated") - logAnnotationArrayValue(resolver, "KotlinAnnotated") + logAnnotationArrayValues(resolver, "JavaAnnotated") + logAnnotationArrayValues(resolver, "KotlinAnnotated") return emptyList() } @@ -34,14 +34,16 @@ class AnnotationArrayValueTypeProcessor : AbstractTestProcessor() { return results } - private fun logAnnotationArrayValue(resolver: Resolver, className: String) { + private fun logAnnotationArrayValues(resolver: Resolver, className: String) { val annotated = resolver.getClassDeclarationByName(className)!! - val annotation = annotated.annotations.single { it.shortName.asString() == "JavaAnnotation" } - val argument = annotation.arguments.single() - val value = argument.value - val argumentName = argument.name?.asString() - results.add("$className $argumentName is Array<*>: ${value is Array<*>}") - results.add("$className $argumentName size: ${value.sizeOrNull()}") + listOf("JavaAnnotation", "KotlinAnnotation").forEach { annotationName -> + val annotation = annotated.annotations.single { it.shortName.asString() == annotationName } + val argument = annotation.arguments.single() + val value = argument.value + val argumentName = argument.name?.asString() + results.add("$className $annotationName $argumentName is Array<*>: ${value is Array<*>}") + results.add("$className $annotationName $argumentName size: ${value.sizeOrNull()}") + } } private fun Any?.sizeOrNull(): Int? { diff --git a/kotlin-analysis-api/testData/annotationArrayValueType.kt b/kotlin-analysis-api/testData/annotationArrayValueType.kt index b3c5360ce0..aa87c52a37 100644 --- a/kotlin-analysis-api/testData/annotationArrayValueType.kt +++ b/kotlin-analysis-api/testData/annotationArrayValueType.kt @@ -16,10 +16,14 @@ */ // TEST PROCESSOR: AnnotationArrayValueTypeProcessor // EXPECTED: -// JavaAnnotated args is Array<*>: true -// JavaAnnotated args size: 2 -// KotlinAnnotated args is Array<*>: true -// KotlinAnnotated args size: 2 +// JavaAnnotated JavaAnnotation args is Array<*>: true +// JavaAnnotated JavaAnnotation args size: 2 +// JavaAnnotated KotlinAnnotation args is Array<*>: true +// JavaAnnotated KotlinAnnotation args size: 2 +// KotlinAnnotated JavaAnnotation args is Array<*>: true +// KotlinAnnotated JavaAnnotation args size: 2 +// KotlinAnnotated KotlinAnnotation args is Array<*>: true +// KotlinAnnotated KotlinAnnotation args size: 2 // END // FILE: JavaAnnotation.java public @interface JavaAnnotation { @@ -33,8 +37,14 @@ public @interface NestedAnnotation { // FILE: JavaAnnotated.java @JavaAnnotation(args = {@NestedAnnotation(value = "one"), @NestedAnnotation(value = "two")}) +@KotlinAnnotation(args = {@KotlinNestedAnnotation(value = "one"), @KotlinNestedAnnotation(value = "two")}) class JavaAnnotated {} // FILE: KotlinAnnotated.kt +annotation class KotlinAnnotation(val args: Array) + +annotation class KotlinNestedAnnotation(val value: String) + @JavaAnnotation(args = [NestedAnnotation(value = "one"), NestedAnnotation(value = "two")]) +@KotlinAnnotation(args = [KotlinNestedAnnotation(value = "one"), KotlinNestedAnnotation(value = "two")]) class KotlinAnnotated