Check the MPP model for unused Kotlin source sets, warn when found
Issue #KT-26963 Fixed
This commit is contained in:
+31
@@ -5,6 +5,7 @@
|
|||||||
package org.jetbrains.kotlin.gradle
|
package org.jetbrains.kotlin.gradle
|
||||||
|
|
||||||
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
|
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.mpp.UnusedSourceSetsChecker
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
|
import org.jetbrains.kotlin.gradle.plugin.sources.METADATA_CONFIGURATION_NAME_SUFFIX
|
||||||
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks
|
import org.jetbrains.kotlin.gradle.plugin.sources.SourceSetConsistencyChecks
|
||||||
import org.jetbrains.kotlin.gradle.util.checkBytecodeContains
|
import org.jetbrains.kotlin.gradle.util.checkBytecodeContains
|
||||||
@@ -1062,4 +1063,34 @@ class NewMultiplatformIT : BaseGradleIT() {
|
|||||||
assertFileExists("foo/2.txt")
|
assertFileExists("foo/2.txt")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@Test
|
||||||
|
fun testUnusedSourceSetsReport() = with(Project("sample-lib", gradleVersion, "new-mpp-lib-and-app")) {
|
||||||
|
setupWorkingDir()
|
||||||
|
|
||||||
|
gradleBuildScript().appendText("\nkotlin { sourceSets { foo { } } }")
|
||||||
|
|
||||||
|
build {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains(UnusedSourceSetsChecker.WARNING_PREFIX_ONE, UnusedSourceSetsChecker.WARNING_INTRO)
|
||||||
|
}
|
||||||
|
|
||||||
|
gradleBuildScript().appendText("\nkotlin { sourceSets { bar { dependsOn foo } } }")
|
||||||
|
|
||||||
|
build {
|
||||||
|
assertSuccessful()
|
||||||
|
assertContains(UnusedSourceSetsChecker.WARNING_PREFIX_MANY, UnusedSourceSetsChecker.WARNING_INTRO)
|
||||||
|
}
|
||||||
|
|
||||||
|
gradleBuildScript().appendText("\nkotlin { sourceSets { jvm6Main { dependsOn bar } } }")
|
||||||
|
|
||||||
|
build {
|
||||||
|
assertSuccessful()
|
||||||
|
assertNotContains(
|
||||||
|
UnusedSourceSetsChecker.WARNING_PREFIX_ONE,
|
||||||
|
UnusedSourceSetsChecker.WARNING_PREFIX_MANY,
|
||||||
|
UnusedSourceSetsChecker.WARNING_INTRO
|
||||||
|
)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
+15
-9
@@ -94,6 +94,8 @@ class KotlinMultiplatformPlugin(
|
|||||||
|
|
||||||
// propagate compiler plugin options to the source set language settings
|
// propagate compiler plugin options to the source set language settings
|
||||||
setupCompilerPluginOptions(project)
|
setupCompilerPluginOptions(project)
|
||||||
|
|
||||||
|
UnusedSourceSetsChecker.checkSourceSets(project)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun setupCompilerPluginOptions(project: Project) {
|
private fun setupCompilerPluginOptions(project: Project) {
|
||||||
@@ -104,14 +106,7 @@ class KotlinMultiplatformPlugin(
|
|||||||
.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
.compilations.getByName(KotlinCompilation.MAIN_COMPILATION_NAME)
|
||||||
|
|
||||||
val primaryCompilationsBySourceSet by lazy { // don't evaluate eagerly: Android targets are not created at this point
|
val primaryCompilationsBySourceSet by lazy { // don't evaluate eagerly: Android targets are not created at this point
|
||||||
val allCompilationsForSourceSets =
|
val allCompilationsForSourceSets = compilationsBySourceSet(project)
|
||||||
project.multiplatformExtension!!.targets
|
|
||||||
.flatMap { target ->
|
|
||||||
target.compilations.flatMap { compilation ->
|
|
||||||
compilation.allKotlinSourceSets.map { it to compilation }
|
|
||||||
}
|
|
||||||
}
|
|
||||||
.groupBy(keySelector = { (sourceSet, _) -> sourceSet }, valueTransform = { (_, compilation) -> compilation })
|
|
||||||
|
|
||||||
allCompilationsForSourceSets.mapValues { (_, compilations) -> // choose one primary compilation
|
allCompilationsForSourceSets.mapValues { (_, compilations) -> // choose one primary compilation
|
||||||
when (compilations.size) {
|
when (compilations.size) {
|
||||||
@@ -305,4 +300,15 @@ class KotlinMultiplatformPlugin(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
internal val KotlinTarget.defaultArtifactId get() = "${project.name}-${name.toLowerCase()}"
|
internal val KotlinTarget.defaultArtifactId get() = "${project.name}-${name.toLowerCase()}"
|
||||||
|
|
||||||
|
internal fun compilationsBySourceSet(project: Project): Map<KotlinSourceSet, Set<KotlinCompilation>> =
|
||||||
|
HashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>().also { result ->
|
||||||
|
for (target in project.multiplatformExtension!!.targets) {
|
||||||
|
for (compilation in target.compilations) {
|
||||||
|
for (sourceSet in compilation.allKotlinSourceSets) {
|
||||||
|
result.getOrPut(sourceSet) { mutableSetOf() }.add(compilation)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
+48
@@ -0,0 +1,48 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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
|
||||||
|
|
||||||
|
import org.gradle.api.Project
|
||||||
|
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
|
||||||
|
import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet
|
||||||
|
|
||||||
|
object UnusedSourceSetsChecker {
|
||||||
|
const val WARNING_PREFIX_ONE =
|
||||||
|
"The Kotlin source set"
|
||||||
|
|
||||||
|
const val WARNING_PREFIX_MANY =
|
||||||
|
"The following Kotlin source sets were"
|
||||||
|
|
||||||
|
const val WARNING_INTRO = "configured but not added to any Kotlin compilation"
|
||||||
|
|
||||||
|
const val WARNING_BOTTOM_LINE =
|
||||||
|
"You can add a source set to a target's compilation by connecting it with the compilation's default source set using 'dependsOn'.\n" +
|
||||||
|
"See https://kotlinlang.org/docs/reference/building-mpp-with-gradle.html#connecting-source-sets"
|
||||||
|
|
||||||
|
private fun reportUnusedSourceSets(project: Project, sourceSets: Set<KotlinSourceSet>) {
|
||||||
|
require(sourceSets.isNotEmpty())
|
||||||
|
val message = when (sourceSets.size) {
|
||||||
|
1 -> "$WARNING_PREFIX_ONE ${sourceSets.single().name} was $WARNING_INTRO. $WARNING_BOTTOM_LINE"
|
||||||
|
else -> {
|
||||||
|
val list = sourceSets.joinToString("\n", "\n", "\n") { " * ${it.name}" }
|
||||||
|
"$WARNING_PREFIX_MANY $WARNING_INTRO:$list$WARNING_BOTTOM_LINE"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
project.logger.warn("\n" + message) // make sure the message stands out
|
||||||
|
}
|
||||||
|
|
||||||
|
fun checkSourceSets(project: Project) {
|
||||||
|
project.afterEvaluate {
|
||||||
|
val compilationsBySourceSet = compilationsBySourceSet(project)
|
||||||
|
val unusedSourceSets = project.kotlinExtension.sourceSets.filter {
|
||||||
|
compilationsBySourceSet[it]?.isEmpty() ?: true
|
||||||
|
}
|
||||||
|
if (unusedSourceSets.isNotEmpty()) {
|
||||||
|
reportUnusedSourceSets(project, unusedSourceSets.toSet())
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user