Add test for missing synthetic Java fields
diff --git a/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/ReachableAnnotationsFromGivenClasses.kt b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/ReachableAnnotationsFromGivenClasses.kt new file mode 100644 index 0000000..3e6e040 --- /dev/null +++ b/kotlin-analysis-api/src/test/kotlin/com/google/devtools/ksp/processor/ReachableAnnotationsFromGivenClasses.kt
@@ -0,0 +1,55 @@ +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 +import com.google.devtools.ksp.symbol.KSAnnotation +import com.google.devtools.ksp.symbol.KSDeclaration +import com.google.devtools.ksp.symbol.KSNode +import com.google.devtools.ksp.visitor.KSTopDownVisitor + +class ReachableAnnotationsFromGivenClasses( + val classNames: List<String>, + override val enableNewFeatures: Boolean +) : AbstractTestProcessor() { + + private val results = mutableListOf<String>() + + override fun toResult(): List<String> = results + + override fun process(resolver: Resolver): List<KSAnnotated> { + val seenNames = mutableSetOf<String>() + val seenNodes = mutableSetOf<KSNode>() + val visitor = DeclarationVisitor(seenNodes) + classNames.forEach { className -> + resolver + .getClassDeclarationByName(className) + ?.accept(visitor, seenNames) + } + results.addAll(seenNames) + return emptyList() + } + + inner class DeclarationVisitor(val seen: MutableSet<KSNode>) : + KSTopDownVisitor<MutableSet<String>, Unit>(enableNewFeatures) { + override fun defaultHandler( + node: KSNode, + data: MutableSet<String> + ) { + seen.add(node) + } + + override fun visitDeclaration(declaration: KSDeclaration, data: MutableSet<String>) { + data.add(declaration.qualifiedName?.asString() ?: declaration.simpleName.asString()) + super.visitDeclaration(declaration, data) + } + + override fun visitAnnotation(annotation: KSAnnotation, data: MutableSet<String>) { + super.visitAnnotation(annotation, data) + val declaration = annotation.annotationType.resolve().declaration + if (!seen.contains(declaration)) { + declaration.accept(this, data) + } + } + } +}
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 a0c0c47..2a3ecd1 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
@@ -17,6 +17,8 @@ package com.google.devtools.ksp.test +import com.google.devtools.ksp.test.annotations.Bug +import com.google.devtools.ksp.test.annotations.BugState import org.jetbrains.kotlin.test.TestMetadata import org.junit.jupiter.api.Test @@ -61,6 +63,18 @@ } } -class AAConfiguredUnitTestSuite : AAConfiguredUnitTestSuiteBase(enableNewFeatures = false) +class AAConfiguredUnitTestSuite : AAConfiguredUnitTestSuiteBase(enableNewFeatures = false) { + @TestMetadata("javaBackingFieldUsedInKotlin.kt") + @Test + override fun testJavaBackingFieldUsedInKotlin() { + runTest("$AA_PATH/javaBackingFieldUsedInKotlin.kt") + } +} -class AAConfiguredNewFeaturesUnitTestSuite : AAConfiguredUnitTestSuiteBase(enableNewFeatures = true) +class AAConfiguredNewFeaturesUnitTestSuite : AAConfiguredUnitTestSuiteBase(enableNewFeatures = true) { + @TestMetadata("javaBackingFieldUsedInKotlin.kt") + @Test + override fun testJavaBackingFieldUsedInKotlin() { + runFailingTest("$AA_PATH/javaBackingFieldUsedInKotlin.kt") + } +}
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 055ffb3..addb4ee 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
@@ -510,6 +510,11 @@ runTest("$AA_PATH/isMutable.kt") } + @Bug("https://github.com/google/ksp/issues/3191", BugState.OPEN) + @TestMetadata("javaBackingFieldUsedInKotlin.kt") + @Test + abstract fun testJavaBackingFieldUsedInKotlin() + @Bug("https://github.com/google/ksp/issues/3123", BugState.OPEN) @Bug("https://github.com/google/ksp/issues/3125", BugState.FIXED) @Bug("https://github.com/google/ksp/issues/3155", BugState.OPEN)
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 2e9dd94..2da81a6 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
@@ -61,6 +61,18 @@ } } -class PsiConfiguredUnitTestSuite : PsiConfiguredUnitTestSuiteBase(enableNewFeatures = false) +class PsiConfiguredUnitTestSuite : PsiConfiguredUnitTestSuiteBase(enableNewFeatures = false) { + @TestMetadata("javaBackingFieldUsedInKotlin.kt") + @Test + override fun testJavaBackingFieldUsedInKotlin() { + runTest("$AA_PATH/javaBackingFieldUsedInKotlin.kt") + } +} -class PsiConfiguredNewFeaturesUnitTestSuite : PsiConfiguredUnitTestSuiteBase(enableNewFeatures = true) +class PsiConfiguredNewFeaturesUnitTestSuite : PsiConfiguredUnitTestSuiteBase(enableNewFeatures = true) { + @TestMetadata("javaBackingFieldUsedInKotlin.kt") + @Test + override fun testJavaBackingFieldUsedInKotlin() { + runFailingTest("$AA_PATH/javaBackingFieldUsedInKotlin.kt") + } +}
diff --git a/kotlin-analysis-api/testData/javaBackingFieldUsedInKotlin.kt b/kotlin-analysis-api/testData/javaBackingFieldUsedInKotlin.kt new file mode 100644 index 0000000..4dee270 --- /dev/null +++ b/kotlin-analysis-api/testData/javaBackingFieldUsedInKotlin.kt
@@ -0,0 +1,40 @@ +/* + * 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: ReachableAnnotationsFromGivenClasses +// PROCESSOR INPUT: MyClass +// EXPECTED: +// MyClass +// com.example.MyAnnotation +// EXPECT CURRENT: com.example.MyAnnotation.myValue +// EXPECT NEXT: com.example.MyAnnotation.myValue.field +// EXPECT NEXT: com.example.MyAnnotation.myValue +// <init> +// END + +// FILE: MyAnnotation.java +package com.example; + +public @interface MyAnnotation { + int myValue() default 42; +} + +// FILE: MyClass.kt +import com.example.MyAnnotation + +@MyAnnotation +class MyClass