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 b9e4ac13aee..25cde869311 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 @@ -354,6 +354,16 @@ object KotlinToolingDiagnostics { } } } + + object KotlinSourceSetDependsOnDefaultCompilationSourceSet : ToolingDiagnosticFactory(WARNING) { + operator fun invoke(dependeeName: String, dependencyName: String) = build( + """ + Kotlin Source Set '$dependeeName' can't depend on '$dependencyName' which is a default source set for compilation. + None of source sets can depend on the compilation default source sets. + Please remove this dependency edge. + """.trimIndent() + ) + } } private fun String.indentLines(nSpaces: Int = 4, skipFirstLine: Boolean = true): String { diff --git a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/KotlinSourceSetTreeDependsOnMismatchChecker.kt b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/KotlinSourceSetTreeDependsOnMismatchChecker.kt index 6f7edffd87e..8642546cd87 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/KotlinSourceSetTreeDependsOnMismatchChecker.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/common/kotlin/org/jetbrains/kotlin/gradle/plugin/diagnostics/checkers/KotlinSourceSetTreeDependsOnMismatchChecker.kt @@ -9,6 +9,7 @@ import org.jetbrains.kotlin.gradle.plugin.KotlinSourceSet import org.jetbrains.kotlin.gradle.plugin.KotlinTargetHierarchy.SourceSetTree import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinSourceSetDependsOnDefaultCompilationSourceSet import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinSourceSetTreeDependsOnMismatch import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget @@ -53,6 +54,8 @@ internal object KotlinSourceSetTreeDependsOnMismatchChecker : KotlinGradleProjec } } + reportAllDependentsOfLeafSourceSets(collector, leafSourceSets.keys, reverseSourceSetDependencies) + for ((badSourceSet, _) in badSourceSets) { val dependents = reverseSourceSetDependencies[badSourceSet].orEmpty() @@ -63,11 +66,8 @@ internal object KotlinSourceSetTreeDependsOnMismatchChecker : KotlinGradleProjec // until underlying dependent source sets relations are fixed if (dependents.any { it in badSourceSets }) continue - // If [badSourceSet] is also a leaf source set then all its dependents edges are incorrect - // Therefore report everything that depend on the leaf source set (i.e. iosX64Test -> iosX64Main) - // NB: Cyclic diagnostics such as iosX64Main -> commonMain -> iosX64Main is handled in [AbstractKotlinSourceSet::dependsOn] if (badSourceSet in leafSourceSets) { - dependents.forEach { collector.report(project, KotlinSourceSetTreeDependsOnMismatch(it.name, badSourceSet.name)) } + // It should be reported in [reportAllDependentsOfLeafSourceSets] continue } @@ -105,6 +105,22 @@ internal object KotlinSourceSetTreeDependsOnMismatchChecker : KotlinGradleProjec } } + private fun KotlinGradleProjectCheckerContext.reportAllDependentsOfLeafSourceSets( + collector: KotlinToolingDiagnosticsCollector, + leafSourceSets: Set, + reverseSourceSetDependencies: Map>, + ) { + for (leafSourceSet in leafSourceSets) { + val dependents = reverseSourceSetDependencies[leafSourceSet].orEmpty() + for (dependent in dependents) { + collector.report( + project, + KotlinSourceSetDependsOnDefaultCompilationSourceSet(dependent.name, leafSourceSet.name) + ) + } + } + } + private fun KotlinGradleProjectCheckerContext.reportSingleSourceSetWithDifferentSourceSetTree( collector: KotlinToolingDiagnosticsCollector, badSourceSet: KotlinSourceSet, diff --git a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/diagnosticsTests/KotlinSourceSetTreeDependsOnMismatchTest.kt b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/diagnosticsTests/KotlinSourceSetTreeDependsOnMismatchTest.kt index 785ace64c45..4b111a83152 100644 --- a/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/diagnosticsTests/KotlinSourceSetTreeDependsOnMismatchTest.kt +++ b/libraries/tools/kotlin-gradle-plugin/src/functionalTest/kotlin/org/jetbrains/kotlin/gradle/unitTests/diagnosticsTests/KotlinSourceSetTreeDependsOnMismatchTest.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle.unitTests.diagnosticsTests import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinSourceSetTreeDependsOnMismatch +import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinSourceSetDependsOnDefaultCompilationSourceSet import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnostic import org.jetbrains.kotlin.gradle.plugin.diagnostics.kotlinToolingDiagnosticsCollector import org.jetbrains.kotlin.gradle.util.* @@ -27,9 +28,13 @@ class KotlinSourceSetTreeDependsOnMismatchTest { } } project.evaluate() + val expectedDiagnosticsIds = listOf( + KotlinSourceSetTreeDependsOnMismatch.id, + KotlinSourceSetDependsOnDefaultCompilationSourceSet.id + ) return project.kotlinToolingDiagnosticsCollector .getDiagnosticsForProject(project) - .filter { it.id == KotlinSourceSetTreeDependsOnMismatch.id } // ignore other diagnostics that can appear as well + .filter { it.id in expectedDiagnosticsIds } // ignore other diagnostics that can appear as well } private fun checkSingleBadSourceSetDependency( @@ -86,13 +91,31 @@ class KotlinSourceSetTreeDependsOnMismatchTest { @Test fun `iosX64Test cant depend on iosX64Main`() = checkSingleBadSourceSetDependency( dependent = "iosX64Test", - dependency = "iosX64Main" + dependency = "iosX64Main", + KotlinSourceSetDependsOnDefaultCompilationSourceSet(dependeeName = "iosX64Test", dependencyName = "iosX64Main") ) @Test fun `iosX64Main cant depend on iosX64Test`() = checkSingleBadSourceSetDependency( dependent = "iosX64Main", - dependency = "iosX64Test" + dependency = "iosX64Test", + KotlinSourceSetDependsOnDefaultCompilationSourceSet(dependeeName = "iosX64Main", dependencyName = "iosX64Test") + ) + + @Test + fun `iosX64Main cant depend on iosArm64Main`() = checkSingleBadSourceSetDependency( + dependent = "iosX64Main", + dependency = "iosArm64Main", + KotlinSourceSetDependsOnDefaultCompilationSourceSet(dependeeName = "iosX64Main", dependencyName = "iosArm64Main") + ) + + @Test + fun `iosX64Main cant depend on iosArm64Main -- mixed scenario`() = checkDiagnostics { + sourceSets.getByName("iosX64Main").dependsOn(sourceSets.getByName("iosArm64Main")) + sourceSets.getByName("iosArm64Test").dependsOn(sourceSets.getByName("iosArm64Main")) + }.assertDiagnostics( + KotlinSourceSetDependsOnDefaultCompilationSourceSet(dependeeName = "iosArm64Test", dependencyName = "iosArm64Main"), + KotlinSourceSetDependsOnDefaultCompilationSourceSet(dependeeName = "iosX64Main", dependencyName = "iosArm64Main") ) @Test