Move coroutine state update logic to KotlinProjectConfigurator

This commit is contained in:
Dmitry Jemerov
2017-08-18 15:36:22 +02:00
parent e781b70170
commit 6fbb370eae
9 changed files with 114 additions and 72 deletions
+1
View File
@@ -17,5 +17,6 @@
<orderEntry type="module" module-name="frontend.java" />
<orderEntry type="module" module-name="js.frontend" />
<orderEntry type="module" module-name="frontend.script" />
<orderEntry type="module" module-name="kotlin-gradle-tooling" />
</component>
</module>
@@ -20,6 +20,7 @@ import com.intellij.codeInsight.CodeInsightUtilCore
import com.intellij.ide.actions.OpenFileAction
import com.intellij.openapi.extensions.Extensions
import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtil
import com.intellij.openapi.project.Project
@@ -33,8 +34,12 @@ import com.intellij.openapi.vfs.WritingAccessProvider
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import org.jetbrains.kotlin.config.CoroutineSupport
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion
import org.jetbrains.kotlin.idea.quickfix.ChangeCoroutineSupportFix
import org.jetbrains.kotlin.idea.util.application.executeCommand
import org.jetbrains.kotlin.idea.util.application.executeWriteCommand
import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId
@@ -177,6 +182,24 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator {
return isModified
}
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
if (runtimeUpdateRequired) {
Messages.showErrorDialog(module.project,
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
"Please update the version in your build script.",
ChangeCoroutineSupportFix.getFixText(state))
return
}
val element = changeCoroutineConfiguration(module, CoroutineSupport.getCompilerArgument(state))
if (element != null) {
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
}
}
companion object {
fun getManipulator(file: PsiFile): GradleBuildScriptManipulator = when (file) {
is KtFile -> KotlinBuildScriptManipulator(file)
@@ -20,11 +20,13 @@ import com.intellij.codeInsight.CodeInsightUtilCore
import com.intellij.ide.actions.OpenFileAction
import com.intellij.ide.highlighter.JavaFileType
import com.intellij.openapi.command.WriteCommandAction
import com.intellij.openapi.fileEditor.OpenFileDescriptor
import com.intellij.openapi.module.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.ui.Messages
import com.intellij.openapi.vfs.WritingAccessProvider
import com.intellij.psi.PsiElement
import com.intellij.psi.PsiFile
import com.intellij.psi.PsiManager
import com.intellij.psi.search.FileTypeIndex
@@ -35,12 +37,17 @@ import org.jetbrains.idea.maven.dom.model.MavenDomPlugin
import org.jetbrains.idea.maven.model.MavenId
import org.jetbrains.idea.maven.project.MavenProjectsManager
import org.jetbrains.idea.maven.utils.MavenArtifactScope
import org.jetbrains.kotlin.config.CoroutineSupport
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.configuration.*
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
import org.jetbrains.kotlin.idea.framework.ui.ConfigureDialogWithModulesAndVersion
import org.jetbrains.kotlin.idea.maven.PomFile
import org.jetbrains.kotlin.idea.maven.changeCoroutineConfiguration
import org.jetbrains.kotlin.idea.maven.excludeMavenChildrenModules
import org.jetbrains.kotlin.idea.maven.kotlinPluginId
import org.jetbrains.kotlin.idea.quickfix.ChangeCoroutineSupportFix
import org.jetbrains.kotlin.idea.util.application.runReadAction
abstract class KotlinMavenConfigurator
@@ -187,6 +194,43 @@ abstract class KotlinMavenConfigurator
}
}
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
val messageTitle = ChangeCoroutineSupportFix.getFixText(state)
if (runtimeUpdateRequired) {
Messages.showErrorDialog(module.project,
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
"Please update the version in your build script.",
messageTitle)
return
}
val element = changeMavenCoroutineConfiguration(module, CoroutineSupport.getCompilerArgument(state), messageTitle)
if (element != null) {
OpenFileDescriptor(module.project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
}
}
private fun changeMavenCoroutineConfiguration(module: Module, value: String, messageTitle: String): PsiElement? {
fun doChangeMavenCoroutineConfiguration(): PsiElement? {
val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null
val pom = PomFile.forFileOrNull(psi) ?: return null
return pom.changeCoroutineConfiguration(value)
}
val element = doChangeMavenCoroutineConfiguration()
if (element == null) {
Messages.showErrorDialog(module.project,
"Failed to update.pom.xml. Please update the file manually.",
messageTitle)
}
return element
}
companion object {
val NAME = "maven"
+1 -1
View File
@@ -67,7 +67,7 @@
<orderEntry type="module" module-name="idea-maven" />
<orderEntry type="module" module-name="backend.jvm" />
<orderEntry type="library" name="kotlin-reflect" level="project" />
<orderEntry type="module" module-name="idea-gradle" scope="TEST" />
<orderEntry type="module" module-name="idea-gradle" />
<orderEntry type="module" module-name="sam-with-receiver-cli" scope="TEST" />
</component>
</module>
@@ -168,7 +168,7 @@ fun getConfigurableModules(project: Project): List<ModuleSourceRootGroup> {
}
fun getAbleToRunConfigurators(module: Module): Collection<KotlinProjectConfigurator> {
val moduleGroup = ModuleSourceRootMap(module.project).toModuleGroup(module)
val moduleGroup = module.toModuleGroup()
return allConfigurators().filter {
it.getStatus(moduleGroup) == ConfigureKotlinStatus.CAN_BE_CONFIGURED
}
@@ -203,6 +203,12 @@ fun getCanBeConfiguredModulesWithKotlinFiles(project: Project, excludeModules: C
}.map { it.baseModule }
}
fun findApplicableConfigurator(module: Module): KotlinProjectConfigurator {
val moduleGroup = module.toModuleGroup()
return allConfigurators().find { it.getStatus(moduleGroup) != ConfigureKotlinStatus.NON_APPLICABLE }
?: KotlinJavaModuleConfigurator.instance
}
fun hasAnyKotlinRuntimeInScope(module: Module): Boolean {
return runReadAction {
val scope = module.getModuleWithDependenciesAndLibrariesScope(hasKotlinFilesOnlyInTests(module))
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.idea.configuration
import com.intellij.openapi.extensions.ExtensionPointName
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.resolve.TargetPlatform
enum class ConfigureKotlinStatus {
@@ -47,6 +48,8 @@ interface KotlinProjectConfigurator {
val targetPlatform: TargetPlatform
fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State)
companion object {
val EP_NAME = ExtensionPointName.create<KotlinProjectConfigurator>("org.jetbrains.kotlin.projectConfigurator")
}
@@ -28,9 +28,14 @@ import com.intellij.openapi.vfs.LocalFileSystem
import com.intellij.openapi.vfs.VfsUtil
import com.intellij.openapi.vfs.VfsUtilCore
import org.jetbrains.annotations.Contract
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersion
import org.jetbrains.kotlin.idea.KotlinPluginUtil
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
import org.jetbrains.kotlin.idea.framework.ui.CreateLibraryDialogWithModules
import org.jetbrains.kotlin.idea.framework.ui.FileUIUtils
import org.jetbrains.kotlin.idea.quickfix.askUpdateRuntime
import org.jetbrains.kotlin.idea.util.application.runWriteAction
import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor
import org.jetbrains.kotlin.idea.versions.findKotlinRuntimeLibrary
@@ -325,6 +330,23 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj
!KotlinPluginUtil.isGradleModule(module)
}
override fun changeCoroutineConfiguration(module: Module, state: LanguageFeature.State) {
val runtimeUpdateRequired = state != LanguageFeature.State.DISABLED &&
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
if (runtimeUpdateRequired && !askUpdateRuntime(module, LanguageFeature.Coroutines.sinceApiVersion)) {
return
}
val facetSettings = KotlinFacetSettingsProvider.getInstance(module.project).getInitializedSettings(module)
ModuleRootModificationUtil.updateModel(module) {
facetSettings.coroutineSupport = state
facetSettings.apiLevel = LanguageVersion.KOTLIN_1_1
facetSettings.languageLevel = LanguageVersion.KOTLIN_1_1
}
}
companion object {
val DEFAULT_LIBRARY_DIR = "lib"
@@ -58,6 +58,8 @@ class ModuleSourceRootMap(val modules: Collection<Module>) {
fun toModuleGroup(module: Module): ModuleSourceRootGroup = groupByBaseModules(listOf(module)).single()
}
fun Module.toModuleGroup() = ModuleSourceRootMap(project).toModuleGroup(this)
private fun isSourceRootPrefix(externalId: String, previousModuleExternalId: String)
= externalId.length < previousModuleExternalId.length && previousModuleExternalId.startsWith(externalId)
@@ -18,30 +18,18 @@ 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.Module
import com.intellij.openapi.module.ModuleUtilCore
import com.intellij.openapi.project.Project
import com.intellij.openapi.roots.ModuleRootModificationUtil
import com.intellij.openapi.roots.ex.ProjectRootManagerEx
import com.intellij.openapi.ui.Messages
import com.intellij.psi.PsiElement
import com.intellij.psi.xml.XmlFile
import org.jetbrains.kotlin.cli.common.arguments.CommonCompilerArguments
import org.jetbrains.kotlin.config.CoroutineSupport
import org.jetbrains.kotlin.config.KotlinFacetSettingsProvider
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersion
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.configuration.findApplicableConfigurator
import org.jetbrains.kotlin.idea.facet.KotlinFacet
import org.jetbrains.kotlin.idea.facet.getRuntimeLibraryVersion
import org.jetbrains.kotlin.idea.maven.PomFile
import org.jetbrains.kotlin.idea.maven.changeCoroutineConfiguration
import org.jetbrains.kotlin.idea.maven.configuration.KotlinMavenConfigurator
import org.jetbrains.kotlin.psi.KtFile
sealed class ChangeCoroutineSupportFix(
@@ -57,58 +45,7 @@ sealed class ChangeCoroutineSupportFix(
override fun invoke(project: Project, editor: Editor?, file: KtFile) {
val module = ModuleUtilCore.findModuleForPsiElement(file) ?: return
val runtimeUpdateRequired = coroutineSupportEnabled &&
(getRuntimeLibraryVersion(module)?.startsWith("1.0") ?: false)
if (KotlinPluginUtil.isGradleModule(module) || KotlinPluginUtil.isMavenModule(module)) {
if (runtimeUpdateRequired) {
Messages.showErrorDialog(project,
"Coroutines support requires version 1.1 or later of the Kotlin runtime library. " +
"Please update the version in your build script.",
super.getText())
return
}
val element = if (KotlinPluginUtil.isGradleModule(module))
KotlinWithGradleConfigurator.changeCoroutineConfiguration(
module, CoroutineSupport.getCompilerArgument(coroutineSupport)
)
else
changeMavenCoroutineConfiguration(module, CoroutineSupport.getCompilerArgument(coroutineSupport))
if (element != null) {
OpenFileDescriptor(project, element.containingFile.virtualFile, element.textRange.startOffset).navigate(true)
}
return
}
if (runtimeUpdateRequired && !askUpdateRuntime(module, LanguageFeature.Coroutines.sinceApiVersion)) {
return
}
val facetSettings = KotlinFacetSettingsProvider.getInstance(project).getInitializedSettings(module)
ModuleRootModificationUtil.updateModel(module) {
facetSettings.coroutineSupport = coroutineSupport
facetSettings.apiLevel = LanguageVersion.KOTLIN_1_1
facetSettings.languageLevel = LanguageVersion.KOTLIN_1_1
}
}
private fun changeMavenCoroutineConfiguration(module: Module, value: String): PsiElement? {
fun doChangeMavenCoroutineConfiguration(): PsiElement? {
val psi = KotlinMavenConfigurator.findModulePomFile(module) as? XmlFile ?: return null
val pom = PomFile.forFileOrNull(psi) ?: return null
return pom.changeCoroutineConfiguration(value)
}
val element = doChangeMavenCoroutineConfiguration()
if (element == null) {
Messages.showErrorDialog(module.project,
"Failed to update.pom.xml. Please update the file manually.",
text)
}
return element
findApplicableConfigurator(module).changeCoroutineConfiguration(module, coroutineSupport)
}
}
@@ -135,14 +72,18 @@ sealed class ChangeCoroutineSupportFix(
override fun getFamilyName() = "Enable/Disable coroutine support"
override fun getText(): String {
return when (coroutineSupport) {
LanguageFeature.State.ENABLED -> "Enable coroutine support"
LanguageFeature.State.ENABLED_WITH_WARNING -> "Enable coroutine support (with warning)"
LanguageFeature.State.ENABLED_WITH_ERROR, LanguageFeature.State.DISABLED -> "Disable coroutine support"
}
return getFixText(coroutineSupport)
}
companion object : KotlinIntentionActionsFactory() {
fun getFixText(state: LanguageFeature.State): String {
return when (state) {
LanguageFeature.State.ENABLED -> "Enable coroutine support"
LanguageFeature.State.ENABLED_WITH_WARNING -> "Enable coroutine support (with warning)"
LanguageFeature.State.ENABLED_WITH_ERROR, LanguageFeature.State.DISABLED -> "Disable coroutine support"
}
}
override fun doCreateActions(diagnostic: Diagnostic): List<IntentionAction> {
val newCoroutineSupports = when (diagnostic.factory) {
Errors.EXPERIMENTAL_FEATURE_ERROR -> {