Add explicit api mode flag to top-level kotlin {} DSL block in Gradle

for both MPP and single-target projects.

For now, it is only applied to source sets that are connected to 'main'
compilation. It seems fine for all projects except android ones.
There's a way to determine android variant for source set,
but importing android projects seems to be made via other code path.

 #KT-36019 Fixed
 #KT-37652 Open
This commit is contained in:
Leonid Startsev
2020-02-13 13:34:19 +03:00
parent 59148cdce4
commit f0dc809255
3 changed files with 67 additions and 32 deletions
@@ -1,17 +1,6 @@
/* /*
* Copyright 2010-2017 JetBrains s.r.o. * Copyright 2010-2020 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.
* 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 package org.jetbrains.kotlin.gradle.dsl
@@ -57,6 +46,12 @@ open class KotlinProjectExtension : KotlinSourceSetContainer {
val experimental: ExperimentalExtension val experimental: ExperimentalExtension
get() = DslObject(this).extensions.getByType(ExperimentalExtension::class.java) get() = DslObject(this).extensions.getByType(ExperimentalExtension::class.java)
var explicitApi: ExplicitApiMode? = null
fun explicitApi() {
explicitApi = ExplicitApiMode.Strict
}
override var sourceSets: NamedDomainObjectContainer<KotlinSourceSet> override var sourceSets: NamedDomainObjectContainer<KotlinSourceSet>
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
get() = DslObject(this).extensions.getByName("sourceSets") as NamedDomainObjectContainer<KotlinSourceSet> get() = DslObject(this).extensions.getByName("sourceSets") as NamedDomainObjectContainer<KotlinSourceSet>
@@ -229,3 +224,11 @@ enum class NativeCacheKind(val produce: String?, val outputKind: CompilerOutputK
NativeCacheKind.values().firstOrNull { it.name.equals(argument, ignoreCase = true) } NativeCacheKind.values().firstOrNull { it.name.equals(argument, ignoreCase = true) }
} }
} }
enum class ExplicitApiMode(private val cliOption: String) {
Strict("strict"),
Warning("warning"),
Disabled("disabled");
fun toCompilerArg() = "-Xexplicit-api=$cliOption"
}
@@ -1,3 +1,8 @@
/*
* Copyright 2010-2020 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 package org.jetbrains.kotlin.gradle.plugin
import com.android.build.gradle.* import com.android.build.gradle.*
@@ -498,6 +503,7 @@ internal abstract class AbstractKotlinPlugin(
fun configureProjectGlobalSettings(project: Project, kotlinPluginVersion: String) { fun configureProjectGlobalSettings(project: Project, kotlinPluginVersion: String) {
configureDefaultVersionsResolutionStrategy(project, kotlinPluginVersion) configureDefaultVersionsResolutionStrategy(project, kotlinPluginVersion)
configureClassInspectionForIC(project) configureClassInspectionForIC(project)
project.setupGeneralKotlinExtensionParameters()
} }
fun configureTarget( fun configureTarget(
@@ -1,5 +1,5 @@
/* /*
* Copyright 2010-2018 JetBrains s.r.o. and Kotlin Programming Language contributors. * Copyright 2010-2020 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. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.gradle.dsl.configureOrCreate
import org.jetbrains.kotlin.gradle.dsl.kotlinExtension import org.jetbrains.kotlin.gradle.dsl.kotlinExtension
import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension import org.jetbrains.kotlin.gradle.dsl.multiplatformExtension
import org.jetbrains.kotlin.gradle.plugin.* import org.jetbrains.kotlin.gradle.plugin.*
import org.jetbrains.kotlin.gradle.plugin.mpp.KotlinMultiplatformPlugin.Companion.sourceSetFreeCompilerArgsPropertyName
import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder import org.jetbrains.kotlin.gradle.plugin.sources.DefaultLanguageSettingsBuilder
import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope import org.jetbrains.kotlin.gradle.plugin.sources.KotlinDependencyScope
import org.jetbrains.kotlin.gradle.plugin.sources.checkSourceSetVisibilityRequirements import org.jetbrains.kotlin.gradle.plugin.sources.checkSourceSetVisibilityRequirements
@@ -97,6 +98,7 @@ class KotlinMultiplatformPlugin(
// propagate compiler plugin options to the source set language settings // propagate compiler plugin options to the source set language settings
setupAdditionalCompilerArguments(project) setupAdditionalCompilerArguments(project)
project.setupGeneralKotlinExtensionParameters()
project.pluginManager.apply(ScriptingGradleSubplugin::class.java) project.pluginManager.apply(ScriptingGradleSubplugin::class.java)
} }
@@ -134,22 +136,6 @@ class KotlinMultiplatformPlugin(
val associatedCompilation = primaryCompilationsBySourceSet[sourceSet] ?: metadataCompilation val associatedCompilation = primaryCompilationsBySourceSet[sourceSet] ?: metadataCompilation
project.tasks.getByName(associatedCompilation.compileKotlinTaskName) as AbstractCompile project.tasks.getByName(associatedCompilation.compileKotlinTaskName) as AbstractCompile
} }
// Also set ad-hoc free compiler args from the internal project property
freeCompilerArgsProvider = project.provider {
val propertyValue = with(project.extensions.extraProperties) {
val sourceSetFreeCompilerArgsPropertyName = sourceSetFreeCompilerArgsPropertyName(sourceSet.name)
if (has(sourceSetFreeCompilerArgsPropertyName)) {
get(sourceSetFreeCompilerArgsPropertyName)
} else null
}
mutableListOf<String>().apply {
when (propertyValue) {
is String -> add(propertyValue)
is Iterable<*> -> addAll(propertyValue.map { it.toString() })
}
}
}
} }
} }
} }
@@ -314,7 +300,7 @@ class KotlinMultiplatformPlugin(
companion object { companion object {
const val METADATA_TARGET_NAME = "metadata" const val METADATA_TARGET_NAME = "metadata"
private fun sourceSetFreeCompilerArgsPropertyName(sourceSetName: String) = internal fun sourceSetFreeCompilerArgsPropertyName(sourceSetName: String) =
"kotlin.mpp.freeCompilerArgsForSourceSet.$sourceSetName" "kotlin.mpp.freeCompilerArgsForSourceSet.$sourceSetName"
internal const val GRADLE_NO_METADATA_WARNING = "This build consumes Gradle module metadata but does not produce " + internal const val GRADLE_NO_METADATA_WARNING = "This build consumes Gradle module metadata but does not produce " +
@@ -404,3 +390,43 @@ internal fun sourcesJarTask(
return result return result
} }
internal fun Project.setupGeneralKotlinExtensionParameters() {
val sourceSetsInMainCompilation by lazy {
CompilationSourceSetUtil.compilationsBySourceSets(project).filterValues { compilations ->
compilations.any {
// kotlin main compilation
it.name == KotlinCompilation.MAIN_COMPILATION_NAME
// android compilation which is NOT in tested variant
|| (it as? KotlinJvmAndroidCompilation)?.let { getTestedVariantData(it.androidVariant) == null } == true
}
}.keys
}
kotlinExtension.sourceSets.all { sourceSet ->
(sourceSet.languageSettings as? DefaultLanguageSettingsBuilder)?.run {
// Set ad-hoc free compiler args from the internal project property
freeCompilerArgsProvider = project.provider {
val propertyValue = with(project.extensions.extraProperties) {
val sourceSetFreeCompilerArgsPropertyName = sourceSetFreeCompilerArgsPropertyName(sourceSet.name)
if (has(sourceSetFreeCompilerArgsPropertyName)) {
get(sourceSetFreeCompilerArgsPropertyName)
} else null
}
mutableListOf<String>().apply {
when (propertyValue) {
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)
}
}
}
}
}