Fix explicitApiMode could be overwritten by freeCompilerArgs
Now tasks has a separate task input for 'explicitApiMode' which is passed to Kotlin compiler via arg, rather than free compiler args. ^KT-57653 Fixed
This commit is contained in:
committed by
Space Team
parent
d3043b6f1c
commit
2ea65bd658
+6
-1
@@ -34,7 +34,10 @@ interface KotlinTopLevelExtensionConfig {
|
||||
/**
|
||||
* Different modes that can be used to set the level of issue reporting for [KotlinTopLevelExtensionConfig.explicitApi] option.
|
||||
*/
|
||||
enum class ExplicitApiMode(val cliOption: String) {
|
||||
enum class ExplicitApiMode(
|
||||
@Deprecated("Should not be exposed in api", level = DeprecationLevel.ERROR)
|
||||
val cliOption: String
|
||||
) {
|
||||
/** Report issues as errors. */
|
||||
Strict("strict"),
|
||||
|
||||
@@ -44,5 +47,7 @@ enum class ExplicitApiMode(val cliOption: String) {
|
||||
/** Disable issues reporting. */
|
||||
Disabled("disable");
|
||||
|
||||
@Deprecated("Should not be exposed in api", level = DeprecationLevel.ERROR)
|
||||
@Suppress("DEPRECATION_ERROR")
|
||||
fun toCompilerArg() = "-Xexplicit-api=$cliOption"
|
||||
}
|
||||
|
||||
+145
@@ -0,0 +1,145 @@
|
||||
/*
|
||||
* 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
|
||||
|
||||
import org.gradle.api.logging.LogLevel
|
||||
import org.gradle.util.GradleVersion
|
||||
import org.jetbrains.kotlin.gradle.testbase.*
|
||||
import org.jetbrains.kotlin.konan.target.HostManager
|
||||
import org.jetbrains.kotlin.konan.target.KonanTarget
|
||||
import org.junit.jupiter.api.DisplayName
|
||||
import kotlin.io.path.appendText
|
||||
|
||||
@DisplayName("Explicit API DSL")
|
||||
@JvmGradlePluginTests
|
||||
class ExplicitApiIT : KGPBaseTest() {
|
||||
|
||||
@DisplayName("Explicit api warning mode produces warnings")
|
||||
@GradleTest
|
||||
fun explicitApiWarning(gradleVersion: GradleVersion) {
|
||||
project(
|
||||
"simpleProject",
|
||||
gradleVersion,
|
||||
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
) {
|
||||
buildGradle.appendText(
|
||||
"""
|
||||
|
|
||||
|kotlin.explicitApiWarning()
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
build("compileKotlin") {
|
||||
assertTasksExecuted(":compileKotlin")
|
||||
|
||||
assertCompilerArgument(":compileKotlin", "-Xexplicit-api=warning")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("Explicit api strict mode produces errors on violation")
|
||||
@GradleTest
|
||||
fun explicitApiStrict(gradleVersion: GradleVersion) {
|
||||
project(
|
||||
"simpleProject",
|
||||
gradleVersion,
|
||||
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
) {
|
||||
buildGradle.appendText(
|
||||
"""
|
||||
|
|
||||
|kotlin.explicitApi()
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
buildAndFail("compileKotlin") {
|
||||
assertTasksFailed(":compileKotlin")
|
||||
|
||||
assertCompilerArgument(":compileKotlin", "-Xexplicit-api=strict")
|
||||
assertOutputContains("Visibility must be specified in explicit API mode")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("KT-57653: Explicit api warning mode is not overridden by freeCompilerArgs")
|
||||
@GradleTest
|
||||
fun explicitApiWarningFreeArgsOverride(gradleVersion: GradleVersion) {
|
||||
project(
|
||||
"simpleProject",
|
||||
gradleVersion,
|
||||
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
) {
|
||||
buildGradle.appendText(
|
||||
//language=groovy
|
||||
"""
|
||||
|
|
||||
|kotlin.explicitApiWarning()
|
||||
|
|
||||
|tasks.withType(org.jetbrains.kotlin.gradle.tasks.KotlinCompile.class).configureEach {
|
||||
| compilerOptions.freeCompilerArgs.add("-Xcontext-receivers")
|
||||
|}
|
||||
|
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
build("compileKotlin") {
|
||||
assertTasksExecuted(":compileKotlin")
|
||||
|
||||
assertCompilerArgument(":compileKotlin", "-Xcontext-receivers")
|
||||
assertCompilerArgument(":compileKotlin", "-Xexplicit-api=warning")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@DisplayName("MPP: explicit api warning works for MPP tasks")
|
||||
@GradleTest
|
||||
@MppGradlePluginTests
|
||||
fun explicitApiMpp(gradleVersion: GradleVersion) {
|
||||
project(
|
||||
"new-mpp-lib-and-app/sample-lib",
|
||||
gradleVersion,
|
||||
buildOptions = defaultBuildOptions.copy(logLevel = LogLevel.DEBUG)
|
||||
) {
|
||||
buildGradle.appendText(
|
||||
//language=groovy
|
||||
"""
|
||||
|
|
||||
|kotlin.explicitApiWarning()
|
||||
""".trimMargin()
|
||||
)
|
||||
|
||||
build(":compileCommonMainKotlinMetadata") {
|
||||
assertTasksExecuted(":compileCommonMainKotlinMetadata")
|
||||
assertCompilerArgument(":compileCommonMainKotlinMetadata", "-Xexplicit-api=warning")
|
||||
}
|
||||
|
||||
build(":compileKotlinJvm6") {
|
||||
assertTasksExecuted(":compileKotlinJvm6")
|
||||
assertCompilerArgument(":compileKotlinJvm6", "-Xexplicit-api=warning")
|
||||
}
|
||||
|
||||
build(":compileKotlinNodeJs") {
|
||||
assertTasksExecuted(":compileKotlinNodeJs")
|
||||
assertCompilerArgument(":compileKotlinNodeJs", "-Xexplicit-api=warning")
|
||||
}
|
||||
|
||||
val nativeTaskName = when (HostManager.host) {
|
||||
KonanTarget.LINUX_X64 -> ":compileKotlinLinux64"
|
||||
KonanTarget.MACOS_ARM64 -> ":compileKotlinMacos64"
|
||||
KonanTarget.MINGW_X64 -> ":compileKotlinMingw64"
|
||||
else -> null
|
||||
}
|
||||
if (nativeTaskName != null) {
|
||||
build(nativeTaskName) {
|
||||
assertTasksExecuted(nativeTaskName)
|
||||
assertNativeTasksCommandLineArguments(nativeTaskName) {
|
||||
assertCommandLineArgumentsContain("-Xexplicit-api=warning", commandLineArguments = it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+12
@@ -156,6 +156,18 @@ abstract class KotlinTopLevelExtension(internal val project: Project) : KotlinTo
|
||||
}
|
||||
}
|
||||
|
||||
internal fun ExplicitApiMode.toCompilerValue() = when (this) {
|
||||
ExplicitApiMode.Strict -> "strict"
|
||||
ExplicitApiMode.Warning -> "warning"
|
||||
ExplicitApiMode.Disabled -> "disable"
|
||||
}
|
||||
|
||||
internal fun KotlinTopLevelExtension.explicitApiModeAsCompilerArg(): String? {
|
||||
val cliOption = explicitApi?.toCompilerValue()
|
||||
|
||||
return cliOption?.let { "-Xexplicit-api=$it" }
|
||||
}
|
||||
|
||||
open class KotlinProjectExtension @Inject constructor(project: Project) : KotlinTopLevelExtension(project), KotlinSourceSetContainer {
|
||||
override var sourceSets: NamedDomainObjectContainer<KotlinSourceSet>
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
|
||||
-25
@@ -1,25 +0,0 @@
|
||||
/*
|
||||
* Copyright 2010-2017 JetBrains s.r.o.
|
||||
*
|
||||
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||
* you may not use this file except in compliance with the License.
|
||||
* You may obtain a copy of the License at
|
||||
*
|
||||
* http://www.apache.org/licenses/LICENSE-2.0
|
||||
*
|
||||
* Unless required by applicable law or agreed to in writing, software
|
||||
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||
* See the License for the specific language governing permissions and
|
||||
* limitations under the License.
|
||||
*/
|
||||
|
||||
package org.jetbrains.kotlin.gradle.dsl
|
||||
|
||||
import org.jetbrains.kotlin.cli.common.arguments.CommonToolArguments
|
||||
|
||||
fun KotlinCommonToolOptions.copyFreeCompilerArgsToArgs(args: CommonToolArguments) {
|
||||
// cast to List<Any> is important because in Groovy a GString can be inside of a list
|
||||
val freeArgs = (freeCompilerArgs as List<Any>).map(Any::toString)
|
||||
args.freeArgs += freeArgs
|
||||
}
|
||||
+2
-1
@@ -3,6 +3,7 @@
|
||||
package org.jetbrains.kotlin.gradle.kpm.idea
|
||||
|
||||
import org.jetbrains.kotlin.compilerRunner.konanHome
|
||||
import org.jetbrains.kotlin.gradle.dsl.explicitApiModeAsCompilerArg
|
||||
import org.jetbrains.kotlin.gradle.idea.kpm.IdeaKpmProject
|
||||
import org.jetbrains.kotlin.gradle.idea.kpm.IdeaKpmProjectImpl
|
||||
import org.jetbrains.kotlin.gradle.idea.serialize.IdeaKotlinExtrasSerializationExtension
|
||||
@@ -147,7 +148,7 @@ internal fun IdeaKpmProjectBuildingContext.IdeaKpmProject(extension: KotlinPm20P
|
||||
return IdeaKpmProjectImpl(
|
||||
gradlePluginVersion = extension.project.getKotlinPluginVersion(),
|
||||
coreLibrariesVersion = extension.coreLibrariesVersion,
|
||||
explicitApiModeCliOption = extension.explicitApi?.cliOption,
|
||||
explicitApiModeCliOption = extension.explicitApiModeAsCompilerArg(),
|
||||
kotlinNativeHome = File(extension.project.konanHome).absoluteFile,
|
||||
modules = extension.modules.map { module -> IdeaKpmModule(module) }
|
||||
)
|
||||
|
||||
-16
@@ -320,17 +320,6 @@ internal fun sourcesJarTaskNamed(
|
||||
}
|
||||
|
||||
internal fun Project.setupGeneralKotlinExtensionParameters() {
|
||||
val sourceSetsInMainCompilation by lazy {
|
||||
kotlinExtension.sourceSets.filter { sourceSet ->
|
||||
sourceSet.internal.compilations.any {
|
||||
// kotlin main compilation
|
||||
it.isMain()
|
||||
// android compilation which is NOT in tested variant
|
||||
|| (it as? KotlinJvmAndroidCompilation)?.let { getTestedVariantData(it.androidVariant) == null } == true
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
kotlinExtension.sourceSets.all { sourceSet ->
|
||||
(sourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run {
|
||||
|
||||
@@ -348,11 +337,6 @@ internal fun Project.setupGeneralKotlinExtensionParameters() {
|
||||
is String -> add(propertyValue)
|
||||
is Iterable<*> -> addAll(propertyValue.map { it.toString() })
|
||||
}
|
||||
|
||||
val explicitApiState = project.kotlinExtension.explicitApi?.toCompilerArg()
|
||||
// do not look into lazy set if explicitApiMode was not enabled
|
||||
if (explicitApiState != null && sourceSet in sourceSetsInMainCompilation)
|
||||
add(explicitApiState)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
@@ -21,6 +21,7 @@ import org.gradle.api.tasks.Exec
|
||||
import org.gradle.api.tasks.TaskProvider
|
||||
import org.gradle.language.base.plugins.LifecycleBasePlugin
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinNativeCompilerOptions
|
||||
import org.jetbrains.kotlin.gradle.dsl.topLevelExtension
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilation.Companion.TEST_COMPILATION_NAME
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinCompilationInfo.KPM
|
||||
import org.jetbrains.kotlin.gradle.plugin.KotlinPluginLifecycle.Stage.ReadyForExecution
|
||||
@@ -380,6 +381,7 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
|
||||
konanTarget: KonanTarget
|
||||
): TaskProvider<KotlinNativeCompile> {
|
||||
val project = compilationInfo.project
|
||||
val ext = project.topLevelExtension
|
||||
val compileTaskProvider = project.registerTask<KotlinNativeCompile>(
|
||||
compilationInfo.compileKotlinTaskName,
|
||||
listOf(
|
||||
@@ -400,6 +402,10 @@ open class KotlinNativeTargetConfigurator<T : KotlinNativeTarget> : AbstractKotl
|
||||
}
|
||||
it.compilerOptions.useK2.disallowChanges()
|
||||
it.runViaBuildToolsApi.value(false).disallowChanges() // K/N is not yet supported
|
||||
|
||||
it.explicitApiMode
|
||||
.value(project.providers.provider { ext.explicitApi })
|
||||
.finalizeValueOnRead()
|
||||
}
|
||||
|
||||
compilationInfo.classesDirs.from(compileTaskProvider.map { it.outputFile })
|
||||
|
||||
+7
@@ -16,6 +16,7 @@ import org.gradle.api.artifacts.result.DependencyResult
|
||||
import org.gradle.api.artifacts.result.ResolvedDependencyResult
|
||||
import org.gradle.api.file.*
|
||||
import org.gradle.api.model.ObjectFactory
|
||||
import org.gradle.api.provider.Property
|
||||
import org.gradle.api.provider.Provider
|
||||
import org.gradle.api.provider.ProviderFactory
|
||||
import org.gradle.api.tasks.*
|
||||
@@ -146,6 +147,10 @@ abstract class AbstractKotlinNativeCompile<
|
||||
@get:Internal
|
||||
abstract val baseName: String
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal abstract val explicitApiMode: Property<ExplicitApiMode>
|
||||
|
||||
@get:Internal
|
||||
protected val konanTarget by project.provider {
|
||||
when (val compilation = compilation) {
|
||||
@@ -457,6 +462,8 @@ internal constructor(
|
||||
}
|
||||
|
||||
KotlinNativeCompilerOptionsHelper.fillCompilerArguments(compilerOptions, args)
|
||||
|
||||
explicitApiMode.orNull?.run { args.explicitApi = toCompilerValue() }
|
||||
}
|
||||
|
||||
pluginClasspath { args ->
|
||||
|
||||
+5
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.compilerRunner.GradleCompilerRunner
|
||||
import org.jetbrains.kotlin.compilerRunner.UsesCompilerSystemPropertiesService
|
||||
import org.jetbrains.kotlin.compilerRunner.createGradleCompilerRunner
|
||||
import org.jetbrains.kotlin.daemon.common.MultiModuleICSettings
|
||||
import org.jetbrains.kotlin.gradle.dsl.ExplicitApiMode
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinCommonCompilerOptions
|
||||
import org.jetbrains.kotlin.gradle.incremental.UsesIncrementalModuleInfoBuildService
|
||||
import org.jetbrains.kotlin.gradle.internal.UsesClassLoadersCachingBuildService
|
||||
@@ -109,6 +110,10 @@ abstract class AbstractKotlinCompile<T : CommonCompilerArguments> @Inject constr
|
||||
@get:Internal
|
||||
val startParameters = BuildReportsService.getStartParameters(project)
|
||||
|
||||
@get:Input
|
||||
@get:Optional
|
||||
internal abstract val explicitApiMode: Property<ExplicitApiMode>
|
||||
|
||||
@get:Internal
|
||||
internal abstract val suppressKotlinOptionsFreeArgsModificationWarning: Property<Boolean>
|
||||
|
||||
|
||||
+2
@@ -165,6 +165,8 @@ abstract class Kotlin2JsCompile @Inject constructor(
|
||||
args.fragmentRefines = multiplatformStructure.fragmentRefinesCompilerArgs
|
||||
}
|
||||
|
||||
explicitApiMode.orNull?.run { args.explicitApi = toCompilerValue() }
|
||||
|
||||
// Overriding freeArgs from compilerOptions with enhanced one + additional one set on execution phase
|
||||
// containing additional arguments based on the js compilation configuration
|
||||
args.freeArgs = executionTimeFreeCompilerArgs ?: enhancedFreeCompilerArgs.get().toList()
|
||||
|
||||
+3
-2
@@ -29,9 +29,8 @@ import org.jetbrains.kotlin.compilerRunner.GradleCompilerEnvironment
|
||||
import org.jetbrains.kotlin.compilerRunner.IncrementalCompilationEnvironment
|
||||
import org.jetbrains.kotlin.compilerRunner.OutputItemsCollectorImpl
|
||||
import org.jetbrains.kotlin.config.JvmTarget
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptions
|
||||
import org.jetbrains.kotlin.gradle.dsl.*
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmCompilerOptionsHelper
|
||||
import org.jetbrains.kotlin.gradle.dsl.KotlinJvmOptions
|
||||
import org.jetbrains.kotlin.gradle.dsl.jvm.JvmTargetValidationMode
|
||||
import org.jetbrains.kotlin.gradle.dsl.usesK2
|
||||
import org.jetbrains.kotlin.gradle.internal.tasks.allOutputFiles
|
||||
@@ -248,6 +247,8 @@ abstract class KotlinCompile @Inject constructor(
|
||||
if (localExecutionTimeFreeCompilerArgs != null) {
|
||||
args.freeArgs = localExecutionTimeFreeCompilerArgs
|
||||
}
|
||||
|
||||
explicitApiMode.orNull?.run { args.explicitApi = toCompilerValue() }
|
||||
}
|
||||
|
||||
pluginClasspath { args ->
|
||||
|
||||
+2
@@ -90,6 +90,8 @@ abstract class KotlinCompileCommon @Inject constructor(
|
||||
|
||||
args.destination = destinationDirectory.get().asFile.normalize().absolutePath
|
||||
|
||||
explicitApiMode.orNull?.run { args.explicitApi = toCompilerValue() }
|
||||
|
||||
KotlinCommonCompilerOptionsHelper.fillCompilerArguments(compilerOptions, args)
|
||||
|
||||
val localExecutionTimeFreeCompilerArgs = executionTimeFreeCompilerArgs
|
||||
|
||||
+4
@@ -121,6 +121,10 @@ internal abstract class AbstractKotlinCompileConfig<TASK : AbstractKotlinCompile
|
||||
}
|
||||
task.runViaBuildToolsApi.convention(propertiesProvider.runKotlinCompilerViaBuildToolsApi).finalizeValueOnRead()
|
||||
task.classLoadersCachingService.value(cachedClassLoadersService).disallowChanges()
|
||||
|
||||
task.explicitApiMode
|
||||
.value(project.providers.provider { ext.explicitApi })
|
||||
.finalizeValueOnRead()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-7
@@ -100,7 +100,7 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotl
|
||||
|
||||
|
||||
constructor(project: Project, ext: KotlinTopLevelExtension) : super(
|
||||
project, ext, languageSettings = getDefaultLangSetting(project, ext)
|
||||
project, ext, languageSettings = getDefaultLangSetting(project)
|
||||
)
|
||||
|
||||
companion object {
|
||||
@@ -111,12 +111,8 @@ internal open class BaseKotlinCompileConfig<TASK : KotlinCompile> : AbstractKotl
|
||||
private const val JAR_ARTIFACT_TYPE = "jar"
|
||||
const val CLASSPATH_ENTRY_SNAPSHOT_ARTIFACT_TYPE = "classpath-entry-snapshot"
|
||||
|
||||
private fun getDefaultLangSetting(project: Project, ext: KotlinTopLevelExtension): Provider<LanguageSettings> {
|
||||
return project.provider {
|
||||
DefaultLanguageSettingsBuilder().also {
|
||||
it.freeCompilerArgsProvider = project.provider { listOfNotNull(ext.explicitApi?.toCompilerArg()) }
|
||||
}
|
||||
}
|
||||
private fun getDefaultLangSetting(project: Project): Provider<LanguageSettings> {
|
||||
return project.provider { DefaultLanguageSettingsBuilder() }
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+1
-1
@@ -140,6 +140,6 @@ class KotlinCompileApiTest {
|
||||
fun testTopLevelExtension() {
|
||||
plugin.kotlinExtension.explicitApi = ExplicitApiMode.Strict
|
||||
project.evaluate()
|
||||
assertTrue(ExplicitApiMode.Strict.toCompilerArg() in taskImpl.compilerOptions.freeCompilerArgs.get())
|
||||
assertEquals(ExplicitApiMode.Strict, taskImpl.explicitApiMode.orNull)
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user