diff --git a/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CliArgumentStringBuilder.kt b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CliArgumentStringBuilder.kt new file mode 100644 index 00000000000..6fff47ae6f4 --- /dev/null +++ b/compiler/cli/cli-common/src/org/jetbrains/kotlin/cli/common/arguments/CliArgumentStringBuilder.kt @@ -0,0 +1,24 @@ +/* + * 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.cli.common.arguments + +import org.jetbrains.kotlin.config.LanguageFeature + +object CliArgumentStringBuilder { + const val languagePrefix = "-XXLanguage:" + + private val LanguageFeature.State.sign: String + get() = when (this) { + LanguageFeature.State.ENABLED -> "+" + LanguageFeature.State.DISABLED -> "-" + LanguageFeature.State.ENABLED_WITH_WARNING -> "+" // not supported normally + LanguageFeature.State.ENABLED_WITH_ERROR -> "-" // not supported normally + } + + fun LanguageFeature.buildArgumentString(state: LanguageFeature.State): String { + return "$languagePrefix${state.sign}$name" + } +} \ No newline at end of file diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GroovyBuildScriptManipulator.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GroovyBuildScriptManipulator.kt index 63429e0f041..e5151466863 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GroovyBuildScriptManipulator.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/GroovyBuildScriptManipulator.kt @@ -21,6 +21,8 @@ import com.intellij.openapi.roots.ExternalLibraryDescriptor import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiElement import com.intellij.psi.codeStyle.CodeStyleManager +import org.jetbrains.kotlin.cli.common.arguments.CliArgumentStringBuilder.buildArgumentString +import org.jetbrains.kotlin.cli.common.arguments.CliArgumentStringBuilder.languagePrefix import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator.Companion.getBuildScriptSettingsPsiFile import org.jetbrains.kotlin.idea.util.application.runReadAction @@ -156,14 +158,7 @@ class GroovyBuildScriptManipulator( state: LanguageFeature.State, forTests: Boolean ): PsiElement? { - val sign = when (state) { - LanguageFeature.State.ENABLED -> "+" - LanguageFeature.State.DISABLED -> "-" - LanguageFeature.State.ENABLED_WITH_WARNING -> "+" // not supported normally - LanguageFeature.State.ENABLED_WITH_ERROR -> "-" // not supported normally - } - val languagePrefix = "-XXLanguage:" - val featureArgumentString = "$languagePrefix$sign${feature.name}" + val featureArgumentString = feature.buildArgumentString(state) val parameterName = "freeCompilerArgs" return addOrReplaceKotlinTaskParameter( scriptFile, diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinBuildScriptManipulator.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinBuildScriptManipulator.kt index 7027d1bd3e7..fbf44b4e60b 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinBuildScriptManipulator.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinBuildScriptManipulator.kt @@ -21,6 +21,8 @@ import com.intellij.openapi.roots.ExternalLibraryDescriptor import com.intellij.openapi.util.text.StringUtil import com.intellij.psi.PsiElement import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.cli.common.arguments.CliArgumentStringBuilder.buildArgumentString +import org.jetbrains.kotlin.cli.common.arguments.CliArgumentStringBuilder.languagePrefix import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator.Companion.getBuildScriptSettingsPsiFile import org.jetbrains.kotlin.idea.inspections.gradle.GradleHeuristicHelper.PRODUCTION_DEPENDENCY_STATEMENTS @@ -311,14 +313,7 @@ class KotlinBuildScriptManipulator( state: LanguageFeature.State, forTests: Boolean ): PsiElement? { - val sign = when (state) { - LanguageFeature.State.ENABLED -> "+" - LanguageFeature.State.DISABLED -> "-" - LanguageFeature.State.ENABLED_WITH_WARNING -> "+" // not supported normally - LanguageFeature.State.ENABLED_WITH_ERROR -> "-" // not supported normally - } - val languagePrefix = "-XXLanguage:" - val featureArgumentString = "$languagePrefix$sign${feature.name}" + val featureArgumentString = feature.buildArgumentString(state) val parameterName = "freeCompilerArgs" return addOrReplaceKotlinTaskParameter( parameterName, diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt index 6f1124f0a32..b4d67de858c 100644 --- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/PomFile.kt @@ -39,7 +39,9 @@ import org.jetbrains.idea.maven.project.MavenProject import org.jetbrains.idea.maven.project.MavenProjectsManager import org.jetbrains.idea.maven.utils.MavenArtifactScope import org.jetbrains.jps.model.java.JavaSourceRootType +import org.jetbrains.kotlin.cli.common.arguments.CliArgumentStringBuilder.buildArgumentString import org.jetbrains.kotlin.config.KotlinSourceRootType +import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.idea.configuration.RepositoryDescription import org.jetbrains.kotlin.idea.maven.configuration.KotlinMavenConfigurator import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType @@ -441,18 +443,6 @@ class PomFile private constructor(private val xmlFile: XmlFile, val domModel: Ma null ) - private fun MavenDomElement.createChildTag(name: String, value: String? = null) = xmlTag?.createChildTag(name, value) - private fun XmlTag.createChildTag(name: String, value: String? = null) = createChildTag(name, namespace, value, false)!! - - private tailrec fun XmlTag.deleteCascade() { - val oldParent = this.parentTag - delete() - - if (oldParent != null && oldParent.subTags.isEmpty()) { - oldParent.deleteCascade() - } - } - private fun ensureElement(projectElement: XmlTag, localName: String): XmlTag { require(localName in recommendedElementsOrder) { "You can only ensure presence or the elements from the recommendation list" } @@ -700,3 +690,40 @@ fun PomFile.changeCoroutineConfiguration(value: String): PsiElement? { ) ?: return null return changeConfigurationOrProperty(kotlinPlugin, "experimentalCoroutines", "kotlin.compiler.experimental.coroutines", value) } + +fun PomFile.changeFeatureConfiguration( + feature: LanguageFeature, + state: LanguageFeature.State +): PsiElement? { + val kotlinPlugin = findPlugin( + MavenId( + KotlinMavenConfigurator.GROUP_ID, + KotlinMavenConfigurator.MAVEN_PLUGIN_ID, + null + ) + ) ?: return null + val configurationTag = kotlinPlugin.configuration.ensureTagExists() + val argsSubTag = configurationTag.findSubTags("args").firstOrNull() + ?: run { + val childTag = configurationTag.createChildTag("args") + configurationTag.add(childTag) as XmlTag + } + + argsSubTag.findSubTags("arg").filter { feature.name in it.value.text }.forEach { it.deleteCascade() } + val featureArgumentString = feature.buildArgumentString(state) + val childTag = argsSubTag.createChildTag("arg", featureArgumentString) + return argsSubTag.add(childTag) +} + +private fun MavenDomElement.createChildTag(name: String, value: String? = null) = xmlTag?.createChildTag(name, value) +private fun XmlTag.createChildTag(name: String, value: String? = null) = createChildTag(name, namespace, value, false)!! + +private tailrec fun XmlTag.deleteCascade() { + val oldParent = this.parentTag + delete() + + if (oldParent != null && oldParent.subTags.isEmpty()) { + oldParent.deleteCascade() + } +} + diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt index 14eaacc0d38..f95c3c950e6 100644 --- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt @@ -290,7 +290,15 @@ protected constructor( ) return } - // TODO: here we should make something like https://kotlinlang.org/docs/reference/using-maven.html#specifying-compiler-options + + val element = changeMavenFeatureConfiguration( + module, feature, state, messageTitle + ) + + if (element != null) { + OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true) + } + } private fun changeMavenCoroutineConfiguration( @@ -315,6 +323,25 @@ protected constructor( return element } + private fun changeMavenFeatureConfiguration( + module: Module, + feature: LanguageFeature, + state: LanguageFeature.State, + messageTitle: String + ): PsiElement? { + val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null + val pom = PomFile.forFileOrNull(psi) ?: return null + val element = pom.changeFeatureConfiguration(feature, state) + if (element == null) { + Messages.showErrorDialog( + module.project, + "Failed to update.pom.xml. Please update the file manually.", + messageTitle + ) + } + return element + } + companion object { const val GROUP_ID = "org.jetbrains.kotlin" const val MAVEN_PLUGIN_ID = "kotlin-maven-plugin" diff --git a/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/MavenUpdateConfigurationQuickFixTest.kt b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/MavenUpdateConfigurationQuickFixTest.kt index 45e046e226b..730406fbaeb 100644 --- a/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/MavenUpdateConfigurationQuickFixTest.kt +++ b/idea/idea-maven/test/org/jetbrains/kotlin/idea/maven/MavenUpdateConfigurationQuickFixTest.kt @@ -74,6 +74,11 @@ class MavenUpdateConfigurationQuickFixTest : MavenImportingTestCase() { doTest("Enable coroutine support in the current module") } + @Test + fun testEnableInlineClasses() { + doTest("Enable inline classes support in the current module") + } + @Test fun testAddKotlinReflect() { doTest("Add kotlin-reflect.jar to the classpath") diff --git a/idea/idea-maven/testData/languageFeature/enableInlineClasses/pom.xml b/idea/idea-maven/testData/languageFeature/enableInlineClasses/pom.xml new file mode 100644 index 00000000000..9711e6ae81d --- /dev/null +++ b/idea/idea-maven/testData/languageFeature/enableInlineClasses/pom.xml @@ -0,0 +1,56 @@ + + + 4.0.0 + + maventest + maventest + 1.0-SNAPSHOT + + $VERSION$ + + + + org.jetbrains.kotlin + kotlin-stdlib-jre8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + + + ${project.basedir}/src/main/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + wrong-goal + compile + + + + test-compile + test-compile + + test-compile + + + + + + + + + \ No newline at end of file diff --git a/idea/idea-maven/testData/languageFeature/enableInlineClasses/pom.xml.after b/idea/idea-maven/testData/languageFeature/enableInlineClasses/pom.xml.after new file mode 100644 index 00000000000..8643092295f --- /dev/null +++ b/idea/idea-maven/testData/languageFeature/enableInlineClasses/pom.xml.after @@ -0,0 +1,61 @@ + + + 4.0.0 + + maventest + maventest + 1.0-SNAPSHOT + + $VERSION$ + + + + org.jetbrains.kotlin + kotlin-stdlib-jre8 + ${kotlin.version} + + + org.jetbrains.kotlin + kotlin-test + ${kotlin.version} + test + + + + + ${project.basedir}/src/main/kotlin + + + org.jetbrains.kotlin + kotlin-maven-plugin + ${kotlin.version} + + + compile + compile + + wrong-goal + compile + + + + test-compile + test-compile + + test-compile + + + + + + -XXLanguage:+InlineClasses + + + + + + + + \ No newline at end of file diff --git a/idea/idea-maven/testData/languageFeature/enableInlineClasses/src.kt b/idea/idea-maven/testData/languageFeature/enableInlineClasses/src.kt new file mode 100644 index 00000000000..046aa8d2172 --- /dev/null +++ b/idea/idea-maven/testData/languageFeature/enableInlineClasses/src.kt @@ -0,0 +1 @@ +inline class My(val x: Int)