From c0bf5a65667b762cb9d2d079eb6beb4fb06959cd Mon Sep 17 00:00:00 2001 From: Andrey Uskov Date: Tue, 4 Jun 2019 01:55:30 +0300 Subject: [PATCH] Import of middle HMPP target platforms is supported --- .../kotlin/platform/CommonPlatforms.kt | 1 + .../kotlin/platform/TargetPlatform.kt | 4 +- .../idea/project/TargetPlatformDetector.java | 7 +-- .../idea/configuration/KotlinMPPDataNodes.kt | 10 ++- .../KotlinMPPGradleProjectResolver.kt | 23 +++---- .../KotlinSourceSetDataService.kt | 28 +++++---- .../kotlin/config/KotlinFacetSettings.kt | 15 ++++- .../kotlin/config/facetSerialization.kt | 25 +++++--- .../kotlin/platform/IdePlatformKind.kt | 22 +++---- .../platform/impl/CommonIdePlatformKind.kt | 2 +- .../kotlin/platform/impl/JsIdePlatformKind.kt | 3 +- .../platform/impl/JvmIdePlatformKind.kt | 3 +- .../platform/impl/NativeIdePlatformKind.kt | 4 +- ...kLibraryValidatorWithDynamicDescription.kt | 4 +- .../facet/KotlinLibraryValidatorCreator.kt | 2 +- .../src/KotlinMPPGradleModel.kt | 21 ++++++- .../src/KotlinMPPGradleModelBuilder.kt | 62 ++++++++++++++++--- .../src/KotlinMPPGradleModelImpl.kt | 28 +++++++-- .../idea/facet/KotlinFacetEditorGeneralTab.kt | 53 ++++++++++------ .../idea/facet/MultipleKotlinFacetEditor.kt | 2 +- .../jetbrains/kotlin/idea/facet/facetUtils.kt | 2 + .../module.iml | 2 +- .../module.iml | 27 ++++++++ .../projectFile.ipr | 41 ++++++++++++ .../src/foo.kt | 0 .../ConfigureKotlinInTempDirTest.kt | 10 +++ .../jps/build/AbstractIncrementalJsJpsTest.kt | 2 + .../jps/build/dependeciestxt/ModulesTxt.kt | 16 +++-- 28 files changed, 316 insertions(+), 103 deletions(-) create mode 100644 idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/module.iml create mode 100644 idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/projectFile.ipr create mode 100644 idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/src/foo.kt diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/platform/CommonPlatforms.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/platform/CommonPlatforms.kt index 2255c9da396..af0c7073ffd 100644 --- a/compiler/cli/cli-common/src/org/jetbrains/kotlin/platform/CommonPlatforms.kt +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/platform/CommonPlatforms.kt @@ -31,6 +31,7 @@ object CommonPlatforms { get() = CompatCommonPlatform val allSimplePlatforms: List + // TODO(auskov): migrate to SimplePlatform? get() = sequence { yieldAll(JvmPlatforms.allJvmPlatforms) yieldAll(KonanPlatforms.allKonanPlatforms) diff --git a/core/descriptors/src/org/jetbrains/kotlin/platform/TargetPlatform.kt b/core/descriptors/src/org/jetbrains/kotlin/platform/TargetPlatform.kt index 88cdb279ade..4171238eaa2 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/platform/TargetPlatform.kt +++ b/core/descriptors/src/org/jetbrains/kotlin/platform/TargetPlatform.kt @@ -79,4 +79,6 @@ interface TargetPlatformVersion { fun TargetPlatform?.isCommon(): Boolean = this != null && this.size > 1 -fun SimplePlatform.toTargetPlatform(): TargetPlatform = TargetPlatform(setOf(this)) \ No newline at end of file +fun SimplePlatform.toTargetPlatform(): TargetPlatform = TargetPlatform(setOf(this)) + +fun SimplePlatform.serializeToString() = "${this.platformName} [${this.targetPlatformVersion.description}]" diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java index d2ff0d2e469..d9a7f8dff1d 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/TargetPlatformDetector.java @@ -24,14 +24,11 @@ import com.intellij.psi.PsiElement; import com.intellij.psi.PsiFile; import kotlin.collections.CollectionsKt; import org.jetbrains.annotations.NotNull; -import org.jetbrains.kotlin.platform.DefaultIdeTargetPlatformKindProvider; -import org.jetbrains.kotlin.platform.IdePlatformKind; +import org.jetbrains.kotlin.platform.*; import org.jetbrains.kotlin.platform.jvm.JvmPlatforms; import org.jetbrains.kotlin.psi.KtCodeFragment; import org.jetbrains.kotlin.psi.KtFile; 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.ScriptDefinition; @@ -65,7 +62,7 @@ public class TargetPlatformDetector { ScriptDefinition scriptDefinition = DefinitionsKt.findScriptDefinition(file); if (scriptDefinition != null) { 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 SimplePlatform simplePlatform = CollectionsKt.single(compilerPlatform); if (simplePlatform.getPlatformName().equals(platformNameFromScriptDefinition)) { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPDataNodes.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPDataNodes.kt index 70e7a0f3467..c0a0d7f03f4 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPDataNodes.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPDataNodes.kt @@ -17,6 +17,8 @@ import com.intellij.util.containers.MultiMap import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments import org.jetbrains.kotlin.gradle.KotlinModule 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.plugins.gradle.util.GradleConstants import java.io.File @@ -32,7 +34,13 @@ val DataNode.kotlinAndroidSourceSets: List? class KotlinSourceSetInfo(val kotlinModule: KotlinModule) : Serializable { var moduleId: String? = null 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 compilerArguments: CommonCompilerArguments? = null var dependencyClasspath: List = emptyList() diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt index 5f7eb8f5b44..c84f27b023a 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinMPPGradleProjectResolver.kt @@ -254,8 +254,8 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { val ignoreCommonSourceSets by lazy { externalProject.notImportedCommonSourceSets() } for (sourceSet in mppModel.sourceSets.values) { - if (sourceSet.platform == KotlinPlatform.ANDROID) continue - if (sourceSet.platform == KotlinPlatform.COMMON && ignoreCommonSourceSets) continue + if (sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)) continue + if (sourceSet.actualPlatforms.supports(KotlinPlatform.COMMON) && ignoreCommonSourceSets) continue val moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx) val existingSourceSetDataNode = sourceSetMap[moduleId]?.first if (existingSourceSetDataNode?.kotlinSourceSet != null) continue @@ -317,7 +317,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { val mppModel = resolverCtx.getMppModel(gradleModule) ?: return if (resolverCtx.getExtraProject(gradleModule, ExternalProject::class.java) == null) return 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.resourceDirs, sourceSet.resourceType, dataNode) } @@ -365,7 +365,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { } } } - val sourceSetGraph = GraphBuilder.directed().build() + val sourceSetGraph = GraphBuilder.directed().build() processSourceSets(gradleModule, mppModel, ideModule, resolverCtx) { dataNode, sourceSet -> sourceSetGraph.addNode(sourceSet) val productionSourceSet = dataNode @@ -384,7 +384,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { } // Workaround: Non-android source sets have commonMain/commonTest in their dependsOn // 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) { KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME } else { @@ -398,7 +398,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { } val closedSourceSetGraph = Graphs.transitiveClosure(sourceSetGraph) for (sourceSet in closedSourceSetGraph.nodes()) { - val isAndroid = sourceSet.platform == KotlinPlatform.ANDROID + val isAndroid = sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID) val fromDataNode = if (isAndroid) { ideModule } else { @@ -418,7 +418,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { sourceSetInfo.addSourceSets(dependeeSourceSets, selfName, gradleModule, resolverCtx) } } - if (sourceSet.platform == KotlinPlatform.ANDROID) continue + if (sourceSet.actualPlatforms.supports(KotlinPlatform.ANDROID)) continue for (dependeeSourceSet in dependeeSourceSets) { val toDataNode = getSiblingKotlinModuleData(dependeeSourceSet, gradleModule, ideModule, resolverCtx) ?: continue addDependency(fromDataNode, toDataNode, dependeeSourceSet.isTestModule) @@ -619,14 +619,15 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { gradleModule: IdeaModule, resolverCtx: ProjectResolverContext ): KotlinSourceSetInfo? { - if (sourceSet.platform.isNotSupported()) return null + if (sourceSet.actualPlatforms.platforms.filter { !it.isNotSupported() }.isEmpty()) return null return KotlinSourceSetInfo(sourceSet).also { info -> val languageSettings = sourceSet.languageSettings info.moduleId = getKotlinModuleId(gradleModule, sourceSet, resolverCtx) info.gradleModuleId = getModuleId(resolverCtx, gradleModule) - info.platform = sourceSet.platform + info.actualPlatforms.addSimplePlatforms(sourceSet.actualPlatforms.platforms) 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.languageVersion = languageSettings.languageVersion it.apiVersion = languageSettings.apiVersion @@ -653,7 +654,7 @@ open class KotlinMPPGradleProjectResolver : AbstractProjectResolverExtension() { return KotlinSourceSetInfo(compilation).also { sourceSetInfo -> sourceSetInfo.moduleId = getKotlinModuleId(gradleModule, compilation, resolverCtx) sourceSetInfo.gradleModuleId = getModuleId(resolverCtx, gradleModule) - sourceSetInfo.platform = compilation.platform + sourceSetInfo.actualPlatforms.addSimplePlatforms(listOf(compilation.platform)) sourceSetInfo.isTestModule = compilation.isTestModule sourceSetInfo.compilerArguments = createCompilerArguments(compilation.arguments.currentArguments, compilation.platform).also { diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinSourceSetDataService.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinSourceSetDataService.kt index 022d9d2ab9d..7618bb8aec3 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinSourceSetDataService.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinSourceSetDataService.kt @@ -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.platform.IdePlatformKindTooling 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.jvm.JvmPlatforms import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData @@ -52,10 +53,10 @@ class KotlinSourceSetDataService : AbstractProjectDataService { - val target = JvmTarget.fromString(moduleData.targetCompatibility ?: "") ?: JvmTarget.DEFAULT - JvmPlatforms.jvmPlatformByTargetVersion(target) + val platformKinds = kotlinSourceSet.actualPlatforms.platforms //TODO(auskov): fix calculation of jvm target + .map { IdePlatformKindTooling.getTooling(it).kind } + .flatMap { + when (it) { + is JvmIdePlatformKind -> { + val target = JvmTarget.fromString(moduleData.targetCompatibility ?: "") ?: JvmTarget.DEFAULT + JvmPlatforms.jvmPlatformByTargetVersion(target).componentPlatforms + } + else -> it.defaultPlatform.componentPlatforms + } } - else -> platformKind.defaultPlatform - } + .distinct() + .toSet() + + val platform = TargetPlatform(platformKinds) val coroutinesProperty = CoroutineSupport.byCompilerArgument( mainModuleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project) diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/config/KotlinFacetSettings.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/config/KotlinFacetSettings.kt index 27306845427..4e10f25b199 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/config/KotlinFacetSettings.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/config/KotlinFacetSettings.kt @@ -26,6 +26,7 @@ import org.jetbrains.kotlin.platform.IdePlatformKind import org.jetbrains.kotlin.platform.TargetPlatformVersion import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.compat.toIdePlatform +import org.jetbrains.kotlin.platform.jvm.JvmPlatforms import org.jetbrains.kotlin.utils.DescriptionAware @Deprecated("Use IdePlatformKind instead.", level = DeprecationLevel.ERROR) @@ -189,12 +190,20 @@ class KotlinFacetSettings { compilerArguments!!.apiVersion = value?.versionString } - val targetPlatform: TargetPlatform? + var targetPlatform: TargetPlatform? = null get() { - val compilerArguments = this.compilerArguments ?: return null - return IdePlatformKind.platformByCompilerArguments(compilerArguments) + // This work-around is required in order to fix importing of the proper JVM target version. + //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") @Deprecated( message = "This accessor is deprecated and will be removed soon, use API from 'org.jetbrains.kotlin.platform.*' packages instead", diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt index b3c3b92dfc2..d451d84c5ba 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/config/facetSerialization.kt @@ -25,16 +25,13 @@ import org.jdom.Element import org.jdom.Text import org.jetbrains.kotlin.cli.common.arguments.* import org.jetbrains.kotlin.load.java.JvmAbi -import org.jetbrains.kotlin.platform.IdePlatformKind -import org.jetbrains.kotlin.platform.TargetPlatform +import org.jetbrains.kotlin.platform.* import org.jetbrains.kotlin.platform.impl.FakeK2NativeCompilerArguments import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind import org.jetbrains.kotlin.platform.js.JsPlatform import org.jetbrains.kotlin.platform.jvm.JdkPlatform import org.jetbrains.kotlin.platform.jvm.JvmPlatform 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 kotlin.reflect.KClass import kotlin.reflect.full.superclasses @@ -67,7 +64,7 @@ private fun readV1Config(element: Element): KotlinFacetSettings { val targetPlatformName = versionInfoElement?.getOptionValue("targetPlatformName") val languageLevel = versionInfoElement?.getOptionValue("languageLevel") val apiLevel = versionInfoElement?.getOptionValue("apiLevel") - val targetPlatform = IdePlatformKind.All_PLATFORMS + val targetPlatform = CommonPlatforms.allSimplePlatforms.union(setOf(CommonPlatforms.defaultCommonPlatform)) .firstOrNull { it.oldFashionedDescription == targetPlatformName } ?: JvmIdePlatformKind.defaultPlatform // FIXME(dsavvinov): choose proper default @@ -115,20 +112,30 @@ private fun readV1Config(element: Element): KotlinFacetSettings { this.compilerSettings = compilerSettings this.compilerArguments = compilerArguments + this.targetPlatform = IdePlatformKind.platformByCompilerArguments(compilerArguments) } } 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") - return IdePlatformKind.All_PLATFORMS - .firstOrNull { it.oldFashionedDescription == platformName } - .orDefault() + // this code could be simplified using union after fixing the equals method in SimplePlatform + val allPlatforms = ArrayList(CommonPlatforms.allSimplePlatforms).also { it.add(CommonPlatforms.defaultCommonPlatform) } + return allPlatforms.firstOrNull { it.oldFashionedDescription == platformName }.orDefault() } private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings { return KotlinFacetSettings().apply { element.getAttributeValue("useProjectSettings")?.let { useProjectSettings = it.toBoolean() } val targetPlatform = element.getFacetPlatformByConfigurationElement() + this.targetPlatform = targetPlatform element.getChild("implements")?.let { val items = it.getChildren("implement") implementedModuleNames = if (items.isNotEmpty()) { @@ -288,7 +295,7 @@ private fun KotlinFacetSettings.writeLatestConfig(element: Element) { val filter = SkipDefaultsSerializationFilter() targetPlatform?.let { - element.setAttribute("platform", it.oldFashionedDescription) + element.setAttribute("allPlatforms", it.componentPlatforms.map { it.serializeToString() }.joinToString(separator = "/")) } if (!useProjectSettings) { element.setAttribute("useProjectSettings", useProjectSettings.toString()) diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/IdePlatformKind.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/IdePlatformKind.kt index 8e222c16a07..72c06542638 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/IdePlatformKind.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/IdePlatformKind.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.platform +import com.intellij.openapi.diagnostic.Logger import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments 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.JvmIdePlatformKind 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 abstract class IdePlatformKind> { - abstract val platforms: List + abstract fun supportsTargetPlatform(platform: TargetPlatform): Boolean abstract val defaultPlatform: TargetPlatform @@ -67,7 +64,6 @@ abstract class IdePlatformKind> { kinds } - val All_PLATFORMS by lazy { ALL_KINDS.flatMap { it.platforms } } fun platformByCompilerArguments(arguments: Args): TargetPlatform? = ALL_KINDS.firstNotNullResult { it.platformByCompilerArguments(arguments) } @@ -76,10 +72,10 @@ abstract class IdePlatformKind> { } val TargetPlatform.idePlatformKind: IdePlatformKind<*> - get() = when (val single = singleOrNull()) { - null -> CommonIdePlatformKind - is JvmPlatform -> JvmIdePlatformKind - is JsPlatform -> JsIdePlatformKind - is KonanPlatform -> NativeIdePlatformKind - else -> error("Unknown platform $single") - } + get() = IdePlatformKind.ALL_KINDS.filter { it.supportsTargetPlatform(this) }.let { list -> + when { + list.size == 1 -> list.first() + list.size > 1 -> list.first().also { Logger.getInstance(IdePlatformKind.javaClass).warn("Found more than one IdePlatformKind [$list] for target [$this].") } + else -> error("Unknown platform $this") + } + } \ No newline at end of file diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/CommonIdePlatformKind.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/CommonIdePlatformKind.kt index f4edd270b5a..6200b08bc08 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/CommonIdePlatformKind.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/CommonIdePlatformKind.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments import org.jetbrains.kotlin.platform.* object CommonIdePlatformKind : IdePlatformKind() { + override fun supportsTargetPlatform(platform: TargetPlatform) = platform.isCommon() override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { return if (arguments is K2MetadataCompilerArguments) @@ -31,7 +32,6 @@ object CommonIdePlatformKind : IdePlatformKind() { 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 argumentsClass get() = K2MetadataCompilerArguments::class.java diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JsIdePlatformKind.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JsIdePlatformKind.kt index 505d6cdd126..1e73d24561c 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JsIdePlatformKind.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JsIdePlatformKind.kt @@ -17,6 +17,7 @@ import org.jetbrains.kotlin.platform.TargetPlatformVersion import org.jetbrains.kotlin.platform.js.JsPlatforms object JsIdePlatformKind : IdePlatformKind() { + override fun supportsTargetPlatform(platform: TargetPlatform): Boolean = platforms.contains(platform) override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { return if (arguments is K2JSCompilerArguments) @@ -25,7 +26,7 @@ object JsIdePlatformKind : IdePlatformKind() { null } - override val platforms get() = listOf(JsPlatforms.defaultJsPlatform) + val platforms get() = listOf(JsPlatforms.defaultJsPlatform) override val defaultPlatform get() = JsPlatforms.defaultJsPlatform @Deprecated( diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt index 92fe6a38596..8ad48e32821 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/JvmIdePlatformKind.kt @@ -18,6 +18,7 @@ import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.platform.jvm.JvmPlatforms object JvmIdePlatformKind : IdePlatformKind() { + override fun supportsTargetPlatform(platform: TargetPlatform): Boolean = platforms.contains(platform) override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { if (arguments !is K2JVMCompilerArguments) return null @@ -42,7 +43,7 @@ object JvmIdePlatformKind : IdePlatformKind() { return K2JVMCompilerArguments() } - override val platforms: List = JvmTarget.values().map { ver -> JvmPlatforms.jvmPlatformByTargetVersion(ver) } + listOf(JvmPlatforms.unspecifiedJvmPlatform) + val platforms: List = JvmTarget.values().map { ver -> JvmPlatforms.jvmPlatformByTargetVersion(ver) } + listOf(JvmPlatforms.unspecifiedJvmPlatform) override val defaultPlatform get() = JvmPlatforms.defaultJvmPlatform override val argumentsClass get() = K2JVMCompilerArguments::class.java diff --git a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/NativeIdePlatformKind.kt b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/NativeIdePlatformKind.kt index ed0fe8f18f4..a637a9538c4 100644 --- a/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/NativeIdePlatformKind.kt +++ b/idea/idea-jps-common/src/org/jetbrains/kotlin/platform/impl/NativeIdePlatformKind.kt @@ -16,6 +16,7 @@ import org.jetbrains.kotlin.platform.TargetPlatformVersion import org.jetbrains.kotlin.platform.konan.KonanPlatforms object NativeIdePlatformKind : IdePlatformKind() { + override fun supportsTargetPlatform(platform: TargetPlatform): Boolean = platform == KonanPlatforms.defaultKonanPlatform override fun platformByCompilerArguments(arguments: CommonCompilerArguments): TargetPlatform? { return if (arguments is FakeK2NativeCompilerArguments) @@ -37,9 +38,6 @@ object NativeIdePlatformKind : IdePlatformKind() { ) override fun getDefaultPlatform(): IdePlatform<*, *> = Platform - override val platforms - get() = listOf(KonanPlatforms.defaultKonanPlatform) - override val argumentsClass get() = FakeK2NativeCompilerArguments::class.java diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt index 6ca2b6e8960..29ec77722e4 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt @@ -37,7 +37,7 @@ class FrameworkLibraryValidatorWithDynamicDescription( private val context: LibrariesValidatorContext, private val validatorsManager: FacetValidatorsManager, private val libraryCategoryName: String, - private val getPlatform: () -> TargetPlatform + private val getPlatform: () -> TargetPlatform? ) : FrameworkLibraryValidator() { private val IdePlatformKind<*>.libraryDescription: CustomLibraryDescription? get() = this.tooling.getLibraryDescription(context.module.project) @@ -69,7 +69,7 @@ class FrameworkLibraryValidatorWithDynamicDescription( } override fun check(): ValidationResult { - val targetPlatform = getPlatform() + val targetPlatform = getPlatform() ?: return ValidationResult("No target platforms selected") if (checkLibraryIsConfigured(targetPlatform.idePlatformKind)) { val conflictingPlatforms = IdePlatformKind.ALL_KINDS diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/KotlinLibraryValidatorCreator.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/KotlinLibraryValidatorCreator.kt index 52c71f3d373..93fb850ae6d 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/KotlinLibraryValidatorCreator.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/facet/KotlinLibraryValidatorCreator.kt @@ -28,6 +28,6 @@ class KotlinLibraryValidatorCreator : KotlinFacetValidatorCreator() { DelegatingLibrariesValidatorContext(editorContext), validatorsManager, "kotlin" - ) { editor.chosenPlatform!! } + ) { editor.getChosenPlatform() } } } \ No newline at end of file diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt index 2c25c23a23b..075cd285d9a 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModel.kt @@ -25,7 +25,6 @@ fun KotlinDependency.deepCopy(cache: MutableMap): KotlinDependency { interface KotlinModule : Serializable { val name: String - val platform: KotlinPlatform val dependencies: Set val isTestModule: Boolean } @@ -35,6 +34,11 @@ interface KotlinSourceSet : KotlinModule { val sourceDirs: Set val resourceDirs: Set val dependsOnSourceSets: Set + val actualPlatforms: KotlinPlatformContainer + @Deprecated("Returns single target platform", ReplaceWith("actualPlatforms.actualPlatforms"), DeprecationLevel.ERROR) + val platform: KotlinPlatform + get() = actualPlatforms.getSinglePlatform() + companion object { const val COMMON_MAIN_SOURCE_SET_NAME = "commonMain" @@ -73,6 +77,8 @@ interface KotlinCompilation : KotlinModule { val arguments: KotlinCompilationArguments val dependencyClasspath: List val disambiguationClassifier: String? + val platform: KotlinPlatform + companion object { const val MAIN_COMPILATION_NAME = "main" @@ -81,7 +87,7 @@ interface KotlinCompilation : KotlinModule { } 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"), JS("js"), NATIVE("native"), @@ -92,6 +98,17 @@ enum class KotlinPlatform(val id: String) { } } +interface KotlinPlatformContainer: Serializable { + val platforms: Collection + + fun supports(simplePlatform: KotlinPlatform): Boolean + + fun addSimplePlatforms(platforms: Collection) + + fun getSinglePlatform() = platforms.singleOrNull() ?: KotlinPlatform.COMMON +} + + interface KotlinTargetJar : Serializable { val archiveFile: File? } diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt index 3cb5067eb4b..41af55cee0e 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelBuilder.kt @@ -48,13 +48,18 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { val sourceSets = buildSourceSets(dependencyResolver, project) ?: return null val sourceSetMap = sourceSets.map { it.name to it }.toMap() val targets = buildTargets(sourceSetMap, dependencyResolver, project) ?: return null - computeSourceSetsDeferredInfo(sourceSets, targets) + computeSourceSetsDeferredInfo(sourceSetMap, targets, isHMPPEnabled(project)) val coroutinesState = getCoroutinesState(project) reportUnresolvedDependencies(targets) val kotlinNativeHome = KotlinNativeHomeEvaluator.getKotlinNativeHome(project) ?: NO_KOTLIN_NATIVE_HOME 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) { targets .asSequence() @@ -73,13 +78,46 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { return getCoroutines(experimentalExt) as? String } + + private fun calculateDependsOnClosure( + sourceSet: KotlinSourceSetImpl?, + sourceSetsMap: Map, + cache: MutableMap> + ): Set { + 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? { val kotlinExt = project.extensions.findByName("kotlin") ?: return null val getSourceSets = kotlinExt.javaClass.getMethodOrNull("getSourceSets") ?: return null @Suppress("UNCHECKED_CAST") val sourceSets = (getSourceSets(kotlinExt) as? NamedDomainObjectContainer)?.asMap?.values ?: emptyList() - 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>() + 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( @@ -376,8 +414,9 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { } private fun computeSourceSetsDeferredInfo( - sourceSets: Collection, - targets: Collection + sourceSets: Map, + targets: Collection, + isHMPPEnabled: Boolean ) { val sourceSetToCompilations = LinkedHashMap>() for (target in targets) { @@ -387,22 +426,29 @@ class KotlinMPPGradleModelBuilder : ModelBuilderService { } } } - for (sourceSet in sourceSets) { + + for (sourceSet in sourceSets.values) { val name = sourceSet.name if (name == KotlinSourceSet.COMMON_MAIN_SOURCE_SET_NAME) { - sourceSet.platform = KotlinPlatform.COMMON sourceSet.isTestModule = false continue } if (name == KotlinSourceSet.COMMON_TEST_SOURCE_SET_NAME) { - sourceSet.platform = KotlinPlatform.COMMON sourceSet.isTestModule = true continue } val compilations = sourceSetToCompilations[sourceSet] 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 } } else { // TODO: change me after design about it diff --git a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt index e95b02a493a..241cee68893 100644 --- a/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt +++ b/idea/kotlin-gradle-tooling/src/KotlinMPPGradleModelImpl.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.gradle import java.io.File import java.util.* +import kotlin.collections.HashSet data class KotlinSourceSetImpl( override val name: String, @@ -15,7 +16,7 @@ data class KotlinSourceSetImpl( override val resourceDirs: Set, override val dependencies: Set, override val dependsOnSourceSets: Set, - val defaultPlatform: KotlinPlatform = KotlinPlatform.COMMON, + val defaultPlatform: KotlinPlatformContainerImpl = KotlinPlatformContainerImpl(), val defaultIsTestModule: Boolean = false ) : KotlinSourceSet { @@ -26,11 +27,11 @@ data class KotlinSourceSetImpl( HashSet(kotlinSourceSet.resourceDirs), kotlinSourceSet.dependencies.map { it.deepCopy(cloningCache) }.toSet(), HashSet(kotlinSourceSet.dependsOnSourceSets), - kotlinSourceSet.platform, + KotlinPlatformContainerImpl(kotlinSourceSet.actualPlatforms), kotlinSourceSet.isTestModule ) - override var platform: KotlinPlatform = defaultPlatform + override var actualPlatforms: KotlinPlatformContainer = defaultPlatform internal set override var isTestModule: Boolean = defaultIsTestModule @@ -171,4 +172,23 @@ data class KotlinMPPGradleModelImpl( ExtraFeaturesImpl(mppModel.extraFeatures.coroutinesState), mppModel.kotlinNativeHome ) -} \ No newline at end of file +} + +class KotlinPlatformContainerImpl() : KotlinPlatformContainer { + private val defaultCommonPlatform = setOf(KotlinPlatform.COMMON) + private var myPlatforms: MutableSet? = null + + + constructor(platform: KotlinPlatformContainer) : this() { + myPlatforms = HashSet(platform.platforms) + } + + override val platforms: Collection + get() = myPlatforms ?: defaultCommonPlatform + + override fun supports(simplePlatform: KotlinPlatform): Boolean = platforms.contains(simplePlatform) + + override fun addSimplePlatforms(platforms: Collection) { + (myPlatforms ?: HashSet().apply { myPlatforms = this }).addAll(platforms) + } +} diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt index 4aae91aedc3..fb8d0181154 100644 --- a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt +++ b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorGeneralTab.kt @@ -21,6 +21,7 @@ import com.intellij.ide.actions.ShowSettingsUtilImpl import com.intellij.openapi.project.Project import com.intellij.openapi.ui.ComboBox import com.intellij.ui.HoverHyperlinkLabel +import com.intellij.util.ui.CheckBox import com.intellij.util.ui.FormBuilder import com.intellij.util.ui.ThreeStateCheckBox 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.idea.compiler.configuration.* import org.jetbrains.kotlin.idea.core.util.onTextChange -import org.jetbrains.kotlin.platform.IdePlatformKind -import org.jetbrains.kotlin.platform.idePlatformKind -import org.jetbrains.kotlin.platform.TargetPlatform -import org.jetbrains.kotlin.platform.isCommon +import org.jetbrains.kotlin.platform.* import org.jetbrains.kotlin.platform.js.isJs import org.jetbrains.kotlin.platform.jvm.isJvm import java.awt.BorderLayout @@ -62,7 +60,7 @@ class KotlinFacetEditorGeneralTab( lateinit var useProjectSettingsCheckBox: ThreeStateCheckBox - lateinit var targetPlatformComboBox: ComboBox + lateinit var platformToCheckbox: Map private lateinit var projectSettingsLink: HoverHyperlinkLabel @@ -93,9 +91,12 @@ class KotlinFacetEditorGeneralTab( ) useProjectSettingsCheckBox = ThreeStateCheckBox("Use project settings").apply { isThirdStateEnabled = isMultiEditor } - targetPlatformComboBox = ComboBox(IdePlatformKind.All_PLATFORMS.toTypedArray()).apply { - setRenderer(DescriptionListCellRenderer()) - } + platformToCheckbox = CommonPlatforms + .allSimplePlatforms + .flatMap { it.componentPlatforms } + .distinct() + .sortedBy { it.platformName } + .associate { Pair(it, ThreeStateCheckBox(it.platformName).apply {isThirdStateEnabled = isMultiEditor} ) } projectSettingsLink = HoverHyperlinkLabel("Edit project settings").apply { addHyperlinkListener { 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 .createFormBuilder() .addComponent(JPanel(BorderLayout()).apply { add(useProjectSettingsCheckBox, BorderLayout.WEST) add(projectSettingsLink, BorderLayout.EAST) - }) - .addLabeledComponent("&Target platform: ", targetPlatformComboBox) + }).addLabeledComponent("Selected target platforms:", targetPlatformsPanel) .addComponent(compilerConfigurable.createComponent()!!.apply { border = null }) @@ -125,14 +130,16 @@ class KotlinFacetEditorGeneralTab( updateCompilerConfigurable() } - targetPlatformComboBox.addActionListener { - updateCompilerConfigurable() + platformToCheckbox.values.forEach { + it.addActionListener { + updateCompilerConfigurable() + } } } internal fun updateCompilerConfigurable() { val useProjectSettings = useProjectSettingsCheckBox.isSelected - compilerConfigurable.setTargetPlatform(chosenPlatform?.idePlatformKind) + compilerConfigurable.setTargetPlatform(getChosenPlatform()?.idePlatformKind) compilerConfigurable.setEnabled(!useProjectSettings) if (useProjectSettings) { compilerConfigurable.commonCompilerArguments = KotlinCommonCompilerArgumentsHolder.getInstance(project).settings.unfrozen() as CommonCompilerArguments? @@ -149,13 +156,15 @@ class KotlinFacetEditorGeneralTab( compilerConfigurable.reset() } - val chosenPlatform: TargetPlatform? - get() = targetPlatformComboBox.selectedItemTyped + fun getChosenPlatform(): TargetPlatform? { + val simplePlatforms = platformToCheckbox.filter { it.value.isSelected }.map { it.key }.toSet() + return if (simplePlatforms.isEmpty()) null else TargetPlatform(simplePlatforms) + } } inner class ArgumentConsistencyValidator : FacetEditorValidator() { 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 { editor.compilerConfigurable.applyTo( this, @@ -270,7 +279,9 @@ class KotlinFacetEditorGeneralTab( apiVersionComboBox.validateOnChange() coroutineSupportComboBox.validateOnChange() } - editor.targetPlatformComboBox.validateOnChange() + editor.platformToCheckbox.values.forEach { + it.validateOnChange() + } editor.updateCompilerConfigurable() isInitialized = true @@ -285,7 +296,7 @@ class KotlinFacetEditorGeneralTab( override fun isModified(): Boolean { if (!isInitialized) return false 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 } @@ -293,7 +304,9 @@ class KotlinFacetEditorGeneralTab( if (!isInitialized) return validateOnce { 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.updateCompilerConfigurable() } @@ -305,7 +318,7 @@ class KotlinFacetEditorGeneralTab( editor.compilerConfigurable.apply() with(configuration.settings) { useProjectSettings = editor.useProjectSettingsCheckBox.isSelected - editor.chosenPlatform?.let { + editor.getChosenPlatform()?.let { if (it != targetPlatform) { val platformArguments = when { it.isJvm() -> editor.compilerConfigurable.k2jvmCompilerArguments diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/MultipleKotlinFacetEditor.kt b/idea/src/org/jetbrains/kotlin/idea/facet/MultipleKotlinFacetEditor.kt index c57ad924574..e75059c144c 100644 --- a/idea/src/org/jetbrains/kotlin/idea/facet/MultipleKotlinFacetEditor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/facet/MultipleKotlinFacetEditor.kt @@ -41,7 +41,7 @@ class MultipleKotlinFacetEditor( initialize() editors.flatMap { it.editorTabs.filterIsInstance() }.forEach { it.initializeIfNeeded() } helper.bind(useProjectSettingsCheckBox, editors) { it.tabEditor.useProjectSettingsCheckBox } - helper.bind(targetPlatformComboBox, editors) { it.tabEditor.targetPlatformComboBox } + //TODO(auskov): Support bulk editing target platforms? with(compilerConfigurable) { helper.bind(reportWarningsCheckBox, editors) { it.compilerConfigurable.reportWarningsCheckBox } helper.bind(enableNewInferenceInIDECheckBox, editors) { it.compilerConfigurable.enableNewInferenceInIDECheckBox } diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt index 0e0c1fda985..1c2cdf5c81a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt @@ -90,6 +90,7 @@ fun KotlinFacetSettings.initializeIfNeeded( targetPlatform.idePlatformKind.tooling.compilerArgumentsForProject(module.project)?.let { mergeBeans(it, this) } mergeBeans(commonArguments, this) } + this.targetPlatform = targetPlatform } if (shouldInferLanguageLevel) { @@ -152,6 +153,7 @@ fun KotlinFacet.configureFacet( val module = module with(configuration.settings) { compilerArguments = null + targetPlatform = null compilerSettings = null initializeIfNeeded( module, diff --git a/idea/testData/configuration/loadAndSaveProjectWithV2FacetConfig/module.iml b/idea/testData/configuration/loadAndSaveProjectWithV2FacetConfig/module.iml index bf66cb0dbcc..51d88d66e97 100644 --- a/idea/testData/configuration/loadAndSaveProjectWithV2FacetConfig/module.iml +++ b/idea/testData/configuration/loadAndSaveProjectWithV2FacetConfig/module.iml @@ -2,7 +2,7 @@ - + diff --git a/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/module.iml b/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/module.iml new file mode 100644 index 00000000000..bf66cb0dbcc --- /dev/null +++ b/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/module.iml @@ -0,0 +1,27 @@ + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/projectFile.ipr b/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/projectFile.ipr new file mode 100644 index 00000000000..a1407e2c8cd --- /dev/null +++ b/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/projectFile.ipr @@ -0,0 +1,41 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/src/foo.kt b/idea/testData/configuration/loadAndSaveProjectWithV2OldPlatformFacetConfig/src/foo.kt new file mode 100644 index 00000000000..e69de29bb2d diff --git a/idea/tests/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInTempDirTest.kt b/idea/tests/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInTempDirTest.kt index f30ce420e2c..a81802e9695 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInTempDirTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInTempDirTest.kt @@ -96,6 +96,16 @@ open class ConfigureKotlinInTempDirTest : AbstractConfigureKotlinInTempDirTest() 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() { KotlinCommonCompilerArgumentsHolder.getInstance(myProject) val settings = myProject.getLanguageVersionSettings() diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJsJpsTest.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJsJpsTest.kt index 568a5e0e78b..743b0aee3f9 100644 --- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJsJpsTest.kt +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/AbstractIncrementalJsJpsTest.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.config.KotlinFacetSettings import org.jetbrains.kotlin.incremental.testingUtils.BuildLogFinder import org.jetbrains.kotlin.incremental.testingUtils.BuildLogFinder.Companion.JS_JPS_LOG import org.jetbrains.kotlin.jps.model.JpsKotlinFacetModuleExtension +import org.jetbrains.kotlin.platform.js.JsPlatforms import java.io.File abstract class AbstractIncrementalJsJpsTest : AbstractIncrementalJpsTest() { @@ -28,6 +29,7 @@ abstract class AbstractIncrementalJsJpsTest : AbstractIncrementalJpsTest() { myProject.modules.forEach { val facet = KotlinFacetSettings() facet.compilerArguments = K2JSCompilerArguments() + facet.targetPlatform = JsPlatforms.defaultJsPlatform it.container.setChild( JpsKotlinFacetModuleExtension.KIND, diff --git a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/dependeciestxt/ModulesTxt.kt b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/dependeciestxt/ModulesTxt.kt index 1a0dc91ae0e..53a4aebe2f6 100644 --- a/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/dependeciestxt/ModulesTxt.kt +++ b/jps-plugin/jps-tests/test/org/jetbrains/kotlin/jps/build/dependeciestxt/ModulesTxt.kt @@ -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.SOURCE_SET_HOLDER 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.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.konan.KonanPlatforms import java.io.File import kotlin.reflect.KMutableProperty1 import kotlin.reflect.full.findAnnotation @@ -253,10 +257,14 @@ class ModulesTxtBuilder { when (flag) { "sourceSetHolder" -> settings.kind = SOURCE_SET_HOLDER "compilationAndSourceSetHolder" -> settings.kind = COMPILATION_AND_SOURCE_SET_HOLDER - "common" -> settings.compilerArguments = K2MetadataCompilerArguments() - "jvm" -> settings.compilerArguments = K2JVMCompilerArguments() - "js" -> settings.compilerArguments = K2JSCompilerArguments() - "native" -> settings.compilerArguments = FakeK2NativeCompilerArguments() + "common" -> settings.compilerArguments = + K2MetadataCompilerArguments().also { settings.targetPlatform = CommonPlatforms.defaultCommonPlatform } + "jvm" -> settings.compilerArguments = + 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 -> { val flagProperty = ModulesTxt.Module.flags[flag] if (flagProperty != null) flagProperty.set(module, true)