From 70f6be5e18afb39de40ce52d2e720e894569cea4 Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 6 Oct 2022 01:29:32 -0700 Subject: [PATCH] Scan Kotlin constants for JavaPsiFacade so that constants in light classes can be resolved by JavaPsiFacade. --- .../ksp/KotlinSymbolProcessingExtension.kt | 40 ++++++++++++++++++ .../google/devtools/ksp/test/Playground3IT.kt | 42 +++++++++++++++++++ .../resources/playground3/build.gradle.kts | 8 ++++ .../resources/playground3/settings.gradle.kts | 19 +++++++++ .../test-processor/build.gradle.kts | 24 +++++++++++ .../src/main/kotlin/TestProcessor.kt | 27 ++++++++++++ ...ols.ksp.processing.SymbolProcessorProvider | 1 + .../playground3/workload/build.gradle.kts | 20 +++++++++ .../src/main/java/com/example/JavaClass.java | 9 ++++ .../src/main/java/com/example/KotlinConsts.kt | 8 ++++ .../src/main/java/com/example/ann/MyAnn.kt | 3 ++ 11 files changed, 201 insertions(+) create mode 100644 integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Playground3IT.kt create mode 100644 integration-tests/src/test/resources/playground3/build.gradle.kts create mode 100644 integration-tests/src/test/resources/playground3/settings.gradle.kts create mode 100644 integration-tests/src/test/resources/playground3/test-processor/build.gradle.kts create mode 100644 integration-tests/src/test/resources/playground3/test-processor/src/main/kotlin/TestProcessor.kt create mode 100644 integration-tests/src/test/resources/playground3/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider create mode 100644 integration-tests/src/test/resources/playground3/workload/build.gradle.kts create mode 100644 integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/JavaClass.java create mode 100644 integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/KotlinConsts.kt create mode 100644 integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/ann/MyAnn.kt diff --git a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt index f912513c7d..854328f2fe 100644 --- a/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt +++ b/compiler-plugin/src/main/kotlin/com/google/devtools/ksp/KotlinSymbolProcessingExtension.kt @@ -31,10 +31,16 @@ import com.google.devtools.ksp.processing.impl.NativePlatformInfoImpl import com.google.devtools.ksp.processing.impl.ResolverImpl import com.google.devtools.ksp.processing.impl.UnknownPlatformInfoImpl import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSDeclarationContainer import com.google.devtools.ksp.symbol.KSFile +import com.google.devtools.ksp.symbol.KSNode +import com.google.devtools.ksp.symbol.KSPropertyDeclaration +import com.google.devtools.ksp.symbol.Modifier import com.google.devtools.ksp.symbol.Origin +import com.google.devtools.ksp.symbol.Visibility import com.google.devtools.ksp.symbol.impl.java.KSFileJavaImpl import com.google.devtools.ksp.symbol.impl.kotlin.KSFileImpl +import com.google.devtools.ksp.visitor.KSDefaultVisitor import com.intellij.openapi.project.Project import com.intellij.openapi.vfs.StandardFileSystems import com.intellij.openapi.vfs.VirtualFileManager @@ -198,6 +204,40 @@ abstract class AbstractKotlinSymbolProcessingExtension( newFiles, deferredSymbols, bindingTrace, project, componentProvider, incrementalContext, options ) + if (!initialized) { + // Visit constants so that JavaPsiFacade knows them. + // The annotation visitor in ResolverImpl covered newFiles already. + ksFiles.filterIsInstance().filter { it !in dirtyFiles }.forEach { + try { + it.accept( + object : KSDefaultVisitor() { + override fun defaultHandler(node: KSNode, data: Unit) = Unit + + override fun visitDeclarationContainer( + declarationContainer: KSDeclarationContainer, + data: Unit + ) { + declarationContainer.declarations.filterNot { + it.getVisibility() == Visibility.PRIVATE + }.forEach { + it.accept(this, Unit) + } + } + + override fun visitPropertyDeclaration(property: KSPropertyDeclaration, data: Unit) { + if (property.modifiers.contains(Modifier.CONST)) { + property.getter // force resolution + } + } + }, + Unit + ) + } catch (_: Exception) { + // Do nothing. + } + } + } + val providers = loadProviders() if (!initialized) { codeGenerator = CodeGeneratorImpl( diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Playground3IT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Playground3IT.kt new file mode 100644 index 0000000000..31610d6ef5 --- /dev/null +++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/Playground3IT.kt @@ -0,0 +1,42 @@ +package com.google.devtools.ksp.test + +import org.gradle.testkit.runner.BuildResult +import org.gradle.testkit.runner.GradleRunner +import org.gradle.testkit.runner.TaskOutcome +import org.junit.Assert +import org.junit.Assume +import org.junit.Rule +import org.junit.Test +import java.io.File + +class Playground3IT { + @Rule + @JvmField + val project: TemporaryTestProject = TemporaryTestProject("playground3") + + private fun GradleRunner.buildAndCheck(vararg args: String, extraCheck: (BuildResult) -> Unit = {}) = + buildAndCheckOutcome(*args, outcome = TaskOutcome.SUCCESS, extraCheck = extraCheck) + + private fun GradleRunner.buildAndCheckOutcome( + vararg args: String, + outcome: TaskOutcome, + extraCheck: (BuildResult) -> Unit = {} + ) { + val result = this.withArguments(*args).build() + + Assert.assertEquals(outcome, result.task(":workload:kspKotlin")?.outcome) + + extraCheck(result) + } + + @Test + fun testPlayground() { + // FIXME: `clean` fails to delete files on windows. + Assume.assumeFalse(System.getProperty("os.name").startsWith("Windows", ignoreCase = true)) + val gradleRunner = GradleRunner.create().withProjectDir(project.root).withDebug(true) + gradleRunner.buildAndCheck(":workload:kspKotlin") + + File(project.root, "workload/src/main/java/com/example/JavaClass.java").appendText("\n") + gradleRunner.buildAndCheck(":workload:kspKotlin") + } +} diff --git a/integration-tests/src/test/resources/playground3/build.gradle.kts b/integration-tests/src/test/resources/playground3/build.gradle.kts new file mode 100644 index 0000000000..c5737a2e0d --- /dev/null +++ b/integration-tests/src/test/resources/playground3/build.gradle.kts @@ -0,0 +1,8 @@ +plugins { + kotlin("jvm") +} + +repositories { + mavenCentral() + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/") +} diff --git a/integration-tests/src/test/resources/playground3/settings.gradle.kts b/integration-tests/src/test/resources/playground3/settings.gradle.kts new file mode 100644 index 0000000000..9d60cbc72f --- /dev/null +++ b/integration-tests/src/test/resources/playground3/settings.gradle.kts @@ -0,0 +1,19 @@ +pluginManagement { + val kotlinVersion: String by settings + val kspVersion: String by settings + val testRepo: String by settings + plugins { + id("com.google.devtools.ksp") version kspVersion + kotlin("jvm") version kotlinVersion + } + repositories { + maven(testRepo) + gradlePluginPortal() + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/") + } +} + +rootProject.name = "playground" + +include(":workload") +include(":test-processor") diff --git a/integration-tests/src/test/resources/playground3/test-processor/build.gradle.kts b/integration-tests/src/test/resources/playground3/test-processor/build.gradle.kts new file mode 100644 index 0000000000..ab249cf06f --- /dev/null +++ b/integration-tests/src/test/resources/playground3/test-processor/build.gradle.kts @@ -0,0 +1,24 @@ +val kspVersion: String by project +val testRepo: String by project + +plugins { + kotlin("jvm") +} + +group = "com.example" +version = "1.0-SNAPSHOT" + +repositories { + maven(testRepo) + mavenCentral() + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/") +} + +dependencies { + implementation(kotlin("stdlib")) + implementation("com.google.devtools.ksp:symbol-processing-api:$kspVersion") +} + +sourceSets.main { + java.srcDirs("src/main/kotlin") +} diff --git a/integration-tests/src/test/resources/playground3/test-processor/src/main/kotlin/TestProcessor.kt b/integration-tests/src/test/resources/playground3/test-processor/src/main/kotlin/TestProcessor.kt new file mode 100644 index 0000000000..7e14192745 --- /dev/null +++ b/integration-tests/src/test/resources/playground3/test-processor/src/main/kotlin/TestProcessor.kt @@ -0,0 +1,27 @@ +import com.google.devtools.ksp.processing.* +import com.google.devtools.ksp.symbol.KSAnnotated +import com.google.devtools.ksp.symbol.KSFunctionDeclaration + +class TestProcessor( + private val codeGenerator: CodeGenerator, + private val options: Map, + private val logger: KSPLogger +) : SymbolProcessor { + override fun process(resolver: Resolver): List { + resolver + .getSymbolsWithAnnotation("com.example.ann.MyAnn") + .filterIsInstance() + .forEach { func -> + val arg = func.annotations.first().arguments.first().value.toString() + if (!arg.startsWith("REPLACE")) + throw IllegalStateException(arg) + } + + return emptyList() + } +} + +class TestProcessorProvider : SymbolProcessorProvider { + override fun create(environment: SymbolProcessorEnvironment): SymbolProcessor = + TestProcessor(environment.codeGenerator, environment.options, environment.logger) +} diff --git a/integration-tests/src/test/resources/playground3/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider b/integration-tests/src/test/resources/playground3/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider new file mode 100644 index 0000000000..c91e3e9e0b --- /dev/null +++ b/integration-tests/src/test/resources/playground3/test-processor/src/main/resources/META-INF/services/com.google.devtools.ksp.processing.SymbolProcessorProvider @@ -0,0 +1 @@ +TestProcessorProvider diff --git a/integration-tests/src/test/resources/playground3/workload/build.gradle.kts b/integration-tests/src/test/resources/playground3/workload/build.gradle.kts new file mode 100644 index 0000000000..f0ea52b0e3 --- /dev/null +++ b/integration-tests/src/test/resources/playground3/workload/build.gradle.kts @@ -0,0 +1,20 @@ +val testRepo: String by project + +plugins { + id("com.google.devtools.ksp") + kotlin("jvm") +} + +version = "1.0-SNAPSHOT" + +repositories { + maven(testRepo) + mavenCentral() + maven("https://maven.pkg.jetbrains.space/kotlin/p/kotlin/bootstrap/") +} + +dependencies { + implementation(kotlin("stdlib")) + implementation(project(":test-processor")) + ksp(project(":test-processor")) +} diff --git a/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/JavaClass.java b/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/JavaClass.java new file mode 100644 index 0000000000..a196f754d5 --- /dev/null +++ b/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/JavaClass.java @@ -0,0 +1,9 @@ +package com.example; + +import com.example.ann.MyAnn; + +public class JavaClass { + @MyAnn(KotlinConsts.ACTION) + public void f() { + } +} diff --git a/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/KotlinConsts.kt b/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/KotlinConsts.kt new file mode 100644 index 0000000000..e5231980fd --- /dev/null +++ b/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/KotlinConsts.kt @@ -0,0 +1,8 @@ +package com.example + +class KotlinConsts { + companion object { + const val ACTION = "REPLACE" + const val ACTION2 = "REPLACE" + } +} diff --git a/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/ann/MyAnn.kt b/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/ann/MyAnn.kt new file mode 100644 index 0000000000..6812ee6350 --- /dev/null +++ b/integration-tests/src/test/resources/playground3/workload/src/main/java/com/example/ann/MyAnn.kt @@ -0,0 +1,3 @@ +package com.example.ann + +annotation class MyAnn(val value: String)