Skip to content

Commit bced480

Browse files
committed
Fix KSP when in use with legacy-kapt plugin
1 parent 9b30f91 commit bced480

20 files changed

Lines changed: 390 additions & 13 deletions

File tree

gradle-plugin/src/main/kotlin/com/google/devtools/ksp/gradle/KspAATask.kt

Lines changed: 33 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -17,9 +17,11 @@
1717

1818
package com.google.devtools.ksp.gradle
1919

20+
import com.android.build.api.variant.AndroidComponentsExtension
2021
import com.google.devtools.ksp.gradle.utils.allKotlinSourceSetsObservable
2122
import com.google.devtools.ksp.gradle.utils.canUseGeneratedKotlinApi
2223
import com.google.devtools.ksp.gradle.utils.enableProjectIsolationCompatibleCodepath
24+
import com.google.devtools.ksp.gradle.utils.isAgpBuiltInKotlinUsed
2325
import com.google.devtools.ksp.impl.KotlinSymbolProcessing
2426
import com.google.devtools.ksp.processing.ExitCode
2527
import com.google.devtools.ksp.processing.KSPCommonConfig
@@ -31,6 +33,7 @@ import com.google.devtools.ksp.processing.KspGradleLogger
3133
import org.gradle.api.DefaultTask
3234
import org.gradle.api.JavaVersion
3335
import org.gradle.api.artifacts.Configuration
36+
import org.gradle.api.attributes.Attribute
3437
import org.gradle.api.file.ConfigurableFileCollection
3538
import org.gradle.api.file.DirectoryProperty
3639
import org.gradle.api.logging.LogLevel
@@ -223,21 +226,38 @@ abstract class KspAATask @Inject constructor(
223226
}
224227

225228
if (kotlinCompilation is KotlinJvmAndroidCompilation) {
226-
// Workaround of a dependency resolution issue of AGP.
227-
// FIXME: figure out how to filter or set variant attributes correctly.
228-
val kaptGeneratedClassesDir = getKaptGeneratedClassesDir(project, sourceSetName)
229-
val kspOutputDir = KspGradleSubplugin.getKspOutputDir(project, sourceSetName, target)
230-
cfg.libraries.from(
231-
project.files(
232-
Callable {
233-
kotlinCompileProvider.get().libraries.filter {
234-
!kspOutputDir.get().asFile.isParentOf(it) &&
235-
!kaptGeneratedClassesDir.isParentOf(it) &&
236-
!(it.isDirectory && it.listFiles()?.isEmpty() == true)
237-
}
229+
if (project.isAgpBuiltInKotlinUsed()) {
230+
// when legacy-kapt plugin is applied, we can't use KotlinCompile.libraries directly
231+
// because it contains the kapt output classes dir leading to circular dependency
232+
val androidComponents = project.extensions.getByType(AndroidComponentsExtension::class.java)
233+
cfg.libraries.from(androidComponents.sdkComponents.bootClasspath)
234+
cfg.libraries.from(
235+
project.provider {
236+
val configuration = project.configurations.getByName(
237+
kotlinCompilation.compileDependencyConfigurationName
238+
)
239+
configuration.incoming.artifactView { config ->
240+
config.attributes.attribute(
241+
Attribute.of("artifactType", String::class.java), "android-classes-jar"
242+
)
243+
}.files
238244
}
239245
)
240-
)
246+
} else {
247+
val kaptGeneratedClassesDir = getKaptGeneratedClassesDir(project, sourceSetName)
248+
val kspOutputDir = KspGradleSubplugin.getKspOutputDir(project, sourceSetName, target)
249+
cfg.libraries.from(
250+
project.files(
251+
Callable {
252+
kotlinCompileProvider.get().libraries.filter {
253+
!kspOutputDir.get().asFile.isParentOf(it) &&
254+
!kaptGeneratedClassesDir.isParentOf(it) &&
255+
!(it.isDirectory && it.listFiles()?.isEmpty() == true)
256+
}
257+
}
258+
)
259+
)
260+
}
241261
} else {
242262
cfg.libraries.from(
243263
project.provider {
Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,34 @@
1+
package com.google.devtools.ksp.test
2+
3+
import com.google.devtools.ksp.test.fixtures.TemporaryTestProject
4+
import org.gradle.testkit.runner.GradleRunner
5+
import org.junit.Assert
6+
import org.junit.Rule
7+
import org.junit.Test
8+
9+
class AndroidDataBindingBuiltInKotlinIT {
10+
@Rule
11+
@JvmField
12+
val project: TemporaryTestProject = TemporaryTestProject("android-data-binding-builtinkotlin")
13+
14+
@Test
15+
fun testPlaygroundAndroid() {
16+
val gradleRunner = GradleRunner.create().withProjectDir(project.root)
17+
18+
// Disabling configuration cache. See https://github.com/google/ksp/issues/299 for details
19+
gradleRunner.withArguments(
20+
"clean",
21+
":app:assemble",
22+
"--configuration-cache-problems=warn",
23+
"--info",
24+
"--stacktrace"
25+
)
26+
.build().let { result ->
27+
val output = result.output.lines()
28+
val kspTask = output.filter {
29+
it.contains(":app:kspDebugKotlin")
30+
}
31+
Assert.assertTrue(kspTask.isNotEmpty())
32+
}
33+
}
34+
}
Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
package com.google.devtools.ksp.test
2+
3+
import com.google.devtools.ksp.test.fixtures.TemporaryTestProject
4+
import org.gradle.testkit.runner.GradleRunner
5+
import org.junit.Assert
6+
import org.junit.Rule
7+
import org.junit.Test
8+
9+
class LegacyKaptKspIT {
10+
@Rule
11+
@JvmField
12+
val project: TemporaryTestProject = TemporaryTestProject("legacy-kapt", "playground")
13+
14+
@Test
15+
fun testPlaygroundAndroid() {
16+
val gradleRunner = GradleRunner.create().withProjectDir(project.root)
17+
gradleRunner.withArguments(
18+
"clean",
19+
":app:testDebugUnitTest",
20+
"--configuration-cache-problems=warn",
21+
"--info",
22+
"--stacktrace"
23+
).build().let { result ->
24+
val output = result.output.lines()
25+
val kspTask = output.filter { it.contains(":app:kspDebugKotlin") }
26+
val kaptTask = output.filter { it.contains(":app:kaptDebugKotlin") }
27+
Assert.assertTrue(kspTask.isNotEmpty())
28+
Assert.assertTrue(kaptTask.isNotEmpty())
29+
}
30+
}
31+
}
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import org.jetbrains.kotlin.gradle.dsl.JvmTarget
2+
3+
plugins {
4+
id("com.android.application")
5+
id("com.google.dagger.hilt.android") version "2.57.2"
6+
id("com.google.devtools.ksp")
7+
}
8+
9+
dependencies {
10+
implementation("androidx.activity:activity:1.11.0")
11+
implementation("com.google.dagger:hilt-android:2.57.2")
12+
ksp("com.google.dagger:hilt-compiler:2.57.2")
13+
}
14+
15+
android {
16+
namespace = "com.example.databinding"
17+
compileSdk = 36
18+
19+
defaultConfig {
20+
applicationId = "com.example.databinding"
21+
minSdk = 24
22+
targetSdk = 36
23+
versionCode = 1
24+
versionName = "1.0"
25+
}
26+
27+
buildFeatures {
28+
dataBinding = true
29+
}
30+
31+
dataBinding {
32+
enable = true
33+
}
34+
35+
compileOptions {
36+
sourceCompatibility = JavaVersion.VERSION_11
37+
targetCompatibility = JavaVersion.VERSION_11
38+
}
39+
}
40+
41+
kotlin {
42+
compilerOptions {
43+
jvmTarget = JvmTarget.JVM_11
44+
}
45+
}
46+
47+
hilt {
48+
enableAggregatingTask = false
49+
}
50+
51+
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<manifest xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<application
6+
android:name=".App"
7+
android:label="KSP #2597 Repro"
8+
android:theme="@android:style/Theme.Material.Light.NoActionBar"
9+
tools:ignore="MissingApplicationIcon">
10+
11+
<activity
12+
android:name=".MainActivity"
13+
android:exported="true">
14+
15+
<intent-filter>
16+
<action android:name="android.intent.action.MAIN" />
17+
<category android:name="android.intent.category.LAUNCHER" />
18+
</intent-filter>
19+
</activity>
20+
21+
</application>
22+
</manifest>
Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
package com.example.databinding
2+
3+
import javax.inject.Inject
4+
import javax.inject.Singleton
5+
6+
@Singleton class A @Inject constructor() {
7+
val string = "a"
8+
}
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
package com.example.databinding
2+
3+
import android.app.Application
4+
import dagger.hilt.android.HiltAndroidApp
5+
6+
@HiltAndroidApp
7+
class App : Application()
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.example.databinding
2+
3+
import android.os.Bundle
4+
import androidx.activity.ComponentActivity
5+
import androidx.annotation.CallSuper
6+
import androidx.annotation.LayoutRes
7+
import androidx.databinding.DataBindingUtil
8+
import androidx.databinding.ViewDataBinding
9+
10+
abstract class BindingActivity<T : ViewDataBinding>(
11+
@get:LayoutRes private val layoutId: Int,
12+
) : ComponentActivity() {
13+
protected lateinit var binding: T
14+
private set
15+
16+
@CallSuper override fun onCreate(savedInstanceState: Bundle?) {
17+
super.onCreate(savedInstanceState)
18+
binding = DataBindingUtil.setContentView<T>(this, layoutId)
19+
}
20+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
package com.example.databinding
2+
3+
import android.os.Bundle
4+
import com.example.databinding.databinding.ActivityMainBinding
5+
import dagger.hilt.android.AndroidEntryPoint
6+
import javax.inject.Inject
7+
8+
@AndroidEntryPoint
9+
class MainActivity : BindingActivity<ActivityMainBinding>(R.layout.activity_main) {
10+
@Inject lateinit var a: A
11+
12+
override fun onCreate(savedInstanceState: Bundle?) {
13+
super.onCreate(savedInstanceState)
14+
binding.a = a
15+
}
16+
}
Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
<?xml version="1.0" encoding="utf-8"?>
2+
<layout xmlns:android="http://schemas.android.com/apk/res/android"
3+
xmlns:tools="http://schemas.android.com/tools">
4+
5+
<data>
6+
<variable
7+
name="a"
8+
type="com.example.databinding.A" />
9+
</data>
10+
11+
<LinearLayout
12+
android:id="@+id/main"
13+
android:layout_width="match_parent"
14+
android:layout_height="match_parent"
15+
android:layout_margin="30dp"
16+
tools:context=".MainActivity">
17+
18+
<TextView
19+
android:layout_width="wrap_content"
20+
android:layout_height="wrap_content"
21+
android:text="@{a.string}" />
22+
23+
</LinearLayout>
24+
</layout>

0 commit comments

Comments
 (0)