• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1 /*
<lambda>null2  * Copyright (C) 2023 The Dagger Authors.
3  *
4  * Licensed under the Apache License, Version 2.0 (the "License");
5  * you may not use this file except in compliance with the License.
6  * You may obtain a copy of the License at
7  *
8  * http://www.apache.org/licenses/LICENSE-2.0
9  *
10  * Unless required by applicable law or agreed to in writing, software
11  * distributed under the License is distributed on an "AS IS" BASIS,
12  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13  * See the License for the specific language governing permissions and
14  * limitations under the License.
15  */
16 
17 package dagger.hilt.android.plugin.util
18 
19 import com.android.build.api.variant.ComponentIdentity
20 import com.google.devtools.ksp.gradle.KspAATask
21 import com.google.devtools.ksp.gradle.KspTask
22 import kotlin.reflect.KClass
23 import org.gradle.api.Project
24 import org.gradle.api.Task
25 import org.gradle.api.tasks.compile.JavaCompile
26 import org.gradle.process.CommandLineArgumentProvider
27 import org.jetbrains.kotlin.gradle.internal.KaptTask
28 
29 internal fun addJavaTaskProcessorOptions(
30   project: Project,
31   variantIdentity: ComponentIdentity,
32   produceArgProvider: (Task) -> CommandLineArgumentProvider
33 ) = project.tasks.withType(JavaCompile::class.java).configureEach { task ->
34   if (task.name == "compile${variantIdentity.name.capitalize()}JavaWithJavac") {
35     task.options.compilerArgumentProviders.add(produceArgProvider.invoke(task))
36   }
37 }
38 
addKaptTaskProcessorOptionsnull39 internal fun addKaptTaskProcessorOptions(
40   project: Project,
41   variantIdentity: ComponentIdentity,
42   produceArgProvider: (Task) -> CommandLineArgumentProvider
43 ) = project.plugins.withId("kotlin-kapt") {
44   checkClass("org.jetbrains.kotlin.gradle.internal.KaptTask") {
45     """
46     The KAPT plugin was detected to be applied but its task class could not be found.
47 
48     This is an indicator that the Hilt Gradle Plugin is using a different class loader because
49     it was declared at the root while KAPT was declared in a sub-project. To fix this, declare
50     both plugins in the same scope, i.e. either at the root (without applying them) or at the
51     sub-projects.
52     """.trimIndent()
53   }
54   project.tasks.withType(KaptTask::class.java).configureEach { task ->
55     if (task.name == "kapt${variantIdentity.name.capitalize()}Kotlin" ||
56         // Task names in shared/src/AndroidMain in KMP projects has a platform suffix.
57         task.name == "kapt${variantIdentity.name.capitalize()}KotlinAndroid") {
58       val argProvider = produceArgProvider.invoke(task)
59       // TODO: Update once KT-58009 is fixed.
60       try {
61         // Because of KT-58009, we need to add a `listOf(argProvider)` instead
62         // of `argProvider`.
63         task.annotationProcessorOptionProviders.add(listOf(argProvider))
64       } catch (e: Throwable) {
65         // Once KT-58009 is fixed, adding `listOf(argProvider)` will fail, we will
66         // pass `argProvider` instead, which is the correct way.
67         task.annotationProcessorOptionProviders.add(argProvider)
68       }
69     }
70   }
71 }
72 
addKspTaskProcessorOptionsnull73 internal fun addKspTaskProcessorOptions(
74   project: Project,
75   variantIdentity: ComponentIdentity,
76   produceArgProvider: (Task) -> CommandLineArgumentProvider
77 ) = project.plugins.withId("com.google.devtools.ksp") {
78   check(kspOneTaskClass != null || kspTwoTaskClass != null) {
79     """
80     The KSP plugin was detected to be applied but its task class could not be found.
81 
82     This is an indicator that the Hilt Gradle Plugin is using a different class loader because
83     it was declared at the root while KSP was declared in a sub-project. To fix this, declare
84     both plugins in the same scope, i.e. either at the root (without applying them) or at the
85     sub-projects.
86 
87     See https://github.com/google/dagger/issues/3965 for more details.
88     """.trimIndent()
89   }
90   fun <T : Task> configureEach(
91     kclass: KClass<T>,
92     block: T.(CommandLineArgumentProvider) -> Unit
93   ) {
94     project.tasks.withType(kclass.java).configureEach { task ->
95       if (task.name == "ksp${variantIdentity.name.capitalize()}Kotlin" ||
96         // Task names in shared/src/AndroidMain in KMP projects has a platform suffix.
97         task.name == "ksp${variantIdentity.name.capitalize()}KotlinAndroid") {
98         val argProvider = produceArgProvider.invoke(task)
99         task.block(argProvider)
100       }
101     }
102   }
103   if (kspOneTaskClass != null) {
104     configureEach(KspTask::class) { commandLineArgumentProviders.add(it) }
105   }
106   if (kspTwoTaskClass != null) {
107     configureEach(KspAATask::class) { commandLineArgumentProviders.add(it) }
108   }
109 }
110 
checkClassnull111 private inline fun checkClass(fqn: String, msg: () -> String) {
112   try {
113     Class.forName(fqn)
114   } catch (ex: ClassNotFoundException) {
115     throw IllegalStateException(msg.invoke(), ex)
116   }
117 }
118 
119 private val kspOneTaskClass =
120   try {
121     Class.forName("com.google.devtools.ksp.gradle.KspTask")
122   } catch (ex: ClassNotFoundException) {
123     null
124   }
125 
126 private val kspTwoTaskClass =
127   try {
128     Class.forName("com.google.devtools.ksp.gradle.KspAATask")
129   } catch (ex: ClassNotFoundException) {
130     null
131   }
132 
isKspTasknull133 internal fun Task.isKspTask() =
134   kspOneTaskClass?.isAssignableFrom(this::class.java) == true ||
135     kspTwoTaskClass?.isAssignableFrom(this::class.java) == true
136 
137