diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt index 1b6283c4a7b..18c6174d593 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinGradleProjectChecker.kt @@ -10,10 +10,7 @@ import org.gradle.api.Project import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider -import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.CommonMainWithDependsOnChecker -import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.DeprecatedKotlinNativeTargetsChecker -import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.MissingNativeStdlibChecker -import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.UnusedSourceSetsChecker +import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.* /** * Interface for generic checks of a Gradle Project with any Kotlin Gradle Plugin applied. @@ -101,6 +98,7 @@ internal interface KotlinGradleProjectChecker { DeprecatedKotlinNativeTargetsChecker, MissingNativeStdlibChecker, UnusedSourceSetsChecker, + AndroidSourceSetLayoutV1SourceSetsNotFoundChecker, ) } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt index 6c63d5e5b64..5634634e4da 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/KotlinToolingDiagnostics.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.plugin.diagnostics import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider +import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.ERROR import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic.Severity.WARNING import org.jetbrains.kotlin.gradle.plugin.sources.android.multiplatformAndroidSourceSetLayoutV1 import org.jetbrains.kotlin.gradle.plugin.sources.android.multiplatformAndroidSourceSetLayoutV2 @@ -161,4 +162,20 @@ object KotlinToolingDiagnostics { object FailedToGetAgpVersionWarning : ToolingDiagnosticFactory(WARNING) { operator fun invoke() = build("Failed to get AndroidGradlePluginVersion") } + + object AndroidSourceSetLayoutV1SourceSetsNotFoundError : ToolingDiagnosticFactory(ERROR) { + operator fun invoke(nameOfRequestedSourceSet: String) = build( + """ + KotlinSourceSet with name '$nameOfRequestedSourceSet' not found: + The SourceSet requested ('$nameOfRequestedSourceSet') was renamed in Kotlin 1.9.0 + + In order to migrate you might want to replace: + sourceSets.getByName("androidTest") -> sourceSets.getByName("androidUnitTest") + sourceSets.getByName("androidAndroidTest") -> sourceSets.getByName("androidInstrumentedTest") + + Learn more about the new Kotlin/Android SourceSet Layout: + https://kotlinlang.org/docs/whatsnew18.html#kotlin-multiplatform-a-new-android-source-set-layout + """.trimIndent() + ) + } } diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/AndroidSourceSetLayoutV1SourceSetsNotFoundChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/AndroidSourceSetLayoutV1SourceSetsNotFoundChecker.kt new file mode 100644 index 00000000000..39ea23bcd10 --- /dev/null +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/AndroidSourceSetLayoutV1SourceSetsNotFoundChecker.kt @@ -0,0 +1,41 @@ +/* + * 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.diagnostics.checkers + +import org.gradle.api.UnknownDomainObjectException +import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle +import org.jetbrains.kotlin.gradle.plugin.configurationResult +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.AndroidSourceSetLayoutV1SourceSetsNotFoundError +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector +import org.jetbrains.kotlin.gradle.plugin.sources.android.kotlinAndroidSourceSetLayout +import org.jetbrains.kotlin.gradle.plugin.sources.android.multiplatformAndroidSourceSetLayoutV2 +import org.jetbrains.kotlin.tooling.core.withClosure + +internal object AndroidSourceSetLayoutV1SourceSetsNotFoundChecker : KotlinGradleProjectChecker { + + private val androidSourceSetRegex by lazy { Regex("""(androidTest|androidAndroidTest)\w*""") } + + override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) { + /* Checker will only try to provide additional diagnostics if the project configuration failed */ + val failure = project.configurationResult.await() as? KotlinPluginLifecycle.ProjectConfigurationResult.Failure ?: return + + /* Checker is only relevant if multiplatformAndroidSourceSetLayoutV2 is applied */ + if (project.kotlinAndroidSourceSetLayout != multiplatformAndroidSourceSetLayoutV2) return + + val allReasons = failure.failures.withClosure { listOfNotNull(it.cause) } + + val unknownAndroidSourceSetNames = allReasons.filterIsInstance() + .filter { it.message.orEmpty().contains("KotlinSourceSet") } + .mapNotNull { androidSourceSetRegex.find(it.message.orEmpty()) } + .map { it.value } + + unknownAndroidSourceSetNames.forEach { unknownAndroidSourceSetName -> + collector.report(project, AndroidSourceSetLayoutV1SourceSetsNotFoundError(unknownAndroidSourceSetName)) + } + } +}