Add quickfix to enable coroutines by editing build.gradle

#KT-15955 Fixed
This commit is contained in:
Dmitry Jemerov
2017-01-27 19:45:41 +01:00
parent da6640971f
commit c170c7b98f
3 changed files with 115 additions and 2 deletions
@@ -40,8 +40,10 @@ import org.jetbrains.kotlin.psi.psiUtil.getChildrenOfType
import org.jetbrains.plugins.gradle.util.GradleConstants
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
import org.jetbrains.plugins.groovy.lang.psi.GroovyPsiElementFactory
import org.jetbrains.plugins.groovy.lang.psi.api.statements.GrStatement
import org.jetbrains.plugins.groovy.lang.psi.api.statements.blocks.GrClosableBlock
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrApplicationStatement
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.GrMethodCall
import org.jetbrains.plugins.groovy.lang.psi.api.statements.expressions.path.GrMethodCallExpression
import org.jetbrains.plugins.groovy.lang.psi.api.util.GrStatementOwner
import java.io.File
@@ -255,6 +257,43 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
}
}
fun changeCoroutineConfiguration(module: Module, coroutineOption: String): PsiElement? {
return changeBuildGradle(module) { gradleFile ->
changeCoroutineConfiguration(gradleFile, coroutineOption)
}
}
fun changeCoroutineConfiguration(gradleFile: GroovyFile, coroutineOption: String): PsiElement? {
val snippet = "coroutines \"$coroutineOption\""
val kotlinBlock = getBlockOrCreate(gradleFile, "kotlin")
val experimentalBlock = getBlockOrCreate(kotlinBlock, "experimental")
addOrReplaceExpression(experimentalBlock, snippet) { stmt ->
(stmt as? GrMethodCall)?.invokedExpression?.text == "coroutines"
}
return kotlinBlock.parent
}
private fun changeBuildGradle(module: Module, body: (GroovyFile) -> PsiElement?): PsiElement? {
val gradleFilePath = getModuleFilePath(module)
val gradleFile = getBuildGradleFile(module.project, gradleFilePath)
if (gradleFile != null && canConfigureFile(gradleFile)) {
return gradleFile.project.executeWriteCommand("Change build.gradle configuration", null) {
body(gradleFile)
}
}
return null
}
private fun addOrReplaceExpression(block: GrClosableBlock, snippet: String, predicate: (GrStatement) -> Boolean) {
block.statements.firstOrNull(predicate)?.let { stmt ->
val newStatement = GroovyPsiElementFactory.getInstance(block.project).createExpressionFromText(snippet)
CodeStyleManager.getInstance(block.project).reformat(newStatement)
stmt.replaceWithStatement(newStatement)
return
}
addLastExpressionInBlockIfNeeded(snippet, block)
}
fun getKotlinStdlibVersion(module: Module): String? {
val gradleFilePath = getModuleFilePath(module)
val gradleFile = getBuildGradleFile(module.project, gradleFilePath) ?: return null
@@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.quickfix
import com.intellij.codeInsight.intention.IntentionAction
import com.intellij.openapi.editor.Editor
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModuleRootModificationUtil
@@ -29,6 +30,7 @@ import org.jetbrains.kotlin.diagnostics.Diagnostic
import org.jetbrains.kotlin.diagnostics.Errors
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.psi.KtFile
@@ -41,6 +43,14 @@ sealed class ChangeCoroutineSupportFix(
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val module = ModuleUtilCore.findModuleForPsiElement(file) ?: return
if (KotlinPluginUtil.isGradleModule(module)) {
val element = KotlinWithGradleConfigurator.changeCoroutineConfiguration(module, coroutineSupport.compilerArgument)
element?.let {
OpenFileDescriptor(project, it.containingFile.virtualFile, it.textRange.startOffset).navigate(true)
}
return
}
val facetSettings = KotlinFacet.get(module)?.configuration?.settings ?: return
ModuleRootModificationUtil.updateModel(module) {
facetSettings.compilerInfo.coroutineSupport = coroutineSupport
@@ -85,10 +95,13 @@ sealed class ChangeCoroutineSupportFix(
else -> return emptyList()
}
val module = ModuleUtilCore.findModuleForPsiElement(diagnostic.psiElement) ?: return emptyList()
if (KotlinPluginUtil.isGradleModule(module) || KotlinPluginUtil.isMavenModule(module)) return emptyList()
if (KotlinPluginUtil.isMavenModule(module)) return emptyList()
val facetSettings = KotlinFacet.get(module)?.configuration?.settings
val configureInProject = (facetSettings == null || facetSettings.useProjectSettings) &&
!KotlinPluginUtil.isGradleModule(module)
val quickFixConstructor: (PsiElement, CoroutineSupport) -> ChangeCoroutineSupportFix =
if (facetSettings == null || facetSettings.useProjectSettings) ::InProject else ::InModule
if (configureInProject) ::InProject else ::InModule
return newCoroutineSupports.map { quickFixConstructor(diagnostic.psiElement, it) }
}
}
@@ -0,0 +1,61 @@
/*
* Copyright 2010-2017 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.gradle
import com.intellij.testFramework.fixtures.LightCodeInsightFixtureTestCase
import org.jetbrains.kotlin.idea.configuration.KotlinWithGradleConfigurator
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.plugins.groovy.lang.psi.GroovyFile
class KotlinWithGradleConfiguratorTest : LightCodeInsightFixtureTestCase() {
fun testAddCoroutinesSupport() {
val buildGradle = myFixture.configureByText("build.gradle", "apply plugin: 'kotlin'\n") as GroovyFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(buildGradle, "enable")
}
myFixture.checkResult(
"""apply plugin: 'kotlin'
|kotlin {
| experimental {
| coroutines "enable"
| }
|}
|""".trimMargin("|"))
}
fun testChangeCoroutinesSupport() {
val buildGradle = myFixture.configureByText("build.gradle",
"""apply plugin: 'kotlin'
|kotlin {
| experimental {
| coroutines "disable"
| }
|}
|""".trimMargin("|")) as GroovyFile
myFixture.project.executeWriteCommand("") {
KotlinWithGradleConfigurator.changeCoroutineConfiguration(buildGradle, "enable")
}
myFixture.checkResult(
"""apply plugin: 'kotlin'
|kotlin {
| experimental {
| coroutines "enable"
| }
|}
|""".trimMargin("|"))
}
}