diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt index 45f5ed97917..414f1414d03 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/InstantExecutionIT.kt @@ -15,7 +15,7 @@ import kotlin.test.fail class InstantExecutionIT : BaseGradleIT() { private val androidGradlePluginVersion: AGPVersion - get() = AGPVersion.v4_0_ALPHA_1 + get() = AGPVersion.v4_0_ALPHA_8 override fun defaultBuildOptions() = super.defaultBuildOptions().copy( @@ -23,7 +23,7 @@ class InstantExecutionIT : BaseGradleIT() { androidGradlePluginVersion = androidGradlePluginVersion ) - private val minimumGradleVersion = GradleVersionRequired.AtLeast("6.1-milestone-1") + private val minimumGradleVersion = GradleVersionRequired.AtLeast("6.1-rc-3") @Test fun testSimpleKotlinJvmProject() = with(Project("kotlinProject", minimumGradleVersion)) { @@ -31,14 +31,37 @@ class InstantExecutionIT : BaseGradleIT() { } @Test - fun testSimpleKotlinAndroidProject() = with(Project("AndroidProject", minimumGradleVersion)) { - applyAndroidAndroid40Alpha4KotlinVersionWorkaround() - testInstantExecutionOf(":Lib:compileFlavor1DebugKotlin", ":Android:compileFlavor1DebugKotlin") + fun testSimpleKotlinAndroidProject() = with(Project("android-dagger", minimumGradleVersion, "kapt2")) { + applyAndroid40Alpha4KotlinVersionWorkaround() + projectDir.resolve("gradle.properties").appendText("\nkapt.incremental.apt=false") + testInstantExecutionOf(":app:compileDebugKotlin", ":app:kaptDebugKotlin", ":app:kaptGenerateStubsDebugKotlin") } - private fun Project.testInstantExecutionOf(vararg taskNames: String) { + @Test + fun testIncrementalKaptProject() = with(getIncrementalKaptProject()) { + testInstantExecutionOf( + ":compileKotlin", + ":kaptKotlin", + buildOptions = defaultBuildOptions().copy( + incremental = true, + kaptOptions = KaptOptions( + verbose = true, + useWorkers = true, + incrementalKapt = true, + includeCompileClasspath = false + ) + ) + ) + } + + private fun getIncrementalKaptProject() = + Project("kaptIncrementalCompilationProject", minimumGradleVersion).apply { + setupIncrementalAptProject("AGGREGATING") + } + + private fun Project.testInstantExecutionOf(vararg taskNames: String, buildOptions: BuildOptions = defaultBuildOptions()) { // First, run a build that serializes the tasks state for instant execution in further builds - instantExecutionOf(*taskNames) { + instantExecutionOf(*taskNames, buildOptions = buildOptions) { assertSuccessful() assertTasksExecuted(*taskNames) checkInstantExecutionSucceeded() @@ -49,12 +72,12 @@ class InstantExecutionIT : BaseGradleIT() { } // Then run a build where tasks states are deserialized to check that they work correctly in this mode - instantExecutionOf(*taskNames) { + instantExecutionOf(*taskNames, buildOptions = buildOptions) { assertSuccessful() assertTasksExecuted(*taskNames) } - instantExecutionOf(*taskNames) { + instantExecutionOf(*taskNames, buildOptions = buildOptions) { assertSuccessful() assertTasksUpToDate(*taskNames) } @@ -66,8 +89,12 @@ class InstantExecutionIT : BaseGradleIT() { } } - private fun Project.instantExecutionOf(vararg tasks: String, check: CompiledProject.() -> Unit) = - build("-Dorg.gradle.unsafe.instant-execution=true", *tasks, check = check) + private fun Project.instantExecutionOf( + vararg tasks: String, + buildOptions: BuildOptions = defaultBuildOptions(), + check: CompiledProject.() -> Unit + ) = + build("-Dorg.gradle.unsafe.instant-execution=true", *tasks, options = buildOptions, check = check) /** * Copies all files from the directory containing the given [htmlReportFile] to a @@ -98,7 +125,7 @@ class InstantExecutionIT : BaseGradleIT() { * test project's repositories, where there's no 'kotlin-eap' repo. * TODO remove this workaround once an Android Gradle plugin version is used that depends on the stable Kotlin version */ - private fun Project.applyAndroidAndroid40Alpha4KotlinVersionWorkaround() { + private fun Project.applyAndroid40Alpha4KotlinVersionWorkaround() { setupWorkingDir() val resolutionStrategyHack = """ diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt index 8d0a8bc5b16..34595cbbd82 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/util/AGPVersion.kt @@ -22,6 +22,6 @@ class AGPVersion private constructor(private val versionNumber: VersionNumber) { val v3_1_0 = fromString("3.1.0") val v3_2_0 = fromString("3.2.0") val v3_3_2 = fromString("3.3.2") - val v4_0_ALPHA_1 = fromString("4.0.0-alpha01") + val v4_0_ALPHA_8 = fromString("4.0.0-alpha08") } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt new file mode 100644 index 00000000000..fcb398a1b70 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/CompilerArgumentsContributor.kt @@ -0,0 +1,126 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.gradle.internal + +import org.gradle.api.tasks.TaskProvider +import org.jetbrains.kotlin.cli.common.arguments.* +import org.jetbrains.kotlin.gradle.dsl.* +import org.jetbrains.kotlin.gradle.logging.kotlinDebug +import org.jetbrains.kotlin.gradle.tasks.* +import org.jetbrains.kotlin.gradle.tasks.KotlinCompile +import org.jetbrains.kotlin.gradle.utils.getValue +import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray +import org.jetbrains.kotlin.incremental.classpathAsList +import org.jetbrains.kotlin.incremental.destinationAsFile + +internal interface CompilerArgumentsContributor { + fun contributeArguments( + args: T, + flags: Collection + ) +} + +internal interface CompilerArgumentsConfigurationFlag + +internal object DefaultsOnly : CompilerArgumentsConfigurationFlag +internal object IgnoreClasspathResolutionErrors : CompilerArgumentsConfigurationFlag + +internal fun compilerArgumentsConfigurationFlags(defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) = + mutableSetOf().apply { + if (defaultsOnly) add(DefaultsOnly) + if (ignoreClasspathResolutionErrors) add(IgnoreClasspathResolutionErrors) + } + +/** The primary purpose of this class is to encapsulate compiler arguments setup done by the AbstractKotlinCompiler tasks, + * but outside the tasks, so that this state & logic can be reused without referencing the task directly. */ +internal open class AbstractKotlinCompileArgumentsContributor( + // Don't save this reference into a property! That would be hostile to Gradle instant execution + taskProvider: TaskProvider> +) : CompilerArgumentsContributor { + private val coroutines by taskProvider.map { it.coroutines } + + protected val logger by taskProvider.map { it.logger } + + private val isMultiplatform by taskProvider.map { it.isMultiplatform } + + private val pluginClasspath by taskProvider.map { it.pluginClasspath } + private val pluginOptions by taskProvider.map { it.pluginOptions } + + override fun contributeArguments( + args: T, + flags: Collection + ) { + args.coroutinesState = when (coroutines) { + Coroutines.ENABLE -> CommonCompilerArguments.ENABLE + Coroutines.WARN -> CommonCompilerArguments.WARN + Coroutines.ERROR -> CommonCompilerArguments.ERROR + Coroutines.DEFAULT -> CommonCompilerArguments.DEFAULT + } + + logger.kotlinDebug { "args.coroutinesState=${args.coroutinesState}" } + + if (logger.isDebugEnabled) { + args.verbose = true + } + + args.multiPlatform = isMultiplatform + + setupPlugins(args) + } + + internal fun setupPlugins(compilerArgs: T) { + compilerArgs.pluginClasspaths = pluginClasspath.toSortedPathsArray() + compilerArgs.pluginOptions = pluginOptions.arguments.toTypedArray() + } +} + +internal open class KotlinJvmCompilerArgumentsContributor( + // Don't save this reference into a property! That would be hostile to Gradle instant execution. Only map it to the task properties. + taskProvider: TaskProvider +) : AbstractKotlinCompileArgumentsContributor(taskProvider) { + + private val moduleName by taskProvider.map { it.moduleName } + + private val friendPaths by taskProvider.map { it.friendPaths } + + private val compileClasspath by taskProvider.map { it.compileClasspath } + + private val destinationDir by taskProvider.map { it.destinationDir } + + private val kotlinOptions by taskProvider.map { + listOfNotNull( + it.parentKotlinOptionsImpl as KotlinJvmOptionsImpl?, + it.kotlinOptions as KotlinJvmOptionsImpl + ) + } + + override fun contributeArguments( + args: K2JVMCompilerArguments, + flags: Collection + ) { + args.fillDefaultValues() + + super.contributeArguments(args, flags) + + args.moduleName = moduleName + logger.kotlinDebug { "args.moduleName = ${args.moduleName}" } + + args.friendPaths = friendPaths + logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" } + + if (DefaultsOnly in flags) return + + args.allowNoSourceFiles = true + args.classpathAsList = try { + compileClasspath.toList().filter { it.exists() } + } catch (e: Exception) { + if (IgnoreClasspathResolutionErrors in flags) emptyList() else throw(e) + } + args.destinationAsFile = destinationDir + + kotlinOptions.forEach { it.updateArguments(args) } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt index f9998cc368e..6c5aae04cac 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptGenerateStubsTask.kt @@ -19,15 +19,12 @@ package org.jetbrains.kotlin.gradle.internal import org.gradle.api.artifacts.Configuration import org.gradle.api.file.FileCollection import org.gradle.api.tasks.* -import org.gradle.api.tasks.incremental.IncrementalTaskInputs import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.gradle.incremental.ChangedFiles -import org.jetbrains.kotlin.gradle.logging.kotlinDebug import org.jetbrains.kotlin.gradle.tasks.FilteringSourceRootsContainer import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.SourceRoots +import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.isParentOf -import org.jetbrains.kotlin.gradle.utils.pathsAsStringRelativeTo import org.jetbrains.kotlin.incremental.classpathAsList import org.jetbrains.kotlin.incremental.destinationAsFile import java.io.File @@ -37,6 +34,7 @@ open class KaptGenerateStubsTask : KotlinCompile() { override val sourceRootsContainer = FilteringSourceRootsContainer(emptyList(), { isSourceRootAllowed(it) }) @get:Internal + @field:Transient // can't serialize task references in Gradle instant execution state internal lateinit var kotlinCompileTask: KotlinCompile @get:OutputDirectory @@ -48,7 +46,7 @@ open class KaptGenerateStubsTask : KotlinCompile() { @get:Classpath @get:InputFiles val kaptClasspath: FileCollection - get() = project.files(*kaptClasspathConfigurations.toTypedArray()) + get() = project.files(kaptClasspathConfigurations) @get:Internal internal lateinit var kaptClasspathConfigurations: List @@ -56,8 +54,9 @@ open class KaptGenerateStubsTask : KotlinCompile() { @get:Classpath @get:InputFiles @Suppress("unused") - internal val kotlinTaskPluginClasspath - get() = kotlinCompileTask.pluginClasspath + internal val kotlinTaskPluginClasspath by project.provider { + kotlinCompileTask.pluginClasspath + } @get:Input override var useModuleDetection: Boolean @@ -66,11 +65,11 @@ open class KaptGenerateStubsTask : KotlinCompile() { error("KaptGenerateStubsTask.useModuleDetection setter should not be called!") } - override fun source(vararg sources: Any?): SourceTask? { + override fun source(vararg sources: Any): SourceTask { return super.source(sourceRootsContainer.add(sources)) } - override fun setSource(sources: Any?) { + override fun setSource(sources: Any) { super.setSource(sourceRootsContainer.set(sources)) } @@ -79,8 +78,15 @@ open class KaptGenerateStubsTask : KotlinCompile() { !stubsDir.isParentOf(source) && !generatedSourcesDir.isParentOf(source) + private val compileKotlinArgumentsContributor by project.provider { + kotlinCompileTask.compilerArgumentsContributor + } + override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { - kotlinCompileTask.setupCompilerArgs(args, ignoreClasspathResolutionErrors = ignoreClasspathResolutionErrors) + compileKotlinArgumentsContributor.contributeArguments(args, compilerArgumentsConfigurationFlags( + defaultsOnly, + ignoreClasspathResolutionErrors + )) val pluginOptionsWithKapt = pluginOptions.withWrappedKaptOptions(withApClasspath = kaptClasspath) args.pluginOptions = (pluginOptionsWithKapt.arguments + args.pluginOptions!!).toTypedArray() @@ -90,10 +96,13 @@ open class KaptGenerateStubsTask : KotlinCompile() { args.destinationAsFile = this.destinationDir } - override fun getSourceRoots(): SourceRoots.ForJvm = + private val sourceRoots by project.provider { kotlinCompileTask.getSourceRoots().let { val javaSourceRoots = it.javaSourceRoots.filterTo(HashSet()) { isSourceRootAllowed(it) } val kotlinSourceFiles = it.kotlinSourceFiles SourceRoots.ForJvm(kotlinSourceFiles, javaSourceRoots) } + } + + override fun getSourceRoots(): SourceRoots.ForJvm = sourceRoots } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt index baa641e14a5..21948a834fd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptTask.kt @@ -14,6 +14,7 @@ import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.tasks.cacheOnlyIfEnabledForKotlin import org.jetbrains.kotlin.gradle.tasks.clearLocalState +import org.jetbrains.kotlin.gradle.utils.getValue import org.jetbrains.kotlin.gradle.utils.isJavaFile import java.io.File import java.util.jar.JarFile @@ -30,6 +31,7 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { override fun localStateDirectories(): FileCollection = project.files() @get:Internal + @field:Transient internal lateinit var kotlinCompileTask: KotlinCompile @get:Internal @@ -38,12 +40,13 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { @get:Classpath @get:InputFiles val kaptClasspath: FileCollection - get() = project.files(*kaptClasspathConfigurations.toTypedArray()) + get() = project.files(kaptClasspathConfigurations) @get:Classpath @get:InputFiles - val compilerClasspath: List - get() = kotlinCompileTask.computedCompilerClasspath + val compilerClasspath: List by project.provider { + kotlinCompileTask.computedCompilerClasspath + } @get:Internal internal lateinit var kaptClasspathConfigurations: List @@ -82,8 +85,9 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { // @Internal because _abiClasspath and _nonAbiClasspath are used for actual checks @get:Internal - val classpath: FileCollection - get() = kotlinCompileTask.classpath + val classpath: FileCollection by project.provider { + kotlinCompileTask.classpath + } @Suppress("unused", "DeprecatedCallableAddReplaceWith") @Deprecated( @@ -92,8 +96,9 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { ) @get:CompileClasspath @get:InputFiles - internal val internalAbiClasspath: FileCollection - get() = if (includeCompileClasspath) project.files() else kotlinCompileTask.classpath + internal val internalAbiClasspath: FileCollection by project.provider { + if (includeCompileClasspath) project.files() else kotlinCompileTask.classpath + } @Suppress("unused", "DeprecatedCallableAddReplaceWith") @@ -103,8 +108,9 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { ) @get:Classpath @get:InputFiles - internal val internalNonAbiClasspath: FileCollection - get() = if (includeCompileClasspath) kotlinCompileTask.classpath else project.files() + internal val internalNonAbiClasspath: FileCollection by project.provider { + if (includeCompileClasspath) kotlinCompileTask.classpath else project.files() + } @get:Internal var useBuildCache: Boolean = false @@ -120,10 +126,14 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { return result } + // store the files before filtering, so that Gradle doesn't serialize the filtered collection for instant execution state and reuse it + private val unfilteredJavaSourceRoots by project.provider { + (kotlinCompileTask.sourceRootsContainer.sourceRoots + stubsDir) + } + @get:Internal protected val javaSourceRoots: Set - get() = (kotlinCompileTask.sourceRootsContainer.sourceRoots + stubsDir) - .filterTo(HashSet(), ::isRootAllowed) + get() = unfilteredJavaSourceRoots.filterTo(HashSet(), ::isRootAllowed) private fun isRootAllowed(file: File): Boolean = file.exists() && @@ -163,8 +173,10 @@ abstract class KaptTask : ConventionTask(), TaskWithLocalState { } // TODO(gavra): Here we assume that kotlinc and javac output is available for incremental runs. We should insert some checks. - @Internal - protected fun getCompiledSources() = listOfNotNull(kotlinCompileTask.destinationDir, kotlinCompileTask.javaOutputDir) + @get:Internal + internal val compiledSources by project.provider { + listOfNotNull(kotlinCompileTask.destinationDir, kotlinCompileTask.javaOutputDir) + } protected fun getIncrementalChanges(inputs: IncrementalTaskInputs): KaptIncrementalChanges { return if (isIncremental) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt index 625076ea5c9..aa218fd15ed 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/internal/kapt/KaptWithKotlincTask.kt @@ -23,6 +23,8 @@ import org.jetbrains.kotlin.gradle.logging.GradleKotlinLogger import org.jetbrains.kotlin.gradle.logging.GradlePrintingMessageCollector import org.jetbrains.kotlin.gradle.plugin.PLUGIN_CLASSPATH_CONFIGURATION_NAME import org.jetbrains.kotlin.gradle.tasks.CompilerPluginOptions +import org.jetbrains.kotlin.gradle.utils.getValue +import org.jetbrains.kotlin.gradle.utils.optionalProvider import org.jetbrains.kotlin.gradle.utils.toSortedPathsArray import java.io.File @@ -43,8 +45,15 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput = emptyList() private var processIncrementally = false + private val javaPackagePrefix by project.optionalProvider { kotlinCompileTask.javaPackagePrefix } + private val buildReportMode by project.optionalProvider { kotlinCompileTask.buildReportMode } + @TaskAction fun compile(inputs: IncrementalTaskInputs) { logger.debug("Running kapt annotation processing using the Kotlin compiler") @@ -87,7 +99,7 @@ open class KaptWithKotlincTask : KaptTask(), CompilerArgumentAwareWithInput - get() = project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).resolve() + val kaptJars: Collection by project.provider { + project.configurations.getByName(KAPT_WORKER_DEPENDENCIES_CONFIGURATION_NAME).resolve() + } @get:Input var isVerbose: Boolean = false @@ -85,7 +87,7 @@ open class KaptWithoutKotlincTask @Inject constructor(private val workerExecutor javaSourceRoots.toList(), changedFiles, - getCompiledSources(), + compiledSources, incAptCache, classpathChanges.toList(), diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt index 0931274bdba..eb9b789a7f7 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/tasks/Tasks.kt @@ -10,7 +10,6 @@ import org.gradle.api.Task import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider import org.gradle.api.tasks.* -import org.gradle.api.tasks.Optional import org.gradle.api.tasks.compile.AbstractCompile import org.gradle.api.tasks.compile.JavaCompile import org.gradle.api.tasks.incremental.IncrementalTaskInputs @@ -24,7 +23,7 @@ import org.jetbrains.kotlin.compilerRunner.* import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings import org.jetbrains.kotlin.gradle.dsl.* import org.jetbrains.kotlin.gradle.incremental.ChangedFiles -import org.jetbrains.kotlin.gradle.internal.CompilerArgumentAwareWithInput +import org.jetbrains.kotlin.gradle.internal.* import org.jetbrains.kotlin.gradle.internal.prepareCompilerArguments import org.jetbrains.kotlin.gradle.internal.tasks.TaskWithLocalState import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles @@ -38,8 +37,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.ownModuleName import org.jetbrains.kotlin.gradle.report.BuildReportMode import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.incremental.ChangedFiles -import org.jetbrains.kotlin.incremental.classpathAsList -import org.jetbrains.kotlin.incremental.destinationAsFile import org.jetbrains.kotlin.utils.LibraryUtils import java.io.File import javax.inject.Inject @@ -174,12 +171,12 @@ abstract class AbstractKotlinCompile() : AbstractKo // Store this file collection before it is filtered by File::exists to ensure that Gradle Instant execution doesn't serialize the // filtered files, losing those that don't exist yet and will only be created during build private val compileClasspathImpl by project.provider { - classpath + additionalClasspath + classpath + project.files(additionalClasspath) } @get:Internal // classpath already participates in the checks internal val compileClasspath: Iterable - get() = compileClasspathImpl.filter { it.exists() } + get() = compileClasspathImpl @field:Transient private val sourceFilesExtensionsSources: MutableList> = mutableListOf() @@ -218,7 +215,8 @@ abstract class AbstractKotlinCompile() : AbstractKo internal val coroutinesStr: String get() = coroutines.name - private val coroutines: Coroutines by project.provider { + @get:Internal + internal val coroutines: Coroutines by project.provider { kotlinExt.experimental.coroutines ?: coroutinesFromGradleProperties ?: Coroutines.DEFAULT @@ -317,27 +315,16 @@ abstract class AbstractKotlinCompile() : AbstractKo */ internal abstract fun callCompilerAsync(args: T, sourceRoots: SourceRoots, changedFiles: ChangedFiles) - private val isMultiplatform: Boolean by project.provider { + @get:Internal + internal val isMultiplatform: Boolean by project.provider { project.plugins.any { it is KotlinPlatformPluginBase || it is KotlinMultiplatformPluginWrapper } } override fun setupCompilerArgs(args: T, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { - args.coroutinesState = when (coroutines) { - Coroutines.ENABLE -> CommonCompilerArguments.ENABLE - Coroutines.WARN -> CommonCompilerArguments.WARN - Coroutines.ERROR -> CommonCompilerArguments.ERROR - Coroutines.DEFAULT -> CommonCompilerArguments.DEFAULT - } - - logger.kotlinDebug { "args.coroutinesState=${args.coroutinesState}" } - - if (logger.isDebugEnabled) { - args.verbose = true - } - - args.multiPlatform = isMultiplatform - - setupPlugins(args) + AbstractKotlinCompileArgumentsContributor(thisTaskProvider).contributeArguments( + args, + compilerArgumentsConfigurationFlags(defaultsOnly, ignoreClasspathResolutionErrors) + ) } internal fun setupPlugins(compilerArgs: T) { @@ -351,6 +338,9 @@ abstract class AbstractKotlinCompile() : AbstractKo } } +internal inline val T.thisTaskProvider: TaskProvider + get() = checkNotNull(project.locateTask(name)) + @CacheableTask open class KotlinCompile : AbstractKotlinCompile(), KotlinJvmCompile { @get:Internal @@ -390,28 +380,15 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl K2JVMCompilerArguments() override fun setupCompilerArgs(args: K2JVMCompilerArguments, defaultsOnly: Boolean, ignoreClasspathResolutionErrors: Boolean) { - args.apply { fillDefaultValues() } - super.setupCompilerArgs(args, defaultsOnly = defaultsOnly, ignoreClasspathResolutionErrors = ignoreClasspathResolutionErrors) + compilerArgumentsContributor.contributeArguments(args, compilerArgumentsConfigurationFlags( + defaultsOnly, + ignoreClasspathResolutionErrors + )) + } - args.moduleName = moduleName - logger.kotlinDebug { "args.moduleName = ${args.moduleName}" } - - args.friendPaths = friendPaths - logger.kotlinDebug { "args.friendPaths = ${args.friendPaths?.joinToString() ?: "[]"}" } - - if (defaultsOnly) return - - args.allowNoSourceFiles = true - args.classpathAsList = try { - compileClasspath.toList() - } catch (e: Exception) { - if (ignoreClasspathResolutionErrors) emptyList() else throw(e) - } - args.destinationAsFile = destinationDir - parentKotlinOptionsImpl?.updateArguments(args) - kotlinOptionsImpl.updateArguments(args) - - logger.kotlinDebug { "$name destinationDir = $destinationDir" } + @get:Internal + internal val compilerArgumentsContributor: CompilerArgumentsContributor by project.provider { + KotlinJvmCompilerArgumentsContributor(thisTaskProvider) } @Internal @@ -488,13 +465,13 @@ open class KotlinCompile : AbstractKotlinCompile(), Kotl } // override setSource to track source directory sets and files (for generated android folders) - override fun setSource(sources: Any?) { + override fun setSource(sources: Any) { sourceRootsContainer.set(sources) super.setSource(sources) } // override source to track source directory sets and files (for generated android folders) - override fun source(vararg sources: Any?): SourceTask? { + override fun source(vararg sources: Any): SourceTask { sourceRootsContainer.add(*sources) return super.source(*sources) } diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt index 6d3467302cf..4a6cb057b17 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/utils/providerApiUtils.kt @@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.utils import org.gradle.api.Project import org.gradle.api.provider.Property import org.gradle.api.provider.Provider +import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty internal operator fun Provider.getValue(thisRef: Any?, property: KProperty<*>) = get() @@ -22,4 +23,14 @@ internal fun Project.newProperty(initialize: (() -> T)? = null): Prope (project.objects.property(Any::class.java) as Property).apply { if (initialize != null) set(provider(initialize)) - } \ No newline at end of file + } + +private class OptionalProviderDelegate(private val provider: Provider) : ReadOnlyProperty { + override fun getValue(thisRef: Any?, property: KProperty<*>): T? = + if (provider.isPresent) + provider.get() + else null +} + +internal fun Project.optionalProvider(initialize: () -> T?): ReadOnlyProperty = + OptionalProviderDelegate(provider(initialize)) \ No newline at end of file