Refactor the kapt Gradle plugin to use the new plugins API and TCA

This commit is contained in:
Sergey Igushkin
2020-06-06 00:23:19 +03:00
parent 96ed30a449
commit 4dbc6803ba
7 changed files with 292 additions and 226 deletions
@@ -7,44 +7,56 @@ package org.jetbrains.kotlin.gradle.internal
import com.android.build.gradle.BaseExtension
import com.android.build.gradle.api.AndroidSourceSet
import com.android.builder.model.SourceProvider
import com.android.build.gradle.api.BaseVariant
import com.android.build.gradle.api.SourceKind
import com.intellij.openapi.util.SystemInfo
import org.gradle.api.GradleException
import org.gradle.api.Plugin
import org.gradle.api.Project
import org.gradle.api.Task
import org.gradle.api.artifacts.Configuration
import org.gradle.api.artifacts.Dependency
import org.gradle.api.attributes.Attribute
import org.gradle.api.attributes.Usage
import org.gradle.api.tasks.SourceSet
import org.gradle.api.tasks.TaskDependency
import org.gradle.api.file.FileCollection
import org.gradle.api.provider.Provider
import org.gradle.api.tasks.*
import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.api.tasks.compile.JavaCompile
import org.gradle.process.CommandLineArgumentProvider
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedClassesDir
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedKotlinSourcesDir
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.getKaptGeneratedSourcesDir
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.CLASS_STRUCTURE_ARTIFACT_TYPE
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.StructureArtifactTransform
import org.jetbrains.kotlin.gradle.model.builder.KaptModelBuilder
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation
import org.jetbrains.kotlin.gradle.tasks.KotlinCompileTaskData
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile
import org.jetbrains.kotlin.gradle.tasks.locateTask
import org.jetbrains.kotlin.gradle.tasks.registerTask
import java.io.ByteArrayOutputStream
import java.io.File
import java.io.ObjectOutputStream
import java.util.*
import java.util.concurrent.Callable
import javax.inject.Inject
// apply plugin: 'kotlin-kapt'
class Kapt3GradleSubplugin @Inject internal constructor(private val registry: ToolingModelBuilderRegistry) : Plugin<Project> {
companion object {
fun isEnabled(project: Project) = project.plugins.findPlugin(Kapt3GradleSubplugin::class.java) != null
class Kapt3GradleSubplugin @Inject internal constructor(private val registry: ToolingModelBuilderRegistry) :
KotlinCompilerPluginSupportPlugin {
override fun apply(project: Project) {
project.extensions.create("kapt", KaptExtension::class.java)
project.configurations.create(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply {
project.getKotlinPluginVersion()?.let { kotlinPluginVersion ->
val kaptDependency = getPluginArtifact().run { "$groupId:$artifactId:$kotlinPluginVersion" }
dependencies.add(project.dependencies.create(kaptDependency))
} ?: throw GradleException("Kotlin plugin should be enabled before 'kotlin-kapt'")
}
registry.register(KaptModelBuilder())
}
companion object {
@JvmStatic
fun getKaptGeneratedClassesDir(project: Project, sourceSetName: String) =
File(project.buildDir, "tmp/kapt3/classes/$sourceSetName")
@@ -56,41 +68,7 @@ class Kapt3GradleSubplugin @Inject internal constructor(private val registry: To
@JvmStatic
fun getKaptGeneratedKotlinSourcesDir(project: Project, sourceSetName: String) =
File(project.buildDir, "generated/source/kaptKotlin/$sourceSetName")
}
override fun apply(project: Project) {
project.extensions.create("kapt", KaptExtension::class.java)
Kapt3KotlinGradleSubplugin().run {
project.configurations.create(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).apply {
project.getKotlinPluginVersion()?.let { kotlinPluginVersion ->
val kaptDependency = getPluginArtifact().run { "$groupId:$artifactId:$kotlinPluginVersion" }
dependencies.add(project.dependencies.create(kaptDependency))
} ?: throw GradleException("Kotlin plugin should be enabled before 'kotlin-kapt'")
}
}
registry.register(KaptModelBuilder())
}
}
abstract class KaptVariantData<T>(val variantData: T) {
abstract val name: String
abstract val sourceProviders: Iterable<SourceProvider>
abstract fun addJavaSourceFoldersToModel(generatedFilesDir: File)
abstract val annotationProcessorOptions: Map<String, String>?
abstract fun registerGeneratedJavaSource(
project: Project,
kaptTask: KaptTask,
javaTask: AbstractCompile
)
open val annotationProcessorOptionProviders: List<*>
get() = emptyList<Any>()
}
// Subplugin for the Kotlin Gradle plugin
class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
companion object {
private val VERBOSE_OPTION_NAME = "kapt.verbose"
private val USE_WORKER_API = "kapt.use.worker.api"
private val INFO_AS_WARNINGS = "kapt.info.as.warnings"
@@ -139,7 +117,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
fun findMainKaptConfiguration(project: Project) = project.findKaptConfiguration(SourceSet.MAIN_SOURCE_SET_NAME)
fun createAptConfigurationIfNeeded(project: Project, sourceSetName: String): Configuration {
val configurationName = Kapt3KotlinGradleSubplugin.getKaptConfigurationName(sourceSetName)
val configurationName = getKaptConfigurationName(sourceSetName)
project.configurations.findByName(configurationName)?.let { return it }
val aptConfiguration = project.configurations.create(configurationName).apply {
@@ -148,7 +126,7 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
attributes.attribute(Usage.USAGE_ATTRIBUTE, project.objects.named(Usage::class.java, Usage.JAVA_RUNTIME))
}
if (aptConfiguration.name != Kapt3KotlinGradleSubplugin.MAIN_KAPT_CONFIGURATION_NAME) {
if (aptConfiguration.name != MAIN_KAPT_CONFIGURATION_NAME) {
// The main configuration can be created after the current one. We should handle this case
val mainConfiguration = findMainKaptConfiguration(project)
?: createAptConfigurationIfNeeded(project, SourceSet.MAIN_SOURCE_SET_NAME)
@@ -158,11 +136,13 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
return aptConfiguration
}
fun isEnabled(project: Project) =
project.plugins.any { it is Kapt3GradleSubplugin }
}
private val kotlinToKaptGenerateStubsTasksMap = mutableMapOf<KotlinCompile, KaptGenerateStubsTask>()
override fun isApplicable(project: Project, task: AbstractCompile) = task is KotlinCompile && Kapt3GradleSubplugin.isEnabled(project)
override fun isApplicable(kotlinCompilation: KotlinCompilation<*>) =
(kotlinCompilation.platformType == KotlinPlatformType.jvm || kotlinCompilation.platformType == KotlinPlatformType.androidJvm)
private fun Kapt3SubpluginContext.getKaptStubsDir() = temporaryKaptDirectory("stubs")
@@ -178,13 +158,12 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
return dir
}
private inner class Kapt3SubpluginContext(
internal inner class Kapt3SubpluginContext(
val project: Project,
val kotlinCompile: KotlinCompile,
val javaCompile: AbstractCompile?,
val kaptVariantData: KaptVariantData<*>?,
val javaCompile: TaskProvider<out AbstractCompile>?,
val variantData: Any?,
val sourceSetName: String,
val kotlinCompilation: KotlinCompilation<*>?,
val kotlinCompilation: KotlinCompilation<*>,
val kaptExtension: KaptExtension,
val kaptClasspathConfigurations: List<Configuration>
) {
@@ -193,19 +172,18 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
val classesOutputDir = getKaptGeneratedClassesDir(project, sourceSetName)
val includeCompileClasspath =
kaptExtension.includeCompileClasspath
?: Kapt3KotlinGradleSubplugin.includeCompileClasspath(project)
?: includeCompileClasspath(project)
?: true
val kotlinCompile: TaskProvider<KotlinCompile>
// Can't use just kotlinCompilation.compileKotlinTaskProvider, as the latter is not statically-known to be KotlinCompile
get() = checkNotNull(project.locateTask(kotlinCompilation.compileKotlinTaskName))
}
override fun apply(
project: Project,
kotlinCompile: KotlinCompile,
javaCompile: AbstractCompile?,
variantData: Any?,
androidProjectHandler: Any?,
kotlinCompilation: KotlinCompilation<*>?
): List<SubpluginOption> {
assert((variantData != null) xor (kotlinCompilation != null))
override fun applyToCompilation(
kotlinCompilation: KotlinCompilation<*>
): Provider<List<SubpluginOption>> {
val project = kotlinCompilation.target.project
val buildDependencies = arrayListOf<TaskDependency>()
val kaptConfigurations = arrayListOf<Configuration>()
@@ -217,17 +195,14 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
}
}
val kaptVariantData = variantData as? KaptVariantData<*>
val androidVariantData: BaseVariant? = (kotlinCompilation as? KotlinJvmAndroidCompilation)?.androidVariant
val sourceSetName = if (kaptVariantData != null) {
for (provider in kaptVariantData.sourceProviders) {
val sourceSetName = if (androidVariantData != null) {
for (provider in androidVariantData.sourceSets) {
handleSourceSet((provider as AndroidSourceSet).name)
}
kaptVariantData.name
androidVariantData.name
} else {
if (kotlinCompilation == null) error("In non-Android projects, Kotlin compilation should not be null")
handleSourceSet(kotlinCompilation.compilationName)
kotlinCompilation.compilationName
}
@@ -236,75 +211,103 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
val nonEmptyKaptConfigurations = kaptConfigurations.filter { it.dependencies.isNotEmpty() }
val javaCompileOrNull = findJavaTaskForKotlinCompilation(kotlinCompilation)
val context = Kapt3SubpluginContext(
project, kotlinCompile, javaCompile,
kaptVariantData, sourceSetName, kotlinCompilation, kaptExtension, nonEmptyKaptConfigurations
project, javaCompileOrNull,
androidVariantData, sourceSetName, kotlinCompilation, kaptExtension, nonEmptyKaptConfigurations
)
val kaptGenerateStubsTask = context.createKaptGenerateStubsTask()
val kaptTask = context.createKaptKotlinTask(useWorkerApi = project.isUseWorkerApi())
val kaptGenerateStubsTaskProvider: TaskProvider<KaptGenerateStubsTask> = context.createKaptGenerateStubsTask()
val kaptTaskProvider: TaskProvider<out KaptTask> = context.createKaptKotlinTask(useWorkerApi = project.isUseWorkerApi())
kaptGenerateStubsTask.source(*kaptConfigurations.toTypedArray())
kaptGenerateStubsTaskProvider.configure { kaptGenerateStubsTask ->
kaptGenerateStubsTask.source(*kaptConfigurations.toTypedArray())
kaptGenerateStubsTask.dependsOn(*buildDependencies.toTypedArray())
kaptGenerateStubsTask.dependsOn(*kotlinCompile.dependsOn.toTypedArray())
kaptGenerateStubsTask.dependsOn(*buildDependencies.toTypedArray())
kaptGenerateStubsTask.dependsOn(
project.provider {
kotlinCompilation.compileKotlinTask.dependsOn.filter { it !is TaskProvider<*> || it.name != kaptTaskProvider.name }
}
)
kaptTask.dependsOn(kaptGenerateStubsTask)
kotlinCompile.dependsOn(kaptTask)
if (androidVariantData != null) {
kaptGenerateStubsTask.inputs.files(
Callable {
// Avoid circular dependency: the stubs task need the Java sources, but the Java sources generated by Kapt should be
// excluded, as the Kapt tasks depend on the stubs ones, and having them in the input would lead to a cycle
val kaptJavaOutput = kaptTaskProvider.get().destinationDir
androidVariantData.getSourceFolders(SourceKind.JAVA).filter { it.dir != kaptJavaOutput }
}
).withPathSensitivity(PathSensitivity.RELATIVE)
}
}
kaptTaskProvider.configure { kaptTask ->
kaptTask.dependsOn(kaptGenerateStubsTaskProvider)
}
context.kotlinCompile.configure { it.dependsOn(kaptTaskProvider) }
/** Plugin options are applied to kapt*Compile inside [createKaptKotlinTask] */
return emptyList()
}
override fun getSubpluginKotlinTasks(project: Project, kotlinCompile: KotlinCompile): List<AbstractCompile> {
val kaptGenerateStubsTask = kotlinToKaptGenerateStubsTasksMap[kotlinCompile]
return if (kaptGenerateStubsTask == null) emptyList() else listOf(kaptGenerateStubsTask)
return project.provider { emptyList<SubpluginOption>() }
}
// This method should be called no more than once for each Kapt3SubpluginContext
private fun Kapt3SubpluginContext.buildOptions(aptMode: String, javacOptions: Map<String, String>): List<SubpluginOption> {
val pluginOptions = mutableListOf<SubpluginOption>()
val generatedFilesDir = getKaptGeneratedSourcesDir(project, sourceSetName)
kaptVariantData?.addJavaSourceFoldersToModel(generatedFilesDir)
pluginOptions += SubpluginOption("aptMode", aptMode)
private fun Kapt3SubpluginContext.buildOptions(
aptMode: String,
javacOptions: Provider<Map<String, String>>
): Provider<List<SubpluginOption>> {
disableAnnotationProcessingInJavaTask()
pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir))
pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName)))
return project.provider {
val pluginOptions = mutableListOf<SubpluginOption>()
pluginOptions += FilesSubpluginOption("incrementalData", listOf(getKaptIncrementalDataDir()))
val generatedFilesDir = getKaptGeneratedSourcesDir(project, sourceSetName)
KaptWithAndroid.androidVariantData(this)?.addJavaSourceFoldersToModel(generatedFilesDir)
val annotationProcessors = kaptExtension.processors
if (annotationProcessors.isNotEmpty()) {
pluginOptions += SubpluginOption("processors", annotationProcessors)
pluginOptions += SubpluginOption("aptMode", aptMode)
pluginOptions += FilesSubpluginOption("sources", listOf(generatedFilesDir))
pluginOptions += FilesSubpluginOption("classes", listOf(getKaptGeneratedClassesDir(project, sourceSetName)))
pluginOptions += FilesSubpluginOption("incrementalData", listOf(getKaptIncrementalDataDir()))
val annotationProcessors = kaptExtension.processors
if (annotationProcessors.isNotEmpty()) {
pluginOptions += SubpluginOption("processors", annotationProcessors)
}
kotlinSourcesOutputDir.mkdirs()
val apOptions = getAPOptions().get()
pluginOptions += CompositeSubpluginOption(
"apoptions",
lazy { encodeList(apOptions.associate { it.key to it.value }) },
apOptions
)
pluginOptions += SubpluginOption("javacArguments", encodeList(javacOptions.get()))
pluginOptions += SubpluginOption("includeCompileClasspath", includeCompileClasspath.toString())
addMiscOptions(pluginOptions)
pluginOptions
}
kotlinSourcesOutputDir.mkdirs()
val apOptions = getAPOptions()
pluginOptions += CompositeSubpluginOption("apoptions", lazy { encodeList(apOptions.associate { it.key to it.value }) }, apOptions)
pluginOptions += SubpluginOption("javacArguments", encodeList(javacOptions))
pluginOptions += SubpluginOption("includeCompileClasspath", includeCompileClasspath.toString())
addMiscOptions(pluginOptions)
return pluginOptions
}
private fun Kapt3SubpluginContext.getAPOptions(): List<SubpluginOption> {
val androidPlugin = kaptVariantData?.let {
private fun Kapt3SubpluginContext.getAPOptions(): Provider<List<SubpluginOption>> = project.provider {
val androidVariantData = KaptWithAndroid.androidVariantData(this)
val androidPlugin = androidVariantData?.let {
project.extensions.findByName("android") as? BaseExtension
}
val androidOptions = kaptVariantData?.annotationProcessorOptions ?: emptyMap()
val androidOptions = androidVariantData?.annotationProcessorOptions ?: emptyMap()
val apOptionsFromProviders =
kaptVariantData?.annotationProcessorOptionProviders
androidVariantData?.annotationProcessorOptionProviders
?.flatMap { (it as CommandLineArgumentProvider).asArguments() }
.orEmpty()
@@ -317,30 +320,44 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
}
val apOptionsPairsList: List<Pair<String, String>> =
kaptExtension.getAdditionalArguments(project, kaptVariantData?.variantData, androidPlugin).toList() +
kaptExtension.getAdditionalArguments(project, androidVariantData, androidPlugin).toList() +
androidOptions.toList()
return apOptionsPairsList.map { SubpluginOption(it.first, it.second) } +
apOptionsPairsList.map { SubpluginOption(it.first, it.second) } +
FilesSubpluginOption(KAPT_KOTLIN_GENERATED, listOf(kotlinSourcesOutputDir)) +
subluginOptionsFromProvidedApOptions
}
private fun Kapt3SubpluginContext.registerSubpluginOptions(
task: Task,
container: CompilerPluginOptions,
options: List<SubpluginOption>
taskProvider: TaskProvider<*>,
optionsProvider: Provider<List<SubpluginOption>>
) {
val compilerPluginId = getCompilerPluginId()
task.registerSubpluginOptionsAsInputs(compilerPluginId, options)
taskProvider.configure { taskInstance ->
val container = when (taskInstance) {
is KaptGenerateStubsTask -> taskInstance.pluginOptions
is KaptWithKotlincTask -> taskInstance.pluginOptions
is KaptWithoutKotlincTask -> taskInstance.processorOptions
else -> error("Unexpected task ${taskInstance.name} (${taskInstance.javaClass})")
}
for (option in options) {
container.addPluginArgument(compilerPluginId, option)
val compilerPluginId = getCompilerPluginId()
val options = optionsProvider.get()
taskInstance.registerSubpluginOptionsAsInputs(compilerPluginId, options)
for (option in options) {
container.addPluginArgument(compilerPluginId, option)
}
}
// Also register all the subplugin options from the Kotlin task:
project.afterEvaluate {
kotlinCompile.pluginOptions.subpluginOptionsByPluginId.forEach { (pluginId, options) ->
task.registerSubpluginOptionsAsInputs("kotlinCompile.$pluginId", options)
project.whenEvaluated {
taskProvider.configure { taskInstance ->
kotlinCompile.get().pluginOptions.subpluginOptionsByPluginId.forEach { (pluginId, options) ->
taskInstance.registerSubpluginOptionsAsInputs("kotlinCompile.$pluginId", options)
}
}
}
}
@@ -379,95 +396,111 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
}
}
private fun Kapt3SubpluginContext.createKaptKotlinTask(useWorkerApi: Boolean): KaptTask {
private fun Kapt3SubpluginContext.createKaptKotlinTask(useWorkerApi: Boolean): TaskProvider<out KaptTask> {
val taskClass = if (useWorkerApi) KaptWithoutKotlincTask::class.java else KaptWithKotlincTask::class.java
val taskName = getKaptTaskName("kapt")
val kaptTask = project.tasks.create(taskName, taskClass)
kaptTask.useBuildCache = kaptExtension.useBuildCache
kaptTask.kotlinCompileTask = kotlinCompile
kaptTask.stubsDir = getKaptStubsDir()
kaptTask.destinationDir = sourcesOutputDir
kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir
kaptTask.classesDir = classesOutputDir
kaptTask.includeCompileClasspath = includeCompileClasspath
kaptTask.isIncremental = project.isIncrementalKapt()
if (kaptTask.isIncremental) {
kaptTask.incAptCache = getKaptIncrementalAnnotationProcessingCache()
kaptTask.localState.register(kaptTask.incAptCache)
var classStructureIfIncremental: Configuration? = null
if (project.isIncrementalKapt()) {
maybeRegisterTransform(project)
val classStructure = project.configurations.create("_classStructure${taskName}")
classStructureIfIncremental = project.configurations.create("_classStructure${taskName}")
// Wrap the `kotlinCompile.classpath` into a file collection, so that, if the classpath is represented by a configuration,
// the configuration is not extended (via extendsFrom, which normally happens when one configuration is _added_ into another)
// but is instead included as the (lazily) resolved files. This is needed because the class structure configuration doesn't have
// the attributes that are potentially needed to resolve dependencies on MPP modules, and the classpath configuration does.
project.dependencies.add(classStructure.name, project.files(project.provider { kotlinCompile.classpath }))
kaptTask.classpathStructure = classStructure.incoming.artifactView { viewConfig ->
viewConfig.attributes.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}.files
project.dependencies.add(classStructureIfIncremental.name, project.files(project.provider { kotlinCompile.get().classpath }))
}
kotlinCompilation?.run {
output.apply {
addClassesDir { project.files(classesOutputDir).builtBy(kaptTask) }
val kaptTaskProvider = project.registerTask(taskName, taskClass, emptyList()) { kaptTask ->
kaptTask.useBuildCache = kaptExtension.useBuildCache
kaptTask.kotlinCompileTask = kotlinCompilation.compileKotlinTaskProvider.get() as KotlinCompile
kaptTask.stubsDir = getKaptStubsDir()
kaptTask.destinationDir = sourcesOutputDir
kaptTask.kotlinSourcesDestinationDir = kotlinSourcesOutputDir
kaptTask.classesDir = classesOutputDir
kaptTask.includeCompileClasspath = includeCompileClasspath
kaptTask.isIncremental = project.isIncrementalKapt()
if (kaptTask.isIncremental) {
kaptTask.incAptCache = getKaptIncrementalAnnotationProcessingCache()
kaptTask.localState.register(kaptTask.incAptCache)
kaptTask.classpathStructure = classStructureIfIncremental!!.incoming.artifactView { viewConfig ->
viewConfig.attributes.attribute(artifactType, CLASS_STRUCTURE_ARTIFACT_TYPE)
}.files
if (kaptTask is KaptWithKotlincTask) {
kaptTask.pluginOptions.addPluginArgument(
getCompilerPluginId(),
SubpluginOption("incrementalCache", kaptTask.incAptCache!!.absolutePath)
)
}
}
kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
KaptWithAndroid.androidVariantData(this)?.annotationProcessorOptionProviders?.let {
kaptTask.annotationProcessorOptionProviders.add(it)
}
}
kotlinCompile.source(sourcesOutputDir, kotlinSourcesOutputDir)
kotlinCompilation.output.apply {
addClassesDir { project.files(classesOutputDir).builtBy(kaptTaskProvider) }
}
kotlinCompilation.compileKotlinTaskProvider.configure {
it as SourceTask
it.source(sourcesOutputDir, kotlinSourcesOutputDir)
}
if (javaCompile != null) {
if (kaptVariantData != null) {
kaptVariantData.registerGeneratedJavaSource(project, kaptTask, javaCompile)
val androidVariantData = KaptWithAndroid.androidVariantData(this)
if (androidVariantData != null) {
KaptWithAndroid.registerGeneratedJavaSourceForAndroid(this, project, androidVariantData, kaptTaskProvider)
} else {
registerGeneratedJavaSource(kaptTask, javaCompile)
registerGeneratedJavaSource(kaptTaskProvider, javaCompile)
}
}
kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
kaptVariantData?.annotationProcessorOptionProviders?.let {
kaptTask.annotationProcessorOptionProviders.add(it)
val dslJavacOptions: Provider<Map<String, String>> = project.provider {
kaptExtension.getJavacOptions().toMutableMap().also { result ->
if (javaCompile != null && "-source" !in result && "--source" !in result && "--release" !in result) {
val sourceOptionKey = if (SystemInfo.isJavaVersionAtLeast(12, 0, 0)) {
"--source"
} else {
"-source"
}
result[sourceOptionKey] = javaCompile.get().sourceCompatibility
}
}
}
val dslJavacOptions = kaptExtension.getJavacOptions().toMutableMap()
if (javaCompile != null && "-source" !in dslJavacOptions && "--source" !in dslJavacOptions && "--release" !in dslJavacOptions) {
val sourceOptionKey = if (SystemInfo.isJavaVersionAtLeast(12, 0, 0)) {
"--source"
} else {
"-source"
}
dslJavacOptions[sourceOptionKey] = javaCompile.sourceCompatibility
}
if (kaptTask is KaptWithKotlincTask) {
if (kaptTask.isIncremental) {
kaptTask.pluginOptions.addPluginArgument(
getCompilerPluginId(),
SubpluginOption("incrementalCache", kaptTask.incAptCache!!.absolutePath))
}
if (taskClass == KaptWithKotlincTask::class.java) {
val subpluginOptions = buildOptions("apt", dslJavacOptions)
registerSubpluginOptions(kaptTask, kaptTask.pluginOptions, subpluginOptions)
registerSubpluginOptions(kaptTaskProvider, subpluginOptions)
}
if (kaptTask is KaptWithoutKotlincTask) {
with(kaptTask) {
isVerbose = project.isKaptVerbose()
mapDiagnosticLocations = kaptExtension.mapDiagnosticLocations
annotationProcessorFqNames = kaptExtension.processors.split(',').filter { it.isNotEmpty() }
javacOptions = dslJavacOptions
if (taskClass == KaptWithoutKotlincTask::class.java) {
kaptTaskProvider.configure {
it as KaptWithoutKotlincTask
it.isVerbose = project.isKaptVerbose()
it.mapDiagnosticLocations = kaptExtension.mapDiagnosticLocations
it.annotationProcessorFqNames = kaptExtension.processors.split(',').filter { it.isNotEmpty() }
it.javacOptions = dslJavacOptions.get()
}
val subpluginOptions = getAPOptions()
registerSubpluginOptions(kaptTask, kaptTask.processorOptions, subpluginOptions)
registerSubpluginOptions(kaptTaskProvider, subpluginOptions)
}
return kaptTask
return kaptTaskProvider
}
private fun maybeRegisterTransform(project: Project) {
@@ -487,33 +520,35 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
}
}
private fun Kapt3SubpluginContext.createKaptGenerateStubsTask(): KaptGenerateStubsTask {
private fun Kapt3SubpluginContext.createKaptGenerateStubsTask(): TaskProvider<KaptGenerateStubsTask> {
val kaptTaskName = getKaptTaskName("kaptGenerateStubs")
KotlinCompileTaskData.register(kaptTaskName, KotlinCompileTaskData.get(project, kotlinCompile.name).compilation).apply {
KotlinCompileTaskData.register(kaptTaskName, kotlinCompilation).apply {
useModuleDetection.set(KotlinCompileTaskData.get(project, kotlinCompile.name).useModuleDetection)
destinationDir.set(project.provider { getKaptIncrementalDataDir() })
}
val kaptTask = project.tasks.create(
kaptTaskName,
KaptGenerateStubsTask::class.java
)
val kaptTaskProvider = project.registerTask<KaptGenerateStubsTask>(kaptTaskName) { kaptTask ->
kaptTask.kotlinCompileTask = kotlinCompile.get()
kaptTask.kotlinCompileTask = kotlinCompile
kotlinToKaptGenerateStubsTasksMap[kotlinCompile] = kaptTask
kaptTask.stubsDir = getKaptStubsDir()
kaptTask.setDestinationDir { getKaptIncrementalDataDir() }
kaptTask.mapClasspath { kaptTask.kotlinCompileTask.classpath }
kaptTask.generatedSourcesDir = sourcesOutputDir
kaptTask.stubsDir = getKaptStubsDir()
kaptTask.setDestinationDir { getKaptIncrementalDataDir() }
kaptTask.mapClasspath { kotlinCompile.classpath }
kaptTask.generatedSourcesDir = sourcesOutputDir
PropertiesProvider(project).mapKotlinTaskProperties(kaptTask)
kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
kaptTask.kaptClasspathConfigurations = kaptClasspathConfigurations
PropertiesProvider(project).mapKotlinTaskProperties(kaptTask)
}
val subpluginOptions = buildOptions("stubs", kaptExtension.getJavacOptions())
registerSubpluginOptions(kaptTask, kaptTask.pluginOptions, subpluginOptions)
project.whenEvaluated {
addCompilationSourcesToExternalCompileTask(kotlinCompilation, kaptTaskProvider)
}
return kaptTask
val subpluginOptions = buildOptions("stubs", project.provider { kaptExtension.getJavacOptions() })
registerSubpluginOptions(kaptTaskProvider, subpluginOptions)
return kaptTaskProvider
}
private fun Kapt3SubpluginContext.getKaptTaskName(prefix: String): String {
@@ -524,8 +559,11 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
}
private fun Kapt3SubpluginContext.disableAnnotationProcessingInJavaTask() {
(javaCompile as? JavaCompile)?.let { javaCompile ->
val options = javaCompile.options
javaCompile?.configure { javaCompileInstance ->
if (javaCompileInstance !is JavaCompile)
return@configure
val options = javaCompileInstance.options
// 'android-apt' (com.neenbedankt) adds a File instance to compilerArgs (List<String>).
// Although it's not our problem, we need to handle this case properly.
val oldCompilerArgs: List<Any> = options.compilerArgs
@@ -539,8 +577,8 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
// Filter out the argument providers that are related to annotation processing and therefore already used by Kapt.
// This is done to avoid outputs intersections between Kapt and and javaCompile and make the up-to-date check for
// javaCompile more granular as it does not perform annotation processing:
if (kaptVariantData != null) {
options.compilerArgumentProviders.removeAll(kaptVariantData.annotationProcessorOptionProviders)
KaptWithAndroid.androidVariantData(this)?.let { androidVariantData ->
options.compilerArgumentProviders.removeAll(androidVariantData.annotationProcessorOptionProviders)
}
}
}
@@ -552,11 +590,38 @@ class Kapt3KotlinGradleSubplugin : KotlinGradleSubplugin<KotlinCompile> {
}
private val artifactType = Attribute.of("artifactType", String::class.java)
// Don't reference the BaseVariant type in the Kapt plugin signatures, as those type references will fail to link when there's no Android
// Gradle plugin on the project's plugin classpath
private object KaptWithAndroid {
// Avoid loading the BaseVariant type at call sites and instead lazily load it when evaluation reaches it in the body using inline:
@Suppress("NOTHING_TO_INLINE")
inline fun androidVariantData(context: Kapt3GradleSubplugin.Kapt3SubpluginContext): BaseVariant? = context.variantData as? BaseVariant
internal fun registerGeneratedJavaSource(kaptTask: KaptTask, javaTask: AbstractCompile) {
val generatedJavaSources = javaTask.project.fileTree(kaptTask.destinationDir)
generatedJavaSources.include("**/*.java")
javaTask.source(generatedJavaSources)
@Suppress("NOTHING_TO_INLINE")
// Avoid loading the BaseVariant type at call sites and instead lazily load it when evaluation reaches it in the body using inline:
inline fun registerGeneratedJavaSourceForAndroid(
kapt3SubpluginContext: Kapt3GradleSubplugin.Kapt3SubpluginContext,
project: Project,
variantData: BaseVariant,
kaptTask: TaskProvider<out KaptTask>
) {
val kaptSourceOutput = project.fileTree(kapt3SubpluginContext.sourcesOutputDir).builtBy(kaptTask)
kaptSourceOutput.include("**/*.java")
variantData.registerExternalAptJavaOutput(kaptSourceOutput)
kaptTask.configure { kaptTaskInstance ->
variantData.dataBindingDependencyArtifactsIfSupported?.let { dataBindingArtifacts ->
kaptTaskInstance.dependsOn(dataBindingArtifacts)
}
}
}
}
internal fun registerGeneratedJavaSource(kaptTask: TaskProvider<out KaptTask>, javaTaskProvider: TaskProvider<out AbstractCompile>) {
javaTaskProvider.configure { javaTask ->
val generatedJavaSources = javaTask.project.fileTree(kaptTask.map { it.destinationDir })
generatedJavaSources.include("**/*.java")
javaTask.source(generatedJavaSources)
}
}
internal fun Configuration.getNamedDependencies(): List<Dependency> = allDependencies.filter { it.group != null && it.name != null }
@@ -583,7 +648,7 @@ internal fun checkAndroidAnnotationProcessorDependencyUsage(project: Project) {
ANNOTATION_PROCESSOR -> "kapt"
else -> {
val configurationName = apConfigurationName.dropLast(ANNOTATION_PROCESSOR_CAP.length)
Kapt3KotlinGradleSubplugin.getKaptConfigurationName(configurationName)
Kapt3GradleSubplugin.getKaptConfigurationName(configurationName)
}
}
@@ -9,7 +9,7 @@ import org.gradle.api.tasks.*
import org.gradle.api.tasks.incremental.IncrementalTaskInputs
import org.gradle.workers.IsolationMode
import org.gradle.workers.WorkerExecutor
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin.Companion.KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.internal.kapt.incremental.KaptIncrementalChanges
import org.jetbrains.kotlin.gradle.plugin.CompositeSubpluginOption
import org.jetbrains.kotlin.gradle.plugin.KotlinAndroidPluginWrapper
@@ -49,7 +49,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor
lateinit var javacOptions: Map<String, String>
private fun getAnnotationProcessorOptions(): Map<String, String> {
val options = processorOptions.subpluginOptionsByPluginId[Kapt3KotlinGradleSubplugin.KAPT_SUBPLUGIN_ID] ?: return emptyMap()
val options = processorOptions.subpluginOptionsByPluginId[Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID] ?: return emptyMap()
val result = mutableMapOf<String, String>()
for (option in options) {
@@ -53,7 +53,7 @@ internal fun CompilerPluginOptions.withWrappedKaptOptions(
val resultOptionsByPluginId: MutableMap<String, List<SubpluginOption>> =
subpluginOptionsByPluginId.toMutableMap()
resultOptionsByPluginId.compute(Kapt3KotlinGradleSubplugin.KAPT_SUBPLUGIN_ID) { _, kaptOptions ->
resultOptionsByPluginId.compute(Kapt3GradleSubplugin.KAPT_SUBPLUGIN_ID) { _, kaptOptions ->
val changedFilesOption = changedFiles.map { SubpluginOption("changedFile", it.canonicalPath) }
val classpathChangesOption = classpathChanges.map { SubpluginOption("classpathChange", it) }
val processIncrementallyOption = SubpluginOption("processIncrementally", processIncrementally.toString())
@@ -33,8 +33,7 @@ import org.gradle.api.tasks.compile.AbstractCompile
import org.gradle.jvm.tasks.Jar
import org.gradle.tooling.provider.model.ToolingModelBuilderRegistry
import org.jetbrains.kotlin.gradle.dsl.*
import org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin
import org.jetbrains.kotlin.gradle.internal.KaptVariantData
import org.jetbrains.kotlin.gradle.internal.Kapt3GradleSubplugin
import org.jetbrains.kotlin.gradle.internal.checkAndroidAnnotationProcessorDependencyUsage
import org.jetbrains.kotlin.gradle.logging.kotlinDebug
import org.jetbrains.kotlin.gradle.model.builder.KotlinModelBuilder
@@ -202,7 +201,7 @@ internal class Kotlin2JvmSourceSetProcessor(
override fun doTargetSpecificProcessing() {
ifKaptEnabled(project) {
Kapt3KotlinGradleSubplugin.createAptConfigurationIfNeeded(project, kotlinCompilation.compilationName)
Kapt3GradleSubplugin.createAptConfigurationIfNeeded(project, kotlinCompilation.compilationName)
}
ScriptingGradleSubplugin.configureForSourceSet(project, kotlinCompilation.compilationName)
@@ -785,7 +784,7 @@ abstract class AbstractAndroidProjectHandler(private val kotlinConfigurationTool
sourceSet.addConvention(KOTLIN_DSL_NAME, kotlinSourceSet)
ifKaptEnabled(project) {
Kapt3KotlinGradleSubplugin.createAptConfigurationIfNeeded(project, sourceSet.name)
Kapt3GradleSubplugin.createAptConfigurationIfNeeded(project, sourceSet.name)
}
}
@@ -31,6 +31,7 @@ import org.jetbrains.kotlin.gradle.plugin.COMPILER_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.KotlinMultiplatformPluginWrapper
import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformPluginBase
import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithTransitiveClosure
import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName
import org.jetbrains.kotlin.gradle.report.BuildReportMode
@@ -251,6 +252,7 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments>() : AbstractKo
@get:Internal // takes part in the compiler arguments
val friendPaths: Array<String> by project.provider {
taskData.compilation.run {
if (this !is AbstractKotlinCompilation<*>) return@run emptyArray<String>()
associateWithTransitiveClosure
.flatMap { it.output.classesDirs }
.plus(friendArtifacts)
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.tasks
import org.gradle.api.Project
import org.gradle.api.plugins.ExtraPropertiesExtension
import org.gradle.api.provider.Property
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation
import org.jetbrains.kotlin.gradle.plugin.mpp.AbstractKotlinCompilation
import org.jetbrains.kotlin.gradle.utils.getValue
import java.io.File
@@ -15,7 +16,7 @@ import java.io.File
internal open class KotlinCompileTaskData(
val taskName: String,
@field:Transient // cannot be serialized for Gradle Instant Execution, but actually is not needed when a task is deserialized
val compilation: AbstractKotlinCompilation<*>,
val compilation: KotlinCompilation<*>,
val destinationDir: Property<File>,
val useModuleDetection: Property<Boolean>
) {
@@ -40,7 +41,7 @@ internal open class KotlinCompileTaskData(
fun register(
taskName: String,
compilation: AbstractKotlinCompilation<*>
compilation: KotlinCompilation<*>
): KotlinCompileTaskData {
val project = compilation.target.project
val container = project.getTaskDataMap()
@@ -1,3 +1,2 @@
org.jetbrains.kotlin.gradle.internal.AndroidSubplugin
org.jetbrains.kotlin.gradle.internal.Kapt3KotlinGradleSubplugin
org.jetbrains.kotlin.gradle.scripting.internal.ScriptingKotlinGradleSubplugin