Skip to content

Commit

Permalink
Merge branch 'google:main' into main
Browse files Browse the repository at this point in the history
  • Loading branch information
mkmuir0 authored Nov 18, 2024
2 parents af59154 + ece7ae3 commit 0fb79bb
Show file tree
Hide file tree
Showing 35 changed files with 666 additions and 132 deletions.
2 changes: 1 addition & 1 deletion .github/workflows/auto-merge.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ jobs:
- uses: actions/checkout@v2
with:
fetch-depth: 0
ref: 1.0.27-release
ref: 1.0.29-release

- name: merge commits from main to release branch
run: |
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -38,12 +38,14 @@ interface Resolver {
fun getAllFiles(): Sequence<KSFile>

/**
* Get all symbols with specified annotation.
* Get all symbols with specified annotation in the current compilation unit.
* Note that in multiple round processing, only symbols from deferred symbols of last round and symbols from newly generated files will be returned in this function.
*
* @param annotationName is the fully qualified name of the annotation; using '.' as separator.
* @param inDepth whether to check symbols in depth, i.e. check symbols from local declarations. Operation can be expensive if true.
* @return Elements annotated with the specified annotation.
*
* @see getDeclarationsFromPackage to get declarations outside the current compilation unit.
*/
fun getSymbolsWithAnnotation(annotationName: String, inDepth: Boolean = false): Sequence<KSAnnotated>

Expand Down Expand Up @@ -231,6 +233,9 @@ interface Resolver {

/**
* Returns declarations with the given package name.
*
* getDeclarationsFromPackage looks for declaration in the whole classpath, including dependencies.
*
* @param packageName the package name to look up.
* @return A sequence of [KSDeclaration] with matching package name.
* This will return declarations from both dependencies and source.
Expand Down
6 changes: 3 additions & 3 deletions build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -102,12 +102,12 @@ subprojects {
pluginManager.withPlugin("org.jetbrains.kotlin.jvm") {
configure<JavaPluginExtension> {
toolchain.languageVersion.set(compileJavaVersion)
sourceCompatibility = JavaVersion.VERSION_11
targetCompatibility = JavaVersion.VERSION_11
sourceCompatibility = JavaVersion.VERSION_1_8
targetCompatibility = JavaVersion.VERSION_1_8
}
configure<KotlinJvmProjectExtension> {
compilerOptions {
jvmTarget = JvmTarget.JVM_11
jvmTarget = JvmTarget.JVM_1_8
languageVersion.set(KotlinVersion.KOTLIN_1_9)
apiVersion.set(languageVersion)
}
Expand Down
1 change: 0 additions & 1 deletion common-deps/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ description = "Kotlin Symbol Processor"
val kotlinBaseVersion: String by project
val junitVersion: String by project
val googleTruthVersion: String by project
val agpBaseVersion: String by project
val signingKey: String? by project
val signingPassword: String? by project

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -13,10 +13,12 @@ class KSNameImpl private constructor(val name: String) : KSName {
}

override fun getQualifier(): String {
return name.split(".").dropLast(1).joinToString(".")
val lastIndex = name.lastIndexOf('.')
return if (lastIndex != -1) name.substring(0, lastIndex) else ""
}

override fun getShortName(): String {
return name.split(".").last()
val lastIndex = name.lastIndexOf('.')
return if (lastIndex != -1) name.substring(lastIndex + 1) else name
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -185,7 +185,7 @@ abstract class AbstractKSPTest(frontend: FrontendKind<*>) : DisposableTest() {
"-classpath", classpath,
"-d", module.outDir.path
)
compileJavaFiles(javaFiles, options, assertions = JUnit5Assertions)
compileJavaFiles(javaFiles, options)
}

fun runTest(@TestDataFile path: String) {
Expand Down
13 changes: 7 additions & 6 deletions docs/ksp2cmdline.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,21 +2,22 @@

KSP2 has 4 main classes, one for each platform: `KSPJvmMain`, `KSPJsMain`, `KSPNativeMain`, `KSPCommonMain`. They reside
in the same jars from the
[artifacts.zip](https://github.com/google/ksp/releases/download/2.0.0-1.0.21/artifacts.zip) in the
[release page](https://github.com/google/ksp/releases/tag/2.0.0-1.0.21):
* `symbol-processing-aa-2.0.0-1.0.21.jar`
[artifacts.zip](https://github.com/google/ksp/releases/download/2.0.21-1.0.26/artifacts.zip) in the
[release page](https://github.com/google/ksp/releases/tag/2.0.21-1.0.26):
* `symbol-processing-aa-2.0.21-1.0.26.jar`

and depend on:
* `symbol-processing-common-deps-2.0.0-1.0.21.jar`
* `symbol-processing-common-deps-2.0.21-1.0.26.jar`

You’ll also need the Kotlin runtime:
* `kotlin-stdlib-2.0.0.jar`
* `kotlin-stdlib-2.0.21.jar`
* `kotlinx-coroutines-core-jvm-1.6.4.jar`

Taking `KSPJvmMain` for example,

```
java -cp \
kotlin-analysis-api-2.0.0-1.0.21.jar:common-deps-2.0.0-1.0.21.jar:symbol-processing-api-2.0.0-1.0.21.jar:kotlin-stdlib-2.0.0.jar \
kotlin-analysis-api-2.0.21-1.0.26.jar:common-deps-2.0.21-1.0.26.jar:symbol-processing-api-2.0.21-1.0.26.jar:kotlin-stdlib-2.0.21.jar:kotlinx-coroutines-core-jvm-1.6.4.jar \
com.google.devtools.ksp.cmdline.KSPJvmMain \
-jvm-target 11 \
-module-name=main \
Expand Down
7 changes: 4 additions & 3 deletions docs/ksp2entrypoints.md
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
# Calling KSP2 In Programs

There are two flavors of KSP2 artifacts: `symbol-processing-aa` and `symbol-processing-aa-embeddable`. They are both
uber jars that include almost all runtime dependencies except `kotlin-stdlib` and `symbol-processing-common-deps`.
The `-embeddable` version is the regular version with all the runtime dependencies renamed, so that it can be used with
a Kotlin compiler in the same classpath without name clash. When in doubt, use `symbol-processing-aa-embeddable`.
uber jars that include almost all runtime dependencies except `kotlin-stdlib`, `kotlinx-coroutines` and
`symbol-processing-common-deps`. The `-embeddable` version is the regular version with all the runtime dependencies
renamed, so that it can be used with a Kotlin compiler in the same classpath without name clash. When in doubt, use
`symbol-processing-aa-embeddable`.

Calling KSP2 consists of just 4 steps:
1. Load processors
Expand Down
5 changes: 5 additions & 0 deletions gradle-plugin/build.gradle.kts
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ val googleTruthVersion: String by project
val agpBaseVersion: String by project
val signingKey: String? by project
val signingPassword: String? by project
val aaCoroutinesVersion: String? by project

tasks.withType<KotlinCompile> {
compilerOptions.freeCompilerArgs.add("-Xjvm-default=all-compatibility")
Expand Down Expand Up @@ -148,6 +149,8 @@ abstract class WriteVersionSrcTask : DefaultTask() {
abstract val kspVersion: Property<String>
@get:Input
abstract val kotlinVersion: Property<String>
@get:Input
abstract val coroutinesVersion: Property<String>

@get:OutputDirectory
abstract val outputSrcDir: DirectoryProperty
Expand All @@ -159,6 +162,7 @@ abstract class WriteVersionSrcTask : DefaultTask() {
package com.google.devtools.ksp.gradle
val KSP_KOTLIN_BASE_VERSION = "${kotlinVersion.get()}"
val KSP_VERSION = "${kspVersion.get()}"
val KSP_COROUTINES_VERSION = "${coroutinesVersion.get()}"
""".trimIndent()
)
}
Expand All @@ -167,6 +171,7 @@ abstract class WriteVersionSrcTask : DefaultTask() {
val writeVersionSrcTask = tasks.register<WriteVersionSrcTask>("generateKSPVersions") {
kspVersion = version.toString()
kotlinVersion = kotlinBaseVersion
coroutinesVersion = aaCoroutinesVersion
outputSrcDir = layout.buildDirectory.dir("generated/ksp-versions")
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -39,21 +39,17 @@ import java.util.concurrent.Callable
@Suppress("UnstableApiUsage") // some android APIs are unsable.
object AndroidPluginIntegration {

private val agpPluginIds = listOf("com.android.application", "com.android.library", "com.android.dynamic-feature")

fun forEachAndroidSourceSet(project: Project, onSourceSet: (String) -> Unit) {
agpPluginIds.forEach { agpPluginId ->
project.pluginManager.withPlugin(agpPluginId) {
// for android apps, we need a configuration per source set
decorateAndroidExtension(project, onSourceSet)
}
project.pluginManager.withPlugin("com.android.base") {
// for android modules, we need a configuration per source set
decorateAndroidExtension(project, onSourceSet)
}
}

private fun decorateAndroidExtension(project: Project, onSourceSet: (String) -> Unit) {
val sourceSets = when (val androidExt = project.extensions.getByName("android")) {
is BaseExtension -> androidExt.sourceSets
is CommonExtension<*, *, *, *, *, *> -> androidExt.sourceSets
is CommonExtension<*, *, *, *> -> androidExt.sourceSets
else -> throw RuntimeException("Unsupported Android Gradle plugin version.")
}
sourceSets.all {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -24,11 +24,13 @@ import org.gradle.api.artifacts.Configuration
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.logging.LogLevel
import org.gradle.api.provider.ListProperty
import org.gradle.api.provider.MapProperty
import org.gradle.api.provider.Property
import org.gradle.api.provider.SetProperty
import org.gradle.api.tasks.*
import org.gradle.api.tasks.Optional
import org.gradle.process.CommandLineArgumentProvider
import org.gradle.work.ChangeType
import org.gradle.work.Incremental
import org.gradle.work.InputChanges
Expand All @@ -43,6 +45,7 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinNativeCompilation
import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool
import org.jetbrains.kotlin.gradle.tasks.KotlinNativeCompile
import org.jetbrains.kotlin.konan.target.HostManager
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
Expand All @@ -62,6 +65,9 @@ abstract class KspAATask @Inject constructor(
@get:Nested
abstract val kspConfig: KspGradleConfig

@get:Nested
abstract val commandLineArgumentProviders: ListProperty<CommandLineArgumentProvider>

@TaskAction
fun execute(inputChanges: InputChanges) {
// FIXME: Create a class loader with clean classpath instead of shadowing existing ones. It'll require either:
Expand Down Expand Up @@ -143,14 +149,22 @@ abstract class KspAATask @Inject constructor(
"${KspGradleSubplugin.KSP_GROUP_ID}:symbol-processing-aa-embeddable:$KSP_VERSION"
),
project.dependencies.create("org.jetbrains.kotlin:kotlin-stdlib:$KSP_KOTLIN_BASE_VERSION"),
project.dependencies.create(
"org.jetbrains.kotlinx:kotlinx-coroutines-core-jvm:$KSP_COROUTINES_VERSION"
),
).apply {
isTransitive = false
}
val kspTaskProvider = project.tasks.register(kspTaskName, KspAATask::class.java) { kspAATask ->
kspAATask.kspClasspath.from(kspAADepCfg)
kspAATask.kspConfig.let { cfg ->
cfg.processorClasspath.from(processorClasspath)
cfg.moduleName.value(project.name)
// Ref: https://github.com/JetBrains/kotlin/blob/6535f86dfe36effeba976802ebd56a5a56071f45/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt#L92
val moduleName = when (val compilationName = kotlinCompilation.name) {
KotlinCompilation.MAIN_COMPILATION_NAME -> project.name
else -> "${project.name}_$compilationName"
}
cfg.moduleName.value(moduleName)
val kotlinOutputDir = KspGradleSubplugin.getKspKotlinOutputDir(project, sourceSetName, target)
val javaOutputDir = KspGradleSubplugin.getKspJavaOutputDir(project, sourceSetName, target)
val filteredTasks =
Expand Down Expand Up @@ -211,8 +225,9 @@ abstract class KspAATask @Inject constructor(
)
)
cfg.processorOptions.putAll(kspExtension.apOptions)
cfg.processorOptions.putAll(
kspExtension.commandLineArgumentProviders.map { providers ->

fun ListProperty<CommandLineArgumentProvider>.mapArgProviders() =
map { providers ->
buildMap {
for (provider in providers) {
provider.asArguments().forEach { argument ->
Expand All @@ -225,7 +240,10 @@ abstract class KspAATask @Inject constructor(
}
}
}
)

cfg.processorOptions.putAll(kspExtension.commandLineArgumentProviders.mapArgProviders())
cfg.processorOptions.putAll(kspAATask.commandLineArgumentProviders.mapArgProviders())

val logLevel = LogLevel.entries.first {
project.logger.isEnabled(it)
}
Expand Down Expand Up @@ -266,6 +284,11 @@ abstract class KspAATask @Inject constructor(
val konanTargetName = kotlinCompilation.target.konanTarget.name
cfg.konanTargetName.value(konanTargetName)
cfg.konanHome.value((kotlinCompileProvider.get() as KotlinNativeCompile).konanHome)
kspAATask.onlyIf {
HostManager().enabled.any {
it.name == konanTargetName
}
}
}

// TODO: pass targets of common
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -32,15 +32,25 @@ import org.junit.Assume
import org.junit.Rule
import org.junit.Test
import org.junit.rules.TemporaryFolder
import org.junit.runner.RunWith
import org.junit.runners.Parameterized

@RunWith(Parameterized::class)
class GradleCompilationTest(val useKSP2: Boolean) {

companion object {
@JvmStatic
@Parameterized.Parameters(name = "KSP2={0}")
fun params() = listOf(arrayOf(true), arrayOf(false))
}

class GradleCompilationTest {
@Rule
@JvmField
val tmpDir = TemporaryFolder()

@Rule
@JvmField
val testRule = KspIntegrationTestRule(tmpDir)
val testRule = KspIntegrationTestRule(tmpDir, useKSP2)

@Test
fun errorMessageFailsCompilation() {
Expand Down Expand Up @@ -239,8 +249,8 @@ class GradleCompilationTest {
)
testRule.appModule.dependencies.addAll(
listOf(
artifact(configuration = "ksp", "androidx.room:room-compiler:2.4.2"),
artifact(configuration = "implementation", "androidx.room:room-runtime:2.4.2")
artifact(configuration = "ksp", "androidx.room:room-compiler:2.6.1"),
artifact(configuration = "implementation", "androidx.room:room-runtime:2.6.1")
)
)
testRule.appModule.buildFileAdditions.add(
Expand All @@ -267,6 +277,13 @@ class GradleCompilationTest {
}
}
}
tasks.withType<com.google.devtools.ksp.gradle.KspAATask>().configureEach {
doFirst {
kspConfig.processorOptions.get().forEach { (key, value) ->
println("apoption=${'$'}key=${'$'}value")
}
}
}
""".trimIndent()
)
Expand Down Expand Up @@ -343,6 +360,17 @@ class GradleCompilationTest {
println("commandLine=${'$'}{commandLine.asArguments()}")
}
}
tasks.withType<com.google.devtools.ksp.gradle.KspAATask>().configureEach {
val destination = project.layout.projectDirectory.dir("schemas-${'$'}{this.name}")
commandLineArgumentProviders.add(Provider(destination.asFile))
kspConfig.processorOptions.get().forEach { (key, value) ->
println("apoption=${'$'}key=${'$'}value")
}
commandLineArgumentProviders.get().forEach { commandLine ->
println("commandLine=${'$'}{commandLine.asArguments()}")
}
}
}
""".trimIndent()
)
Expand All @@ -366,6 +394,11 @@ class GradleCompilationTest {
println("HAS LIBRARY: ${'$'}{it.path}")
}
}
tasks.withType<com.google.devtools.ksp.gradle.KspAATask>().configureEach {
kspConfig.libraries.files.forEach {
println("HAS LIBRARY: ${'$'}{it.path}")
}
}
}
""".trimIndent()
)
Expand All @@ -389,6 +422,7 @@ class GradleCompilationTest {

@Test
fun changingKsp2AtRuntime() {
Assume.assumeFalse(useKSP2)
testRule.setupAppAsJvmApp()
testRule.appModule.buildFileAdditions.add(
"""
Expand All @@ -414,4 +448,16 @@ class GradleCompilationTest {
)
testRule.runner().withArguments(":app:assembleDebug").build()
}

/**
* Regression test for https://github.com/google/ksp/issues/2174
*/
@Test
fun androidGradlePluginBuiltInKotlinWithKspAppliedFirst() {
testRule.setupAppAsAndroidApp(applyKspPluginFirst = true)
// Enable AGP's built-in Kotlin support for test fixtures
testRule.runner()
.withArguments("tasks", "-Pandroid.experimental.enableTestFixturesKotlinSupport=true")
.build()
}
}
Loading

0 comments on commit 0fb79bb

Please sign in to comment.