Import of middle HMPP target platforms is supported

This commit is contained in:
Andrey Uskov
2019-06-04 01:55:30 +03:00
parent c0594c2ee3
commit c0bf5a6566
28 changed files with 316 additions and 103 deletions
@@ -31,6 +31,7 @@ object CommonPlatforms {
get() = CompatCommonPlatform get() = CompatCommonPlatform
val allSimplePlatforms: List<TargetPlatform> val allSimplePlatforms: List<TargetPlatform>
// TODO(auskov): migrate to SimplePlatform?
get() = sequence { get() = sequence {
yieldAll(JvmPlatforms.allJvmPlatforms) yieldAll(JvmPlatforms.allJvmPlatforms)
yieldAll(KonanPlatforms.allKonanPlatforms) yieldAll(KonanPlatforms.allKonanPlatforms)
@@ -80,3 +80,5 @@ interface TargetPlatformVersion {
fun TargetPlatform?.isCommon(): Boolean = this != null && this.size > 1 fun TargetPlatform?.isCommon(): Boolean = this != null && this.size > 1
fun SimplePlatform.toTargetPlatform(): TargetPlatform = TargetPlatform(setOf(this)) fun SimplePlatform.toTargetPlatform(): TargetPlatform = TargetPlatform(setOf(this))
fun SimplePlatform.serializeToString() = "${this.platformName} [${this.targetPlatformVersion.description}]"
@@ -24,14 +24,11 @@ import com.intellij.psi.PsiElement;
import com.intellij.psi.PsiFile; import com.intellij.psi.PsiFile;
import kotlin.collections.CollectionsKt; import kotlin.collections.CollectionsKt;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.kotlin.platform.DefaultIdeTargetPlatformKindProvider; import org.jetbrains.kotlin.platform.*;
import org.jetbrains.kotlin.platform.IdePlatformKind;
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms; import org.jetbrains.kotlin.platform.jvm.JvmPlatforms;
import org.jetbrains.kotlin.psi.KtCodeFragment; import org.jetbrains.kotlin.psi.KtCodeFragment;
import org.jetbrains.kotlin.psi.KtFile; import org.jetbrains.kotlin.psi.KtFile;
import org.jetbrains.kotlin.psi.KtPsiFactoryKt; import org.jetbrains.kotlin.psi.KtPsiFactoryKt;
import org.jetbrains.kotlin.platform.TargetPlatform;
import org.jetbrains.kotlin.platform.SimplePlatform;
import org.jetbrains.kotlin.scripting.definitions.DefinitionsKt; import org.jetbrains.kotlin.scripting.definitions.DefinitionsKt;
import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition; import org.jetbrains.kotlin.scripting.definitions.ScriptDefinition;
@@ -65,7 +62,7 @@ public class TargetPlatformDetector {
ScriptDefinition scriptDefinition = DefinitionsKt.findScriptDefinition(file); ScriptDefinition scriptDefinition = DefinitionsKt.findScriptDefinition(file);
if (scriptDefinition != null) { if (scriptDefinition != null) {
String platformNameFromScriptDefinition = scriptDefinition.getPlatform(); String platformNameFromScriptDefinition = scriptDefinition.getPlatform();
for (TargetPlatform compilerPlatform : IdePlatformKind.Companion.getAll_PLATFORMS()) { for (TargetPlatform compilerPlatform : CommonPlatforms.INSTANCE.getAllSimplePlatforms()) {
// FIXME(dsavvinov): get rid of matching by name // FIXME(dsavvinov): get rid of matching by name
SimplePlatform simplePlatform = CollectionsKt.single(compilerPlatform); SimplePlatform simplePlatform = CollectionsKt.single(compilerPlatform);
if (simplePlatform.getPlatformName().equals(platformNameFromScriptDefinition)) { if (simplePlatform.getPlatformName().equals(platformNameFromScriptDefinition)) {
@@ -17,6 +17,8 @@ import com.intellij.util.containers.MultiMap
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.gradle.KotlinModule import org.jetbrains.kotlin.gradle.KotlinModule
import org.jetbrains.kotlin.gradle.KotlinPlatform import org.jetbrains.kotlin.gradle.KotlinPlatform
import org.jetbrains.kotlin.gradle.KotlinPlatformContainer
import org.jetbrains.kotlin.gradle.KotlinPlatformContainerImpl
import org.jetbrains.kotlin.idea.util.CopyableDataNodeUserDataProperty import org.jetbrains.kotlin.idea.util.CopyableDataNodeUserDataProperty
import org.jetbrains.plugins.gradle.util.GradleConstants import org.jetbrains.plugins.gradle.util.GradleConstants
import java.io.File import java.io.File
@@ -32,7 +34,13 @@ val DataNode<ModuleData>.kotlinAndroidSourceSets: List<KotlinSourceSetInfo>?
class KotlinSourceSetInfo(val kotlinModule: KotlinModule) : Serializable { class KotlinSourceSetInfo(val kotlinModule: KotlinModule) : Serializable {
var moduleId: String? = null var moduleId: String? = null
var gradleModuleId: String = "" var gradleModuleId: String = ""
var platform: KotlinPlatform = KotlinPlatform.COMMON
var actualPlatforms: KotlinPlatformContainer = KotlinPlatformContainerImpl()
@Deprecated("Returns only single TargetPlatform", ReplaceWith("actualPlatforms.actualPlatforms"), DeprecationLevel.ERROR)
val platform: KotlinPlatform
get() = actualPlatforms.getSinglePlatform()
var defaultCompilerArguments: CommonCompilerArguments? = null var defaultCompilerArguments: CommonCompilerArguments? = null
var compilerArguments: CommonCompilerArguments? = null var compilerArguments: CommonCompilerArguments? = null
var dependencyClasspath: List<String> = emptyList() var dependencyClasspath: List<String> = emptyList()
@@ -254,8 +254,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() } val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() }
for (sourceSet in mppModel.sourceSets.values) { for (sourceSet in mppModel.sourceSets.values) {
if (sourceSet.platform == KotlinPlatform.ANDROID) continue if (sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)) continue
if (sourceSet.platform == KotlinPlatform.COMMON && ignoreCommonSourceSets) continue if (sourceSet.actualPlatforms.supports(KotlinPlatform.COMMON) && ignoreCommonSourceSets) continue
val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx) val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
val existingSourceSetDataNode = sourceSetMap[moduleId]?.first val existingSourceSetDataNode = sourceSetMap[moduleId]?.first
if (existingSourceSetDataNode?.kotlinSourceSet != null) continue if (existingSourceSetDataNode?.kotlinSourceSet != null) continue
@@ -317,7 +317,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
val mppModel = resolverCtx.getMppModel(gradleModule) ?: return val mppModel = resolverCtx.getMppModel(gradleModule) ?: return
if (resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java) == null) return if (resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java) == null) return
processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet -> processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet ->
if (dataNode == null || sourceSet.platform == KotlinPlatform.ANDROID) return@processSourceSets if (dataNode == null || sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)) return@processSourceSets
createContentRootData(sourceSet.sourceDirs, sourceSet.sourceType, dataNode) createContentRootData(sourceSet.sourceDirs, sourceSet.sourceType, dataNode)
createContentRootData(sourceSet.resourceDirs, sourceSet.resourceType, dataNode) createContentRootData(sourceSet.resourceDirs, sourceSet.resourceType, dataNode)
} }
@@ -365,7 +365,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
} }
} }
} }
val sourceSetGraph = GraphBuilder.directed().build<KotlinModule>() val sourceSetGraph = GraphBuilder.directed().build<KotlinSourceSet>()
processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet -> processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet ->
sourceSetGraph.addNode(sourceSet) sourceSetGraph.addNode(sourceSet)
val productionSourceSet = dataNode val productionSourceSet = dataNode
@@ -384,7 +384,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
} }
// Workaround: Non-android source sets have commonMain/commonTest in their dependsOn // Workaround: Non-android source sets have commonMain/commonTest in their dependsOn
// Remove when the same is implemented for Android modules as well // Remove when the same is implemented for Android modules as well
if (sourceSet.platform == KotlinPlatform.ANDROID) { if (sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)) {
val commonSourceSetName = if (sourceSet.isTestModule) { val commonSourceSetName = if (sourceSet.isTestModule) {
KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME
} else { } else {
@@ -398,7 +398,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
} }
val closedSourceSetGraph = Graphs.transitiveClosure(sourceSetGraph) val closedSourceSetGraph = Graphs.transitiveClosure(sourceSetGraph)
for (sourceSet in closedSourceSetGraph.nodes()) { for (sourceSet in closedSourceSetGraph.nodes()) {
val isAndroid = sourceSet.platform == KotlinPlatform.ANDROID val isAndroid = sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)
val fromDataNode = if (isAndroid) { val fromDataNode = if (isAndroid) {
ideModule ideModule
} else { } else {
@@ -418,7 +418,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
sourceSetInfo.addSourceSets(dependeeSourceSets, selfName, gradleModule, resolverCtx) sourceSetInfo.addSourceSets(dependeeSourceSets, selfName, gradleModule, resolverCtx)
} }
} }
if (sourceSet.platform == KotlinPlatform.ANDROID) continue if (sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)) continue
for (dependeeSourceSet in dependeeSourceSets) { for (dependeeSourceSet in dependeeSourceSets) {
val toDataNode = getSiblingKotlinModuleData(dependeeSourceSet, gradleModule, ideModule, resolverCtx) ?: continue val toDataNode = getSiblingKotlinModuleData(dependeeSourceSet, gradleModule, ideModule, resolverCtx) ?: continue
addDependency(fromDataNode, toDataNode, dependeeSourceSet.isTestModule) addDependency(fromDataNode, toDataNode, dependeeSourceSet.isTestModule)
@@ -619,14 +619,15 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
gradleModule: IdeaModule, gradleModule: IdeaModule,
resolverCtx: ProjectResolverContext resolverCtx: ProjectResolverContext
): KotlinSourceSetInfo? { ): KotlinSourceSetInfo? {
if (sourceSet.platform.isNotSupported()) return null if (sourceSet.actualPlatforms.platforms.filter { !it.isNotSupported() }.isEmpty()) return null
return KotlinSourceSetInfo(sourceSet).also { info -> return KotlinSourceSetInfo(sourceSet).also { info ->
val languageSettings = sourceSet.languageSettings val languageSettings = sourceSet.languageSettings
info.moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx) info.moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx)
info.gradleModuleId = getModuleId(resolverCtx, gradleModule) info.gradleModuleId = getModuleId(resolverCtx, gradleModule)
info.platform = sourceSet.platform info.actualPlatforms.addSimplePlatforms(sourceSet.actualPlatforms.platforms)
info.isTestModule = sourceSet.isTestModule info.isTestModule = sourceSet.isTestModule
info.compilerArguments = createCompilerArguments(emptyList(), sourceSet.platform).also { //TODO(auskov): target flours are lost here
info.compilerArguments = createCompilerArguments(emptyList(), sourceSet.actualPlatforms.getSinglePlatform()).also {
it.multiPlatform = true it.multiPlatform = true
it.languageVersion = languageSettings.languageVersion it.languageVersion = languageSettings.languageVersion
it.apiVersion = languageSettings.apiVersion it.apiVersion = languageSettings.apiVersion
@@ -653,7 +654,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() {
return KotlinSourceSetInfo(compilation).also { sourceSetInfo -> return KotlinSourceSetInfo(compilation).also { sourceSetInfo ->
sourceSetInfo.moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx) sourceSetInfo.moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx)
sourceSetInfo.gradleModuleId = getModuleId(resolverCtx, gradleModule) sourceSetInfo.gradleModuleId = getModuleId(resolverCtx, gradleModule)
sourceSetInfo.platform = compilation.platform sourceSetInfo.actualPlatforms.addSimplePlatforms(listOf(compilation.platform))
sourceSetInfo.isTestModule = compilation.isTestModule sourceSetInfo.isTestModule = compilation.isTestModule
sourceSetInfo.compilerArguments = sourceSetInfo.compilerArguments =
createCompilerArguments(compilation.arguments.currentArguments, compilation.platform).also { createCompilerArguments(compilation.arguments.currentArguments, compilation.platform).also {
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.idea.inspections.gradle.findAll
import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion
import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling import org.jetbrains.kotlin.idea.platform.IdePlatformKindTooling
import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData
@@ -52,10 +53,10 @@ class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetDat
val sourceSetData = nodeToImport.data val sourceSetData = nodeToImport.data
val kotlinSourceSet = nodeToImport.kotlinSourceSet ?: continue val kotlinSourceSet = nodeToImport.kotlinSourceSet ?: continue
val ideModule = modelsProvider.findIdeModule(sourceSetData) ?: continue val ideModule = modelsProvider.findIdeModule(sourceSetData) ?: continue
val platform = kotlinSourceSet.platform val platform = kotlinSourceSet.actualPlatforms
val rootModel = modelsProvider.getModifiableRootModel(ideModule) val rootModel = modelsProvider.getModifiableRootModel(ideModule)
if (platform != KotlinPlatform.JVM && platform != KotlinPlatform.ANDROID) { if (!platform.supports(KotlinPlatform.JVM) && !platform.supports(KotlinPlatform.ANDROID)) {
migrateNonJvmSourceFolders(rootModel) migrateNonJvmSourceFolders(rootModel)
} }
@@ -99,16 +100,21 @@ class KotlinSourceSetDataService : AbstractProjectDataService<GradleSourceSetDat
?.data ?.data
?.let { findKotlinPluginVersion(it) }// ?: return null TODO: Fix in CLion or our plugin KT-27623 ?.let { findKotlinPluginVersion(it) }// ?: return null TODO: Fix in CLion or our plugin KT-27623
val platformKind = IdePlatformKindTooling.getTooling(kotlinSourceSet.platform).kind val platformKinds = kotlinSourceSet.actualPlatforms.platforms //TODO(auskov): fix calculation of jvm target
.map { IdePlatformKindTooling.getTooling(it).kind }
// FIXME(dsavvinov): it seems to convert platforms back-and-forth, clean-up needed .flatMap {
val platform = when (platformKind) { when (it) {
is JvmIdePlatformKind -> { is JvmIdePlatformKind -> {
val target = JvmTarget.fromString(moduleData.targetCompatibility ?: "") ?: JvmTarget.DEFAULT val target = JvmTarget.fromString(moduleData.targetCompatibility ?: "") ?: JvmTarget.DEFAULT
JvmPlatforms.jvmPlatformByTargetVersion(target) JvmPlatforms.jvmPlatformByTargetVersion(target).componentPlatforms
}
else -> it.defaultPlatform.componentPlatforms
}
} }
else -> platformKind.defaultPlatform .distinct()
} .toSet()
val platform = TargetPlatform(platformKinds)
val coroutinesProperty = CoroutineSupport.byCompilerArgument( val coroutinesProperty = CoroutineSupport.byCompilerArgument(
mainModuleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project) mainModuleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project)
@@ -26,6 +26,7 @@ import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatformVersion import org.jetbrains.kotlin.platform.TargetPlatformVersion
import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.compat.toIdePlatform import org.jetbrains.kotlin.platform.compat.toIdePlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.utils.DescriptionAware import org.jetbrains.kotlin.utils.DescriptionAware
@Deprecated("Use IdePlatformKind instead.", level = DeprecationLevel.ERROR) @Deprecated("Use IdePlatformKind instead.", level = DeprecationLevel.ERROR)
@@ -189,12 +190,20 @@ class KotlinFacetSettings {
compilerArguments!!.apiVersion = value?.versionString compilerArguments!!.apiVersion = value?.versionString
} }
val targetPlatform: TargetPlatform? var targetPlatform: TargetPlatform? = null
get() { get() {
val compilerArguments = this.compilerArguments ?: return null // This work-around is required in order to fix importing of the proper JVM target version.
return IdePlatformKind.platformByCompilerArguments(compilerArguments) //TODO(auskov): this hack should be removed after fixing equals in SimplePlatform
val args = compilerArguments
val mappedPlatforms = field?.componentPlatforms?.flatMap {
if (JvmPlatforms.defaultJvmPlatform.first() == it && args != null) (IdePlatformKind.platformByCompilerArguments(args)
?: return null) else listOf(it)
}?.toSet() ?: return null
return TargetPlatform(mappedPlatforms)
} }
@Suppress("DEPRECATION_ERROR") @Suppress("DEPRECATION_ERROR")
@Deprecated( @Deprecated(
message = "This accessor is deprecated and will be removed soon, use API from 'org.jetbrains.kotlin.platform.*' packages instead", message = "This accessor is deprecated and will be removed soon, use API from 'org.jetbrains.kotlin.platform.*' packages instead",
@@ -25,16 +25,13 @@ import org.jdom.Element
import org.jdom.Text import org.jdom.Text
import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.load.java.JvmAbi
import org.jetbrains.kotlin.platform.IdePlatformKind import org.jetbrains.kotlin.platform.*
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.impl.FakeK2NativeCompilerArguments import org.jetbrains.kotlin.platform.impl.FakeK2NativeCompilerArguments
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.js.JsPlatform import org.jetbrains.kotlin.platform.js.JsPlatform
import org.jetbrains.kotlin.platform.jvm.JdkPlatform import org.jetbrains.kotlin.platform.jvm.JdkPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatform import org.jetbrains.kotlin.platform.jvm.JvmPlatform
import org.jetbrains.kotlin.platform.konan.KonanPlatform import org.jetbrains.kotlin.platform.konan.KonanPlatform
import org.jetbrains.kotlin.platform.oldFashionedDescription
import org.jetbrains.kotlin.platform.orDefault
import java.lang.reflect.Modifier import java.lang.reflect.Modifier
import kotlin.reflect.KClass import kotlin.reflect.KClass
import kotlin.reflect.full.superclasses import kotlin.reflect.full.superclasses
@@ -67,7 +64,7 @@ private fun readV1Config(element: Element): KotlinFacetSettings {
val targetPlatformName = versionInfoElement?.getOptionValue("targetPlatformName") val targetPlatformName = versionInfoElement?.getOptionValue("targetPlatformName")
val languageLevel = versionInfoElement?.getOptionValue("languageLevel") val languageLevel = versionInfoElement?.getOptionValue("languageLevel")
val apiLevel = versionInfoElement?.getOptionValue("apiLevel") val apiLevel = versionInfoElement?.getOptionValue("apiLevel")
val targetPlatform = IdePlatformKind.All_PLATFORMS val targetPlatform = CommonPlatforms.allSimplePlatforms.union(setOf(CommonPlatforms.defaultCommonPlatform))
.firstOrNull { it.oldFashionedDescription == targetPlatformName } .firstOrNull { it.oldFashionedDescription == targetPlatformName }
?: JvmIdePlatformKind.defaultPlatform // FIXME(dsavvinov): choose proper default ?: JvmIdePlatformKind.defaultPlatform // FIXME(dsavvinov): choose proper default
@@ -115,20 +112,30 @@ private fun readV1Config(element: Element): KotlinFacetSettings {
this.compilerSettings = compilerSettings this.compilerSettings = compilerSettings
this.compilerArguments = compilerArguments this.compilerArguments = compilerArguments
this.targetPlatform = IdePlatformKind.platformByCompilerArguments(compilerArguments)
} }
} }
fun Element.getFacetPlatformByConfigurationElement(): TargetPlatform { fun Element.getFacetPlatformByConfigurationElement(): TargetPlatform {
val platformNames = getAttributeValue("allPlatforms")?.split('/')?.toSet()
if (platformNames != null) {
return TargetPlatform(CommonPlatforms.allSimplePlatforms
.flatMap { it.componentPlatforms }
.filter { platformNames.contains(it.serializeToString()) }
.toSet())
}
// failed to read list of all platforms. Fallback to legacy algorythm
val platformName = getAttributeValue("platform") val platformName = getAttributeValue("platform")
return IdePlatformKind.All_PLATFORMS // this code could be simplified using union after fixing the equals method in SimplePlatform
.firstOrNull { it.oldFashionedDescription == platformName } val allPlatforms = ArrayList(CommonPlatforms.allSimplePlatforms).also { it.add(CommonPlatforms.defaultCommonPlatform) }
.orDefault() return allPlatforms.firstOrNull { it.oldFashionedDescription == platformName }.orDefault()
} }
private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings { private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings {
return KotlinFacetSettings().apply { return KotlinFacetSettings().apply {
element.getAttributeValue("useProjectSettings")?.let { useProjectSettings = it.toBoolean() } element.getAttributeValue("useProjectSettings")?.let { useProjectSettings = it.toBoolean() }
val targetPlatform = element.getFacetPlatformByConfigurationElement() val targetPlatform = element.getFacetPlatformByConfigurationElement()
this.targetPlatform = targetPlatform
element.getChild("implements")?.let { element.getChild("implements")?.let {
val items = it.getChildren("implement") val items = it.getChildren("implement")
implementedModuleNames = if (items.isNotEmpty()) { implementedModuleNames = if (items.isNotEmpty()) {
@@ -288,7 +295,7 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) {
val filter = SkipDefaultsSerializationFilter() val filter = SkipDefaultsSerializationFilter()
targetPlatform?.let { targetPlatform?.let {
element.setAttribute("platform", it.oldFashionedDescription) element.setAttribute("allPlatforms", it.componentPlatforms.map { it.serializeToString() }.joinToString(separator = "/"))
} }
if (!useProjectSettings) { if (!useProjectSettings) {
element.setAttribute("useProjectSettings", useProjectSettings.toString()) element.setAttribute("useProjectSettings", useProjectSettings.toString())
@@ -7,6 +7,7 @@
package org.jetbrains.kotlin.platform package org.jetbrains.kotlin.platform
import com.intellij.openapi.diagnostic.Logger
import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.config.isJps import org.jetbrains.kotlin.config.isJps
@@ -14,14 +15,10 @@ import org.jetbrains.kotlin.platform.impl.CommonIdePlatformKind
import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind import org.jetbrains.kotlin.platform.impl.JsIdePlatformKind
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind import org.jetbrains.kotlin.platform.impl.NativeIdePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.js.JsPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatform
import org.jetbrains.kotlin.platform.konan.KonanPlatform
import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult import org.jetbrains.kotlin.utils.addToStdlib.firstNotNullResult
abstract class IdePlatformKind<Kind : IdePlatformKind<Kind>> { abstract class IdePlatformKind<Kind : IdePlatformKind<Kind>> {
abstract val platforms: List<TargetPlatform> abstract fun supportsTargetPlatform(platform: TargetPlatform): Boolean
abstract val defaultPlatform: TargetPlatform abstract val defaultPlatform: TargetPlatform
@@ -67,7 +64,6 @@ abstract class IdePlatformKind<Kind : IdePlatformKind<Kind>> {
kinds kinds
} }
val All_PLATFORMS by lazy { ALL_KINDS.flatMap { it.platforms } }
fun <Args : CommonCompilerArguments> platformByCompilerArguments(arguments: Args): TargetPlatform? = fun <Args : CommonCompilerArguments> platformByCompilerArguments(arguments: Args): TargetPlatform? =
ALL_KINDS.firstNotNullResult { it.platformByCompilerArguments(arguments) } ALL_KINDS.firstNotNullResult { it.platformByCompilerArguments(arguments) }
@@ -76,10 +72,10 @@ abstract class IdePlatformKind<Kind : IdePlatformKind<Kind>> {
} }
val TargetPlatform.idePlatformKind: IdePlatformKind<*> val TargetPlatform.idePlatformKind: IdePlatformKind<*>
get() = when (val single = singleOrNull()) { get() = IdePlatformKind.ALL_KINDS.filter { it.supportsTargetPlatform(this) }.let { list ->
null -> CommonIdePlatformKind when {
is JvmPlatform -> JvmIdePlatformKind list.size == 1 -> list.first()
is JsPlatform -> JsIdePlatformKind list.size > 1 -> list.first().also { Logger.getInstance(IdePlatformKind.javaClass).warn("Found more than one IdePlatformKind [$list] for target [$this].") }
is KonanPlatform -> NativeIdePlatformKind else -> error("Unknown platform $this")
else -> error("Unknown platform $single") }
} }
@@ -13,6 +13,7 @@ import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
import org.jetbrains.kotlin.platform.* import org.jetbrains.kotlin.platform.*
object CommonIdePlatformKind : IdePlatformKind<CommonIdePlatformKind>() { object CommonIdePlatformKind : IdePlatformKind<CommonIdePlatformKind>() {
override fun supportsTargetPlatform(platform: TargetPlatform) = platform.isCommon()
override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? {
return if (arguments is K2MetadataCompilerArguments) return if (arguments is K2MetadataCompilerArguments)
@@ -31,7 +32,6 @@ object CommonIdePlatformKind : IdePlatformKind<CommonIdePlatformKind>() {
return K2MetadataCompilerArguments() // TODO(dsavvinov): review that, as now MPP !== K2Metadata return K2MetadataCompilerArguments() // TODO(dsavvinov): review that, as now MPP !== K2Metadata
} }
override val platforms get() = listOf(CommonPlatforms.defaultCommonPlatform)
override val defaultPlatform get() = CommonPlatforms.defaultCommonPlatform override val defaultPlatform get() = CommonPlatforms.defaultCommonPlatform
override val argumentsClass get() = K2MetadataCompilerArguments::class.java override val argumentsClass get() = K2MetadataCompilerArguments::class.java
@@ -17,6 +17,7 @@ import org.jetbrains.kotlin.platform.TargetPlatformVersion
import org.jetbrains.kotlin.platform.js.JsPlatforms import org.jetbrains.kotlin.platform.js.JsPlatforms
object JsIdePlatformKind : IdePlatformKind<JsIdePlatformKind>() { object JsIdePlatformKind : IdePlatformKind<JsIdePlatformKind>() {
override fun supportsTargetPlatform(platform: TargetPlatform): Boolean = platforms.contains(platform)
override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? {
return if (arguments is K2JSCompilerArguments) return if (arguments is K2JSCompilerArguments)
@@ -25,7 +26,7 @@ object JsIdePlatformKind : IdePlatformKind<JsIdePlatformKind>() {
null null
} }
override val platforms get() = listOf(JsPlatforms.defaultJsPlatform) val platforms get() = listOf(JsPlatforms.defaultJsPlatform)
override val defaultPlatform get() = JsPlatforms.defaultJsPlatform override val defaultPlatform get() = JsPlatforms.defaultJsPlatform
@Deprecated( @Deprecated(
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
object JvmIdePlatformKind : IdePlatformKind<JvmIdePlatformKind>() { object JvmIdePlatformKind : IdePlatformKind<JvmIdePlatformKind>() {
override fun supportsTargetPlatform(platform: TargetPlatform): Boolean = platforms.contains(platform)
override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? {
if (arguments !is K2JVMCompilerArguments) return null if (arguments !is K2JVMCompilerArguments) return null
@@ -42,7 +43,7 @@ object JvmIdePlatformKind : IdePlatformKind<JvmIdePlatformKind>() {
return K2JVMCompilerArguments() return K2JVMCompilerArguments()
} }
override val platforms: List<TargetPlatform> = JvmTarget.values().map { ver -> JvmPlatforms.jvmPlatformByTargetVersion(ver) } + listOf(JvmPlatforms.unspecifiedJvmPlatform) val platforms: List<TargetPlatform> = JvmTarget.values().map { ver -> JvmPlatforms.jvmPlatformByTargetVersion(ver) } + listOf(JvmPlatforms.unspecifiedJvmPlatform)
override val defaultPlatform get() = JvmPlatforms.defaultJvmPlatform override val defaultPlatform get() = JvmPlatforms.defaultJvmPlatform
override val argumentsClass get() = K2JVMCompilerArguments::class.java override val argumentsClass get() = K2JVMCompilerArguments::class.java
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.platform.TargetPlatformVersion
import org.jetbrains.kotlin.platform.konan.KonanPlatforms import org.jetbrains.kotlin.platform.konan.KonanPlatforms
object NativeIdePlatformKind : IdePlatformKind<NativeIdePlatformKind>() { object NativeIdePlatformKind : IdePlatformKind<NativeIdePlatformKind>() {
override fun supportsTargetPlatform(platform: TargetPlatform): Boolean = platform == KonanPlatforms.defaultKonanPlatform
override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? {
return if (arguments is FakeK2NativeCompilerArguments) return if (arguments is FakeK2NativeCompilerArguments)
@@ -37,9 +38,6 @@ object NativeIdePlatformKind : IdePlatformKind<NativeIdePlatformKind>() {
) )
override fun getDefaultPlatform(): IdePlatform<*, *> = Platform override fun getDefaultPlatform(): IdePlatform<*, *> = Platform
override val platforms
get() = listOf(KonanPlatforms.defaultKonanPlatform)
override val argumentsClass override val argumentsClass
get() = FakeK2NativeCompilerArguments::class.java get() = FakeK2NativeCompilerArguments::class.java
@@ -37,7 +37,7 @@ class FrameworkLibraryValidatorWithDynamicDescription(
private val context: LibrariesValidatorContext, private val context: LibrariesValidatorContext,
private val validatorsManager: FacetValidatorsManager, private val validatorsManager: FacetValidatorsManager,
private val libraryCategoryName: String, private val libraryCategoryName: String,
private val getPlatform: () -> TargetPlatform private val getPlatform: () -> TargetPlatform?
) : FrameworkLibraryValidator() { ) : FrameworkLibraryValidator() {
private val IdePlatformKind<*>.libraryDescription: CustomLibraryDescription? private val IdePlatformKind<*>.libraryDescription: CustomLibraryDescription?
get() = this.tooling.getLibraryDescription(context.module.project) get() = this.tooling.getLibraryDescription(context.module.project)
@@ -69,7 +69,7 @@ class FrameworkLibraryValidatorWithDynamicDescription(
} }
override fun check(): ValidationResult { override fun check(): ValidationResult {
val targetPlatform = getPlatform() val targetPlatform = getPlatform() ?: return ValidationResult("No target platforms selected")
if (checkLibraryIsConfigured(targetPlatform.idePlatformKind)) { if (checkLibraryIsConfigured(targetPlatform.idePlatformKind)) {
val conflictingPlatforms = IdePlatformKind.ALL_KINDS val conflictingPlatforms = IdePlatformKind.ALL_KINDS
@@ -28,6 +28,6 @@ class KotlinLibraryValidatorCreator : KotlinFacetValidatorCreator() {
DelegatingLibrariesValidatorContext(editorContext), DelegatingLibrariesValidatorContext(editorContext),
validatorsManager, validatorsManager,
"kotlin" "kotlin"
) { editor.chosenPlatform!! } ) { editor.getChosenPlatform() }
} }
} }
@@ -25,7 +25,6 @@ fun KotlinDependency.deepCopy(cache: MutableMap<Any, Any>): KotlinDependency {
interface KotlinModule : Serializable { interface KotlinModule : Serializable {
val name: String val name: String
val platform: KotlinPlatform
val dependencies: Set<KotlinDependency> val dependencies: Set<KotlinDependency>
val isTestModule: Boolean val isTestModule: Boolean
} }
@@ -35,6 +34,11 @@ interface KotlinSourceSet : KotlinModule {
val sourceDirs: Set<File> val sourceDirs: Set<File>
val resourceDirs: Set<File> val resourceDirs: Set<File>
val dependsOnSourceSets: Set<String> val dependsOnSourceSets: Set<String>
val actualPlatforms: KotlinPlatformContainer
@Deprecated("Returns single target platform", ReplaceWith("actualPlatforms.actualPlatforms"), DeprecationLevel.ERROR)
val platform: KotlinPlatform
get() = actualPlatforms.getSinglePlatform()
companion object { companion object {
const val COMMON_MAIN_SOURCE_SET_NAME = "commonMain" const val COMMON_MAIN_SOURCE_SET_NAME = "commonMain"
@@ -73,6 +77,8 @@ interface KotlinCompilation : KotlinModule {
val arguments: KotlinCompilationArguments val arguments: KotlinCompilationArguments
val dependencyClasspath: List<String> val dependencyClasspath: List<String>
val disambiguationClassifier: String? val disambiguationClassifier: String?
val platform: KotlinPlatform
companion object { companion object {
const val MAIN_COMPILATION_NAME = "main" const val MAIN_COMPILATION_NAME = "main"
@@ -81,7 +87,7 @@ interface KotlinCompilation : KotlinModule {
} }
enum class KotlinPlatform(val id: String) { enum class KotlinPlatform(val id: String) {
COMMON("common"), COMMON("common"), // this platform is left only for compatibility with NMPP (should not be used in HMPP)
JVM("jvm"), JVM("jvm"),
JS("js"), JS("js"),
NATIVE("native"), NATIVE("native"),
@@ -92,6 +98,17 @@ enum class KotlinPlatform(val id: String) {
} }
} }
interface KotlinPlatformContainer: Serializable {
val platforms: Collection<KotlinPlatform>
fun supports(simplePlatform: KotlinPlatform): Boolean
fun addSimplePlatforms(platforms: Collection<KotlinPlatform>)
fun getSinglePlatform() = platforms.singleOrNull() ?: KotlinPlatform.COMMON
}
interface KotlinTargetJar : Serializable { interface KotlinTargetJar : Serializable {
val archiveFile: File? val archiveFile: File?
} }
@@ -48,13 +48,18 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
val sourceSets = buildSourceSets(dependencyResolver, project) ?: return null val sourceSets = buildSourceSets(dependencyResolver, project) ?: return null
val sourceSetMap = sourceSets.map { it.name to it }.toMap() val sourceSetMap = sourceSets.map { it.name to it }.toMap()
val targets = buildTargets(sourceSetMap, dependencyResolver, project) ?: return null val targets = buildTargets(sourceSetMap, dependencyResolver, project) ?: return null
computeSourceSetsDeferredInfo(sourceSets, targets) computeSourceSetsDeferredInfo(sourceSetMap, targets, isHMPPEnabled(project))
val coroutinesState = getCoroutinesState(project) val coroutinesState = getCoroutinesState(project)
reportUnresolvedDependencies(targets) reportUnresolvedDependencies(targets)
val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME
return KotlinMPPGradleModelImpl(sourceSetMap, targets, ExtraFeaturesImpl(coroutinesState), kotlinNativeHome) return KotlinMPPGradleModelImpl(sourceSetMap, targets, ExtraFeaturesImpl(coroutinesState), kotlinNativeHome)
} }
private fun isHMPPEnabled(project: Project): Boolean {
//TODO(auskov): replace with Project.isKotlinGranularMetadataEnabled after merging with gradle pranch
return (project.findProperty("kotlin.mpp.enableGranularSourceSetsMetadata") as? String)?.toBoolean() ?: false
}
private fun reportUnresolvedDependencies(targets: Collection<KotlinTarget>) { private fun reportUnresolvedDependencies(targets: Collection<KotlinTarget>) {
targets targets
.asSequence() .asSequence()
@@ -73,13 +78,46 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
return getCoroutines(experimentalExt) as? String return getCoroutines(experimentalExt) as? String
} }
private fun calculateDependsOnClosure(
sourceSet: KotlinSourceSetImpl?,
sourceSetsMap: Map<String, KotlinSourceSetImpl>,
cache: MutableMap<String, Set<String>>
): Set<String> {
return if (sourceSet == null) {
emptySet()
} else {
cache[sourceSet.name] ?: sourceSet.dependsOnSourceSets.flatMap { name ->
calculateDependsOnClosure(
sourceSetsMap[name],
sourceSetsMap,
cache
).union(setOf(name))
}.toSet().also { cache[sourceSet.name] = it }
}
}
private fun buildSourceSets(dependencyResolver: DependencyResolver, project: Project): Collection<KotlinSourceSetImpl>? { private fun buildSourceSets(dependencyResolver: DependencyResolver, project: Project): Collection<KotlinSourceSetImpl>? {
val kotlinExt = project.extensions.findByName("kotlin") ?: return null val kotlinExt = project.extensions.findByName("kotlin") ?: return null
val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null
@Suppress("UNCHECKED_CAST") @Suppress("UNCHECKED_CAST")
val sourceSets = val sourceSets =
(getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>() (getSourceSets(kotlinExt) as? NamedDomainObjectContainer<Named>)?.asMap?.values ?: emptyList<Named>()
return sourceSets.mapNotNull { buildSourceSet(it, dependencyResolver, project) } val allSourceSets = sourceSets.mapNotNull { buildSourceSet(it, dependencyResolver, project) }
val map = allSourceSets.map { it.name to it }.toMap()
val dependsOnCache = HashMap<String, Set<String>>()
return allSourceSets.map { sourceSet ->
KotlinSourceSetImpl(
sourceSet.name,
sourceSet.languageSettings,
sourceSet.sourceDirs,
sourceSet.resourceDirs,
sourceSet.dependencies,
calculateDependsOnClosure(sourceSet, map, dependsOnCache),
sourceSet.actualPlatforms as KotlinPlatformContainerImpl,
sourceSet.isTestModule
)
}
} }
private fun buildSourceSet( private fun buildSourceSet(
@@ -376,8 +414,9 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
} }
private fun computeSourceSetsDeferredInfo( private fun computeSourceSetsDeferredInfo(
sourceSets: Collection<KotlinSourceSetImpl>, sourceSets: Map<String, KotlinSourceSetImpl>,
targets: Collection<KotlinTarget> targets: Collection<KotlinTarget>,
isHMPPEnabled: Boolean
) { ) {
val sourceSetToCompilations = LinkedHashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>() val sourceSetToCompilations = LinkedHashMap<KotlinSourceSet, MutableSet<KotlinCompilation>>()
for (target in targets) { for (target in targets) {
@@ -387,22 +426,29 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService {
} }
} }
} }
for (sourceSet in sourceSets) {
for (sourceSet in sourceSets.values) {
val name = sourceSet.name val name = sourceSet.name
if (name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) { if (name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) {
sourceSet.platform = KotlinPlatform.COMMON
sourceSet.isTestModule = false sourceSet.isTestModule = false
continue continue
} }
if (name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) { if (name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) {
sourceSet.platform = KotlinPlatform.COMMON
sourceSet.isTestModule = true sourceSet.isTestModule = true
continue continue
} }
val compilations = sourceSetToCompilations[sourceSet] val compilations = sourceSetToCompilations[sourceSet]
if (compilations != null) { if (compilations != null) {
sourceSet.platform = compilations.map { it.platform }.distinct().singleOrNull() ?: KotlinPlatform.COMMON val platforms = compilations.map { it.platform }
sourceSet.actualPlatforms.addSimplePlatforms(platforms)
if (isHMPPEnabled) {
sourceSet.dependsOnSourceSets.mapNotNull { sourceSets[it] }.forEach {
it?.actualPlatforms?.addSimplePlatforms(platforms)
}
}
sourceSet.isTestModule = compilations.all { it.isTestModule } sourceSet.isTestModule = compilations.all { it.isTestModule }
} else { } else {
// TODO: change me after design about it // TODO: change me after design about it
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle
import java.io.File import java.io.File
import java.util.* import java.util.*
import kotlin.collections.HashSet
data class KotlinSourceSetImpl( data class KotlinSourceSetImpl(
override val name: String, override val name: String,
@@ -15,7 +16,7 @@ data class KotlinSourceSetImpl(
override val resourceDirs: Set<File>, override val resourceDirs: Set<File>,
override val dependencies: Set<KotlinDependency>, override val dependencies: Set<KotlinDependency>,
override val dependsOnSourceSets: Set<String>, override val dependsOnSourceSets: Set<String>,
val defaultPlatform: KotlinPlatform = KotlinPlatform.COMMON, val defaultPlatform: KotlinPlatformContainerImpl = KotlinPlatformContainerImpl(),
val defaultIsTestModule: Boolean = false val defaultIsTestModule: Boolean = false
) : KotlinSourceSet { ) : KotlinSourceSet {
@@ -26,11 +27,11 @@ data class KotlinSourceSetImpl(
HashSet(kotlinSourceSet.resourceDirs), HashSet(kotlinSourceSet.resourceDirs),
kotlinSourceSet.dependencies.map { it.deepCopy(cloningCache) }.toSet(), kotlinSourceSet.dependencies.map { it.deepCopy(cloningCache) }.toSet(),
HashSet(kotlinSourceSet.dependsOnSourceSets), HashSet(kotlinSourceSet.dependsOnSourceSets),
kotlinSourceSet.platform, KotlinPlatformContainerImpl(kotlinSourceSet.actualPlatforms),
kotlinSourceSet.isTestModule kotlinSourceSet.isTestModule
) )
override var platform: KotlinPlatform = defaultPlatform override var actualPlatforms: KotlinPlatformContainer = defaultPlatform
internal set internal set
override var isTestModule: Boolean = defaultIsTestModule override var isTestModule: Boolean = defaultIsTestModule
@@ -172,3 +173,22 @@ data class KotlinMPPGradleModelImpl(
mppModel.kotlinNativeHome mppModel.kotlinNativeHome
) )
} }
class KotlinPlatformContainerImpl() : KotlinPlatformContainer {
private val defaultCommonPlatform = setOf(KotlinPlatform.COMMON)
private var myPlatforms: MutableSet<KotlinPlatform>? = null
constructor(platform: KotlinPlatformContainer) : this() {
myPlatforms = HashSet<KotlinPlatform>(platform.platforms)
}
override val platforms: Collection<KotlinPlatform>
get() = myPlatforms ?: defaultCommonPlatform
override fun supports(simplePlatform: KotlinPlatform): Boolean = platforms.contains(simplePlatform)
override fun addSimplePlatforms(platforms: Collection<KotlinPlatform>) {
(myPlatforms ?: HashSet<KotlinPlatform>().apply { myPlatforms = this }).addAll(platforms)
}
}
@@ -21,6 +21,7 @@ import com.intellij.ide.actions.ShowSettingsUtilImpl
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.ComboBox import com.intellij.openapi.ui.ComboBox
import com.intellij.ui.HoverHyperlinkLabel import com.intellij.ui.HoverHyperlinkLabel
import com.intellij.util.ui.CheckBox
import com.intellij.util.ui.FormBuilder import com.intellij.util.ui.FormBuilder
import com.intellij.util.ui.ThreeStateCheckBox import com.intellij.util.ui.ThreeStateCheckBox
import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.cli.common.arguments.*
@@ -29,10 +30,7 @@ import org.jetbrains.kotlin.config.createArguments
import org.jetbrains.kotlin.config.splitArgumentString import org.jetbrains.kotlin.config.splitArgumentString
import org.jetbrains.kotlin.idea.compiler.configuration.* import org.jetbrains.kotlin.idea.compiler.configuration.*
import org.jetbrains.kotlin.idea.core.util.onTextChange import org.jetbrains.kotlin.idea.core.util.onTextChange
import org.jetbrains.kotlin.platform.IdePlatformKind import org.jetbrains.kotlin.platform.*
import org.jetbrains.kotlin.platform.idePlatformKind
import org.jetbrains.kotlin.platform.TargetPlatform
import org.jetbrains.kotlin.platform.isCommon
import org.jetbrains.kotlin.platform.js.isJs import org.jetbrains.kotlin.platform.js.isJs
import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.jvm.isJvm
import java.awt.BorderLayout import java.awt.BorderLayout
@@ -62,7 +60,7 @@ class KotlinFacetEditorGeneralTab(
lateinit var useProjectSettingsCheckBox: ThreeStateCheckBox lateinit var useProjectSettingsCheckBox: ThreeStateCheckBox
lateinit var targetPlatformComboBox: ComboBox<TargetPlatform> lateinit var platformToCheckbox: Map<SimplePlatform, ThreeStateCheckBox>
private lateinit var projectSettingsLink: HoverHyperlinkLabel private lateinit var projectSettingsLink: HoverHyperlinkLabel
@@ -93,9 +91,12 @@ class KotlinFacetEditorGeneralTab(
) )
useProjectSettingsCheckBox = ThreeStateCheckBox("Use project settings").apply { isThirdStateEnabled = isMultiEditor } useProjectSettingsCheckBox = ThreeStateCheckBox("Use project settings").apply { isThirdStateEnabled = isMultiEditor }
targetPlatformComboBox = ComboBox<TargetPlatform>(IdePlatformKind.All_PLATFORMS.toTypedArray()).apply { platformToCheckbox = CommonPlatforms
setRenderer(DescriptionListCellRenderer()) .allSimplePlatforms
} .flatMap { it.componentPlatforms }
.distinct()
.sortedBy { it.platformName }
.associate { Pair(it, ThreeStateCheckBox(it.platformName).apply {isThirdStateEnabled = isMultiEditor} ) }
projectSettingsLink = HoverHyperlinkLabel("Edit project settings").apply { projectSettingsLink = HoverHyperlinkLabel("Edit project settings").apply {
addHyperlinkListener { addHyperlinkListener {
ShowSettingsUtilImpl.showSettingsDialog(project, compilerConfigurable.id, "") ShowSettingsUtilImpl.showSettingsDialog(project, compilerConfigurable.id, "")
@@ -105,13 +106,17 @@ class KotlinFacetEditorGeneralTab(
} }
} }
val targetPlatformsPanel = JPanel()
platformToCheckbox.values.forEach {
targetPlatformsPanel.add(it)
it.isEnabled = true //TODO(auskov): think about enabling/disabling editing facet settings
}
val contentPanel = FormBuilder val contentPanel = FormBuilder
.createFormBuilder() .createFormBuilder()
.addComponent(JPanel(BorderLayout()).apply { .addComponent(JPanel(BorderLayout()).apply {
add(useProjectSettingsCheckBox, BorderLayout.WEST) add(useProjectSettingsCheckBox, BorderLayout.WEST)
add(projectSettingsLink, BorderLayout.EAST) add(projectSettingsLink, BorderLayout.EAST)
}) }).addLabeledComponent("Selected target platforms:", targetPlatformsPanel)
.addLabeledComponent("&Target platform: ", targetPlatformComboBox)
.addComponent(compilerConfigurable.createComponent()!!.apply { .addComponent(compilerConfigurable.createComponent()!!.apply {
border = null border = null
}) })
@@ -125,14 +130,16 @@ class KotlinFacetEditorGeneralTab(
updateCompilerConfigurable() updateCompilerConfigurable()
} }
targetPlatformComboBox.addActionListener { platformToCheckbox.values.forEach {
updateCompilerConfigurable() it.addActionListener {
updateCompilerConfigurable()
}
} }
} }
internal fun updateCompilerConfigurable() { internal fun updateCompilerConfigurable() {
val useProjectSettings = useProjectSettingsCheckBox.isSelected val useProjectSettings = useProjectSettingsCheckBox.isSelected
compilerConfigurable.setTargetPlatform(chosenPlatform?.idePlatformKind) compilerConfigurable.setTargetPlatform(getChosenPlatform()?.idePlatformKind)
compilerConfigurable.setEnabled(!useProjectSettings) compilerConfigurable.setEnabled(!useProjectSettings)
if (useProjectSettings) { if (useProjectSettings) {
compilerConfigurable.commonCompilerArguments = KotlinCommonCompilerArgumentsHolder.getInstance(project).settings.unfrozen() as CommonCompilerArguments? compilerConfigurable.commonCompilerArguments = KotlinCommonCompilerArgumentsHolder.getInstance(project).settings.unfrozen() as CommonCompilerArguments?
@@ -149,13 +156,15 @@ class KotlinFacetEditorGeneralTab(
compilerConfigurable.reset() compilerConfigurable.reset()
} }
val chosenPlatform: TargetPlatform? fun getChosenPlatform(): TargetPlatform? {
get() = targetPlatformComboBox.selectedItemTyped val simplePlatforms = platformToCheckbox.filter { it.value.isSelected }.map { it.key }.toSet()
return if (simplePlatforms.isEmpty()) null else TargetPlatform(simplePlatforms)
}
} }
inner class ArgumentConsistencyValidator : FacetEditorValidator() { inner class ArgumentConsistencyValidator : FacetEditorValidator() {
override fun check(): ValidationResult { override fun check(): ValidationResult {
val platform = editor.chosenPlatform ?: return ValidationResult.OK val platform = editor.getChosenPlatform() ?: return ValidationResult("At least one target platform should be selected")
val primaryArguments = platform.createArguments { val primaryArguments = platform.createArguments {
editor.compilerConfigurable.applyTo( editor.compilerConfigurable.applyTo(
this, this,
@@ -270,7 +279,9 @@ class KotlinFacetEditorGeneralTab(
apiVersionComboBox.validateOnChange() apiVersionComboBox.validateOnChange()
coroutineSupportComboBox.validateOnChange() coroutineSupportComboBox.validateOnChange()
} }
editor.targetPlatformComboBox.validateOnChange() editor.platformToCheckbox.values.forEach {
it.validateOnChange()
}
editor.updateCompilerConfigurable() editor.updateCompilerConfigurable()
isInitialized = true isInitialized = true
@@ -285,7 +296,7 @@ class KotlinFacetEditorGeneralTab(
override fun isModified(): Boolean { override fun isModified(): Boolean {
if (!isInitialized) return false if (!isInitialized) return false
if (editor.useProjectSettingsCheckBox.isSelected != configuration.settings.useProjectSettings) return true if (editor.useProjectSettingsCheckBox.isSelected != configuration.settings.useProjectSettings) return true
if (editor.chosenPlatform != configuration.settings.targetPlatform) return true if (editor.getChosenPlatform() != configuration.settings.targetPlatform) return true
return !editor.useProjectSettingsCheckBox.isSelected && editor.compilerConfigurable.isModified return !editor.useProjectSettingsCheckBox.isSelected && editor.compilerConfigurable.isModified
} }
@@ -293,7 +304,9 @@ class KotlinFacetEditorGeneralTab(
if (!isInitialized) return if (!isInitialized) return
validateOnce { validateOnce {
editor.useProjectSettingsCheckBox.isSelected = configuration.settings.useProjectSettings editor.useProjectSettingsCheckBox.isSelected = configuration.settings.useProjectSettings
editor.targetPlatformComboBox.selectedItem = configuration.settings.targetPlatform editor.platformToCheckbox.forEach {
it.value.isSelected = configuration.settings.targetPlatform?.contains(it.key) ?: false
}
editor.compilerConfigurable.reset() editor.compilerConfigurable.reset()
editor.updateCompilerConfigurable() editor.updateCompilerConfigurable()
} }
@@ -305,7 +318,7 @@ class KotlinFacetEditorGeneralTab(
editor.compilerConfigurable.apply() editor.compilerConfigurable.apply()
with(configuration.settings) { with(configuration.settings) {
useProjectSettings = editor.useProjectSettingsCheckBox.isSelected useProjectSettings = editor.useProjectSettingsCheckBox.isSelected
editor.chosenPlatform?.let { editor.getChosenPlatform()?.let {
if (it != targetPlatform) { if (it != targetPlatform) {
val platformArguments = when { val platformArguments = when {
it.isJvm() -> editor.compilerConfigurable.k2jvmCompilerArguments it.isJvm() -> editor.compilerConfigurable.k2jvmCompilerArguments
@@ -41,7 +41,7 @@ class MultipleKotlinFacetEditor(
initialize() initialize()
editors.flatMap { it.editorTabs.filterIsInstance<KotlinFacetEditorGeneralTab>() }.forEach { it.initializeIfNeeded() } editors.flatMap { it.editorTabs.filterIsInstance<KotlinFacetEditorGeneralTab>() }.forEach { it.initializeIfNeeded() }
helper.bind(useProjectSettingsCheckBox, editors) { it.tabEditor.useProjectSettingsCheckBox } helper.bind(useProjectSettingsCheckBox, editors) { it.tabEditor.useProjectSettingsCheckBox }
helper.bind(targetPlatformComboBox, editors) { it.tabEditor.targetPlatformComboBox } //TODO(auskov): Support bulk editing target platforms?
with(compilerConfigurable) { with(compilerConfigurable) {
helper.bind(reportWarningsCheckBox, editors) { it.compilerConfigurable.reportWarningsCheckBox } helper.bind(reportWarningsCheckBox, editors) { it.compilerConfigurable.reportWarningsCheckBox }
helper.bind(enableNewInferenceInIDECheckBox, editors) { it.compilerConfigurable.enableNewInferenceInIDECheckBox } helper.bind(enableNewInferenceInIDECheckBox, editors) { it.compilerConfigurable.enableNewInferenceInIDECheckBox }
@@ -90,6 +90,7 @@ fun KotlinFacetSettings.initializeIfNeeded(
targetPlatform.idePlatformKind.tooling.compilerArgumentsForProject(module.project)?.let { mergeBeans(it, this) } targetPlatform.idePlatformKind.tooling.compilerArgumentsForProject(module.project)?.let { mergeBeans(it, this) }
mergeBeans(commonArguments, this) mergeBeans(commonArguments, this)
} }
this.targetPlatform = targetPlatform
} }
if (shouldInferLanguageLevel) { if (shouldInferLanguageLevel) {
@@ -152,6 +153,7 @@ fun KotlinFacet.configureFacet(
val module = module val module = module
with(configuration.settings) { with(configuration.settings) {
compilerArguments = null compilerArguments = null
targetPlatform = null
compilerSettings = null compilerSettings = null
initializeIfNeeded( initializeIfNeeded(
module, module,
@@ -2,7 +2,7 @@
<module type="JAVA_MODULE" version="4"> <module type="JAVA_MODULE" version="4">
<component name="FacetManager"> <component name="FacetManager">
<facet type="kotlin-language" name="Kotlin"> <facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.8" useProjectSettings="false"> <configuration version="2" allPlatforms="JVM [1.8]" useProjectSettings="false">
<compilerSettings> <compilerSettings>
<option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" /> <option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" />
</compilerSettings> </compilerSettings>
@@ -0,0 +1,27 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="JAVA_MODULE" version="4">
<component name="FacetManager">
<facet type="kotlin-language" name="Kotlin">
<configuration version="2" platform="JVM 1.8" useProjectSettings="false">
<compilerSettings>
<option name="additionalArguments" value="-version -Xallow-kotlin-package -Xskip-metadata-version-check" />
</compilerSettings>
<compilerArguments>
<option name="jvmTarget" value="1.7" />
<option name="languageVersion" value="1.1" />
<option name="apiVersion" value="1.0" />
<option name="coroutinesEnable" value="true" />
</compilerArguments>
</configuration>
</facet>
</component>
<component name="NewModuleRootManager" inherit-compiler-output="true">
<exclude-output />
<content url="file://$MODULE_DIR$">
<sourceFolder url="file://$MODULE_DIR$/src" isTestSource="false" />
</content>
<orderEntry type="jdk" jdkName="1.8" jdkType="JavaSDK" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="library" name="KotlinJavaRuntime (2)" level="project" />
</component>
</module>
@@ -0,0 +1,41 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="CompilerConfiguration">
<resourceExtensions />
<wildcardResourcePatterns>
<entry name="!?*.java" />
<entry name="!?*.form" />
<entry name="!?*.class" />
<entry name="!?*.groovy" />
<entry name="!?*.scala" />
<entry name="!?*.flex" />
<entry name="!?*.kt" />
<entry name="!?*.clj" />
<entry name="!?*.aj" />
</wildcardResourcePatterns>
<annotationProcessing>
<profile default="true" name="Default" enabled="false">
<processorPath useClasspath="true" />
</profile>
</annotationProcessing>
</component>
<component name="CopyrightManager" default="" />
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/module.iml" filepath="$PROJECT_DIR$/module.iml" />
</modules>
</component>
<component name="ProjectRootManager" version="2" languageLevel="JDK_1_8" default="true" assert-keyword="true" jdk-15="true" project-jdk-name="1.8" project-jdk-type="JavaSDK">
<output url="file://$PROJECT_DIR$/out" />
</component>
<component name="libraryTable">
<library name="KotlinJavaRuntime (2)">
<CLASSES>
<root url="jar://$PROJECT_DIR$/../mockRuntime11/kotlin-runtime.jar!/" />
</CLASSES>
<JAVADOC />
<SOURCES>
</SOURCES>
</library>
</component>
</project>
@@ -96,6 +96,16 @@ open class ConfigureKotlinInTempDirTest : AbstractConfigureKotlinInTempDirTest()
Assert.assertEquals(moduleFileContentBefore, moduleFileContentAfter) Assert.assertEquals(moduleFileContentBefore, moduleFileContentAfter)
} }
//TODO(auskov): test parsing common target platform with multiple versions of java, add parsing common platforms
fun testLoadAndSaveProjectWithV2OldPlatformFacetConfig() {
val moduleFileContentBefore = String(module.moduleFile!!.contentsToByteArray())
val application = ApplicationManager.getApplication() as ApplicationImpl
application.isSaveAllowed = true
application.saveAll()
val moduleFileContentAfter = String(module.moduleFile!!.contentsToByteArray())
Assert.assertEquals(moduleFileContentBefore.replace("platform=\"JVM 1.8\"", "allPlatforms=\"JVM [1.8]\""), moduleFileContentAfter)
}
fun testApiVersionWithoutLanguageVersion() { fun testApiVersionWithoutLanguageVersion() {
KotlinCommonCompilerArgumentsHolder.getInstance(myProject) KotlinCommonCompilerArgumentsHolder.getInstance(myProject)
val settings = myProject.getLanguageVersionSettings() val settings = myProject.getLanguageVersionSettings()
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.config.KotlinFacetSettings
import org.jetbrains.kotlin.incremental.testingUtils.BuildLogFinder import org.jetbrains.kotlin.incremental.testingUtils.BuildLogFinder
import org.jetbrains.kotlin.incremental.testingUtils.BuildLogFinder.Companion.JS_JPS_LOG import org.jetbrains.kotlin.incremental.testingUtils.BuildLogFinder.Companion.JS_JPS_LOG
import org.jetbrains.kotlin.jps.model.JpsKotlinFacetModuleExtension import org.jetbrains.kotlin.jps.model.JpsKotlinFacetModuleExtension
import org.jetbrains.kotlin.platform.js.JsPlatforms
import java.io.File import java.io.File
abstract class AbstractIncrementalJsJpsTest : AbstractIncrementalJpsTest() { abstract class AbstractIncrementalJsJpsTest : AbstractIncrementalJpsTest() {
@@ -28,6 +29,7 @@ abstract class AbstractIncrementalJsJpsTest : AbstractIncrementalJpsTest() {
myProject.modules.forEach { myProject.modules.forEach {
val facet = KotlinFacetSettings() val facet = KotlinFacetSettings()
facet.compilerArguments = K2JSCompilerArguments() facet.compilerArguments = K2JSCompilerArguments()
facet.targetPlatform = JsPlatforms.defaultJsPlatform
it.container.setChild( it.container.setChild(
JpsKotlinFacetModuleExtension.KIND, JpsKotlinFacetModuleExtension.KIND,
@@ -15,9 +15,13 @@ import org.jetbrains.kotlin.config.KotlinFacetSettings
import org.jetbrains.kotlin.config.KotlinModuleKind.COMPILATION_AND_SOURCE_SET_HOLDER import org.jetbrains.kotlin.config.KotlinModuleKind.COMPILATION_AND_SOURCE_SET_HOLDER
import org.jetbrains.kotlin.config.KotlinModuleKind.SOURCE_SET_HOLDER import org.jetbrains.kotlin.config.KotlinModuleKind.SOURCE_SET_HOLDER
import org.jetbrains.kotlin.jps.build.dependeciestxt.ModulesTxt.Dependency.Kind.* import org.jetbrains.kotlin.jps.build.dependeciestxt.ModulesTxt.Dependency.Kind.*
import org.jetbrains.kotlin.platform.CommonPlatforms
import org.jetbrains.kotlin.platform.impl.FakeK2NativeCompilerArguments import org.jetbrains.kotlin.platform.impl.FakeK2NativeCompilerArguments
import org.jetbrains.kotlin.platform.isCommon import org.jetbrains.kotlin.platform.isCommon
import org.jetbrains.kotlin.platform.js.JsPlatforms
import org.jetbrains.kotlin.platform.jvm.JvmPlatforms
import org.jetbrains.kotlin.platform.jvm.isJvm import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.platform.konan.KonanPlatforms
import java.io.File import java.io.File
import kotlin.reflect.KMutableProperty1 import kotlin.reflect.KMutableProperty1
import kotlin.reflect.full.findAnnotation import kotlin.reflect.full.findAnnotation
@@ -253,10 +257,14 @@ class ModulesTxtBuilder {
when (flag) { when (flag) {
"sourceSetHolder" -> settings.kind = SOURCE_SET_HOLDER "sourceSetHolder" -> settings.kind = SOURCE_SET_HOLDER
"compilationAndSourceSetHolder" -> settings.kind = COMPILATION_AND_SOURCE_SET_HOLDER "compilationAndSourceSetHolder" -> settings.kind = COMPILATION_AND_SOURCE_SET_HOLDER
"common" -> settings.compilerArguments = K2MetadataCompilerArguments() "common" -> settings.compilerArguments =
"jvm" -> settings.compilerArguments = K2JVMCompilerArguments() K2MetadataCompilerArguments().also { settings.targetPlatform = CommonPlatforms.defaultCommonPlatform }
"js" -> settings.compilerArguments = K2JSCompilerArguments() "jvm" -> settings.compilerArguments =
"native" -> settings.compilerArguments = FakeK2NativeCompilerArguments() K2JVMCompilerArguments().also { settings.targetPlatform = JvmPlatforms.defaultJvmPlatform }
"js" -> settings.compilerArguments =
K2JSCompilerArguments().also { settings.targetPlatform = JsPlatforms.defaultJsPlatform }
"native" -> settings.compilerArguments =
FakeK2NativeCompilerArguments().also { settings.targetPlatform = KonanPlatforms.defaultKonanPlatform }
else -> { else -> {
val flagProperty = ModulesTxt.Module.flags[flag] val flagProperty = ModulesTxt.Module.flags[flag]
if (flagProperty != null) flagProperty.set(module, true) if (flagProperty != null) flagProperty.set(module, true)