MPP: Refactoring, extract IDE platform kinds, allow to add custom platforms

Original commit: d00f5b335a
This commit is contained in:
Yan Zhulanow
2018-08-30 18:46:59 +05:00
parent fd8083bb4b
commit dc022aef69
13 changed files with 284 additions and 82 deletions
+1
View File
@@ -10,6 +10,7 @@ dependencies {
compile(project(":compiler:util"))
compile(project(":compiler:cli-common"))
compile(project(":compiler:frontend.java"))
compile(project(":js:js.frontend"))
compileOnly(intellijDep())
compileOnly(intellijDep("jps-standalone")) { includeJars("jps-model") }
}
@@ -20,33 +20,12 @@ import com.intellij.openapi.components.ServiceManager
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.platform.IdePlatform
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.utils.DescriptionAware
sealed class TargetPlatformKind<out Version : TargetPlatformVersion>(
val version: Version,
val name: String
) : DescriptionAware {
override val description = "$name ${version.description}"
class Jvm(version: JvmTarget) : TargetPlatformKind<JvmTarget>(version, "JVM") {
companion object {
val JVM_PLATFORMS by lazy { JvmTarget.values().map(::Jvm) }
operator fun get(version: JvmTarget) = JVM_PLATFORMS[version.ordinal]
}
}
object JavaScript : TargetPlatformKind<TargetPlatformVersion.NoVersion>(TargetPlatformVersion.NoVersion, "JavaScript")
object Common : TargetPlatformKind<TargetPlatformVersion.NoVersion>(TargetPlatformVersion.NoVersion, "Common (experimental)")
companion object {
val ALL_PLATFORMS: List<TargetPlatformKind<*>> by lazy { Jvm.JVM_PLATFORMS + JavaScript + Common }
val DEFAULT_PLATFORM: TargetPlatformKind<*>
get() = Jvm[JvmTarget.DEFAULT]
}
}
object CoroutineSupport {
@JvmStatic
fun byCompilerArguments(arguments: CommonCompilerArguments?): LanguageFeature.State =
@@ -183,15 +162,16 @@ class KotlinFacetSettings {
compilerArguments!!.apiVersion = value?.versionString
}
val targetPlatformKind: TargetPlatformKind<*>?
get() = compilerArguments?.let {
when (it) {
val platform: IdePlatform<*, *>?
get() {
val compilerArguments = this.compilerArguments
return when (compilerArguments) {
is K2JVMCompilerArguments -> {
val jvmTarget = it.jvmTarget ?: JvmTarget.DEFAULT.description
TargetPlatformKind.Jvm.JVM_PLATFORMS.firstOrNull { it.version.description >= jvmTarget }
val jvmTarget = compilerArguments.jvmTarget ?: JvmTarget.DEFAULT.description
JvmIdePlatformKind.platforms.firstOrNull { it.version.description >= jvmTarget }
}
is K2JSCompilerArguments -> TargetPlatformKind.JavaScript
is K2MetadataCompilerArguments -> TargetPlatformKind.Common
is K2JSCompilerArguments -> JsIdePlatformKind.Platform
is K2MetadataCompilerArguments -> CommonIdePlatformKind.Platform
else -> null
}
}
@@ -220,22 +200,6 @@ class KotlinFacetSettings {
var sourceSetNames: List<String> = emptyList()
}
fun TargetPlatformKind<*>.createCompilerArguments(init: CommonCompilerArguments.() -> Unit = {}): CommonCompilerArguments {
val arguments = when (this) {
is TargetPlatformKind.Jvm -> K2JVMCompilerArguments()
is TargetPlatformKind.JavaScript -> K2JSCompilerArguments()
is TargetPlatformKind.Common -> K2MetadataCompilerArguments()
}
arguments.init()
if (arguments is K2JVMCompilerArguments) {
arguments.jvmTarget = this@createCompilerArguments.version.description
}
return arguments
}
interface KotlinFacetSettingsProvider {
fun getSettings(module: Module): KotlinFacetSettings?
fun getInitializedSettings(module: Module): KotlinFacetSettings
@@ -25,7 +25,10 @@ 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.resolve.jvm.platform.JvmPlatform
import org.jetbrains.kotlin.platform.IdePlatform
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
import org.jetbrains.kotlin.platform.orDefault
import java.lang.reflect.Modifier
import kotlin.reflect.KClass
import kotlin.reflect.full.superclasses
@@ -44,8 +47,9 @@ private fun readV1Config(element: Element): KotlinFacetSettings {
val targetPlatformName = versionInfoElement?.getOptionValue("targetPlatformName")
val languageLevel = versionInfoElement?.getOptionValue("languageLevel")
val apiLevel = versionInfoElement?.getOptionValue("apiLevel")
val targetPlatform = TargetPlatformKind.ALL_PLATFORMS.firstOrNull { it.description == targetPlatformName }
?: TargetPlatformKind.Jvm[JvmTarget.DEFAULT]
val targetPlatform = IdePlatformKind.All_PLATFORMS
.firstOrNull { it.description == targetPlatformName }
?: JvmIdePlatformKind.defaultPlatform
val compilerInfoElement = element.getOptionBody("compilerInfo")
@@ -59,7 +63,7 @@ private fun readV1Config(element: Element): KotlinFacetSettings {
val jvmArgumentsElement = compilerInfoElement?.getOptionBody("k2jvmCompilerArguments")
val jsArgumentsElement = compilerInfoElement?.getOptionBody("k2jsCompilerArguments")
val compilerArguments = targetPlatform.createCompilerArguments { freeArgs = ArrayList() }
val compilerArguments = targetPlatform.createArguments { freeArgs = arrayListOf() }
commonArgumentsElement?.let { XmlSerializer.deserializeInto(compilerArguments, it) }
when (compilerArguments) {
@@ -94,15 +98,17 @@ private fun readV1Config(element: Element): KotlinFacetSettings {
}
}
fun Element.getFacetPlatformByConfigurationElement(): TargetPlatformKind<*> {
fun Element.getFacetPlatformByConfigurationElement(): IdePlatform<*, *> {
val platformName = getAttributeValue("platform")
return TargetPlatformKind.ALL_PLATFORMS.firstOrNull { it.description == platformName } ?: TargetPlatformKind.DEFAULT_PLATFORM
return IdePlatformKind.All_PLATFORMS
.firstOrNull { it.description == platformName }
.orDefault()
}
private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings {
return KotlinFacetSettings().apply {
element.getAttributeValue("useProjectSettings")?.let { useProjectSettings = it.toBoolean() }
val platformKind = element.getFacetPlatformByConfigurationElement()
val targetPlatform = element.getFacetPlatformByConfigurationElement()
element.getChild("implements")?.let {
val items = it.getChildren("implement")
implementedModuleNames = if (items.isNotEmpty()) {
@@ -130,7 +136,7 @@ private fun readV2AndLaterConfig(element: Element): KotlinFacetSettings {
XmlSerializer.deserializeInto(compilerSettings!!, it)
}
element.getChild("compilerArguments")?.let {
compilerArguments = platformKind.createCompilerArguments { freeArgs = ArrayList() }
compilerArguments = targetPlatform.createArguments { freeArgs = ArrayList() }
XmlSerializer.deserializeInto(compilerArguments!!, it)
compilerArguments!!.detectVersionAutoAdvance()
}
@@ -256,7 +262,7 @@ private fun buildChildElement(element: Element, tag: String, bean: Any, filter:
private fun KotlinFacetSettings.writeLatestConfig(element: Element) {
val filter = SkipDefaultsSerializationFilter()
targetPlatformKind?.let {
platform?.let {
element.setAttribute("platform", it.description)
}
if (!useProjectSettings) {
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.platform
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.ServiceManager
import org.jetbrains.kotlin.platform.impl.JvmIdePlatformKind
interface DefaultIdeTargetPlatformKindProvider {
val defaultPlatform: IdePlatform<*, *>
companion object {
val defaultPlatform: IdePlatform<*, *>
get() {
if (ApplicationManager.getApplication() == null) {
// TODO support passing custom platforms in JPS
return JvmIdePlatformKind.defaultPlatform
}
return ServiceManager.getService(DefaultIdeTargetPlatformKindProvider::class.java).defaultPlatform
}
}
}
@@ -0,0 +1,21 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.platform
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.config.TargetPlatformVersion
abstract class IdePlatform<Kind : IdePlatformKind<Kind>, Arguments : CommonCompilerArguments> {
abstract val kind: Kind
abstract val version: TargetPlatformVersion
abstract fun createArguments(init: Arguments.() -> Unit = {}): Arguments
val description
get() = kind.name + " " + version.description
override fun toString() = description
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("IdePlatformKindUtil")
package org.jetbrains.kotlin.platform
import com.intellij.openapi.application.ApplicationManager
import org.jetbrains.kotlin.extensions.ApplicationExtensionDescriptor
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
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.resolve.TargetPlatform
abstract class IdePlatformKind<Kind : IdePlatformKind<Kind>> {
abstract val compilerPlatform: TargetPlatform
abstract val platforms: List<IdePlatform<Kind, *>>
abstract val defaultPlatform: IdePlatform<Kind, *>
abstract val argumentsClass: Class<out CommonCompilerArguments>
abstract val name: String
override fun equals(other: Any?): Boolean = javaClass == other?.javaClass
override fun hashCode(): Int = javaClass.hashCode()
companion object : ApplicationExtensionDescriptor<IdePlatformKind<*>>(
"org.jetbrains.kotlin.idePlatformKind", IdePlatformKind::class.java
) {
// For using only in JPS
private val JPS_KINDS = listOf(JvmIdePlatformKind, JsIdePlatformKind, CommonIdePlatformKind)
val ALL_KINDS by lazy {
if (ApplicationManager.getApplication() == null) {
return@lazy JPS_KINDS
}
val kinds = getInstances()
require(kinds.isNotEmpty()) { "Platform list is empty" }
kinds
}
val All_PLATFORMS by lazy { ALL_KINDS.flatMap { it.platforms } }
val IDE_PLATFORMS_BY_COMPILER_PLATFORMS by lazy { ALL_KINDS.map { it.compilerPlatform to it }.toMap() }
}
}
val TargetPlatform.idePlatformKind: IdePlatformKind<*>
get() = IdePlatformKind.IDE_PLATFORMS_BY_COMPILER_PLATFORMS[this] ?: error("Unknown platform $this")
fun IdePlatformKind<*>?.orDefault(): IdePlatformKind<*> {
return this ?: DefaultIdeTargetPlatformKindProvider.defaultPlatform.kind
}
fun IdePlatform<*, *>?.orDefault(): IdePlatform<*, *> {
return this ?: DefaultIdeTargetPlatformKindProvider.defaultPlatform
}
@@ -0,0 +1,37 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("CommonIdePlatformUtil")
package org.jetbrains.kotlin.platform.impl
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
import org.jetbrains.kotlin.config.TargetPlatformVersion
import org.jetbrains.kotlin.platform.IdePlatform
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.resolve.TargetPlatform
object CommonIdePlatformKind : IdePlatformKind<CommonIdePlatformKind>() {
override val compilerPlatform get() = TargetPlatform.Common
override val platforms get() = listOf(Platform)
override val defaultPlatform get() = Platform
override val argumentsClass get() = K2MetadataCompilerArguments::class.java
override val name get() = "Common (experimental)"
object Platform : IdePlatform<CommonIdePlatformKind, CommonCompilerArguments>() {
override val kind get() = CommonIdePlatformKind
override val version get() = TargetPlatformVersion.NoVersion
override fun createArguments(init: CommonCompilerArguments.() -> Unit) = K2MetadataCompilerArguments().apply(init)
}
}
val IdePlatformKind<*>?.isCommon
get() = this is CommonIdePlatformKind
val IdePlatform<*, *>?.isCommon
get() = this is CommonIdePlatformKind.Platform
@@ -0,0 +1,12 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.platform.impl
import org.jetbrains.kotlin.platform.DefaultIdeTargetPlatformKindProvider
class IdeaDefaultIdeTargetPlatformKindProvider private constructor() : DefaultIdeTargetPlatformKindProvider {
override val defaultPlatform = JvmIdePlatformKind.defaultPlatform
}
@@ -0,0 +1,36 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("JsIdePlatformUtil")
package org.jetbrains.kotlin.platform.impl
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.config.TargetPlatformVersion
import org.jetbrains.kotlin.js.resolve.JsPlatform
import org.jetbrains.kotlin.platform.IdePlatform
import org.jetbrains.kotlin.platform.IdePlatformKind
object JsIdePlatformKind : IdePlatformKind<JsIdePlatformKind>() {
override val compilerPlatform get() = JsPlatform
override val platforms get() = listOf(Platform)
override val defaultPlatform get() = Platform
override val argumentsClass get() = K2JSCompilerArguments::class.java
override val name get() = "JavaScript"
object Platform : IdePlatform<JsIdePlatformKind, K2JSCompilerArguments>() {
override val kind get() = JsIdePlatformKind
override val version get() = TargetPlatformVersion.NoVersion
override fun createArguments(init: K2JSCompilerArguments.() -> Unit) = K2JSCompilerArguments().apply(init)
}
}
val IdePlatformKind<*>?.isJavaScript
get() = this is JsIdePlatformKind
val IdePlatform<*, *>?.isJavaScript
get() = this is JsIdePlatformKind.Platform
@@ -0,0 +1,38 @@
/*
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
* that can be found in the license/LICENSE.txt file.
*/
@file:JvmName("JvmIdePlatformUtil")
package org.jetbrains.kotlin.platform.impl
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.config.JvmTarget
import org.jetbrains.kotlin.platform.IdePlatform
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
object JvmIdePlatformKind : IdePlatformKind<JvmIdePlatformKind>() {
override val compilerPlatform get() = JvmPlatform
override val platforms = JvmTarget.values().map { ver -> Platform(ver) }
override val defaultPlatform get() = Platform(JvmTarget.JVM_1_6)
override val argumentsClass get() = K2JVMCompilerArguments::class.java
override val name get() = "JVM"
data class Platform(override val version: JvmTarget) : IdePlatform<JvmIdePlatformKind, K2JVMCompilerArguments>() {
override val kind get() = JvmIdePlatformKind
override fun createArguments(init: K2JVMCompilerArguments.() -> Unit) = K2JVMCompilerArguments()
.apply(init)
.apply { jvmTarget = this@Platform.version.description }
}
}
val IdePlatformKind<*>?.isJvm
get() = this is JvmIdePlatformKind
val IdePlatform<*, *>?.isJvm
get() = this is JvmIdePlatformKind.Platform
@@ -6,13 +6,13 @@
package org.jetbrains.kotlin.jps.build.dependeciestxt
import org.jetbrains.jps.model.java.JpsJavaDependencyScope
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments
import org.jetbrains.kotlin.cli.common.arguments.K2MetadataCompilerArguments
import org.jetbrains.kotlin.config.CompilerSettings
import org.jetbrains.kotlin.config.KotlinFacetSettings
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.platform.impl.isCommon
import org.jetbrains.kotlin.platform.impl.isJvm
import java.io.File
import kotlin.reflect.KMutableProperty1
import kotlin.reflect.full.findAnnotation
@@ -41,16 +41,14 @@ data class DependenciesTxt(
*/
var kotlinFacetSettings: KotlinFacetSettings? = null
lateinit var jpsModule: JpsModule
val dependencies = mutableListOf<Dependency>()
val usages = mutableListOf<Dependency>()
val isCommonModule
get() = kotlinFacetSettings?.targetPlatformKind == TargetPlatformKind.Common
get() = kotlinFacetSettings?.platform.isCommon
val isJvmModule
get() = kotlinFacetSettings?.targetPlatformKind is TargetPlatformKind.Jvm
get() = kotlinFacetSettings?.platform.isJvm
val expectedBy
get() = dependencies.filter { it.expectedBy }
@@ -10,16 +10,14 @@ import org.jetbrains.jps.model.ex.JpsElementChildRoleBase
import org.jetbrains.jps.model.java.JpsJavaExtensionService
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.kotlin.cli.common.arguments.*
import org.jetbrains.kotlin.config.CompilerSettings
import org.jetbrains.kotlin.config.KotlinFacetSettings
import org.jetbrains.kotlin.config.KotlinModuleKind
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.config.*
import org.jetbrains.kotlin.platform.IdePlatform
val JpsModule.kotlinFacet: JpsKotlinFacetModuleExtension?
get() = container.getChild(JpsKotlinFacetModuleExtension.KIND)
val JpsModule.targetPlatform: TargetPlatformKind<*>?
get() = kotlinFacet?.settings?.targetPlatformKind
val JpsModule.platform: IdePlatform<*, *>?
get() = kotlinFacet?.settings?.platform
val JpsModule.kotlinKind: KotlinModuleKind
get() = kotlinFacet?.settings?.kind ?: KotlinModuleKind.DEFAULT
@@ -10,12 +10,13 @@ import org.jetbrains.jps.builders.ModuleBasedBuildTargetType
import org.jetbrains.jps.builders.java.JavaModuleBuildTargetType
import org.jetbrains.jps.incremental.CompileContext
import org.jetbrains.jps.incremental.ModuleBuildTarget
import org.jetbrains.jps.model.java.JpsJavaModuleType
import org.jetbrains.jps.model.library.JpsOrderRootType
import org.jetbrains.jps.model.module.JpsModule
import org.jetbrains.jps.util.JpsPathUtil
import org.jetbrains.kotlin.config.TargetPlatformKind
import org.jetbrains.kotlin.jps.model.targetPlatform
import org.jetbrains.kotlin.jps.model.platform
import org.jetbrains.kotlin.platform.DefaultIdeTargetPlatformKindProvider
import org.jetbrains.kotlin.platform.IdePlatformKind
import org.jetbrains.kotlin.platform.impl.*
import org.jetbrains.kotlin.utils.LibraryUtils
import java.util.concurrent.ConcurrentHashMap
@@ -25,9 +26,6 @@ fun ModuleBuildTarget(module: JpsModule, isTests: Boolean) =
val JpsModule.productionBuildTarget
get() = ModuleBuildTarget(this, false)
val JpsModule.testBuildTarget
get() = ModuleBuildTarget(this, true)
private val kotlinBuildTargetsCompileContextKey = Key<KotlinBuildTargets>("kotlinBuildTargets")
val CompileContext.kotlinBuildTargets: KotlinBuildTargets
@@ -59,10 +57,13 @@ class KotlinBuildTargets internal constructor(val compileContext: CompileContext
if (target.targetType !is ModuleBasedBuildTargetType) return null
return byJpsModuleBuildTarget.computeIfAbsent(target) {
when (target.module.targetPlatform ?: detectTargetPlatform(target)) {
is TargetPlatformKind.Common -> KotlinCommonModuleBuildTarget(compileContext, target)
is TargetPlatformKind.JavaScript -> KotlinJsModuleBuildTarget(compileContext, target)
is TargetPlatformKind.Jvm -> KotlinJvmModuleBuildTarget(compileContext, target)
val platform = target.module.platform?.kind ?: detectTargetPlatform(target)
when {
platform.isCommon -> KotlinCommonModuleBuildTarget(compileContext, target)
platform.isJavaScript -> KotlinJsModuleBuildTarget(compileContext, target)
platform.isJvm -> KotlinJvmModuleBuildTarget(compileContext, target)
else -> error("Invalid platform $platform")
}
}
}
@@ -71,10 +72,13 @@ class KotlinBuildTargets internal constructor(val compileContext: CompileContext
* Compatibility for KT-14082
* todo: remove when all projects migrated to facets
*/
private fun detectTargetPlatform(target: ModuleBuildTarget): TargetPlatformKind<*> {
if (hasJsStdLib(target)) return TargetPlatformKind.JavaScript
private fun detectTargetPlatform(target: ModuleBuildTarget): IdePlatformKind<*> {
if (hasJsStdLib(target)) {
return JsIdePlatformKind
}
return TargetPlatformKind.DEFAULT_PLATFORM
return JvmIdePlatformKind
return DefaultIdeTargetPlatformKindProvider.defaultPlatform.kind
}
private fun hasJsStdLib(target: ModuleBuildTarget): Boolean {