diff --git a/ChangeLog.md b/ChangeLog.md
index 7176e9c4a42..ca0be947da9 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -207,6 +207,7 @@ These artifacts include extensions for the types available in the latter JDKs, s
- [`KT-12398`](https://youtrack.jetbrains.com/issue/KT-12398) Call Hierarchy: Show Kotlin usages of Java methods
- [`KT-13976`](https://youtrack.jetbrains.com/issue/KT-13976) Search Everywhere: Render function parameter types
- [`KT-13977`](https://youtrack.jetbrains.com/issue/KT-13977) Search Everywhere: Render extension type in prefix position
+- Implement Kotlin facet
#### Intention actions, inspections and quickfixes
diff --git a/idea/src/META-INF/plugin.xml b/idea/src/META-INF/plugin.xml
index fe1be9146f2..dae14becd52 100644
--- a/idea/src/META-INF/plugin.xml
+++ b/idea/src/META-INF/plugin.xml
@@ -731,6 +731,8 @@
+
+
org.jetbrains.kotlin.idea.intentions.FoldInitializerAndIfToElvisIntention
Kotlin
diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt b/idea/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt
new file mode 100644
index 00000000000..29ee3e95ffa
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/facet/FrameworkLibraryValidatorWithDynamicDescription.kt
@@ -0,0 +1,72 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.facet
+
+import com.intellij.facet.impl.ui.libraries.LibrariesValidatorContext
+import com.intellij.facet.ui.FacetConfigurationQuickFix
+import com.intellij.facet.ui.FacetValidatorsManager
+import com.intellij.facet.ui.ValidationResult
+import com.intellij.facet.ui.libraries.FrameworkLibraryValidator
+import com.intellij.ide.IdeBundle
+import com.intellij.openapi.roots.ui.configuration.libraries.AddCustomLibraryDialog
+import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription
+import com.intellij.openapi.roots.ui.configuration.libraries.LibraryPresentationManager
+import javax.swing.JComponent
+
+// Based on com.intellij.facet.impl.ui.libraries.FrameworkLibraryValidatorImpl
+class FrameworkLibraryValidatorWithDynamicDescription(
+ private val context: LibrariesValidatorContext,
+ private val validatorsManager: FacetValidatorsManager,
+ private val libraryCategoryName: String,
+ private val getLibraryDescription: () -> CustomLibraryDescription
+) : FrameworkLibraryValidator() {
+ override fun check(): ValidationResult {
+ val libraryDescription = getLibraryDescription()
+ val libraryKinds = libraryDescription.suitableLibraryKinds
+ var found = false
+ val presentationManager = LibraryPresentationManager.getInstance()
+ context.rootModel
+ .orderEntries()
+ .using(context.modulesProvider)
+ .recursively()
+ .librariesOnly()
+ .forEachLibrary { library ->
+ if (presentationManager.isLibraryOfKind(library, context.librariesContainer, libraryKinds)) {
+ found = true
+ }
+ !found
+ }
+ if (found) return ValidationResult.OK
+
+ return ValidationResult(
+ IdeBundle.message("label.missed.libraries.text", libraryCategoryName),
+ LibrariesQuickFix(libraryDescription)
+ )
+ }
+
+ private inner class LibrariesQuickFix(
+ private val myDescription: CustomLibraryDescription
+ ) : FacetConfigurationQuickFix(IdeBundle.message("button.fix")) {
+ override fun run(place: JComponent) {
+ val dialog = AddCustomLibraryDialog.createDialog(myDescription, context.librariesContainer,
+ context.module, context.modifiableRootModel,
+ null)
+ dialog.show()
+ validatorsManager.validate()
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacet.kt b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacet.kt
new file mode 100644
index 00000000000..f6d2e746997
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacet.kt
@@ -0,0 +1,34 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.facet
+
+import com.intellij.facet.Facet
+import com.intellij.facet.FacetManager.getInstance
+import com.intellij.openapi.module.Module
+
+class KotlinFacet(
+ module: Module,
+ name: String,
+ configuration: KotlinFacetConfiguration
+) : Facet(KotlinFacetType.INSTANCE, module, name, configuration, null) {
+ companion object {
+ fun get(module: Module): KotlinFacet? {
+ if (module.isDisposed) return null
+ return getInstance(module).getFacetByType(KotlinFacetType.TYPE_ID)
+ }
+ }
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetConfiguration.kt b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetConfiguration.kt
new file mode 100644
index 00000000000..83a4c134e11
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetConfiguration.kt
@@ -0,0 +1,66 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.facet
+
+import com.intellij.facet.FacetConfiguration
+import com.intellij.facet.ui.FacetEditorContext
+import com.intellij.facet.ui.FacetEditorTab
+import com.intellij.facet.ui.FacetValidatorsManager
+import com.intellij.openapi.components.PersistentStateComponent
+import org.jdom.Element
+import org.jetbrains.kotlin.idea.util.DescriptionAware
+
+class KotlinFacetConfiguration : FacetConfiguration, PersistentStateComponent {
+ enum class LanguageLevel(override val description: String) : DescriptionAware {
+ KOTLIN_1_0("1.0"),
+ KOTLIN_1_1("1.1")
+ }
+
+ enum class TargetPlatform(override val description: String) : DescriptionAware {
+ JVM_1_6("JVM 1.6"),
+ JVM_1_8("JVM 1.8"),
+ JS("JavaScript")
+ }
+
+ class Settings {
+ var languageLevel: LanguageLevel? = null
+ var targetPlatformKind: TargetPlatform? = null
+ }
+
+ private var settings = Settings()
+
+ @Suppress("OverridingDeprecatedMember")
+ override fun readExternal(element: Element?) {
+
+ }
+
+ @Suppress("OverridingDeprecatedMember")
+ override fun writeExternal(element: Element?) {
+
+ }
+
+ override fun loadState(state: Settings) {
+ this.settings = settings
+ }
+
+ override fun getState() = settings
+
+ override fun createEditorTabs(
+ editorContext: FacetEditorContext,
+ validatorsManager: FacetValidatorsManager
+ ): Array = arrayOf(KotlinFacetEditorTab(this, editorContext, validatorsManager))
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorTab.kt b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorTab.kt
new file mode 100644
index 00000000000..2f688ebfce2
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetEditorTab.kt
@@ -0,0 +1,165 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.facet
+
+import com.intellij.facet.impl.ui.libraries.DelegatingLibrariesValidatorContext
+import com.intellij.facet.ui.FacetEditorContext
+import com.intellij.facet.ui.FacetEditorTab
+import com.intellij.facet.ui.FacetValidatorsManager
+import com.intellij.facet.ui.libraries.FrameworkLibraryValidator
+import com.intellij.framework.library.LibraryVersionProperties
+import com.intellij.openapi.projectRoots.JavaSdk
+import com.intellij.openapi.projectRoots.JavaSdkVersion
+import com.intellij.openapi.roots.LibraryOrderEntry
+import com.intellij.openapi.roots.libraries.Library
+import com.intellij.openapi.roots.ui.configuration.libraries.CustomLibraryDescription
+import com.intellij.util.ui.FormBuilder
+import org.jetbrains.kotlin.idea.framework.JSLibraryStdDescription
+import org.jetbrains.kotlin.idea.framework.JSLibraryStdPresentationProvider
+import org.jetbrains.kotlin.idea.framework.JavaRuntimeLibraryDescription
+import org.jetbrains.kotlin.idea.framework.getLibraryProperties
+import org.jetbrains.kotlin.idea.util.DescriptionAware
+import org.jetbrains.kotlin.idea.versions.bundledRuntimeVersion
+import java.awt.BorderLayout
+import java.awt.Component
+import javax.swing.*
+
+class KotlinFacetEditorTab(
+ private val configuration: KotlinFacetConfiguration,
+ private val editorContext: FacetEditorContext,
+ validatorsManager: FacetValidatorsManager
+) : FacetEditorTab() {
+ class DescriptionListCellRenderer : DefaultListCellRenderer() {
+ override fun getListCellRendererComponent(list: JList<*>?, value: Any?, index: Int, isSelected: Boolean, cellHasFocus: Boolean): Component {
+ return super.getListCellRendererComponent(list, value, index, isSelected, cellHasFocus).apply {
+ text = (value as? DescriptionAware)?.description ?: ""
+ }
+ }
+ }
+
+ private val KotlinFacetConfiguration.TargetPlatform.libraryDescription: CustomLibraryDescription
+ get() {
+ return when (this) {
+ KotlinFacetConfiguration.TargetPlatform.JVM_1_6, KotlinFacetConfiguration.TargetPlatform.JVM_1_8 ->
+ JavaRuntimeLibraryDescription(editorContext.project)
+ KotlinFacetConfiguration.TargetPlatform.JS ->
+ JSLibraryStdDescription(editorContext.project)
+ }
+ }
+
+ private val languageVersionComboBox =
+ JComboBox(KotlinFacetConfiguration.LanguageLevel.values()).apply {
+ setRenderer(DescriptionListCellRenderer())
+ }
+
+ private val targetPlatformComboBox =
+ JComboBox(KotlinFacetConfiguration.TargetPlatform.values()).apply {
+ setRenderer(DescriptionListCellRenderer())
+ }
+
+ private val validator: FrameworkLibraryValidator
+
+ private fun getRuntimeLibraryVersions(
+ libToProperties: Library.() -> LibraryVersionProperties?
+ ): List {
+ return editorContext
+ .rootModel
+ .orderEntries
+ .asSequence()
+ .filterIsInstance()
+ .mapNotNull { it.library?.libToProperties()?.versionString }
+ .toList()
+ }
+
+ private fun getDefaultTargetPlatform(): KotlinFacetConfiguration.TargetPlatform {
+ getRuntimeLibraryVersions { getLibraryProperties(JSLibraryStdPresentationProvider.getInstance(), this) }.firstOrNull()?.let { javaLib ->
+ return KotlinFacetConfiguration.TargetPlatform.JS
+ }
+
+ val sdk = editorContext.rootModel.sdk
+ val sdkVersion = (sdk?.sdkType as? JavaSdk)?.getVersion(sdk!!)
+ return when {
+ sdkVersion != null && sdkVersion <= JavaSdkVersion.JDK_1_6 -> KotlinFacetConfiguration.TargetPlatform.JVM_1_6
+ else -> KotlinFacetConfiguration.TargetPlatform.JVM_1_8
+ }
+ }
+
+ private fun getDefaultLanguageLevel(): KotlinFacetConfiguration.LanguageLevel {
+ val libVersion = bundledRuntimeVersion()
+ return when {
+ libVersion.startsWith("1.0") -> KotlinFacetConfiguration.LanguageLevel.KOTLIN_1_0
+ else -> KotlinFacetConfiguration.LanguageLevel.KOTLIN_1_1
+ }
+ }
+
+ init {
+ validator = FrameworkLibraryValidatorWithDynamicDescription(
+ DelegatingLibrariesValidatorContext(editorContext),
+ validatorsManager,
+ "kotlin"
+ ) { (targetPlatformComboBox.selectedItem as KotlinFacetConfiguration.TargetPlatform).libraryDescription }
+ validatorsManager.registerValidator(validator)
+
+ targetPlatformComboBox.addActionListener {
+ validatorsManager.validate()
+ }
+
+ with(configuration.state) {
+ if (targetPlatformKind == null) {
+ targetPlatformKind = getDefaultTargetPlatform()
+ }
+
+ if (languageLevel == null) {
+ languageLevel = getDefaultLanguageLevel()
+ }
+ }
+
+ reset()
+ }
+
+ override fun isModified(): Boolean {
+ return languageVersionComboBox.selectedItem != configuration.state.languageLevel
+ || targetPlatformComboBox.selectedItem != configuration.state.targetPlatformKind
+ }
+
+ override fun reset() {
+ languageVersionComboBox.selectedItem = configuration.state.languageLevel
+ targetPlatformComboBox.selectedItem = configuration.state.targetPlatformKind
+ }
+
+ override fun apply() {
+ configuration.state.languageLevel = languageVersionComboBox.selectedItem as KotlinFacetConfiguration.LanguageLevel?
+ configuration.state.targetPlatformKind = targetPlatformComboBox.selectedItem as KotlinFacetConfiguration.TargetPlatform?
+ }
+
+ override fun getDisplayName() = "Kotlin"
+
+ override fun createComponent(): JComponent {
+ val mainPanel = JPanel(BorderLayout())
+ val contentPanel = FormBuilder
+ .createFormBuilder()
+ .addLabeledComponent("&Language version: ", languageVersionComboBox)
+ .addLabeledComponent("&Target platform: ", targetPlatformComboBox)
+ .panel
+ mainPanel.add(contentPanel, BorderLayout.NORTH)
+ return mainPanel
+ }
+
+ override fun disposeUIResources() {
+
+ }
+}
diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetType.kt b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetType.kt
new file mode 100644
index 00000000000..f48229db128
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/facet/KotlinFacetType.kt
@@ -0,0 +1,51 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.facet
+
+import com.intellij.facet.Facet
+import com.intellij.facet.FacetType
+import com.intellij.facet.FacetTypeId
+import com.intellij.facet.FacetTypeRegistry
+import com.intellij.openapi.module.JavaModuleType
+import com.intellij.openapi.module.Module
+import com.intellij.openapi.module.ModuleType
+import org.jetbrains.kotlin.idea.KotlinIcons
+import javax.swing.Icon
+
+class KotlinFacetType : FacetType(TYPE_ID, ID, NAME) {
+ companion object {
+ val TYPE_ID = FacetTypeId("kotlin-language")
+ val ID = "kotlin-language"
+ val NAME = "Kotlin"
+
+ val INSTANCE: KotlinFacetType
+ get() = FacetTypeRegistry.getInstance().findFacetType(TYPE_ID) as KotlinFacetType
+ }
+
+ override fun isSuitableModuleType(moduleType: ModuleType<*>) = moduleType is JavaModuleType
+
+ override fun getIcon(): Icon = KotlinIcons.SMALL_LOGO
+
+ override fun createDefaultConfiguration() = KotlinFacetConfiguration()
+
+ override fun createFacet(
+ module: Module,
+ name: String,
+ configuration: KotlinFacetConfiguration,
+ underlyingFacet: Facet<*>?
+ ) = KotlinFacet(module, name, configuration)
+}
\ No newline at end of file
diff --git a/idea/src/org/jetbrains/kotlin/idea/util/DescriptionAware.kt b/idea/src/org/jetbrains/kotlin/idea/util/DescriptionAware.kt
new file mode 100644
index 00000000000..ed35e497448
--- /dev/null
+++ b/idea/src/org/jetbrains/kotlin/idea/util/DescriptionAware.kt
@@ -0,0 +1,21 @@
+/*
+ * Copyright 2010-2016 JetBrains s.r.o.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package org.jetbrains.kotlin.idea.util
+
+interface DescriptionAware {
+ val description: String
+}