From 0ee19cf28f9971149223766906ace62225291f9e Mon Sep 17 00:00:00 2001 From: Sergey Igushkin Date: Thu, 30 Aug 2018 17:47:52 +0300 Subject: [PATCH] Support -Xcommon-sources in new MPP In new MPP, add source sets taking part in more than one compilation to the tasks' `commonSourceSet` in order to pass them as -Xcommon-sources Issue #KT-26515 Fixed --- .../kotlin/gradle/NewMultiplatformIT.kt | 34 +++++++++++++++++ .../gradle/plugin/mpp/kotlinCompilations.kt | 38 +++++++++++++++++-- 2 files changed, 68 insertions(+), 4 deletions(-) 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 0a6bba74159..47bb563fe96 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 @@ -369,4 +369,38 @@ class NewMultiplatformIT : BaseGradleIT() { } } } + + + @Test + fun testOptionalExpectations() = with(Project("new-mpp-lib-with-tests", gradleVersion)) { + setupWorkingDir() + + projectDir.resolve("src/commonMain/kotlin/Optional.kt").writeText( + """ + @file:Suppress("EXPERIMENTAL_API_USAGE_ERROR") + @OptionalExpectation + expect annotation class Optional(val value: String) + + @Optional("optionalAnnotationValue") + class OptionalCommonUsage + """.trimIndent() + ) + + build("compileKotlinJvmWithoutJava") { + assertSuccessful() + assertFileExists(targetClassesDir("jvmWithoutJava") + "OptionalCommonUsage.class") + } + + projectDir.resolve("src/jvmWithoutJavaMain/kotlin/OptionalImpl.kt").writeText( + "\n" + """ + @Optional("should fail, see KT-25196") + class OptionalPlatformUsage + """.trimIndent() + ) + + build("compileKotlinJvmWithoutJava") { + assertFailed() + assertContains("Declaration annotated with '@OptionalExpectation' can only be used in common module sources") + } + } } \ No newline at end of file diff --git a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt index bdb4143a68d..071b0fe76e9 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/main/kotlin/org/jetbrains/kotlin/gradle/plugin/mpp/kotlinCompilations.kt @@ -12,6 +12,7 @@ import org.gradle.api.file.FileCollection import org.gradle.api.tasks.SourceSet import org.gradle.api.tasks.SourceSetOutput import org.gradle.util.ConfigureUtil +import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.sources.defaultSourceSetLanguageSettingsChecker @@ -19,6 +20,7 @@ import org.jetbrains.kotlin.gradle.plugin.sources.getSourceSetHierarchy import org.jetbrains.kotlin.gradle.tasks.AbstractKotlinCompile import org.jetbrains.kotlin.gradle.utils.addExtendsFromRelation import org.jetbrains.kotlin.gradle.utils.lowerCamelCaseName +import java.util.* internal fun KotlinCompilation.composeName(prefix: String? = null, suffix: String? = null): String { val compilationNamePart = compilationName.takeIf { it != KotlinCompilation.MAIN_COMPILATION_NAME } @@ -62,8 +64,12 @@ abstract class AbstractKotlinCompilation( override val kotlinSourceSets: MutableSet = mutableSetOf() - open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet) { - (target.project.tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*>).source(sourceSet.kotlin) + open fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) { + val compileTask = target.project.tasks.getByName(compileKotlinTaskName) as AbstractKotlinCompile<*> + compileTask.source(sourceSet.kotlin) + if (addAsCommonSources) { + compileTask.commonSourceSet += sourceSet.kotlin + } } override fun source(sourceSet: KotlinSourceSet) { @@ -71,7 +77,10 @@ abstract class AbstractKotlinCompilation( with(target.project) { whenEvaluated { sourceSet.getSourceSetHierarchy().forEach { sourceSet -> - addSourcesToCompileTask(sourceSet) + val isCommonSource = + CompilationSourceSetUtil.sourceSetsInMultipleCompilations(project)?.contains(sourceSet) ?: false + + addSourcesToCompileTask(sourceSet, addAsCommonSources = isCommonSource) // Use `forced = false` since `api`, `implementation`, and `compileOnly` may be missing in some cases like // old Java & Android projects: @@ -295,7 +304,8 @@ class KotlinNativeCompilation( "klibrary" ) - override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet) { + override fun addSourcesToCompileTask(sourceSet: KotlinSourceSet, addAsCommonSources: Boolean) { + // TODO: support optional expectations allSources += sourceSet.kotlin } @@ -308,4 +318,24 @@ class KotlinNativeCompilation( val FRAMEWORK = NativeOutputKind.FRAMEWORK } +} + +private object CompilationSourceSetUtil { + // Cache the results per project + private val projectSourceSetsInMultipleCompilationsCache = WeakHashMap>() + + fun sourceSetsInMultipleCompilations(project: Project) = + projectSourceSetsInMultipleCompilationsCache.computeIfAbsent(project) { _ -> + check(project.state.executed) { "Should only be computed after the project is evaluated" } + + val compilations = (project.kotlinExtension as? KotlinMultiplatformExtension)?.targets?.flatMap { it.compilations } + ?: return@computeIfAbsent null + + compilations + .flatMap { compilation -> compilation.allKotlinSourceSets.map { sourceSet -> compilation to sourceSet } } + .groupingBy { (_, sourceSet) -> sourceSet } + .eachCount() + .filterValues { it > 1 } + .keys + } } \ No newline at end of file