[Gradle] Report KotlinTargetAlreadyDeclared from checker

Rephrase diagnostic message and add kotl.in link for details.

^KT-59316 Verification Pending
This commit is contained in:
Anton Lakotka
2023-07-17 23:10:21 +02:00
committed by Space Team
parent 0e34d0b01a
commit b08d12e477
5 changed files with 58 additions and 58 deletions
@@ -14,11 +14,8 @@ import org.jetbrains.kotlin.gradle.InternalKotlinGradlePluginApi
import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinTargetAlreadyDeclared
import org.jetbrains.kotlin.gradle.plugin.diagnostics.kotlinToolingDiagnosticsCollector
import org.jetbrains.kotlin.gradle.plugin.hierarchy.KotlinHierarchyDslImpl
import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
import javax.inject.Inject
@Suppress("DEPRECATION")
@@ -217,9 +214,6 @@ internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCre
}
existingTarget == null -> {
if (this is KotlinMultiplatformExtension) {
project.reportIfTargetOfTheSameTypeAlreadyCreated(targets, targetPreset, targetName)
}
val newTarget = targetPreset.createTarget(targetName)
targets.add(newTarget)
configure(newTarget)
@@ -237,20 +231,3 @@ internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCre
}
}
private fun Project.reportIfTargetOfTheSameTypeAlreadyCreated(
targets: NamedDomainObjectCollection<KotlinTarget>,
preset: KotlinTargetPreset<*>,
targetName: String,
) {
val existingTargets = targets.matching { it.preset?.name == preset.name }
val targetDslFunctionName = when(preset) {
is KotlinJsIrTargetPreset -> "js"
is KotlinJsTargetPreset -> "js"
is KotlinAndroidTargetPreset -> "androidTarget"
else -> preset.name
}
if (existingTargets.isNotEmpty()) {
kotlinToolingDiagnosticsCollector.report(this, KotlinTargetAlreadyDeclared(targetDslFunctionName, targetName, Throwable()))
}
}
@@ -9,8 +9,8 @@ import org.gradle.api.Plugin
import org.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.AndroidMainSourceSetConventionsChecker
import org.jetbrains.kotlin.gradle.dsl.IosSourceSetConventionChecker
import org.jetbrains.kotlin.gradle.dsl.PlatformSourceSetConventionsChecker
import org.jetbrains.kotlin.gradle.dsl.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.PlatformSourceSetConventionsChecker
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.*
@@ -114,6 +114,7 @@ internal interface KotlinGradleProjectChecker {
PlatformSourceSetConventionsChecker,
AndroidMainSourceSetConventionsChecker,
IosSourceSetConventionChecker,
KotlinTargetAlreadyDeclaredChecker,
)
}
}
@@ -548,27 +548,15 @@ object KotlinToolingDiagnostics {
}
object KotlinTargetAlreadyDeclared : ToolingDiagnosticFactory(WARNING) {
operator fun invoke(targetDslFunctionName: String, targetName: String, trace: Throwable?) = build(
operator fun invoke(targetDslFunctionName: String) = build(
"""
Kotlin Target '$targetDslFunctionName()' is already declared.
Declaring multiple Kotlin Targets of the same type is deprecated.
Declaring multiple Kotlin Targets of the same type is not recommended
and will become an error in the upcoming Kotlin releases.
i.e.
kotlin {
$targetDslFunctionName()
$targetDslFunctionName("$targetName") /* <- second '$targetDslFunctionName' target in the project is deprecated */
}
Please use different Gradle Projects or create Kotlin Compilations.
For example:
kotlin {
$targetDslFunctionName() {
val $targetName by compilations.creating
}
}
""".trimIndent(),
throwable = trace
Read https://kotl.in/04i2n7 for details.
""".trimIndent()
)
}
}
@@ -0,0 +1,46 @@
/*
* 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.jetbrains.kotlin.gradle.plugin.KotlinTarget
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.KotlinTargetAlreadyDeclared
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinAndroidTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinJsTargetPreset
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMetadataTarget
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
internal object KotlinTargetAlreadyDeclaredChecker : KotlinGradleProjectChecker {
override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) {
val targets = multiplatformExtension?.awaitTargets() ?: return
val duplicatedTargets = targets
.filter { it !is KotlinMetadataTarget }
.groupBy { it.preset?.name }
.filterValues { it.size > 1 }
for (targetsGroup in duplicatedTargets.values) {
val targetDslFunctionName = targetsGroup.first()
.targetDslFunctionName
// skip targets without known dsl function such as external targets
?: continue
collector.report(project, KotlinTargetAlreadyDeclared(targetDslFunctionName))
}
}
/**
* DSL names are taken from [org.jetbrains.kotlin.gradle.dsl.KotlinTargetContainerWithPresetFunctions]
*/
private val KotlinTarget.targetDslFunctionName
get() = when (preset) {
is KotlinJsIrTargetPreset -> "js"
is KotlinJsTargetPreset -> "js"
is KotlinAndroidTargetPreset -> "androidTarget"
else -> preset?.name
}
}
@@ -67,10 +67,7 @@ class KotlinTargetAlreadyDeclaredTest {
}
project.evaluate()
project.assertContainsDiagnostic(
KotlinTargetAlreadyDeclared("jvm", "jvm2", null),
ignoreThrowable = true
)
project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("jvm"))
}
@Test
@@ -83,10 +80,7 @@ class KotlinTargetAlreadyDeclaredTest {
}
project.evaluate()
project.assertContainsDiagnostic(
KotlinTargetAlreadyDeclared("linuxArm64", "linux", null),
ignoreThrowable = true
)
project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("linuxArm64"))
}
@Test
@@ -101,10 +95,7 @@ class KotlinTargetAlreadyDeclaredTest {
}
project.evaluate()
project.assertContainsDiagnostic(
KotlinTargetAlreadyDeclared("androidTarget", "android2", null),
ignoreThrowable = true
)
project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("androidTarget"))
}
@Test
@@ -117,9 +108,6 @@ class KotlinTargetAlreadyDeclaredTest {
}
project.evaluate()
project.assertContainsDiagnostic(
KotlinTargetAlreadyDeclared("js", "nodejs", null),
ignoreThrowable = true
)
project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("js"))
}
}