[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.*
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.AfterFinaliseDsl
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.Companion.kotlinPropertiesProvider 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.hierarchy.KotlinHierarchyDslImpl
import org.jetbrains.kotlin.gradle.plugin.mpp.* import org.jetbrains.kotlin.gradle.plugin.mpp.*
import org.jetbrains.kotlin.gradle.targets.js.ir.KotlinJsIrTargetPreset
import javax.inject.Inject import javax.inject.Inject
@Suppress("DEPRECATION") @Suppress("DEPRECATION")
@@ -217,9 +214,6 @@ internal fun <T : KotlinTarget> KotlinTargetsContainerWithPresets.configureOrCre
} }
existingTarget == null -> { existingTarget == null -> {
if (this is KotlinMultiplatformExtension) {
project.reportIfTargetOfTheSameTypeAlreadyCreated(targets, targetPreset, targetName)
}
val newTarget = targetPreset.createTarget(targetName) val newTarget = targetPreset.createTarget(targetName)
targets.add(newTarget) targets.add(newTarget)
configure(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.gradle.api.Project
import org.jetbrains.kotlin.gradle.dsl.AndroidMainSourceSetConventionsChecker import org.jetbrains.kotlin.gradle.dsl.AndroidMainSourceSetConventionsChecker
import org.jetbrains.kotlin.gradle.dsl.IosSourceSetConventionChecker 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.KotlinMultiplatformExtension
import org.jetbrains.kotlin.gradle.dsl.PlatformSourceSetConventionsChecker
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.* import org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.*
@@ -114,6 +114,7 @@ internal interface KotlinGradleProjectChecker {
PlatformSourceSetConventionsChecker, PlatformSourceSetConventionsChecker,
AndroidMainSourceSetConventionsChecker, AndroidMainSourceSetConventionsChecker,
IosSourceSetConventionChecker, IosSourceSetConventionChecker,
KotlinTargetAlreadyDeclaredChecker,
) )
} }
} }
@@ -548,27 +548,15 @@ object KotlinToolingDiagnostics {
} }
object KotlinTargetAlreadyDeclared : ToolingDiagnosticFactory(WARNING) { 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. Kotlin Target '$targetDslFunctionName()' is already declared.
Declaring multiple Kotlin Targets of the same type is deprecated.
i.e. Declaring multiple Kotlin Targets of the same type is not recommended
kotlin { and will become an error in the upcoming Kotlin releases.
$targetDslFunctionName()
$targetDslFunctionName("$targetName") /* <- second '$targetDslFunctionName' target in the project is deprecated */
}
Please use different Gradle Projects or create Kotlin Compilations. Read https://kotl.in/04i2n7 for details.
For example: """.trimIndent()
kotlin {
$targetDslFunctionName() {
val $targetName by compilations.creating
}
}
""".trimIndent(),
throwable = trace
) )
} }
} }
@@ -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.evaluate()
project.assertContainsDiagnostic( project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("jvm"))
KotlinTargetAlreadyDeclared("jvm", "jvm2", null),
ignoreThrowable = true
)
} }
@Test @Test
@@ -83,10 +80,7 @@ class KotlinTargetAlreadyDeclaredTest {
} }
project.evaluate() project.evaluate()
project.assertContainsDiagnostic( project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("linuxArm64"))
KotlinTargetAlreadyDeclared("linuxArm64", "linux", null),
ignoreThrowable = true
)
} }
@Test @Test
@@ -101,10 +95,7 @@ class KotlinTargetAlreadyDeclaredTest {
} }
project.evaluate() project.evaluate()
project.assertContainsDiagnostic( project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("androidTarget"))
KotlinTargetAlreadyDeclared("androidTarget", "android2", null),
ignoreThrowable = true
)
} }
@Test @Test
@@ -117,9 +108,6 @@ class KotlinTargetAlreadyDeclaredTest {
} }
project.evaluate() project.evaluate()
project.assertContainsDiagnostic( project.assertContainsDiagnostic(KotlinTargetAlreadyDeclared("js"))
KotlinTargetAlreadyDeclared("js", "nodejs", null),
ignoreThrowable = true
)
} }
} }