Fix false-positive on checking unused sourcesets in MPP+Android project

AGP could create 'AndroidSourceSet' that does not participate in any
compilation. For this 'AndroidSourceSet's plugin should mark
corresponding KotlinSourceSet as orphan and exclude from check.

Unfortunately filtering them on KotlinSourceSet does not work,
as AGP adds sourcesets into variants lazily. And MPP requires all
SourceSets to be created eagerly. This change excludes all
KotlinSourceSets created for Android compilation from such check.

^KT-48436 Fixed
This commit is contained in:
Yahor Berdnikau
2022-06-23 16:51:58 +02:00
committed by Space
parent 52c4cd7b34
commit a218ad92be
4 changed files with 41 additions and 5 deletions
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.konan.target.HostManager
import org.jetbrains.kotlin.library.KLIB_PROPERTY_SHORT_NAME
import org.jetbrains.kotlin.library.KLIB_PROPERTY_UNIQUE_NAME
import org.junit.Assert
import org.junit.Ignore
import org.junit.Test
import java.util.*
import java.util.jar.JarFile
@@ -1624,6 +1623,25 @@ class NewMultiplatformIT : BaseGradleIT() {
}
}
// https://youtrack.jetbrains.com/issue/KT-48436
@Test
fun testUnusedSourceSetsReportAndroid() = with(Project("new-mpp-android", gradleVersion)) {
setupWorkingDir()
build(
"assembleDebug",
// https://issuetracker.google.com/issues/152187160
options = defaultBuildOptions().copy(androidGradlePluginVersion = AGPVersion.v4_2_0)
) {
assertSuccessful()
assertNotContains(
UnusedSourceSetsChecker.WARNING_PREFIX_ONE,
UnusedSourceSetsChecker.WARNING_PREFIX_MANY,
UnusedSourceSetsChecker.WARNING_INTRO
)
}
}
@Test
fun testIncrementalCompilation() = with(Project("new-mpp-jvm-js-ic", gradleVersion)) {
build("build") {
@@ -20,6 +20,7 @@ package org.jetbrains.kotlin.gradle.plugin
import org.gradle.api.internal.HasConvention
import org.gradle.api.plugins.ExtensionAware
import org.gradle.api.plugins.ExtraPropertiesExtension
@Deprecated("Conventions are deprecated in Gradle")
internal inline fun <reified T : Any> Any.addConvention(name: String, plugin: T) {
@@ -42,3 +43,6 @@ internal inline fun <reified T : Any> Any.addExtension(name: String, extension:
internal inline fun <reified T : Any> Any.getExtension(name: String): T? =
(this as ExtensionAware).extensions.getByName(name) as T?
inline val Any.extraProperties: ExtraPropertiesExtension
get() = (this as ExtensionAware).extensions.extraProperties
@@ -8,6 +8,8 @@ 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
import org.jetbrains.kotlin.gradle.plugin.extraProperties
import org.jetbrains.kotlin.gradle.plugin.whenEvaluated
object UnusedSourceSetsChecker {
const val WARNING_PREFIX_ONE =
@@ -35,11 +37,14 @@ object UnusedSourceSetsChecker {
}
fun checkSourceSets(project: Project) {
// TODO once Android compilations are configured eagerly, move this to afterEvaluate { ... } instead of taskGraph.whenReady { ... }
project.gradle.taskGraph.whenReady { _ ->
project.whenEvaluated {
val compilationsBySourceSet = CompilationSourceSetUtil.compilationsBySourceSets(project)
val unusedSourceSets = project.kotlinExtension.sourceSets.filter {
compilationsBySourceSet[it]?.isEmpty() ?: true
// Ignoring Android source sets
val isAndroidSourceSet = it.extraProperties.has(IS_ANDROID_SOURCE_SET) &&
(it.extraProperties[IS_ANDROID_SOURCE_SET] as Boolean)
!isAndroidSourceSet && compilationsBySourceSet[it]?.isEmpty() ?: true
}
if (unusedSourceSets.isNotEmpty()) {
reportUnusedSourceSets(project, unusedSourceSets.toSet())
@@ -16,13 +16,22 @@ import org.jetbrains.kotlin.gradle.plugin.AbstractAndroidProjectHandler.Companio
import org.jetbrains.kotlin.gradle.plugin.addConvention
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinSourceSetFactory.Companion.defaultSourceFolder
internal const val IS_ANDROID_SOURCE_SET = "android-source-set"
internal fun syncKotlinAndAndroidSourceSets(target: KotlinAndroidTarget) {
val project = target.project
val android = project.extensions.getByName("android") as BaseExtension
val kotlinExtension = project.kotlinExtension
val createdKotlinSourceSets = mutableSetOf<String>()
android.sourceSets.all { androidSourceSet ->
val kotlinSourceSetName = kotlinSourceSetNameForAndroidSourceSet(target, androidSourceSet.name)
val kotlinSourceSet = project.kotlinExtension.sourceSets.maybeCreate(kotlinSourceSetName)
createdKotlinSourceSets.add(kotlinSourceSetName)
val kotlinSourceSet = kotlinExtension.sourceSets.maybeCreate(kotlinSourceSetName)
// Marking KotlinSource set is created for Android compilation to ignore it in UnusedSourceSetChecker
kotlinSourceSet.extraProperties.set(IS_ANDROID_SOURCE_SET, true)
androidSourceSet.addKotlinSources(kotlinSourceSet)
createDefaultDependsOnEdges(target, kotlinSourceSet, androidSourceSet)