[Gradle] Introduce checker of 'kotlin.internal' properties

Those properties are meant for internal use and/or "hacking". Using them
by design provokes big non-suppressible warning
This commit is contained in:
Dmitry Savvinov
2023-07-20 10:05:19 +02:00
committed by Space Team
parent 6c88b92b88
commit a132d37292
7 changed files with 90 additions and 13 deletions
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.gradle.testbase
import org.gradle.testkit.runner.BuildResult
import org.jetbrains.kotlin.gradle.BaseGradleIT
import org.jetbrains.kotlin.gradle.internals.VERBOSE_DIAGNOSTIC_SEPARATOR
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
import org.jetbrains.kotlin.gradle.plugin.diagnostics.ToolingDiagnosticFactory
import kotlin.test.assertNull
import kotlin.test.assertTrue
@@ -68,10 +69,13 @@ fun String.assertNoDiagnostic(diagnosticFactory: ToolingDiagnosticFactory, withS
/**
* NB: Needs verbose mode of diagnostics, see [org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.internalVerboseDiagnostics]
* Because this mode is enabled by the 'kotlin.internal'-property, actual output will always contain
* [org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed].
* For the sake of clarity, this diagnostic is filtered by default.
*/
fun BuildResult.extractProjectsAndTheirVerboseDiagnostics(): String = buildString {
var diagnosticStarted = false
val currentDiagnostic = StringBuilder()
val currentDiagnostic = mutableListOf<String>()
fun startDiagnostic(line: String, lineIndex: Int) {
require(!diagnosticStarted) {
@@ -79,12 +83,12 @@ fun BuildResult.extractProjectsAndTheirVerboseDiagnostics(): String = buildStrin
"Unexpected start of diagnostic $line on line ${lineIndex + 1}. The end of the previous diagnostic wasn't found yet"
}
currentDiagnostic.appendLine(line)
currentDiagnostic += line
diagnosticStarted = true
}
fun continueDiagnostic(line: String) {
currentDiagnostic.appendLine(line)
currentDiagnostic += line
}
fun endDiagnostic(line: String, lineIndex: Int) {
@@ -93,9 +97,16 @@ fun BuildResult.extractProjectsAndTheirVerboseDiagnostics(): String = buildStrin
"Unexpected end of diagnostic $line on line ${lineIndex + 1}"
}
currentDiagnostic.appendLine(line)
currentDiagnostic.appendLine()
append(currentDiagnostic.toString())
currentDiagnostic += line
// Suppress InternalKotlinGradlePluginProperties, but only if the single property it complains about is
// 'kotlin.internal.verboseDiagnostics'
val offendingProperties = currentDiagnostic.asSequence().filter { it.startsWith("kotlin.internal.") }
if (KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed.id !in currentDiagnostic.first() ||
offendingProperties.singleOrNull() != "kotlin.internal.verboseDiagnostics"
) {
appendLine(currentDiagnostic.joinToString(separator = "\n", postfix = "\n"))
}
currentDiagnostic.clear()
diagnosticStarted = false
@@ -48,6 +48,7 @@ import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLI
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_DEFAULT_DEPENDENCY
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_STDLIB_JDK_VARIANTS_VERSION_ALIGNMENT
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.KOTLIN_SUPPRESS_EXPERIMENTAL_IC_OPTIMIZATIONS_WARNING
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider.PropertyNames.MPP_13X_FLAGS_SET_BY_PLUGIN
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
import org.jetbrains.kotlin.gradle.plugin.diagnostics.reportDiagnosticOncePerBuild
import org.jetbrains.kotlin.gradle.plugin.statistics.KotlinBuildStatsService
@@ -213,9 +214,9 @@ internal class PropertiesProvider private constructor(private val project: Proje
get() = booleanProperty(KOTLIN_NATIVE_DEPENDENCY_PROPAGATION)
var mpp13XFlagsSetByPlugin: Boolean
get() = booleanProperty("kotlin.internal.mpp.13X.flags.setByPlugin") ?: false
get() = booleanProperty(MPP_13X_FLAGS_SET_BY_PLUGIN) ?: false
set(value) {
project.extensions.extraProperties.set("kotlin.internal.mpp.13X.flags.setByPlugin", "$value")
project.extensions.extraProperties.set(MPP_13X_FLAGS_SET_BY_PLUGIN, "$value")
}
val mppHierarchicalStructureByDefault: Boolean
@@ -581,7 +582,8 @@ internal class PropertiesProvider private constructor(private val project: Proje
localProperties.getProperty(propName)
}
private fun propertiesWithPrefix(prefix: String): Map<String, String> {
@UnsafeApi
internal fun propertiesWithPrefix(prefix: String): Map<String, String> {
val result: MutableMap<String, String> = mutableMapOf()
project.properties.forEach { (name, value) ->
if (name.startsWith(prefix) && value is String) {
@@ -604,7 +606,6 @@ internal class PropertiesProvider private constructor(private val project: Proje
const val KOTLIN_MPP_ENABLE_GRANULAR_SOURCE_SETS_METADATA = "kotlin.mpp.enableGranularSourceSetsMetadata"
const val KOTLIN_MPP_ENABLE_COMPATIBILITY_METADATA_VARIANT = "kotlin.mpp.enableCompatibilityMetadataVariant"
const val KOTLIN_MPP_ENABLE_CINTEROP_COMMONIZATION = "kotlin.mpp.enableCInteropCommonization"
const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT = "kotlin.internal.mpp.hierarchicalStructureByDefault"
const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_SUPPORT = "kotlin.mpp.hierarchicalStructureSupport"
const val KOTLIN_MPP_DEPRECATED_PROPERTIES_NO_WARN = "kotlin.mpp.deprecatedProperties.nowarn"
const val KOTLIN_MPP_ANDROID_GRADLE_PLUGIN_COMPATIBILITY_NO_WARN = "kotlin.mpp.androidGradlePluginCompatibility.nowarn"
@@ -629,17 +630,24 @@ internal class PropertiesProvider private constructor(private val project: Proje
const val KOTLIN_COMPILER_USE_PRECISE_COMPILATION_RESULTS_BACKUP = "kotlin.compiler.preciseCompilationResultsBackup"
const val KOTLIN_COMPILER_KEEP_INCREMENTAL_COMPILATION_CACHES_IN_MEMORY = "kotlin.compiler.keepIncrementalCompilationCachesInMemory"
const val KOTLIN_SUPPRESS_EXPERIMENTAL_IC_OPTIMIZATIONS_WARNING = "kotlin.compiler.suppressExperimentalICOptimizationsWarning"
const val KOTLIN_CREATE_DEFAULT_MULTIPLATFORM_PUBLICATIONS = "kotlin.internal.mpp.createDefaultMultiplatformPublications"
const val KOTLIN_RUN_COMPILER_VIA_BUILD_TOOLS_API = "kotlin.compiler.runViaBuildToolsApi"
const val KOTLIN_MPP_ALLOW_LEGACY_DEPENDENCIES = "kotlin.mpp.allow.legacy.dependencies"
const val KOTLIN_PUBLISH_JVM_ENVIRONMENT_ATTRIBUTE = "kotlin.publishJvmEnvironmentAttribute"
const val KOTLIN_EXPERIMENTAL_TRY_K2 = "kotlin.experimental.tryK2"
const val KOTLIN_INTERNAL_VERBOSE_DIAGNOSTICS = "kotlin.internal.verboseDiagnostics"
const val KOTLIN_SUPPRESS_GRADLE_PLUGIN_WARNINGS = "kotlin.suppressGradlePluginWarnings"
const val KOTLIN_SUPPRESS_GRADLE_PLUGIN_ERRORS = "kotlin.internal.suppressGradlePluginErrors"
const val KOTLIN_NATIVE_IGNORE_DISABLED_TARGETS = "kotlin.native.ignoreDisabledTargets"
const val KOTLIN_NATIVE_SUPPRESS_EXPERIMENTAL_ARTIFACTS_DSL_WARNING = "kotlin.native.suppressExperimentalArtifactsDslWarning"
const val KONAN_DATA_DIR = "konan.data.dir"
/**
* Internal properties: builds get big non-suppressible warning when such properties are used
* See [org.jetbrains.kotlin.gradle.plugin.diagnostics.checkers.InternalGradlePropertiesUsageChecker]
**/
const val KOTLIN_MPP_HIERARCHICAL_STRUCTURE_BY_DEFAULT = "$KOTLIN_INTERNAL_NAMESPACE.mpp.hierarchicalStructureByDefault"
const val KOTLIN_CREATE_DEFAULT_MULTIPLATFORM_PUBLICATIONS = "$KOTLIN_INTERNAL_NAMESPACE.mpp.createDefaultMultiplatformPublications"
const val KOTLIN_INTERNAL_VERBOSE_DIAGNOSTICS = "$KOTLIN_INTERNAL_NAMESPACE.verboseDiagnostics"
const val KOTLIN_SUPPRESS_GRADLE_PLUGIN_ERRORS = "$KOTLIN_INTERNAL_NAMESPACE.suppressGradlePluginErrors"
const val MPP_13X_FLAGS_SET_BY_PLUGIN = "$KOTLIN_INTERNAL_NAMESPACE.mpp.13X.flags.setByPlugin"
}
companion object {
@@ -651,6 +659,8 @@ internal class PropertiesProvider private constructor(private val project: Proje
private const val KOTLIN_NATIVE_BINARY_OPTION_PREFIX = "kotlin.native.binary."
internal const val KOTLIN_INTERNAL_NAMESPACE = "kotlin.internal"
operator fun invoke(project: Project): PropertiesProvider =
with(project.extensions.extraProperties) {
if (!has(CACHED_PROVIDER_EXT_NAME)) {
@@ -114,6 +114,7 @@ internal interface KotlinGradleProjectChecker {
AndroidMainSourceSetConventionsChecker,
IosSourceSetConventionChecker,
KotlinTargetAlreadyDeclaredChecker,
InternalGradlePropertiesUsageChecker,
)
}
}
@@ -602,6 +602,19 @@ object KotlinToolingDiagnostics {
""".trimIndent()
)
}
object InternalKotlinGradlePluginPropertiesUsed : ToolingDiagnosticFactory(WARNING) {
operator fun invoke(propertiesUsed: Collection<String>) = build(
"""
|ATTENTION! This build uses the following Kotlin Gradle Plugin properties:
|
|${propertiesUsed.joinToString(separator = "\n")}
|
|kotlin.internal-properties are not recommended for production use.
|Stability and future compatibility of the build is not guaranteed.
""".trimMargin()
)
}
}
private fun String.indentLines(nSpaces: Int = 4, skipFirstLine: Boolean = true): String {
@@ -26,6 +26,9 @@ internal class ToolingDiagnosticRenderingOptions(
internal fun ToolingDiagnostic.isSuppressed(options: ToolingDiagnosticRenderingOptions): Boolean {
return when {
// Non-suppressible
id == KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed.id -> false
severity == ToolingDiagnostic.Severity.WARNING -> id in options.suppressedWarningIds
severity == ToolingDiagnostic.Severity.ERROR -> id in options.suppressedErrorIds
@@ -0,0 +1,33 @@
/*
* 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.KotlinPluginLifecycle
import org.jetbrains.kotlin.gradle.plugin.PropertiesProvider
import org.jetbrains.kotlin.gradle.plugin.await
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectChecker
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinGradleProjectCheckerContext
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnostics
import org.jetbrains.kotlin.gradle.plugin.diagnostics.KotlinToolingDiagnosticsCollector
import org.jetbrains.kotlin.tooling.core.UnsafeApi
internal object InternalGradlePropertiesUsageChecker : KotlinGradleProjectChecker {
override suspend fun KotlinGradleProjectCheckerContext.runChecks(collector: KotlinToolingDiagnosticsCollector) {
KotlinPluginLifecycle.Stage.ReadyForExecution.await()
@OptIn(UnsafeApi::class)
val internalPropertiesUsed = kotlinPropertiesProvider.propertiesWithPrefix(PropertiesProvider.KOTLIN_INTERNAL_NAMESPACE).keys
val internalPropertiesFiltered = internalPropertiesUsed.minus(PropertiesProvider.PropertyNames.MPP_13X_FLAGS_SET_BY_PLUGIN)
if (internalPropertiesFiltered.isEmpty()) return
collector.reportOncePerGradleBuild(
project,
KotlinToolingDiagnostics.InternalKotlinGradlePluginPropertiesUsed(internalPropertiesFiltered.sorted()),
// Known issue in edge case: if several Gradle subprojects declare internal properties, only one will be reported
key = InternalGradlePropertiesUsageChecker::class.qualifiedName!!
)
}
}
@@ -0,0 +1,6 @@
[InternalKotlinGradlePluginPropertiesUsed | WARNING] ATTENTION! This build uses the following Kotlin Gradle Plugin properties:
kotlin.internal.suppressGradlePluginErrors
kotlin.internal-properties are not recommended for production use.
Stability and future compatibility of the build is not guaranteed.