diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt index 0f009095b8f..eb9b76ac587 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsIT.kt @@ -209,11 +209,11 @@ internal class CompilerOptionsIT : KGPBaseTest() { """.trimMargin() ) - build("compileKotlinJvm6", forceOutput = true) { + build("compileKotlinJvm6") { assertTasksExecuted(":compileKotlinJvm6") - assert(output.contains("-opt-in another.custom.UnderOptIn,my.custom.OptInAnnotation")) { + assert(output.contains("-opt-in my.custom.OptInAnnotation,another.custom.UnderOptIn")) { printBuildOutput() - "Output does not contain '-opt-in another.custom.UnderOptIn,my.custom.OptInAnnotation'!" + "Output does not contain '-opt-in my.custom.OptInAnnotation,another.custom.UnderOptIn'!" } } } @@ -528,4 +528,97 @@ internal class CompilerOptionsIT : KGPBaseTest() { } } } + + @GradleTest + @DisplayName("Syncs languageSettings changes to the related compiler options") + @MppGradlePluginTests + fun syncLanguageSettingsToCompilerOptions(gradleVersion: GradleVersion) { + project("mpp-default-hierarchy", gradleVersion) { + buildGradle.appendText( + //language=groovy + """ + | + |kotlin.sourceSets.configureEach { + | languageSettings.apiVersion = "1.7" + | languageSettings.languageVersion = "1.8" + |} + | + |tasks.register("printCompilerOptions") { + | dependsOn(kotlinTaskToCheck) + | def tasksContainer = project.tasks + | doLast { + | def kotlinTask = tasks.getByName(kotlinTaskToCheck) as org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask + | logger.warn("###AV:${'$'}{kotlinTask.compilerOptions.apiVersion.getOrNull()}") + | logger.warn("###LV:${'$'}{kotlinTask.compilerOptions.languageVersion.getOrNull()}") + | } + |} + """.trimMargin() + ) + + listOf( + "compileCommonMainKotlinMetadata", + "compileKotlinJvm", + "compileNativeMainKotlinMetadata", + "compileLinuxMainKotlinMetadata", + "compileAppleMainKotlinMetadata", + "compileIosMainKotlinMetadata", + "compileKotlinLinuxX64", + "compileKotlinLinuxArm64", + "compileKotlinIosX64", + "compileKotlinIosArm64" + ).forEach { task -> + build("printCompilerOptions", "-PkotlinTaskToCheck=$task") { + assertOutputContains("###AV:KOTLIN_1_7") + assertOutputContains("###LV:KOTLIN_1_8") + } + } + } + } + + @GradleTest + @DisplayName("Syncs compiler option changes to the related language settings") + @MppGradlePluginTests + fun syncCompilerOptionsToLanguageSettings(gradleVersion: GradleVersion) { + project("mpp-default-hierarchy", gradleVersion) { + buildGradle.appendText( + //language=groovy + """ + | + |tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask.class).all { + | compilerOptions { + | apiVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_7 + | languageVersion = org.jetbrains.kotlin.gradle.dsl.KotlinVersion.KOTLIN_1_8 + | } + |} + | + |tasks.register("printLanguageSettingsOptions") { + | doLast { + | def languageSettings = kotlin.sourceSets.getByName(kotlinSourceSet).languageSettings + | logger.warn("") + | logger.warn("###AV:${'$'}{languageSettings.apiVersion}") + | logger.warn("###LV:${'$'}{languageSettings.languageVersion}") + | } + |} + """.trimMargin() + ) + + listOf( + "commonMain", + "jvmMain", + "nativeMain", + "linuxMain", + "appleMain", + "iosMain", + "linuxX64Main", + "linuxArm64Main", + "iosX64Main", + "iosArm64Main", + ).forEach { sourceSet -> + build("printLanguageSettingsOptions", "-PkotlinSourceSet=${sourceSet}") { + assertOutputContains("###AV:1.7") + assertOutputContains("###LV:1.8") + } + } + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt index f5f34c7f3a8..f13a42dae71 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/CompilerOptionsProjectIT.kt @@ -140,7 +140,7 @@ class CompilerOptionsProjectIT : KGPBaseTest() { | languageVersion = '1.9' | apiVersion = '1.9' | progressiveMode = false - | optInAnnotationsInUse.add("another.CustomOptInAnnotation") + | optIn("another.CustomOptInAnnotation") | enableLanguageFeature("UnitConversionsOnArbitraryExpressions") | } | } diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt index 472ec3d1ec8..348dfc08563 100644 --- a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/kotlin/org/jetbrains/kotlin/gradle/NewMultiplatformIT.kt @@ -778,47 +778,58 @@ open class NewMultiplatformIT : BaseGradleIT() { } @Test - fun testLanguageSettingsConsistency() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) { + fun testLanguageSettingsConsistency() = with( + Project("sample-lib", gradleVersion, "new-mpp-lib-and-app", minLogLevel = LogLevel.INFO) + ) { setupWorkingDir() - gradleBuildScript().appendText( - "\n" + """ - kotlin.sourceSets { - foo { } - bar { dependsOn foo } - } - """.trimIndent() - ) - fun testMonotonousCheck( - initialSetupForSourceSets: String?, sourceSetConfigurationChange: String, expectedErrorHint: String, + initialSetupForSourceSets: String? = null, ) { if (initialSetupForSourceSets != null) { gradleBuildScript().appendText( - "\nkotlin.sourceSets.foo.${initialSetupForSourceSets}\n" + "" + - "kotlin.sourceSets.bar.${initialSetupForSourceSets}", + """ + | + |kotlin.sourceSets.commonMain.${initialSetupForSourceSets} + |kotlin.sourceSets.nativeMain.${initialSetupForSourceSets} + |kotlin.sourceSets.linux64Main.${initialSetupForSourceSets} + |kotlin.sourceSets.macos64Main.${initialSetupForSourceSets} + |kotlin.sourceSets.jvm6Main.${initialSetupForSourceSets} + |kotlin.sourceSets.mingw64Main.${initialSetupForSourceSets} + |kotlin.sourceSets.nodeJsMain.${initialSetupForSourceSets} + |kotlin.sourceSets.wasmMain.${initialSetupForSourceSets} + """.trimMargin() ) } - gradleBuildScript().appendText("\nkotlin.sourceSets.foo.${sourceSetConfigurationChange}") + gradleBuildScript().appendText("\nkotlin.sourceSets.commonMain.${sourceSetConfigurationChange}") build("tasks") { assertFailed() assertContains(expectedErrorHint) } - gradleBuildScript().appendText("\nkotlin.sourceSets.bar.${sourceSetConfigurationChange}") + gradleBuildScript().appendText( + """ + | + |kotlin.sourceSets.nativeMain.${sourceSetConfigurationChange} + |kotlin.sourceSets.linux64Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.macos64Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.jvm6Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.mingw64Main.${sourceSetConfigurationChange} + |kotlin.sourceSets.nodeJsMain.${sourceSetConfigurationChange} + |kotlin.sourceSets.wasmMain.${sourceSetConfigurationChange} + """.trimMargin() + ) build("tasks") { assertSuccessful() } } - fun testMonotonousCheck(sourceSetConfigurationChange: String, expectedErrorHint: String): Unit = - testMonotonousCheck(null, sourceSetConfigurationChange, expectedErrorHint) testMonotonousCheck( - "languageSettings.languageVersion = '1.3'", "languageSettings.languageVersion = '1.4'", - "The language version of the dependent source set must be greater than or equal to that of its dependency." + "The language version of the dependent source set must be greater than or equal to that of its dependency.", + "languageSettings.languageVersion = '1.3'", ) testMonotonousCheck( @@ -835,7 +846,7 @@ open class NewMultiplatformIT : BaseGradleIT() { // don't require doing the same for dependent source sets: gradleBuildScript().appendText( "\n" + """ - kotlin.sourceSets.foo.languageSettings { + kotlin.sourceSets.commonMain.languageSettings { apiVersion = '1.4' enableLanguageFeature('SoundSmartcastForEnumEntries') progressiveMode = true diff --git a/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/mpp-default-hierarchy/build.gradle b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/mpp-default-hierarchy/build.gradle new file mode 100644 index 00000000000..8855596e94e --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin-integration-tests/src/test/resources/testProject/mpp-default-hierarchy/build.gradle @@ -0,0 +1,20 @@ +plugins { + id "org.jetbrains.kotlin.multiplatform" +} + +repositories { + mavenLocal() + mavenCentral() +} + +kotlin { + jvm() + + linuxX64() + linuxArm64() + + iosX64() + iosArm64() + + applyDefaultHierarchyTemplate() +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt index a67722bbb10..a45c4e1b7ae 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/GradleProjectModuleBuilder.kt @@ -165,7 +165,7 @@ class GradleProjectModuleBuilder(private val addInferredSourceSetVisibilityAsExp ?: listOf(compilation.defaultSourceSetName) variantNames.forEach { variantName -> - val variant = KpmBasicVariant(this@apply, variantName, DefaultLanguageSettingsBuilder()) + val variant = KpmBasicVariant(this@apply, variantName, DefaultLanguageSettingsBuilder(project)) moduleByFragment[variant] = this@apply variantToCompilation[variant] = compilation fragments.add(variant) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt index 495b8a2391a..a80cc197ee4 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/KotlinMultiplatformPlugin.kt @@ -204,9 +204,10 @@ internal fun Project.setupGeneralKotlinExtensionParameters() { .awaitPlatformCompilations() .any { KotlinSourceSetTree.orNull(it) == KotlinSourceSetTree.main } - languageSettings.explicitApi = project.providers.provider { - val explicitApiFlag = project.kotlinExtension.explicitApiModeAsCompilerArg() - explicitApiFlag.takeIf { isMainSourceSet } + if (isMainSourceSet) { + languageSettings.explicitApi = project.providers.provider { + project.kotlinExtension.explicitApiModeAsCompilerArg() + } } languageSettings.freeCompilerArgsProvider = project.provider { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt index 881cdcd32fb..e8b202dedee 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/DefautlKotlinCompilationPreConfigure.kt @@ -8,5 +8,6 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory internal val DefaultKotlinCompilationPreConfigure = KotlinCompilationImplFactory.PreConfigure.composite( - KotlinCompilationK2MultiplatformConfigurator + KotlinCompilationK2MultiplatformConfigurator, + KotlinCompilationLanguageSettingsConfigurator, ) \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationLanguageSettingsConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationLanguageSettingsConfigurator.kt new file mode 100644 index 00000000000..dc8b711fffa --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationLanguageSettingsConfigurator.kt @@ -0,0 +1,42 @@ +/* + * Copyright 2010-2023 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.plugin.mpp.compilationImpl + +import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPlatformType +import org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl.factory.KotlinCompilationImplFactory +import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.targets.js.KotlinJsTarget + +/** + * Wires compilations compiler options into source sets [org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet.languageSettings]. + */ +internal object KotlinCompilationLanguageSettingsConfigurator : KotlinCompilationImplFactory.PreConfigure { + override fun configure(compilation: KotlinCompilationImpl) { + // Ignoring non-klib common compilation as it reuses defaultSourceSet with klib common compilation + if (compilation.platformType == KotlinPlatformType.common && + compilation.name == KotlinCompilation.MAIN_COMPILATION_NAME + ) return + + // Ignoring jsLegacy as it shares a source set with jsIR + if (compilation.platformType == KotlinPlatformType.js && + compilation.target is KotlinJsTarget + ) return + + val languageSettingsBuilder = (compilation.defaultSourceSet.languageSettings as DefaultLanguageSettingsBuilder) + if (languageSettingsBuilder.compilationCompilerOptions.isCompleted) { + compilation.target.project.logger.warn( + "Compiler options for compilation ${compilation.name} default source set ${compilation.defaultSourceSet.name} " + + "'languageSettings' was already set!" + ) + return + } + + languageSettingsBuilder + .compilationCompilerOptions + .complete(compilation.compilerOptions.options) + } +} diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt index 88d5a8a516c..72ce544f2c3 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/compilationImpl/KotlinCompilationSourceSetInclusion.kt @@ -9,7 +9,9 @@ package org.jetbrains.kotlin.gradle.plugin.mpp.compilationImpl import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet +import org.jetbrains.kotlin.gradle.plugin.launchInStage import org.jetbrains.kotlin.gradle.plugin.mpp.InternalKotlinCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.addSourcesToKotlinCompileTask import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker @@ -63,7 +65,9 @@ internal class KotlinCompilationSourceSetInclusion( // Temporary solution for checking consistency across source sets participating in a compilation that may // not be interconnected with the dependsOn relation: check the settings as if the default source set of // the compilation depends on the one added to the compilation: - defaultSourceSetLanguageSettingsChecker.runAllChecks(compilation.defaultSourceSet, sourceSet) + compilation.project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseCompilations) { + defaultSourceSetLanguageSettingsChecker.runAllChecks(compilation.defaultSourceSet, sourceSet) + } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt index a5ff495d897..57833e9e04d 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmFragmentInternal.kt @@ -41,7 +41,7 @@ abstract class GradleKpmFragmentInternal @Inject constructor( // TODO pull up to KotlinModuleFragment // FIXME apply to compilation // FIXME check for consistency - override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() + override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder(project) override fun refines(other: GradleKpmFragment) { checkCanRefine(other) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt index 66627fe7281..f4211610dd8 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/pm20/GradleKpmModuleDependencyResolver.kt @@ -81,7 +81,7 @@ internal fun buildSyntheticPlainModule( ): GradleKpmExternalPlainModule { val moduleDependency = resolvedComponentResult.toKpmModuleDependency() return GradleKpmExternalPlainModule(KpmBasicModule(moduleDependency.moduleIdentifier).apply { - KpmBasicVariant(this@apply, singleVariantName, DefaultLanguageSettingsBuilder()).apply { + KpmBasicVariant(this@apply, singleVariantName, DefaultLanguageSettingsBuilder(TODO())).apply { fragments.add(this) this.declaredModuleDependencies.addAll( resolvedComponentResult.dependencies diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt index fb61c3d3baa..3393e72931a 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/ConsistencyChecker.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.sources import org.gradle.api.InvalidUserDataException import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersion +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion import org.jetbrains.kotlin.project.model.LanguageSettings internal class ConsistencyCheck( @@ -21,45 +21,68 @@ internal class FragmentConsistencyChecks( unitName: String, // "fragment" or "source set" private val languageSettings: T.() -> LanguageSettings ) { - private val defaultLanguageVersion = LanguageVersion.LATEST_STABLE + private val defaultLanguageVersion = KotlinVersion.DEFAULT private val languageVersionCheckHint = "The language version of the dependent $unitName must be greater than or equal to that of its dependency." - val languageVersionCheck = ConsistencyCheck( + private val languageVersionCheck = ConsistencyCheck( name = "language version", getValue = { unit -> - unit.languageSettings().languageVersion?.let { parseLanguageVersionSetting(it) } ?: defaultLanguageVersion + unit.languageSettings().getValueIfExists { + languageVersion?.let { KotlinVersion.fromVersion(it) } ?: defaultLanguageVersion + } + }, + leftExtendsRightConsistently = { left, right -> + if (left == null || right == null) true else left >= right }, - leftExtendsRightConsistently = { left, right -> left >= right }, consistencyConditionHint = languageVersionCheckHint ) private val unstableFeaturesHint = "The dependent $unitName must enable all unstable language features that its dependency has." - val unstableFeaturesCheck = ConsistencyCheck>( + private val unstableFeaturesCheck = ConsistencyCheck?>( name = "unstable language feature set", getValue = { unit -> - unit.languageSettings().enabledLanguageFeatures - .map { parseLanguageFeature(it)!! } - .filterTo(mutableSetOf()) { it.kind == LanguageFeature.Kind.UNSTABLE_FEATURE } + unit.languageSettings().getValueIfExists { + enabledLanguageFeatures + .mapNotNull { parseLanguageFeature(it) } + .filterTo(mutableSetOf()) { it.kind == LanguageFeature.Kind.UNSTABLE_FEATURE } + } + }, + leftExtendsRightConsistently = { left, right -> + if (left == null || right == null) true else left.containsAll(right) }, - leftExtendsRightConsistently = { left, right -> left.containsAll(right) }, consistencyConditionHint = unstableFeaturesHint ) private val optInAnnotationsInUseHint = "The dependent $unitName must use all opt-in annotations that its dependency uses." - val optInAnnotationsCheck = ConsistencyCheck>( + private val optInAnnotationsCheck = ConsistencyCheck?>( name = "set of opt-in annotations in use", - getValue = { unit -> unit.languageSettings().optInAnnotationsInUse }, - leftExtendsRightConsistently = { left, right -> left.containsAll(right) }, + getValue = { unit -> unit.languageSettings().getValueIfExists { optInAnnotationsInUse } }, + leftExtendsRightConsistently = { left, right -> + if (left == null || right == null) true else left.containsAll(right) + }, consistencyConditionHint = optInAnnotationsInUseHint ) val allChecks = listOf(languageVersionCheck, unstableFeaturesCheck, optInAnnotationsCheck) + + private fun LanguageSettings.getValueIfExists( + getValue: LanguageSettings.() -> T? + ): T? { + val defaultLanguageSettingsBuilder = this as DefaultLanguageSettingsBuilder + return if (defaultLanguageSettingsBuilder.compilationCompilerOptions.isCompleted) { + getValue(defaultLanguageSettingsBuilder) + } else { + null + } + } } +internal fun parseLanguageFeature(featureName: String) = LanguageFeature.fromString(featureName) + internal class FragmentConsistencyChecker( private val unitsName: String, private val name: T.() -> String, diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt index a4e75a9ee35..9f731e8060b 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultKotlinSourceSet.kt @@ -12,9 +12,8 @@ import org.gradle.api.Project import org.gradle.api.file.SourceDirectorySet import org.jetbrains.kotlin.build.DEFAULT_KOTLIN_SOURCE_FILES_EXTENSIONS import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension -import org.jetbrains.kotlin.gradle.plugin.KotlinDependencyHandler -import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet -import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.plugin.* +import org.jetbrains.kotlin.gradle.plugin.launchInStage import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.tooling.core.MutableExtras @@ -68,7 +67,7 @@ abstract class DefaultKotlinSourceSet @Inject constructor( override val kotlin: SourceDirectorySet = createDefaultSourceDirectorySet(project, "$name Kotlin source") - override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder() + override val languageSettings: LanguageSettingsBuilder = DefaultLanguageSettingsBuilder(project) override val resources: SourceDirectorySet = createDefaultSourceDirectorySet(project, "$name resources") @@ -95,7 +94,7 @@ abstract class DefaultKotlinSourceSet @Inject constructor( dependencies { configure.execute(this) } override fun afterDependsOnAdded(other: KotlinSourceSet) { - project.runProjectConfigurationHealthCheckWhenEvaluated { + project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseCompilations) { defaultSourceSetLanguageSettingsChecker.runAllChecks(this@DefaultKotlinSourceSet, other) } } @@ -175,7 +174,7 @@ abstract class DefaultKotlinSourceSet @Inject constructor( } internal val defaultSourceSetLanguageSettingsChecker = - FragmentConsistencyChecker( + FragmentConsistencyChecker( unitsName = "source sets", name = { name }, checks = FragmentConsistencyChecks( diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt index a4e84496bdd..f0a1618efcf 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/sources/DefaultLanguageSettingsBuilder.kt @@ -5,74 +5,118 @@ package org.jetbrains.kotlin.gradle.plugin.sources -import org.gradle.api.InvalidUserDataException +import org.gradle.api.Project import org.gradle.api.file.FileCollection import org.gradle.api.provider.Provider -import org.jetbrains.kotlin.config.ApiVersion -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.LanguageVersion -import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions +import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptionsDefault import org.jetbrains.kotlin.gradle.dsl.KotlinVersion -import org.jetbrains.kotlin.gradle.dsl.toCompilerValue -import org.jetbrains.kotlin.gradle.plugin.LanguageSettingsBuilder +import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompileTool import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinNativeCompile import org.jetbrains.kotlin.gradle.tasks.toSingleCompilerPluginOptions -import org.jetbrains.kotlin.project.model.LanguageSettings -import kotlin.properties.Delegates +import org.jetbrains.kotlin.gradle.utils.* +import javax.inject.Inject -internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { - private var languageVersionImpl: LanguageVersion? = null +internal open class DefaultLanguageSettingsBuilder @Inject constructor( + @Transient private val project: Project +) : LanguageSettingsBuilder { + internal var compilationCompilerOptions: CompletableFuture = CompletableFuture() - override var languageVersion: String? - get() = languageVersionImpl?.versionString - set(value) { - languageVersionImpl = value?.let { versionString -> - LanguageVersion.fromVersionString(versionString) ?: throw InvalidUserDataException( - "Incorrect language version. Expected one of: ${LanguageVersion.values().joinToString { "'${it.versionString}'" }}" - ) + init { + project.launch { + KotlinPluginLifecycle.Stage.AfterFinaliseCompilations.await() + if (!compilationCompilerOptions.isCompleted) { + // For shared source sets without any associated compilation, it would be a separate instance of common compiler options + compilationCompilerOptions.complete(project.objects.newInstance()) } } - - private var apiVersionImpl: ApiVersion? = null - - override var apiVersion: String? - get() = apiVersionImpl?.versionString - set(value) { - apiVersionImpl = value?.let { versionString -> - parseApiVersionSettings(versionString) ?: throw InvalidUserDataException( - "Incorrect API version. Expected one of: ${apiVersionValues.joinToString { "'${it.versionString}'" }}" - ) - } - } - - // By using 'observable' delegate we are tracking value set by user and not default value, - // so we could propagate it to the compiler options only if it was configured explicitly - internal var setByUserProgressiveMode: Boolean? = null - override var progressiveMode: Boolean by Delegates.observable(false) { _, _, newValue -> - setByUserProgressiveMode = newValue } - private val enabledLanguageFeaturesImpl = mutableSetOf() + override var languageVersion: String? = null + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().languageVersion.orNull?.version + } else { + field + } + set(value) { + field = value + project.launch { + compilationCompilerOptions.await() + .languageVersion + .set(value?.let { KotlinVersion.fromVersion(it) }) + } + } + + override var apiVersion: String? = null + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().apiVersion.orNull?.version + } else { + field + } + set(value) { + field = value + project.launch { + compilationCompilerOptions.await() + .apiVersion + .set(value?.let { KotlinVersion.fromVersion(it) }) + } + } + + override var progressiveMode: Boolean = false + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().progressiveMode.get() + } else { + field + } + set(value) { + field = value + project.launch { + compilationCompilerOptions.await() + .progressiveMode + .set(value) + } + } + + private val enabledLanguageFeaturesField = mutableSetOf() override val enabledLanguageFeatures: Set - get() = enabledLanguageFeaturesImpl.map { it.name }.toSet() + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow() + .freeCompilerArgs + .get() + .filter { it.startsWith("-XXLanguage:+") } + .map { it.substringAfter("-XXLanguage:+") } + .toSet() + } else { + enabledLanguageFeaturesField.toSet() + } override fun enableLanguageFeature(name: String) { - val languageFeature = parseLanguageFeature(name) ?: throw InvalidUserDataException( - "Unknown language feature '${name}'" - ) - enabledLanguageFeaturesImpl += languageFeature + enabledLanguageFeaturesField.add(name) + project.launch { + compilationCompilerOptions.await() + .freeCompilerArgs + .add("-XXLanguage:+$name") + } } - private val optInAnnotationsInUseImpl = mutableSetOf() + private val optInAnnotationsInUseField = mutableSetOf() - override val optInAnnotationsInUse: Set = optInAnnotationsInUseImpl + override val optInAnnotationsInUse: Set + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().optIn.get().toSet() + } else { + optInAnnotationsInUseField.toSet() + } override fun optIn(annotationName: String) { - optInAnnotationsInUseImpl += annotationName + optInAnnotationsInUseField.add(annotationName) + project.launch { + compilationCompilerOptions.await() + .optIn.add(annotationName) + } } /* A Kotlin task that is responsible for code analysis of the owner of this language settings builder. */ @@ -100,65 +144,51 @@ internal class DefaultLanguageSettingsBuilder : LanguageSettingsBuilder { } var freeCompilerArgsProvider: Provider>? = null + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().freeCompilerArgs + } else { + field + } + set(value) { + field = value + // Checking if the provider has value as it overwrites the convention + // https://github.com/gradle/gradle/issues/20266 + if (value != null && value.isPresent) { + project.launch { + compilationCompilerOptions.await() + .freeCompilerArgs.addAll(value) + } + } + } // Kept here for compatibility with IDEA Kotlin import. It relies on explicit api argument in `freeCompilerArgs` to enable related // inspections internal var explicitApi: Provider? = null - - internal val freeCompilerArgsForNonImport: List - get() = freeCompilerArgsProvider?.get().orEmpty() + get() = if (compilationCompilerOptions.isCompleted) { + val freeArgs = compilationCompilerOptions.getOrThrow() + .freeCompilerArgs + .get() + freeArgs.find { it.startsWith("-Xexplicit-api") }?.let { project.providers.provider { it } } + } else { + field + } + set(value) { + field = value + // Checking if the provider has value as it overwrites the convention + // https://github.com/gradle/gradle/issues/20266 + if (value != null && value.isPresent) { + project.launch { + compilationCompilerOptions.await() + .freeCompilerArgs + .add(value) + } + } + } val freeCompilerArgs: List - get() = freeCompilerArgsProvider?.get() - .orEmpty() - .plus(explicitApi?.orNull) - .filterNotNull() + get() = if (compilationCompilerOptions.isCompleted) { + compilationCompilerOptions.getOrThrow().freeCompilerArgs.get() + } else { + emptyList() + } } - -internal fun applyLanguageSettingsToCompilerOptions( - languageSettingsBuilder: LanguageSettings, - compilerOptions: KotlinCommonCompilerOptions, -) = with(compilerOptions) { - val languageSettingsBuilderDefault = languageSettingsBuilder as DefaultLanguageSettingsBuilder - languageSettingsBuilderDefault.languageVersion?.let { - languageVersion.convention(KotlinVersion.fromVersion(it)) - } - languageSettingsBuilderDefault.apiVersion?.let { - apiVersion.convention(KotlinVersion.fromVersion(it)) - } - languageSettingsBuilderDefault.setByUserProgressiveMode?.let { - progressiveMode.convention(it) - } - if (languageSettingsBuilder.optInAnnotationsInUse.isNotEmpty()) optIn.addAll(languageSettingsBuilder.optInAnnotationsInUse) - - val freeArgs = mutableListOf() - languageSettingsBuilder.enabledLanguageFeatures.forEach { featureName -> - freeArgs.add("-XXLanguage:+$featureName") - } - freeArgs.addAll(languageSettingsBuilderDefault.freeCompilerArgsForNonImport) - - if (freeArgs.isNotEmpty()) { - freeCompilerArgs.addAll(freeArgs) - } -} - -private val apiVersionValues = ApiVersion.run { - listOf( - KOTLIN_1_0, - KOTLIN_1_1, - KOTLIN_1_2, - KOTLIN_1_3, - KOTLIN_1_4, - KOTLIN_1_5, - KOTLIN_1_6, - KOTLIN_1_7, - KOTLIN_1_8, - KOTLIN_1_9, - KOTLIN_2_0, - KOTLIN_2_1, - ) -} - -internal fun parseLanguageVersionSetting(versionString: String) = LanguageVersion.fromVersionString(versionString) -internal fun parseApiVersionSettings(versionString: String) = apiVersionValues.find { it.versionString == versionString } -internal fun parseLanguageFeature(featureName: String) = LanguageFeature.fromString(featureName) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt index 17e06b91ed4..969043abd9c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetConfigurator.kt @@ -330,15 +330,6 @@ class KotlinMetadataTargetConfigurator : compileDependencyFiles = project.files() } } - - target.project.runOnceAfterEvaluated("Sync common compilation language settings to compiler options") { - target.compilations.all { compilation -> - applyLanguageSettingsToCompilerOptions( - compilation.defaultSourceSet.languageSettings, - compilation.compilerOptions.options - ) - } - } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt index 874e151b6c1..f2eb084bc07 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/metadata/KotlinMetadataTargetPreset.kt @@ -10,7 +10,6 @@ import org.gradle.api.Project import org.jetbrains.kotlin.gradle.DeprecatedTargetPresetApi import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.* -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions import org.jetbrains.kotlin.gradle.targets.metadata.KotlinMetadataTargetConfigurator @DeprecatedTargetPresetApi @@ -58,12 +57,5 @@ class KotlinMetadataTargetPreset( @Suppress("DEPRECATION") mainCompilation.addSourceSet(commonMainSourceSet) - - project.whenEvaluated { - // Since there's no default source set, apply language settings from commonMain: - mainCompilation.compileTaskProvider.configure { compileKotlinMetadata -> - applyLanguageSettingsToCompilerOptions(commonMainSourceSet.languageSettings, compileKotlinMetadata.compilerOptions) - } - } } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt index 6c96a6851fc..415bb3972a5 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/KotlinNativeTargetConfigurator.kt @@ -35,7 +35,6 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.apple.registerEmbedAndSignAppleFra import org.jetbrains.kotlin.gradle.plugin.mpp.apple.version import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmVariant import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.util.copyAttributes -import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.targets.metadata.isKotlinGranularMetadataEnabled import org.jetbrains.kotlin.gradle.targets.native.* import org.jetbrains.kotlin.gradle.targets.native.internal.* @@ -51,6 +50,7 @@ import org.jetbrains.kotlin.gradle.testing.internal.configureConventions import org.jetbrains.kotlin.gradle.testing.internal.kotlinTestRegistry import org.jetbrains.kotlin.gradle.testing.testTaskName import org.jetbrains.kotlin.gradle.utils.XcodeUtils +import org.jetbrains.kotlin.gradle.utils.named import org.jetbrains.kotlin.gradle.utils.newInstance import org.jetbrains.kotlin.konan.target.HostManager import org.jetbrains.kotlin.konan.target.KonanTarget @@ -95,14 +95,11 @@ open class KotlinNativeTargetConfigurator : AbstractKotl } private fun Project.syncLanguageSettingsToLinkTask(binary: NativeBinary) { - tasks.named(binary.linkTaskName, KotlinNativeLink::class.java).configure { + tasks.named(binary.linkTaskName).configure { linkTask -> // We propagate compilation free args to the link task for now (see KT-33717). - val defaultLanguageSettings = binary.compilation.defaultSourceSet.languageSettings as? DefaultLanguageSettingsBuilder - if (defaultLanguageSettings != null && defaultLanguageSettings.freeCompilerArgsForNonImport.isNotEmpty()) { - it.toolOptions.freeCompilerArgs.addAll( - defaultLanguageSettings.freeCompilerArgsForNonImport - ) - } + linkTask.toolOptions.freeCompilerArgs.addAll( + binary.compilation.compilerOptions.options.freeCompilerArgs + ) } } @@ -254,11 +251,6 @@ open class KotlinNativeTargetConfigurator : AbstractKotl project.syncLanguageSettingsToLinkTask(binary) } } - project.launchInStage(KotlinPluginLifecycle.Stage.FinaliseCompilations) { - target.compilations.all { compilation -> - compilation.compilerOptions.syncLanguageSettings(compilation.defaultSourceSet.languageSettings) - } - } target.binaries.withType(Executable::class.java).all { project.createRunTask(it) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt index 0b90bb34823..b71d6b51b05 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/NativeCompilerOptions.kt @@ -6,21 +6,14 @@ package org.jetbrains.kotlin.gradle.targets.native import org.gradle.api.Project -import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptionsDefault import org.jetbrains.kotlin.gradle.plugin.HasCompilerOptions -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions import org.jetbrains.kotlin.gradle.utils.configureExperimentalTryK2 -import org.jetbrains.kotlin.project.model.LanguageSettings class NativeCompilerOptions(project: Project) : HasCompilerOptions { override val options: KotlinNativeCompilerOptions = project.objects .newInstance(KotlinNativeCompilerOptionsDefault::class.java) .configureExperimentalTryK2(project) - - internal fun syncLanguageSettings(languageSettings: LanguageSettings) { - applyLanguageSettingsToCompilerOptions(languageSettings, options) - } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt index 106d2c9ce74..28d82638581 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/targets/native/tasks/KotlinNativeTasks.kt @@ -38,10 +38,8 @@ import org.jetbrains.kotlin.gradle.plugin.cocoapods.asValidFrameworkName import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmMetadataCompilationData import org.jetbrains.kotlin.gradle.plugin.mpp.pm20.GradleKpmNativeCompilationData -import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService import org.jetbrains.kotlin.gradle.targets.native.KonanPropertiesBuildService -import org.jetbrains.kotlin.gradle.targets.native.internal.isAllowCommonizer import org.jetbrains.kotlin.gradle.targets.native.tasks.* import org.jetbrains.kotlin.gradle.utils.* import org.jetbrains.kotlin.gradle.utils.listFilesOrEmpty @@ -205,16 +203,16 @@ abstract class AbstractKotlinNativeCompile< @get:Input abstract val additionalCompilerOptions: Provider> + @Deprecated("Use implementations compilerOptions") @get:Internal - val languageSettings: LanguageSettings by project.provider { - compilation.languageSettings - } + val languageSettings: LanguageSettings + get() = compilation.languageSettings @Suppress("DeprecatedCallableAddReplaceWith") @get:Deprecated("Replaced with 'compilerOptions.progressiveMode'") @get:Internal val progressiveMode: Boolean - get() = languageSettings.progressiveMode + get() = compilation.compilerOptions.options.progressiveMode.get() // endregion. @Suppress("DeprecatedCallableAddReplaceWith") @@ -373,17 +371,21 @@ internal constructor( replaceWith = ReplaceWith("kotlinOptions.languageVersion") ) val languageVersion: String? - @Optional @Input get() = languageSettings.languageVersion + @Optional @Input get() = compilerOptions.languageVersion.orNull?.version @Deprecated( message = "Replaced with kotlinOptions.apiVersion", replaceWith = ReplaceWith("kotlinOptions.apiVersion") ) val apiVersion: String? - @Optional @Input get() = languageSettings.apiVersion + @Optional @Input get() = compilerOptions.apiVersion.orNull?.version + @Deprecated("Language features is internal Kotlin compiler flags and should not be used directly") val enabledLanguageFeatures: Set - @Input get() = languageSettings.enabledLanguageFeatures + @Internal get() = compilerOptions + .freeCompilerArgs.get() + .filter { it.startsWith("-XXLanguage:+") } + .toSet() @Deprecated( message = "Replaced with compilerOptions.optIn", @@ -414,15 +416,14 @@ internal constructor( fn.call() } + @Suppress("UNCHECKED_CAST") @Deprecated( message = "Replaced with compilerOptions.freeCompilerArgs", replaceWith = ReplaceWith("compilerOptions.freeCompilerArgs.get()") ) @get:Input override val additionalCompilerOptions: Provider> - get() = compilerOptions - .freeCompilerArgs - .map { it + (languageSettings as DefaultLanguageSettingsBuilder).freeCompilerArgsForNonImport } + get() = compilerOptions.freeCompilerArgs as Provider> private val runnerSettings = KotlinNativeCompilerRunner.Settings.fromProject(project) // endregion. diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt index 5e468dc57cf..596849af912 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/AbstractKotlinCompileConfig.kt @@ -19,7 +19,6 @@ import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension import org.jetbrains.kotlin.gradle.dsl.topLevelExtension import org.jetbrains.kotlin.gradle.incremental.IncrementalModuleInfoBuildService import org.jetbrains.kotlin.gradle.internal.ClassLoadersCachingBuildService -import org.jetbrains.kotlin.gradle.internal.KaptGenerateStubsTask import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider import org.jetbrains.kotlin.gradle.plugin.internal.BuildIdService @@ -27,13 +26,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget import org.jetbrains.kotlin.gradle.plugin.mpp.associateWithClosure import org.jetbrains.kotlin.gradle.plugin.mpp.internal -import org.jetbrains.kotlin.gradle.plugin.sources.applyLanguageSettingsToCompilerOptions import org.jetbrains.kotlin.gradle.report.BuildMetricsService import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.tasks.KOTLIN_BUILD_DIR_NAME -import org.jetbrains.kotlin.gradle.tasks.Kotlin2JsCompile import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention -import org.jetbrains.kotlin.project.model.LanguageSettings /** * Configuration for the base compile task, [org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile]. @@ -43,25 +39,10 @@ import org.jetbrains.kotlin.project.model.LanguageSettings */ internal abstract class AbstractKotlinCompileConfig>( project: Project, - val ext: KotlinTopLevelExtension, - private val languageSettings: Provider + val ext: KotlinTopLevelExtension ) : TaskConfigAction(project) { init { - configureTaskProvider { taskProvider -> - project.launchInStage(KotlinPluginLifecycle.Stage.AfterFinaliseCompilations) { - taskProvider.configure { - // KaptGenerateStubs will receive value from linked KotlinCompile task - if (it is KaptGenerateStubsTask) return@configure - - applyLanguageSettingsToCompilerOptions( - languageSettings.get(), - (it as org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask<*>).compilerOptions, - ) - } - } - } - val compilerSystemPropertiesService = CompilerSystemPropertiesService.registerIfAbsent(project) val buildMetricsService = BuildMetricsService.registerIfAbsent(project) val incrementalModuleInfoProvider = @@ -120,6 +101,7 @@ internal abstract class AbstractKotlinCompileConfig task.friendPaths.from({ compilationInfo.friendPaths }) diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt index 5f6b4a7c09b..2d7fbd571cd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/tasks/configuration/KotlinCompileConfig.kt @@ -7,7 +7,6 @@ package org.jetbrains.kotlin.gradle.tasks.configuration import org.gradle.api.Project import org.gradle.api.attributes.Attribute -import org.gradle.api.provider.Provider import org.jetbrains.kotlin.gradle.dsl.KotlinAndroidProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinJvmProjectExtension import org.jetbrains.kotlin.gradle.dsl.KotlinTopLevelExtension @@ -17,12 +16,10 @@ import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmAndroidCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJvmCompilation import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinWithJavaCompilation import org.jetbrains.kotlin.gradle.utils.markResolvable -import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.tcsOrNull import org.jetbrains.kotlin.gradle.report.BuildMetricsService import org.jetbrains.kotlin.gradle.tasks.KotlinCompile import org.jetbrains.kotlin.gradle.utils.providerWithLazyConvention -import org.jetbrains.kotlin.project.model.LanguageSettings internal typealias KotlinCompileConfig = BaseKotlinCompileConfig @@ -99,7 +96,7 @@ internal open class BaseKotlinCompileConfig : AbstractKotl constructor(project: Project, ext: KotlinTopLevelExtension) : super( - project, ext, languageSettings = getDefaultLangSetting(project) + project, ext ) companion object { @@ -109,10 +106,6 @@ internal open class BaseKotlinCompileConfig : AbstractKotl private const val DIRECTORY_ARTIFACT_TYPE = "directory" private const val JAR_ARTIFACT_TYPE = "jar" const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot" - - private fun getDefaultLangSetting(project: Project): Provider { - return project.provider { DefaultLanguageSettingsBuilder() } - } } private fun registerTransformsOnce(project: Project) { diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt index 28feeeb2f2b..bb852aeb8ba 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetApiTests.kt @@ -90,12 +90,12 @@ class ExternalKotlinTargetApiTests { "Expected CompilationAssociator.default being set in ${ExternalKotlinCompilationDescriptorBuilder::class.simpleName}" ) - defaults(kotlin) + defaults(kotlin, "fakeMain") compileTaskName = "main" } val auxCompilation = target.createCompilation { - defaults(kotlin) + defaults(kotlin, "fakeAux") compilationName = "aux" } @@ -114,13 +114,13 @@ class ExternalKotlinTargetApiTests { } val mainCompilation = target.createCompilation { - defaults(kotlin) + defaults(kotlin, "fakeMain") this.compilationAssociator = compilationAssociator this.compileTaskName = "main" } val auxCompilation = target.createCompilation { - defaults(kotlin) + defaults(kotlin, "fakeAux") this.compilationName = "aux" this.compilationAssociator = compilationAssociator } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt index b57da4a691c..822b8b2a49c 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/ExternalKotlinTargetSourcesJarUtilsTest.kt @@ -61,12 +61,12 @@ class ExternalKotlinTargetSourcesJarUtilsTest { val target = multiplatformExtension.createExternalKotlinTarget { defaults() } val mainCompilation = target.createCompilation { - defaults(multiplatformExtension) + defaults(multiplatformExtension, "mainFake") compilationName = "main" } val auxCompilation = target.createCompilation { - defaults(multiplatformExtension) + defaults(multiplatformExtension, "auxFake") compilationName = "aux" } diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt index b9e1d3337e7..714390936ab 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/KotlinMultiplatformSourceSetConventionsTest.kt @@ -8,6 +8,8 @@ package org.jetbrains.kotlin.gradle.unitTests import org.gradle.kotlin.dsl.provideDelegate +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventionsImpl.jvmMain +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformSourceSetConventionsImpl.jvmTest import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.configurationResult @@ -50,21 +52,31 @@ class KotlinMultiplatformSourceSetConventionsTest { } @Test - fun `test - languageSettings`() = buildProjectWithMPP().runLifecycleAwareTest { - multiplatformExtension.apply { - jvm() + fun `test - languageSettings`() { + val project = buildProjectWithMPP() + project.runLifecycleAwareTest { + multiplatformExtension.apply { + jvm() + + sourceSets.jvmMain.languageSettings { + optIn("jvmMain.optIn") + } + + sourceSets.jvmTest.languageSettings { + this.optIn("jvmTest.optIn") + } - sourceSets.jvmMain.languageSettings { - this.optIn("jvmMain.optIn") } - - sourceSets.jvmTest.languageSettings { - this.optIn("jvmTest.optIn") - } - - assertEquals(setOf("jvmMain.optIn"), sourceSets.jvmMain.get().languageSettings.optInAnnotationsInUse) - assertEquals(setOf("jvmTest.optIn"), sourceSets.jvmTest.get().languageSettings.optInAnnotationsInUse) } + + assertEquals( + setOf("jvmMain.optIn"), + project.multiplatformExtension.sourceSets.jvmMain.get().languageSettings.optInAnnotationsInUse + ) + assertEquals( + setOf("jvmTest.optIn"), + project.multiplatformExtension.sourceSets.jvmTest.get().languageSettings.optInAnnotationsInUse + ) } @Test diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/LanguageSettingsTests.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/LanguageSettingsTests.kt new file mode 100644 index 00000000000..c08cfb6cb03 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/LanguageSettingsTests.kt @@ -0,0 +1,107 @@ +/* + * Copyright 2010-2023 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.unitTests + +import org.jetbrains.kotlin.gradle.dsl.KotlinVersion +import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension +import org.jetbrains.kotlin.gradle.tasks.KotlinCompilationTask +import org.jetbrains.kotlin.gradle.tasks.withType +import org.jetbrains.kotlin.gradle.util.buildProjectWithMPP +import org.junit.Test +import kotlin.test.assertEquals + +class LanguageSettingsTests { + + @Test + fun languageSettingsSyncToCompilerOptions() { + val project = buildProjectWithMPP { + with(multiplatformExtension) { + jvm() + + linuxX64() + linuxArm64() + + iosX64() + iosArm64() + + applyDefaultHierarchyTemplate() + + sourceSets.configureEach { + it.languageSettings { + apiVersion = "1.7" + languageVersion = "1.8" + } + } + } + } + + project.evaluate() + + listOf( + "compileCommonMainKotlinMetadata", + "compileKotlinJvm", + "compileNativeMainKotlinMetadata", + "compileLinuxMainKotlinMetadata", + "compileAppleMainKotlinMetadata", + "compileIosMainKotlinMetadata", + "compileKotlinLinuxX64", + "compileKotlinLinuxArm64", + "compileKotlinIosX64", + "compileKotlinIosArm64" + ).forEach { taskName -> + val compileTask = project.tasks.getByName(taskName) as KotlinCompilationTask<*> + with(compileTask.compilerOptions) { + assertEquals(apiVersion.orNull, KotlinVersion.KOTLIN_1_7) + assertEquals(languageVersion.orNull, KotlinVersion.KOTLIN_1_8) + } + } + } + + @Test + fun compilerOptionsSyncToLanguageSettings() { + val project = buildProjectWithMPP { + with(multiplatformExtension) { + jvm() + + linuxX64() + linuxArm64() + + iosX64() + iosArm64() + + applyDefaultHierarchyTemplate() + } + + + tasks.withType>().all { + it.compilerOptions { + apiVersion.set(KotlinVersion.KOTLIN_1_7) + languageVersion.set(KotlinVersion.KOTLIN_1_8) + } + } + } + + project.evaluate() + + listOf( + "commonMain", + "jvmMain", + "nativeMain", + "linuxMain", + "appleMain", + "iosMain", + "linuxX64Main", + "linuxArm64Main", + "iosX64Main", + "iosArm64Main", + ).forEach { sourceSetName -> + with(project.multiplatformExtension.sourceSets.getByName(sourceSetName).languageSettings) { + assertEquals("1.7", apiVersion) + assertEquals("1.8", languageVersion) + } + } + } +} \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt index dfbf1b63cde..fb0a463addd 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/util/externalTargetApiUtils.kt @@ -20,8 +20,11 @@ fun ExternalKotlinTargetDescriptorBuilder.defaults() { targetFactory = TargetFactory(::FakeTarget) } -fun ExternalKotlinCompilationDescriptorBuilder.defaults(kotlin: KotlinMultiplatformExtension) { - compilationName = "fake" +fun ExternalKotlinCompilationDescriptorBuilder.defaults( + kotlin: KotlinMultiplatformExtension, + name: String = "fake" +) { + compilationName = name compilationFactory = CompilationFactory(::FakeCompilation) - defaultSourceSet = kotlin.sourceSets.maybeCreate("fake") + defaultSourceSet = kotlin.sourceSets.maybeCreate(name) }