diff --git a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt
index 8c89047c9b..a5145d37dd 100644
--- a/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt
+++ b/gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt
@@ -17,9 +17,11 @@
package com.google.devtools.ksp.gradle
+import com.android.build.api.variant.AndroidComponentsExtension
import com.google.devtools.ksp.gradle.utils.allKotlinSourceSetsObservable
import com.google.devtools.ksp.gradle.utils.canUseGeneratedKotlinApi
import com.google.devtools.ksp.gradle.utils.enableProjectIsolationCompatibleCodepath
+import com.google.devtools.ksp.gradle.utils.isAgpBuiltInKotlinUsed
import com.google.devtools.ksp.impl.KotlinSymbolProcessing
import com.google.devtools.ksp.processing.ExitCode
import com.google.devtools.ksp.processing.KSPCommonConfig
@@ -31,6 +33,7 @@ import com.google.devtools.ksp.processing.KspGradleLogger
import org.gradle.api.DefaultTask
import org.gradle.api.JavaVersion
import org.gradle.api.artifacts.Configuration
+import org.gradle.api.attributes.Attribute
import org.gradle.api.file.ConfigurableFileCollection
import org.gradle.api.file.DirectoryProperty
import org.gradle.api.logging.LogLevel
@@ -223,21 +226,38 @@ abstract class KspAATask @Inject constructor(
}
if (kotlinCompilation is KotlinJvmAndroidCompilation) {
- // Workaround of a dependency resolution issue of AGP.
- // FIXME: figure out how to filter or set variant attributes correctly.
- val kaptGeneratedClassesDir = getKaptGeneratedClassesDir(project, sourceSetName)
- val kspOutputDir = KspGradleSubplugin.getKspOutputDir(project, sourceSetName, target)
- cfg.libraries.from(
- project.files(
- Callable {
- kotlinCompileProvider.get().libraries.filter {
- !kspOutputDir.get().asFile.isParentOf(it) &&
- !kaptGeneratedClassesDir.isParentOf(it) &&
- !(it.isDirectory && it.listFiles()?.isEmpty() == true)
- }
+ if (project.isAgpBuiltInKotlinUsed()) {
+ // when legacy-kapt plugin is applied, we can't use KotlinCompile.libraries directly
+ // because it contains the kapt output classes dir leading to circular dependency
+ val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
+ cfg.libraries.from(androidComponents.sdkComponents.bootClasspath)
+ cfg.libraries.from(
+ project.provider {
+ val configuration = project.configurations.getByName(
+ kotlinCompilation.compileDependencyConfigurationName
+ )
+ configuration.incoming.artifactView { config ->
+ config.attributes.attribute(
+ Attribute.of("artifactType", String::class.java), "android-classes-jar"
+ )
+ }.files
}
)
- )
+ } else {
+ val kaptGeneratedClassesDir = getKaptGeneratedClassesDir(project, sourceSetName)
+ val kspOutputDir = KspGradleSubplugin.getKspOutputDir(project, sourceSetName, target)
+ cfg.libraries.from(
+ project.files(
+ Callable {
+ kotlinCompileProvider.get().libraries.filter {
+ !kspOutputDir.get().asFile.isParentOf(it) &&
+ !kaptGeneratedClassesDir.isParentOf(it) &&
+ !(it.isDirectory && it.listFiles()?.isEmpty() == true)
+ }
+ }
+ )
+ )
+ }
} else {
cfg.libraries.from(
project.provider {
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidDataBindingBuiltInKotlinIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidDataBindingBuiltInKotlinIT.kt
new file mode 100644
index 0000000000..b32d86a1cc
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/AndroidDataBindingBuiltInKotlinIT.kt
@@ -0,0 +1,34 @@
+package com.google.devtools.ksp.test
+
+import com.google.devtools.ksp.test.fixtures.TemporaryTestProject
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+class AndroidDataBindingBuiltInKotlinIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("android-data-binding-builtinkotlin")
+
+ @Test
+ fun testPlaygroundAndroid() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+
+ // Disabling configuration cache. See https://github.com/google/ksp/issues/299 for details
+ gradleRunner.withArguments(
+ "clean",
+ ":app:assemble",
+ "--configuration-cache-problems=warn",
+ "--info",
+ "--stacktrace"
+ )
+ .build().let { result ->
+ val output = result.output.lines()
+ val kspTask = output.filter {
+ it.contains(":app:kspDebugKotlin")
+ }
+ Assert.assertTrue(kspTask.isNotEmpty())
+ }
+ }
+}
diff --git a/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/LegacyKaptKspIT.kt b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/LegacyKaptKspIT.kt
new file mode 100644
index 0000000000..2ff922bdbe
--- /dev/null
+++ b/integration-tests/src/test/kotlin/com/google/devtools/ksp/test/LegacyKaptKspIT.kt
@@ -0,0 +1,31 @@
+package com.google.devtools.ksp.test
+
+import com.google.devtools.ksp.test.fixtures.TemporaryTestProject
+import org.gradle.testkit.runner.GradleRunner
+import org.junit.Assert
+import org.junit.Rule
+import org.junit.Test
+
+class LegacyKaptKspIT {
+ @Rule
+ @JvmField
+ val project: TemporaryTestProject = TemporaryTestProject("legacy-kapt", "playground")
+
+ @Test
+ fun testPlaygroundAndroid() {
+ val gradleRunner = GradleRunner.create().withProjectDir(project.root)
+ gradleRunner.withArguments(
+ "clean",
+ ":app:testDebugUnitTest",
+ "--configuration-cache-problems=warn",
+ "--info",
+ "--stacktrace"
+ ).build().let { result ->
+ val output = result.output.lines()
+ val kspTask = output.filter { it.contains(":app:kspDebugKotlin") }
+ val kaptTask = output.filter { it.contains(":app:kaptDebugKotlin") }
+ Assert.assertTrue(kspTask.isNotEmpty())
+ Assert.assertTrue(kaptTask.isNotEmpty())
+ }
+ }
+}
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/build.gradle.kts b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/build.gradle.kts
new file mode 100644
index 0000000000..b6a0a6680c
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/build.gradle.kts
@@ -0,0 +1,51 @@
+import org.jetbrains.kotlin.gradle.dsl.JvmTarget
+
+plugins {
+ id("com.android.application")
+ id("com.google.dagger.hilt.android") version "2.57.2"
+ id("com.google.devtools.ksp")
+}
+
+dependencies {
+ implementation("androidx.activity:activity:1.11.0")
+ implementation("com.google.dagger:hilt-android:2.57.2")
+ ksp("com.google.dagger:hilt-compiler:2.57.2")
+}
+
+android {
+ namespace = "com.example.databinding"
+ compileSdk = 36
+
+ defaultConfig {
+ applicationId = "com.example.databinding"
+ minSdk = 24
+ targetSdk = 36
+ versionCode = 1
+ versionName = "1.0"
+ }
+
+ buildFeatures {
+ dataBinding = true
+ }
+
+ dataBinding {
+ enable = true
+ }
+
+ compileOptions {
+ sourceCompatibility = JavaVersion.VERSION_11
+ targetCompatibility = JavaVersion.VERSION_11
+ }
+}
+
+kotlin {
+ compilerOptions {
+ jvmTarget = JvmTarget.JVM_11
+ }
+}
+
+hilt {
+ enableAggregatingTask = false
+}
+
+
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/AndroidManifest.xml b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..f10f89ecc5
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/AndroidManifest.xml
@@ -0,0 +1,22 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/A.kt b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/A.kt
new file mode 100644
index 0000000000..0abd30d1ff
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/A.kt
@@ -0,0 +1,8 @@
+package com.example.databinding
+
+import javax.inject.Inject
+import javax.inject.Singleton
+
+@Singleton class A @Inject constructor() {
+ val string = "a"
+}
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/App.kt b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/App.kt
new file mode 100644
index 0000000000..bb89bea434
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/App.kt
@@ -0,0 +1,7 @@
+package com.example.databinding
+
+import android.app.Application
+import dagger.hilt.android.HiltAndroidApp
+
+@HiltAndroidApp
+class App : Application()
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/BindingActivity.kt b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/BindingActivity.kt
new file mode 100644
index 0000000000..a2d69318f2
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/BindingActivity.kt
@@ -0,0 +1,20 @@
+package com.example.databinding
+
+import android.os.Bundle
+import androidx.activity.ComponentActivity
+import androidx.annotation.CallSuper
+import androidx.annotation.LayoutRes
+import androidx.databinding.DataBindingUtil
+import androidx.databinding.ViewDataBinding
+
+abstract class BindingActivity(
+ @get:LayoutRes private val layoutId: Int,
+) : ComponentActivity() {
+ protected lateinit var binding: T
+ private set
+
+ @CallSuper override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding = DataBindingUtil.setContentView(this, layoutId)
+ }
+}
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/MainActivity.kt b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/MainActivity.kt
new file mode 100644
index 0000000000..4a89581a70
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/kotlin/MainActivity.kt
@@ -0,0 +1,16 @@
+package com.example.databinding
+
+import android.os.Bundle
+import com.example.databinding.databinding.ActivityMainBinding
+import dagger.hilt.android.AndroidEntryPoint
+import javax.inject.Inject
+
+@AndroidEntryPoint
+class MainActivity : BindingActivity(R.layout.activity_main) {
+ @Inject lateinit var a: A
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+ binding.a = a
+ }
+}
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/res/layout/activity_main.xml b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000000..2b1157cd6a
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,24 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/build.gradle.kts b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/build.gradle.kts
new file mode 100644
index 0000000000..023f8a1191
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/build.gradle.kts
@@ -0,0 +1,25 @@
+buildscript {
+ val testRepo: String by project
+
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://redirector.kotlinlang.org/maven/bootstrap/")
+ google()
+ }
+}
+
+plugins {
+ id("com.android.application") apply false
+ id("com.google.devtools.ksp") apply false
+}
+
+allprojects {
+ val testRepo: String by project
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://redirector.kotlinlang.org/maven/bootstrap/")
+ google()
+ }
+}
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/gradle.properties b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/gradle.properties
new file mode 100644
index 0000000000..c132bcc68e
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/gradle.properties
@@ -0,0 +1 @@
+android.newDsl=false
\ No newline at end of file
diff --git a/integration-tests/src/test/resources/android-data-binding-builtinkotlin/settings.gradle.kts b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/settings.gradle.kts
new file mode 100644
index 0000000000..97c1a1ccd4
--- /dev/null
+++ b/integration-tests/src/test/resources/android-data-binding-builtinkotlin/settings.gradle.kts
@@ -0,0 +1,21 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ val agpVersion: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("jvm") version kotlinVersion apply false
+ id("com.android.application") version agpVersion apply false
+ id("com.android.library") version agpVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ maven("https://redirector.kotlinlang.org/maven/bootstrap/")
+ }
+}
+
+include(":app")
diff --git a/integration-tests/src/test/resources/legacy-kapt/app/build.gradle.kts b/integration-tests/src/test/resources/legacy-kapt/app/build.gradle.kts
new file mode 100644
index 0000000000..bd5bc8e0a2
--- /dev/null
+++ b/integration-tests/src/test/resources/legacy-kapt/app/build.gradle.kts
@@ -0,0 +1,24 @@
+plugins {
+ id("com.android.application")
+ id("com.android.legacy-kapt")
+ id("com.google.devtools.ksp")
+}
+dependencies {
+ implementation("androidx.constraintlayout:constraintlayout:2.1.4")
+ ksp("androidx.room:room-compiler:2.4.2")
+ implementation("androidx.room:room-runtime:2.4.2")
+ implementation("androidx.appcompat:appcompat:1.6.1")
+}
+android {
+ namespace = "com.example.kspandroidtestapp"
+ defaultConfig {
+ minSdk = 24
+ }
+ compileSdk = 34
+ buildFeatures {
+ viewBinding = true
+ }
+ viewBinding {
+ enable = true
+ }
+}
diff --git a/integration-tests/src/test/resources/legacy-kapt/app/src/main/AndroidManifest.xml b/integration-tests/src/test/resources/legacy-kapt/app/src/main/AndroidManifest.xml
new file mode 100644
index 0000000000..568741e54f
--- /dev/null
+++ b/integration-tests/src/test/resources/legacy-kapt/app/src/main/AndroidManifest.xml
@@ -0,0 +1,2 @@
+
+
\ No newline at end of file
diff --git a/integration-tests/src/test/resources/legacy-kapt/app/src/main/kotlin/MainActivity.kt b/integration-tests/src/test/resources/legacy-kapt/app/src/main/kotlin/MainActivity.kt
new file mode 100644
index 0000000000..c2114470b6
--- /dev/null
+++ b/integration-tests/src/test/resources/legacy-kapt/app/src/main/kotlin/MainActivity.kt
@@ -0,0 +1,14 @@
+import android.os.Bundle
+import androidx.appcompat.app.AppCompatActivity
+import com.example.kspandroidtestapp.databinding.ActivityMainBinding
+
+class MainActivity : AppCompatActivity() {
+
+ override fun onCreate(savedInstanceState: Bundle?) {
+ super.onCreate(savedInstanceState)
+
+ val binding = ActivityMainBinding.inflate(layoutInflater)
+
+ setContentView(binding.root)
+ }
+}
diff --git a/integration-tests/src/test/resources/legacy-kapt/app/src/main/res/layout/activity_main.xml b/integration-tests/src/test/resources/legacy-kapt/app/src/main/res/layout/activity_main.xml
new file mode 100644
index 0000000000..5b8db93264
--- /dev/null
+++ b/integration-tests/src/test/resources/legacy-kapt/app/src/main/res/layout/activity_main.xml
@@ -0,0 +1,8 @@
+
+
+
\ No newline at end of file
diff --git a/integration-tests/src/test/resources/legacy-kapt/build.gradle.kts b/integration-tests/src/test/resources/legacy-kapt/build.gradle.kts
new file mode 100644
index 0000000000..a47e4969ad
--- /dev/null
+++ b/integration-tests/src/test/resources/legacy-kapt/build.gradle.kts
@@ -0,0 +1,26 @@
+buildscript {
+ val testRepo: String by project
+
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://redirector.kotlinlang.org/maven/bootstrap/")
+ google()
+ }
+}
+
+plugins {
+ id("com.android.application") apply false
+ id("com.android.legacy-kapt") apply false
+ id("com.google.devtools.ksp") apply false
+}
+
+allprojects {
+ val testRepo: String by project
+ repositories {
+ maven(testRepo)
+ mavenCentral()
+ maven("https://redirector.kotlinlang.org/maven/bootstrap/")
+ google()
+ }
+}
diff --git a/integration-tests/src/test/resources/legacy-kapt/gradle.properties b/integration-tests/src/test/resources/legacy-kapt/gradle.properties
new file mode 100644
index 0000000000..c132bcc68e
--- /dev/null
+++ b/integration-tests/src/test/resources/legacy-kapt/gradle.properties
@@ -0,0 +1 @@
+android.newDsl=false
\ No newline at end of file
diff --git a/integration-tests/src/test/resources/legacy-kapt/settings.gradle.kts b/integration-tests/src/test/resources/legacy-kapt/settings.gradle.kts
new file mode 100644
index 0000000000..00d430989f
--- /dev/null
+++ b/integration-tests/src/test/resources/legacy-kapt/settings.gradle.kts
@@ -0,0 +1,22 @@
+pluginManagement {
+ val kotlinVersion: String by settings
+ val kspVersion: String by settings
+ val testRepo: String by settings
+ val agpVersion: String by settings
+ plugins {
+ id("com.google.devtools.ksp") version kspVersion apply false
+ kotlin("jvm") version kotlinVersion apply false
+ id("com.android.legacy-kapt") version agpVersion apply false
+ id("com.android.application") version agpVersion apply false
+ id("com.android.library") version agpVersion apply false
+ }
+ repositories {
+ maven(testRepo)
+ gradlePluginPortal()
+ google()
+ mavenCentral()
+ maven("https://redirector.kotlinlang.org/maven/bootstrap/")
+ }
+}
+
+include(":app")