diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt index 04f8c4ad04c..eca178f67de 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt @@ -31,6 +31,7 @@ import com.intellij.openapi.roots.OrderRootType import com.intellij.openapi.roots.impl.libraries.LibraryEx import com.intellij.openapi.roots.impl.libraries.LibraryImpl import com.intellij.openapi.roots.libraries.PersistentLibraryKind +import com.intellij.openapi.util.Key import com.intellij.util.PathUtil import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments @@ -40,6 +41,8 @@ import org.jetbrains.kotlin.config.JvmTarget import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.TargetPlatformKind import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor +import org.jetbrains.kotlin.gradle.ArgsInfo +import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet import org.jetbrains.kotlin.idea.facet.* import org.jetbrains.kotlin.idea.framework.CommonLibraryKind import org.jetbrains.kotlin.idea.framework.JSLibraryKind @@ -48,11 +51,18 @@ import org.jetbrains.kotlin.idea.inspections.gradle.findAll import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion import org.jetbrains.kotlin.idea.inspections.gradle.getResolvedVersionByModuleData import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders +import org.jetbrains.kotlin.psi.UserDataProperty import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData import java.io.File import java.util.* +var Module.compilerArgumentsBySourceSet + by UserDataProperty(Key.create("CURRENT_COMPILER_ARGUMENTS")) + +var Module.sourceSetName + by UserDataProperty(Key.create("SOURCE_SET_NAME")) + interface GradleProjectImportHandler { companion object : ProjectExtensionDescriptor( "org.jetbrains.kotlin.gradleProjectImportHandler", @@ -173,6 +183,16 @@ private fun detectPlatformByLibrary(moduleNode: DataNode): TargetPla return detectedPlatforms.singleOrNull() ?: detectedPlatforms.firstOrNull { it != TargetPlatformKind.Common } } +@Suppress("unused") // Used in the Android plugin +fun configureFacetByGradleModule( + moduleNode: DataNode, + sourceSetName: String?, + ideModule: Module, + modelsProvider: IdeModifiableModelsProvider +): KotlinFacet? { + return configureFacetByGradleModule(ideModule, modelsProvider, moduleNode, null, sourceSetName) +} + fun configureFacetByGradleModule( ideModule: Module, modelsProvider: IdeModifiableModelsProvider, @@ -202,15 +222,14 @@ fun configureFacetByGradleModule( val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false) kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider) + if (sourceSetNode == null) { + ideModule.compilerArgumentsBySourceSet = moduleNode.compilerArgumentsBySourceSet + ideModule.sourceSetName = sourceSetName + } + val argsInfo = moduleNode.compilerArgumentsBySourceSet?.get(sourceSetName ?: "main") if (argsInfo != null) { - val currentCompilerArguments = argsInfo.currentArguments - val defaultCompilerArguments = argsInfo.defaultArguments - val dependencyClasspath = argsInfo.dependencyClasspath.map { PathUtil.toSystemIndependentName(it) } - if (currentCompilerArguments.isNotEmpty()) { - parseCompilerArgumentsToFacet(currentCompilerArguments, defaultCompilerArguments, kotlinFacet, modelsProvider) - } - adjustClasspath(kotlinFacet, dependencyClasspath) + configureFacetByCompilerArguments(kotlinFacet, argsInfo, modelsProvider) } with(kotlinFacet.configuration.settings) { @@ -228,6 +247,16 @@ fun configureFacetByGradleModule( return kotlinFacet } +fun configureFacetByCompilerArguments(kotlinFacet: KotlinFacet, argsInfo: ArgsInfo, modelsProvider: IdeModifiableModelsProvider?) { + val currentCompilerArguments = argsInfo.currentArguments + val defaultCompilerArguments = argsInfo.defaultArguments + val dependencyClasspath = argsInfo.dependencyClasspath.map { PathUtil.toSystemIndependentName(it) } + if (currentCompilerArguments.isNotEmpty()) { + parseCompilerArgumentsToFacet(currentCompilerArguments, defaultCompilerArguments, kotlinFacet, modelsProvider) + } + adjustClasspath(kotlinFacet, dependencyClasspath) +} + private fun getExplicitOutputPath(moduleNode: DataNode, platformKind: TargetPlatformKind<*>?, sourceSet: String): String? { if (platformKind !== TargetPlatformKind.JavaScript) return null val k2jsArgumentList = moduleNode.compilerArgumentsBySourceSet?.get(sourceSet)?.currentArguments ?: return null diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt.as31 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt.as31 deleted file mode 100644 index ad30760deea..00000000000 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt.as31 +++ /dev/null @@ -1,284 +0,0 @@ -/* - * 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.idea.configuration - -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.externalSystem.model.DataNode -import com.intellij.openapi.externalSystem.model.ProjectKeys -import com.intellij.openapi.externalSystem.model.project.LibraryData -import com.intellij.openapi.externalSystem.model.project.ModuleData -import com.intellij.openapi.externalSystem.model.project.ProjectData -import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider -import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil -import com.intellij.openapi.module.Module -import com.intellij.openapi.module.isQualifiedModuleNamesEnabled -import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.OrderRootType -import com.intellij.openapi.roots.impl.libraries.LibraryEx -import com.intellij.openapi.roots.impl.libraries.LibraryImpl -import com.intellij.openapi.roots.libraries.PersistentLibraryKind -import com.intellij.openapi.util.Key -import com.intellij.util.PathUtil -import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments -import org.jetbrains.kotlin.config.CoroutineSupport -import org.jetbrains.kotlin.config.JvmTarget -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.TargetPlatformKind -import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor -import org.jetbrains.kotlin.gradle.ArgsInfo -import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet -import org.jetbrains.kotlin.idea.facet.* -import org.jetbrains.kotlin.idea.framework.CommonLibraryKind -import org.jetbrains.kotlin.idea.framework.JSLibraryKind -import org.jetbrains.kotlin.idea.framework.detectLibraryKind -import org.jetbrains.kotlin.idea.inspections.gradle.findAll -import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion -import org.jetbrains.kotlin.idea.inspections.gradle.getResolvedVersionByModuleData -import org.jetbrains.kotlin.idea.roots.migrateNonJvmSourceFolders -import org.jetbrains.kotlin.psi.UserDataProperty -import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData -import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData -import java.io.File -import java.util.* - -var Module.compilerArgumentsBySourceSet - by UserDataProperty(Key.create("CURRENT_COMPILER_ARGUMENTS")) - -var Module.sourceSetName - by UserDataProperty(Key.create("SOURCE_SET_NAME")) - -interface GradleProjectImportHandler { - companion object : ProjectExtensionDescriptor( - "org.jetbrains.kotlin.gradleProjectImportHandler", - GradleProjectImportHandler::class.java - ) - - fun importBySourceSet(facet: KotlinFacet, sourceSetNode: DataNode) - fun importByModule(facet: KotlinFacet, moduleNode: DataNode) -} - -class KotlinGradleSourceSetDataService : AbstractProjectDataService() { - override fun getTargetDataKey() = GradleSourceSetData.KEY - - override fun postProcess( - toImport: Collection>, - projectData: ProjectData?, - project: Project, - modelsProvider: IdeModifiableModelsProvider - ) { - for (sourceSetNode in toImport) { - val sourceSetData = sourceSetNode.data - val ideModule = modelsProvider.findIdeModule(sourceSetData) ?: continue - - val moduleNode = ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE) ?: continue - val sourceSetName = sourceSetNode.data.id.let { it.substring(it.lastIndexOf(':') + 1) } - val kotlinFacet = configureFacetByGradleModule(moduleNode, sourceSetName, ideModule, modelsProvider) ?: continue - GradleProjectImportHandler.getInstances(project).forEach { it.importBySourceSet(kotlinFacet, sourceSetNode) } - } - } -} - -class KotlinGradleProjectDataService : AbstractProjectDataService() { - override fun getTargetDataKey() = ProjectKeys.MODULE - - override fun postProcess( - toImport: MutableCollection>, - projectData: ProjectData?, - project: Project, - modelsProvider: IdeModifiableModelsProvider - ) { - for (moduleNode in toImport) { - // If source sets are present, configure facets in the their modules - if (ExternalSystemApiUtil.getChildren(moduleNode, GradleSourceSetData.KEY).isNotEmpty()) continue - - val moduleData = moduleNode.data - val ideModule = modelsProvider.findIdeModule(moduleData) ?: continue - val kotlinFacet = configureFacetByGradleModule(moduleNode, null, ideModule, modelsProvider) ?: continue - GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, moduleNode) } - } - } -} - -class KotlinGradleLibraryDataService : AbstractProjectDataService() { - override fun getTargetDataKey() = ProjectKeys.LIBRARY - - override fun postProcess( - toImport: MutableCollection>, - projectData: ProjectData?, - project: Project, - modelsProvider: IdeModifiableModelsProvider - ) { - if (toImport.isEmpty()) return - val projectDataNode = toImport.first().parent!! - @Suppress("UNCHECKED_CAST") - val moduleDataNodes = projectDataNode.children.filter { it.data is ModuleData } as List> - val anyNonJvmModules = moduleDataNodes.any { detectPlatformByPlugin(it)?.takeIf { it !is TargetPlatformKind.Jvm } != null } - for (libraryDataNode in toImport) { - val ideLibrary = modelsProvider.findIdeLibrary(libraryDataNode.data) ?: continue - - val modifiableModel = modelsProvider.getModifiableLibraryModel(ideLibrary) as LibraryEx.ModifiableModelEx - if (anyNonJvmModules || ideLibrary.name?.looksAsNonJvmLibraryName() == true) { - detectLibraryKind(modifiableModel.getFiles(OrderRootType.CLASSES))?.let { modifiableModel.kind = it } - } else if (ideLibrary is LibraryImpl && (ideLibrary.kind === JSLibraryKind || ideLibrary.kind === CommonLibraryKind)) { - resetLibraryKind(modifiableModel) - } - } - } - - private fun String.looksAsNonJvmLibraryName() = nonJvmSuffixes.any { it in this } - - private fun resetLibraryKind(modifiableModel: LibraryEx.ModifiableModelEx) { - try { - val cls = LibraryImpl::class.java - // Don't use name-based lookup because field names are scrambled in IDEA Ultimate - for (field in cls.declaredFields) { - if (field.type == PersistentLibraryKind::class.java) { - field.isAccessible = true - field.set(modifiableModel, null) - return - } - } - LOG.info("Could not find field of type PersistentLibraryKind in LibraryImpl.class") - } catch (e: Exception) { - LOG.info("Failed to reset library kind", e) - } - } - - companion object { - val LOG = Logger.getInstance(KotlinGradleLibraryDataService::class.java) - - val nonJvmSuffixes = listOf("-common", "-js", "-native", "-kjsm") - } -} - -fun detectPlatformByPlugin(moduleNode: DataNode): TargetPlatformKind<*>? { - return when (moduleNode.platformPluginId) { - "kotlin-platform-jvm" -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6] - "kotlin-platform-js" -> TargetPlatformKind.JavaScript - "kotlin-platform-common" -> TargetPlatformKind.Common - else -> null - } -} - -private fun detectPlatformByLibrary(moduleNode: DataNode): TargetPlatformKind<*>? { - val detectedPlatforms = - mavenLibraryIdToPlatform.entries - .filter { moduleNode.getResolvedVersionByModuleData(KOTLIN_GROUP_ID, listOf(it.key)) != null } - .map { it.value }.distinct() - return detectedPlatforms.singleOrNull() ?: detectedPlatforms.firstOrNull { it != TargetPlatformKind.Common } -} - -fun configureFacetByGradleModule( - moduleNode: DataNode, - sourceSetName: String?, - ideModule: Module, - modelsProvider: IdeModifiableModelsProvider -): KotlinFacet? { - if (!moduleNode.isResolved) return null - - if (!moduleNode.hasKotlinPlugin) { - val facetModel = modelsProvider.getModifiableFacetModel(ideModule) - val facet = facetModel.getFacetByType(KotlinFacetType.TYPE_ID) - if (facet != null) { - facetModel.removeFacet(facet) - } - return null - } - - val compilerVersion = moduleNode.findAll(BuildScriptClasspathData.KEY).firstOrNull()?.data?.let(::findKotlinPluginVersion) - ?: return null - val platformKind = detectPlatformByPlugin(moduleNode) ?: detectPlatformByLibrary(moduleNode) - - val coroutinesProperty = CoroutineSupport.byCompilerArgument( - moduleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project) - ) - - val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false) - kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider) - - ideModule.compilerArgumentsBySourceSet = moduleNode.compilerArgumentsBySourceSet - ideModule.sourceSetName = sourceSetName - - val argsInfo = moduleNode.compilerArgumentsBySourceSet?.get(sourceSetName ?: "main") - if (argsInfo != null) { - configureFacetByCompilerArguments(kotlinFacet, argsInfo, modelsProvider) - } - - with(kotlinFacet.configuration.settings) { - val sourceSetNameForImplementedModules = if (ideModule.getBuildSystemType() == AndroidGradle) null else sourceSetName - implementedModuleNames = getImplementedModuleNames(moduleNode, sourceSetNameForImplementedModules, ideModule.project) - - productionOutputPath = getExplicitOutputPath(moduleNode, platformKind, "main") - testOutputPath = getExplicitOutputPath(moduleNode, platformKind, "test") - } - - kotlinFacet.noVersionAutoAdvance() - - if (platformKind != null && platformKind !is TargetPlatformKind.Jvm) { - migrateNonJvmSourceFolders(modelsProvider.getModifiableRootModel(ideModule)) - } - - return kotlinFacet -} - -fun configureFacetByCompilerArguments(kotlinFacet: KotlinFacet, argsInfo: ArgsInfo, modelsProvider: IdeModifiableModelsProvider?) { - val currentCompilerArguments = argsInfo.currentArguments - val defaultCompilerArguments = argsInfo.defaultArguments - val dependencyClasspath = argsInfo.dependencyClasspath.map { PathUtil.toSystemIndependentName(it) } - if (currentCompilerArguments.isNotEmpty()) { - parseCompilerArgumentsToFacet(currentCompilerArguments, defaultCompilerArguments, kotlinFacet, modelsProvider) - } - adjustClasspath(kotlinFacet, dependencyClasspath) -} - -private fun getImplementedModuleNames(moduleNode: DataNode, sourceSetName: String?, project: Project): List { - val baseModuleNames = moduleNode.implementedModuleNames - if (baseModuleNames.isEmpty() || sourceSetName == null) return baseModuleNames - val delimiter = if(isQualifiedModuleNamesEnabled(project)) "." else "_" - return baseModuleNames.map { "$it$delimiter$sourceSetName" } -} - -private fun getExplicitOutputPath(moduleNode: DataNode, platformKind: TargetPlatformKind<*>?, sourceSet: String): String? { - if (platformKind !== TargetPlatformKind.JavaScript) return null - val k2jsArgumentList = moduleNode.compilerArgumentsBySourceSet?.get(sourceSet)?.currentArguments ?: return null - return K2JSCompilerArguments().apply { parseCommandLineArguments(k2jsArgumentList, this) }.outputFile -} - -private fun adjustClasspath(kotlinFacet: KotlinFacet, dependencyClasspath: List) { - if (dependencyClasspath.isEmpty()) return - val arguments = kotlinFacet.configuration.settings.compilerArguments as? K2JVMCompilerArguments ?: return - val fullClasspath = arguments.classpath?.split(File.pathSeparator) ?: emptyList() - if (fullClasspath.isEmpty()) return - val newClasspath = fullClasspath - dependencyClasspath - arguments.classpath = if (newClasspath.isNotEmpty()) newClasspath.joinToString(File.pathSeparator) else null -} - -private val gradlePropertyFiles = listOf("local.properties", "gradle.properties") - -private fun findKotlinCoroutinesProperty(project: Project): String { - for (propertyFileName in gradlePropertyFiles) { - val propertyFile = project.baseDir.findChild(propertyFileName) ?: continue - val properties = Properties() - properties.load(propertyFile.inputStream) - properties.getProperty("kotlin.coroutines")?.let { return it } - } - - return CoroutineSupport.getCompilerArgument(LanguageFeature.Coroutines.defaultState) -} diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt.as32 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt.as32 deleted file mode 100644 index 2977130f527..00000000000 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinGradleSourceSetDataService.kt.as32 +++ /dev/null @@ -1,279 +0,0 @@ -/* - * 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.idea.configuration - -import com.intellij.openapi.diagnostic.Logger -import com.intellij.openapi.externalSystem.model.DataNode -import com.intellij.openapi.externalSystem.model.ProjectKeys -import com.intellij.openapi.externalSystem.model.project.LibraryData -import com.intellij.openapi.externalSystem.model.project.ModuleData -import com.intellij.openapi.externalSystem.model.project.ProjectData -import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider -import com.intellij.openapi.externalSystem.service.project.manage.AbstractProjectDataService -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil -import com.intellij.openapi.module.Module -import com.intellij.openapi.module.isQualifiedModuleNamesEnabled -import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.OrderRootType -import com.intellij.openapi.roots.impl.libraries.LibraryEx -import com.intellij.openapi.roots.impl.libraries.LibraryImpl -import com.intellij.openapi.roots.libraries.PersistentLibraryKind -import com.intellij.openapi.util.Key -import com.intellij.util.PathUtil -import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments -import org.jetbrains.kotlin.cli.common.arguments.parseCommandLineArguments -import org.jetbrains.kotlin.config.CoroutineSupport -import org.jetbrains.kotlin.config.JvmTarget -import org.jetbrains.kotlin.config.LanguageFeature -import org.jetbrains.kotlin.config.TargetPlatformKind -import org.jetbrains.kotlin.extensions.ProjectExtensionDescriptor -import org.jetbrains.kotlin.gradle.ArgsInfo -import org.jetbrains.kotlin.gradle.CompilerArgumentsBySourceSet -import org.jetbrains.kotlin.idea.facet.* -import org.jetbrains.kotlin.idea.framework.CommonLibraryKind -import org.jetbrains.kotlin.idea.framework.JSLibraryKind -import org.jetbrains.kotlin.idea.framework.detectLibraryKind -import org.jetbrains.kotlin.idea.inspections.gradle.findAll -import org.jetbrains.kotlin.idea.inspections.gradle.findKotlinPluginVersion -import org.jetbrains.kotlin.idea.inspections.gradle.getResolvedVersionByModuleData -import org.jetbrains.kotlin.psi.UserDataProperty -import org.jetbrains.plugins.gradle.model.data.BuildScriptClasspathData -import org.jetbrains.plugins.gradle.model.data.GradleSourceSetData -import java.io.File -import java.util.* - -var Module.compilerArgumentsBySourceSet - by UserDataProperty(Key.create("CURRENT_COMPILER_ARGUMENTS")) - -var Module.sourceSetName - by UserDataProperty(Key.create("SOURCE_SET_NAME")) - -interface GradleProjectImportHandler { - companion object : ProjectExtensionDescriptor( - "org.jetbrains.kotlin.gradleProjectImportHandler", - GradleProjectImportHandler::class.java - ) - - fun importBySourceSet(facet: KotlinFacet, sourceSetNode: DataNode) - fun importByModule(facet: KotlinFacet, moduleNode: DataNode) -} - -class KotlinGradleSourceSetDataService : AbstractProjectDataService() { - override fun getTargetDataKey() = GradleSourceSetData.KEY - - override fun postProcess( - toImport: Collection>, - projectData: ProjectData?, - project: Project, - modelsProvider: IdeModifiableModelsProvider - ) { - for (sourceSetNode in toImport) { - val sourceSetData = sourceSetNode.data - val ideModule = modelsProvider.findIdeModule(sourceSetData) ?: continue - - val moduleNode = ExternalSystemApiUtil.findParent(sourceSetNode, ProjectKeys.MODULE) ?: continue - val sourceSetName = sourceSetNode.data.id.let { it.substring(it.lastIndexOf(':') + 1) } - val kotlinFacet = configureFacetByGradleModule(moduleNode, sourceSetName, ideModule, modelsProvider) ?: continue - GradleProjectImportHandler.getInstances(project).forEach { it.importBySourceSet(kotlinFacet, sourceSetNode) } - } - } -} - -class KotlinGradleProjectDataService : AbstractProjectDataService() { - override fun getTargetDataKey() = ProjectKeys.MODULE - - override fun postProcess( - toImport: MutableCollection>, - projectData: ProjectData?, - project: Project, - modelsProvider: IdeModifiableModelsProvider - ) { - for (moduleNode in toImport) { - // If source sets are present, configure facets in the their modules - if (ExternalSystemApiUtil.getChildren(moduleNode, GradleSourceSetData.KEY).isNotEmpty()) continue - - val moduleData = moduleNode.data - val ideModule = modelsProvider.findIdeModule(moduleData) ?: continue - val kotlinFacet = configureFacetByGradleModule(moduleNode, null, ideModule, modelsProvider) ?: continue - GradleProjectImportHandler.getInstances(project).forEach { it.importByModule(kotlinFacet, moduleNode) } - } - } -} - -class KotlinGradleLibraryDataService : AbstractProjectDataService() { - override fun getTargetDataKey() = ProjectKeys.LIBRARY - - override fun postProcess( - toImport: MutableCollection>, - projectData: ProjectData?, - project: Project, - modelsProvider: IdeModifiableModelsProvider - ) { - if (toImport.isEmpty()) return - val projectDataNode = toImport.first().parent!! - @Suppress("UNCHECKED_CAST") - val moduleDataNodes = projectDataNode.children.filter { it.data is ModuleData } as List> - val anyNonJvmModules = moduleDataNodes.any { detectPlatformByPlugin(it)?.takeIf { it !is TargetPlatformKind.Jvm } != null } - for (libraryDataNode in toImport) { - val ideLibrary = modelsProvider.findIdeLibrary(libraryDataNode.data) ?: continue - - val modifiableModel = modelsProvider.getModifiableLibraryModel(ideLibrary) as LibraryEx.ModifiableModelEx - if (anyNonJvmModules || ideLibrary.name?.looksAsNonJvmLibraryName() == true) { - detectLibraryKind(modifiableModel.getFiles(OrderRootType.CLASSES))?.let { modifiableModel.kind = it } - } else if (ideLibrary is LibraryImpl && (ideLibrary.kind === JSLibraryKind || ideLibrary.kind === CommonLibraryKind)) { - resetLibraryKind(modifiableModel) - } - } - } - - private fun String.looksAsNonJvmLibraryName() = nonJvmSuffixes.any { it in this } - - private fun resetLibraryKind(modifiableModel: LibraryEx.ModifiableModelEx) { - try { - val cls = LibraryImpl::class.java - // Don't use name-based lookup because field names are scrambled in IDEA Ultimate - for (field in cls.declaredFields) { - if (field.type == PersistentLibraryKind::class.java) { - field.isAccessible = true - field.set(modifiableModel, null) - return - } - } - LOG.info("Could not find field of type PersistentLibraryKind in LibraryImpl.class") - } catch (e: Exception) { - LOG.info("Failed to reset library kind", e) - } - } - - companion object { - val LOG = Logger.getInstance(KotlinGradleLibraryDataService::class.java) - - val nonJvmSuffixes = listOf("-common", "-js", "-native", "-kjsm") - } -} - -fun detectPlatformByPlugin(moduleNode: DataNode): TargetPlatformKind<*>? { - return when (moduleNode.platformPluginId) { - "kotlin-platform-jvm" -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6] - "kotlin-platform-js" -> TargetPlatformKind.JavaScript - "kotlin-platform-common" -> TargetPlatformKind.Common - else -> null - } -} - -private fun detectPlatformByLibrary(moduleNode: DataNode): TargetPlatformKind<*>? { - val detectedPlatforms = - mavenLibraryIdToPlatform.entries - .filter { moduleNode.getResolvedVersionByModuleData(KOTLIN_GROUP_ID, listOf(it.key)) != null } - .map { it.value }.distinct() - return detectedPlatforms.singleOrNull() ?: detectedPlatforms.firstOrNull { it != TargetPlatformKind.Common } -} - -fun configureFacetByGradleModule( - moduleNode: DataNode, - sourceSetName: String?, - ideModule: Module, - modelsProvider: IdeModifiableModelsProvider -): KotlinFacet? { - if (!moduleNode.isResolved) return null - - if (!moduleNode.hasKotlinPlugin) { - val facetModel = modelsProvider.getModifiableFacetModel(ideModule) - val facet = facetModel.getFacetByType(KotlinFacetType.TYPE_ID) - if (facet != null) { - facetModel.removeFacet(facet) - } - return null - } - - val compilerVersion = moduleNode.findAll(BuildScriptClasspathData.KEY).firstOrNull()?.data?.let(::findKotlinPluginVersion) - ?: return null - val platformKind = detectPlatformByPlugin(moduleNode) ?: detectPlatformByLibrary(moduleNode) - - val coroutinesProperty = CoroutineSupport.byCompilerArgument( - moduleNode.coroutines ?: findKotlinCoroutinesProperty(ideModule.project) - ) - - val kotlinFacet = ideModule.getOrCreateFacet(modelsProvider, false) - kotlinFacet.configureFacet(compilerVersion, coroutinesProperty, platformKind, modelsProvider) - - ideModule.compilerArgumentsBySourceSet = moduleNode.compilerArgumentsBySourceSet - ideModule.sourceSetName = sourceSetName - - val argsInfo = moduleNode.compilerArgumentsBySourceSet?.get(sourceSetName ?: "main") - if (argsInfo != null) { - configureFacetByCompilerArguments(kotlinFacet, argsInfo, modelsProvider) - } - - with(kotlinFacet.configuration.settings) { - val sourceSetNameForImplementedModules = if (ideModule.getBuildSystemType() == AndroidGradle) null else sourceSetName - implementedModuleNames = getImplementedModuleNames(moduleNode, sourceSetNameForImplementedModules, ideModule.project) - - productionOutputPath = getExplicitOutputPath(moduleNode, platformKind, "main") - testOutputPath = getExplicitOutputPath(moduleNode, platformKind, "test") - } - - kotlinFacet.noVersionAutoAdvance() - - return kotlinFacet -} - -fun configureFacetByCompilerArguments(kotlinFacet: KotlinFacet, argsInfo: ArgsInfo, modelsProvider: IdeModifiableModelsProvider?) { - val currentCompilerArguments = argsInfo.currentArguments - val defaultCompilerArguments = argsInfo.defaultArguments - val dependencyClasspath = argsInfo.dependencyClasspath.map { PathUtil.toSystemIndependentName(it) } - if (currentCompilerArguments.isNotEmpty()) { - parseCompilerArgumentsToFacet(currentCompilerArguments, defaultCompilerArguments, kotlinFacet, modelsProvider) - } - adjustClasspath(kotlinFacet, dependencyClasspath) -} - -private fun getImplementedModuleNames(moduleNode: DataNode, sourceSetName: String?, project: Project): List { - val baseModuleNames = moduleNode.implementedModuleNames - if (baseModuleNames.isEmpty() || sourceSetName == null) return baseModuleNames - val delimiter = if(isQualifiedModuleNamesEnabled(project)) "." else "_" - return baseModuleNames.map { "$it$delimiter$sourceSetName" } -} - -private fun getExplicitOutputPath(moduleNode: DataNode, platformKind: TargetPlatformKind<*>?, sourceSet: String): String? { - if (platformKind !== TargetPlatformKind.JavaScript) return null - val k2jsArgumentList = moduleNode.compilerArgumentsBySourceSet?.get(sourceSet)?.currentArguments ?: return null - return K2JSCompilerArguments().apply { parseCommandLineArguments(k2jsArgumentList, this) }.outputFile -} - -private fun adjustClasspath(kotlinFacet: KotlinFacet, dependencyClasspath: List) { - if (dependencyClasspath.isEmpty()) return - val arguments = kotlinFacet.configuration.settings.compilerArguments as? K2JVMCompilerArguments ?: return - val fullClasspath = arguments.classpath?.split(File.pathSeparator) ?: emptyList() - if (fullClasspath.isEmpty()) return - val newClasspath = fullClasspath - dependencyClasspath - arguments.classpath = if (newClasspath.isNotEmpty()) newClasspath.joinToString(File.pathSeparator) else null -} - -private val gradlePropertyFiles = listOf("local.properties", "gradle.properties") - -private fun findKotlinCoroutinesProperty(project: Project): String { - for (propertyFileName in gradlePropertyFiles) { - val propertyFile = project.baseDir.findChild(propertyFileName) ?: continue - val properties = Properties() - properties.load(propertyFile.inputStream) - properties.getProperty("kotlin.coroutines")?.let { return it } - } - - return CoroutineSupport.getCompilerArgument(LanguageFeature.Coroutines.defaultState) -} diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt index 1fde5c7dac2..16cbd7d32af 100644 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt +++ b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt @@ -96,14 +96,19 @@ abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { dialog.show() if (!dialog.isOK) return - project.executeCommand("Configure Kotlin") { + val collector = configureSilently(project, dialog.modulesToConfigure, dialog.kotlinVersion) + collector.showNotification() + } + + fun configureSilently(project: Project, modules: List, version: String): NotificationMessageCollector { + return project.executeCommand("Configure Kotlin") { val collector = createConfigureKotlinNotificationCollector(project) - val changedFiles = configureWithVersion(project, dialog.modulesToConfigure, dialog.kotlinVersion, collector) + val changedFiles = configureWithVersion(project, modules, version, collector) for (file in changedFiles) { OpenFileAction.openFile(file.virtualFile, project) } - collector.showNotification() + collector } } diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as31 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as31 deleted file mode 100644 index 16cbd7d32af..00000000000 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as31 +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright 2000-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.idea.configuration - -import com.intellij.codeInsight.CodeInsightUtilCore -import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix -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 -import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.roots.DependencyScope -import com.intellij.openapi.roots.ExternalLibraryDescriptor -import com.intellij.openapi.roots.ModuleRootManager -import com.intellij.openapi.ui.Messages -import com.intellij.openapi.vfs.VfsUtil -import com.intellij.openapi.vfs.WritingAccessProvider -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import com.intellij.util.PathUtil -import org.jetbrains.kotlin.config.ApiVersion -import org.jetbrains.kotlin.config.CoroutineSupport -import org.jetbrains.kotlin.config.LanguageFeature -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.util.application.runReadAction -import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor -import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.plugins.gradle.util.GradleConstants -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import java.io.File -import java.util.* - -abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { - - override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus { - val module = moduleSourceRootGroup.baseModule - if (!isApplicable(module)) { - return ConfigureKotlinStatus.NON_APPLICABLE - } - - if (moduleSourceRootGroup.sourceRootModules.all(::hasAnyKotlinRuntimeInScope)) { - return ConfigureKotlinStatus.CONFIGURED - } - - val buildFiles = runReadAction { - listOf( - module.getBuildScriptPsiFile(), - module.project.getTopLevelBuildScriptPsiFile() - ).filterNotNull() - } - - if (buildFiles.isEmpty()) { - return ConfigureKotlinStatus.NON_APPLICABLE - } - - if (buildFiles.none { it.isConfiguredByAnyGradleConfigurator() }) { - return ConfigureKotlinStatus.CAN_BE_CONFIGURED - } - - return ConfigureKotlinStatus.BROKEN - } - - private fun PsiFile.isConfiguredByAnyGradleConfigurator(): Boolean { - return Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME) - .filterIsInstance() - .any { it.isFileConfigured(this) } - } - - protected open fun isApplicable(module: Module): Boolean = - module.getBuildSystemType() == Gradle - - protected open fun getMinimumSupportedVersion() = "1.0.0" - - protected fun PsiFile.isKtDsl() = this is KtFile - - private fun isFileConfigured(buildScript: PsiFile): Boolean = with(getManipulator(buildScript)) { - isConfiguredWithOldSyntax(kotlinPluginName) || isConfigured(getKotlinPluginExpression(buildScript.isKtDsl())) - } - - @JvmSuppressWildcards - override fun configure(project: Project, excludeModules: Collection) { - val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules, getMinimumSupportedVersion()) - - dialog.show() - if (!dialog.isOK) return - - val collector = configureSilently(project, dialog.modulesToConfigure, dialog.kotlinVersion) - collector.showNotification() - } - - fun configureSilently(project: Project, modules: List, version: String): NotificationMessageCollector { - return project.executeCommand("Configure Kotlin") { - val collector = createConfigureKotlinNotificationCollector(project) - val changedFiles = configureWithVersion(project, modules, version, collector) - - for (file in changedFiles) { - OpenFileAction.openFile(file.virtualFile, project) - } - collector - } - } - - fun configureWithVersion( - project: Project, - modulesToConfigure: List, - kotlinVersion: String, - collector: NotificationMessageCollector - ): HashSet { - val filesToOpen = HashSet() - val buildScript = project.getTopLevelBuildScriptPsiFile() - if (buildScript != null && canConfigureFile(buildScript)) { - val isModified = configureBuildScript(buildScript, true, kotlinVersion, collector) - if (isModified) { - filesToOpen.add(buildScript) - } - } - - for (module in modulesToConfigure) { - val file = module.getBuildScriptPsiFile() - if (file != null && canConfigureFile(file)) { - configureModule(module, file, false, kotlinVersion, collector, filesToOpen) - } else { - showErrorMessage(project, "Cannot find build.gradle file for module " + module.name) - } - } - return filesToOpen - } - - open fun configureModule( - module: Module, - file: PsiFile, - isTopLevelProjectFile: Boolean, - version: String, - collector: NotificationMessageCollector, - filesToOpen: MutableCollection - ) { - val isModified = configureBuildScript(file, isTopLevelProjectFile, version, collector) - if (isModified) { - filesToOpen.add(file) - } - } - - protected fun configureModuleBuildScript(file: PsiFile, version: String): Boolean { - val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk } - val jvmTarget = getJvmTarget(sdk, version) - return getManipulator(file).configureModuleBuildScript( - kotlinPluginName, - getKotlinPluginExpression(file.isKtDsl()), - getStdlibArtifactName(sdk, version), - version, - jvmTarget - ) - } - - protected open fun getStdlibArtifactName(sdk: Sdk?, version: String) = getStdlibArtifactId(sdk, version) - - protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null - - protected abstract val kotlinPluginName: String - protected abstract fun getKotlinPluginExpression(forKotlinDsl: Boolean): String - - protected open fun addElementsToFile( - file: PsiFile, - isTopLevelProjectFile: Boolean, - version: String - ): Boolean { - if (!isTopLevelProjectFile) { - var wasModified = getManipulator(file).configureProjectBuildScript(kotlinPluginName, version) - wasModified = wasModified or configureModuleBuildScript(file, version) - return wasModified - } - return false - } - - private fun configureBuildScript( - file: PsiFile, - isTopLevelProjectFile: Boolean, - version: String, - collector: NotificationMessageCollector - ): Boolean { - val isModified = file.project.executeWriteCommand("Configure ${file.name}", null) { - val isModified = addElementsToFile(file, isTopLevelProjectFile, version) - - CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(file) - isModified - } - - val virtualFile = file.virtualFile - if (virtualFile != null && isModified) { - collector.addMessage(virtualFile.path + " was modified") - } - return isModified - } - - override fun updateLanguageVersion( - module: Module, - languageVersion: String?, - apiVersion: String?, - requiredStdlibVersion: ApiVersion, - forTests: Boolean - ) { - val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion -> - runtimeVersion < requiredStdlibVersion - } ?: false - - if (runtimeUpdateRequired) { - Messages.showErrorDialog( - module.project, - "This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " + - "Please update the version in your build script.", - "Update Language Version" - ) - return - } - - val element = changeLanguageVersion(module, languageVersion, apiVersion, forTests) - - element?.let { - OpenFileDescriptor(module.project, it.containingFile.virtualFile, it.textRange.startOffset).navigate(true) - } - } - - 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) - } - } - - override fun addLibraryDependency( - module: Module, - element: PsiElement, - library: ExternalLibraryDescriptor, - libraryJarDescriptors: List - ) { - val scope = OrderEntryFix.suggestScopeByLocation(module, element) - KotlinWithGradleConfigurator.addKotlinLibraryToModule(module, scope, library) - } - - companion object { - fun getManipulator(file: PsiFile, preferNewSyntax: Boolean = true): GradleBuildScriptManipulator<*> = when (file) { - is KtFile -> KotlinBuildScriptManipulator(file, preferNewSyntax) - is GroovyFile -> GroovyBuildScriptManipulator(file, preferNewSyntax) - else -> error("Unknown build script file type (${file::class.qualifiedName})!") - } - - val GROUP_ID = "org.jetbrains.kotlin" - val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin" - - val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\"" - - private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts" - private val KOTLIN_SETTINGS_SCRIPT_NAME = "settings.gradle.kts" - - fun getGroovyDependencySnippet(artifactName: String, scope: String, withVersion: Boolean) = - "$scope \"org.jetbrains.kotlin:$artifactName${if (withVersion) ":\$kotlin_version" else ""}\"" - - fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'" - - fun addKotlinLibraryToModule(module: Module, scope: DependencyScope, libraryDescriptor: ExternalLibraryDescriptor) { - val buildScript = module.getBuildScriptPsiFile() ?: return - if (!canConfigureFile(buildScript)) { - return - } - - getManipulator(buildScript) - .addKotlinLibraryToModuleBuildScript(scope, libraryDescriptor, module.getBuildSystemType() == AndroidGradle) - - buildScript.virtualFile?.let { - createConfigureKotlinNotificationCollector(buildScript.project) - .addMessage(it.path + " was modified") - .showNotification() - } - } - - fun changeCoroutineConfiguration(module: Module, coroutineOption: String): PsiElement? = changeBuildGradle(module) { - getManipulator(it).changeCoroutineConfiguration(coroutineOption) - } - - fun changeLanguageVersion(module: Module, languageVersion: String?, apiVersion: String?, forTests: Boolean) = - changeBuildGradle(module) { buildScriptFile -> - val manipulator = getManipulator(buildScriptFile) - var result: PsiElement? = null - if (languageVersion != null) { - result = manipulator.changeLanguageVersion(languageVersion, forTests) - } - - if (apiVersion != null) { - result = manipulator.changeApiVersion(apiVersion, forTests) - } - - result - } - - private fun changeBuildGradle(module: Module, body: (PsiFile) -> PsiElement?): PsiElement? { - val buildScriptFile = module.getBuildScriptPsiFile() - if (buildScriptFile != null && canConfigureFile(buildScriptFile)) { - return buildScriptFile.project.executeWriteCommand("Change build.gradle configuration", null) { - body(buildScriptFile) - } - } - return null - } - - fun getKotlinStdlibVersion(module: Module): String? { - return module.getBuildScriptPsiFile()?.let { - getManipulator(it).getKotlinStdlibVersion() - } - } - - private fun canConfigureFile(file: PsiFile): Boolean = WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null) - - private fun Module.getBuildScriptPsiFile() = - getBuildScriptFile(GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(project) - - fun Module.getBuildScriptSettingsPsiFile() = - getBuildScriptSettingsFile(GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) - - private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { - findBuildGradleFile(it, GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(this) - } - - fun Module.getTopLevelBuildScriptSettingsPsiFile() = - ExternalSystemApiUtil.getExternalRootProjectPath(this)?.let { externalProjectPath -> - findBuildGradleFile(externalProjectPath, GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) - } - - private fun Module.getBuildScriptFile(vararg fileNames: String): File? { - val moduleDir = File(moduleFilePath).parent - findBuildGradleFile(moduleDir, *fileNames)?.let { - return it - } - - ModuleRootManager.getInstance(this).contentRoots.forEach { root -> - findBuildGradleFile(root.path, *fileNames)?.let { - return it - } - } - - ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> - findBuildGradleFile(externalProjectPath, *fileNames)?.let { - return it - } - } - - return null - } - - private fun Module.getBuildScriptSettingsFile(vararg fileNames: String): File? { - ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> - return generateSequence(externalProjectPath) { - PathUtil.getParentPath(it).let { if (it.isBlank()) null else it } - }.mapNotNull { - findBuildGradleFile(it, *fileNames) - }.firstOrNull() - } - - return null - } - - private fun findBuildGradleFile(path: String, vararg fileNames: String): File? = - fileNames.asSequence().map { File(path + "/" + it) }.firstOrNull { it.exists() } - - private fun File.getPsiFile(project: Project) = VfsUtil.findFileByIoFile(this, true)?.let { - PsiManager.getInstance(project).findFile(it) - } - - private fun showErrorMessage(project: Project, message: String?) { - Messages.showErrorDialog( - project, - "Couldn't configure kotlin-gradle plugin automatically.
" + - (if (message != null) message + "
" else "") + - "
See manual installation instructions here.", - "Configure Kotlin-Gradle Plugin" - ) - } - } -} diff --git a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as32 b/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as32 deleted file mode 100644 index 16cbd7d32af..00000000000 --- a/idea/idea-gradle/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt.as32 +++ /dev/null @@ -1,403 +0,0 @@ -/* - * Copyright 2000-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.idea.configuration - -import com.intellij.codeInsight.CodeInsightUtilCore -import com.intellij.codeInsight.daemon.impl.quickfix.OrderEntryFix -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 -import com.intellij.openapi.projectRoots.Sdk -import com.intellij.openapi.roots.DependencyScope -import com.intellij.openapi.roots.ExternalLibraryDescriptor -import com.intellij.openapi.roots.ModuleRootManager -import com.intellij.openapi.ui.Messages -import com.intellij.openapi.vfs.VfsUtil -import com.intellij.openapi.vfs.WritingAccessProvider -import com.intellij.psi.PsiElement -import com.intellij.psi.PsiFile -import com.intellij.psi.PsiManager -import com.intellij.util.PathUtil -import org.jetbrains.kotlin.config.ApiVersion -import org.jetbrains.kotlin.config.CoroutineSupport -import org.jetbrains.kotlin.config.LanguageFeature -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.util.application.runReadAction -import org.jetbrains.kotlin.idea.versions.LibraryJarDescriptor -import org.jetbrains.kotlin.idea.versions.getStdlibArtifactId -import org.jetbrains.kotlin.psi.KtFile -import org.jetbrains.plugins.gradle.util.GradleConstants -import org.jetbrains.plugins.groovy.lang.psi.GroovyFile -import java.io.File -import java.util.* - -abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { - - override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus { - val module = moduleSourceRootGroup.baseModule - if (!isApplicable(module)) { - return ConfigureKotlinStatus.NON_APPLICABLE - } - - if (moduleSourceRootGroup.sourceRootModules.all(::hasAnyKotlinRuntimeInScope)) { - return ConfigureKotlinStatus.CONFIGURED - } - - val buildFiles = runReadAction { - listOf( - module.getBuildScriptPsiFile(), - module.project.getTopLevelBuildScriptPsiFile() - ).filterNotNull() - } - - if (buildFiles.isEmpty()) { - return ConfigureKotlinStatus.NON_APPLICABLE - } - - if (buildFiles.none { it.isConfiguredByAnyGradleConfigurator() }) { - return ConfigureKotlinStatus.CAN_BE_CONFIGURED - } - - return ConfigureKotlinStatus.BROKEN - } - - private fun PsiFile.isConfiguredByAnyGradleConfigurator(): Boolean { - return Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME) - .filterIsInstance() - .any { it.isFileConfigured(this) } - } - - protected open fun isApplicable(module: Module): Boolean = - module.getBuildSystemType() == Gradle - - protected open fun getMinimumSupportedVersion() = "1.0.0" - - protected fun PsiFile.isKtDsl() = this is KtFile - - private fun isFileConfigured(buildScript: PsiFile): Boolean = with(getManipulator(buildScript)) { - isConfiguredWithOldSyntax(kotlinPluginName) || isConfigured(getKotlinPluginExpression(buildScript.isKtDsl())) - } - - @JvmSuppressWildcards - override fun configure(project: Project, excludeModules: Collection) { - val dialog = ConfigureDialogWithModulesAndVersion(project, this, excludeModules, getMinimumSupportedVersion()) - - dialog.show() - if (!dialog.isOK) return - - val collector = configureSilently(project, dialog.modulesToConfigure, dialog.kotlinVersion) - collector.showNotification() - } - - fun configureSilently(project: Project, modules: List, version: String): NotificationMessageCollector { - return project.executeCommand("Configure Kotlin") { - val collector = createConfigureKotlinNotificationCollector(project) - val changedFiles = configureWithVersion(project, modules, version, collector) - - for (file in changedFiles) { - OpenFileAction.openFile(file.virtualFile, project) - } - collector - } - } - - fun configureWithVersion( - project: Project, - modulesToConfigure: List, - kotlinVersion: String, - collector: NotificationMessageCollector - ): HashSet { - val filesToOpen = HashSet() - val buildScript = project.getTopLevelBuildScriptPsiFile() - if (buildScript != null && canConfigureFile(buildScript)) { - val isModified = configureBuildScript(buildScript, true, kotlinVersion, collector) - if (isModified) { - filesToOpen.add(buildScript) - } - } - - for (module in modulesToConfigure) { - val file = module.getBuildScriptPsiFile() - if (file != null && canConfigureFile(file)) { - configureModule(module, file, false, kotlinVersion, collector, filesToOpen) - } else { - showErrorMessage(project, "Cannot find build.gradle file for module " + module.name) - } - } - return filesToOpen - } - - open fun configureModule( - module: Module, - file: PsiFile, - isTopLevelProjectFile: Boolean, - version: String, - collector: NotificationMessageCollector, - filesToOpen: MutableCollection - ) { - val isModified = configureBuildScript(file, isTopLevelProjectFile, version, collector) - if (isModified) { - filesToOpen.add(file) - } - } - - protected fun configureModuleBuildScript(file: PsiFile, version: String): Boolean { - val sdk = ModuleUtil.findModuleForPsiElement(file)?.let { ModuleRootManager.getInstance(it).sdk } - val jvmTarget = getJvmTarget(sdk, version) - return getManipulator(file).configureModuleBuildScript( - kotlinPluginName, - getKotlinPluginExpression(file.isKtDsl()), - getStdlibArtifactName(sdk, version), - version, - jvmTarget - ) - } - - protected open fun getStdlibArtifactName(sdk: Sdk?, version: String) = getStdlibArtifactId(sdk, version) - - protected open fun getJvmTarget(sdk: Sdk?, version: String): String? = null - - protected abstract val kotlinPluginName: String - protected abstract fun getKotlinPluginExpression(forKotlinDsl: Boolean): String - - protected open fun addElementsToFile( - file: PsiFile, - isTopLevelProjectFile: Boolean, - version: String - ): Boolean { - if (!isTopLevelProjectFile) { - var wasModified = getManipulator(file).configureProjectBuildScript(kotlinPluginName, version) - wasModified = wasModified or configureModuleBuildScript(file, version) - return wasModified - } - return false - } - - private fun configureBuildScript( - file: PsiFile, - isTopLevelProjectFile: Boolean, - version: String, - collector: NotificationMessageCollector - ): Boolean { - val isModified = file.project.executeWriteCommand("Configure ${file.name}", null) { - val isModified = addElementsToFile(file, isTopLevelProjectFile, version) - - CodeInsightUtilCore.forcePsiPostprocessAndRestoreElement(file) - isModified - } - - val virtualFile = file.virtualFile - if (virtualFile != null && isModified) { - collector.addMessage(virtualFile.path + " was modified") - } - return isModified - } - - override fun updateLanguageVersion( - module: Module, - languageVersion: String?, - apiVersion: String?, - requiredStdlibVersion: ApiVersion, - forTests: Boolean - ) { - val runtimeUpdateRequired = getRuntimeLibraryVersion(module)?.let { ApiVersion.parse(it) }?.let { runtimeVersion -> - runtimeVersion < requiredStdlibVersion - } ?: false - - if (runtimeUpdateRequired) { - Messages.showErrorDialog( - module.project, - "This language feature requires version $requiredStdlibVersion or later of the Kotlin runtime library. " + - "Please update the version in your build script.", - "Update Language Version" - ) - return - } - - val element = changeLanguageVersion(module, languageVersion, apiVersion, forTests) - - element?.let { - OpenFileDescriptor(module.project, it.containingFile.virtualFile, it.textRange.startOffset).navigate(true) - } - } - - 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) - } - } - - override fun addLibraryDependency( - module: Module, - element: PsiElement, - library: ExternalLibraryDescriptor, - libraryJarDescriptors: List - ) { - val scope = OrderEntryFix.suggestScopeByLocation(module, element) - KotlinWithGradleConfigurator.addKotlinLibraryToModule(module, scope, library) - } - - companion object { - fun getManipulator(file: PsiFile, preferNewSyntax: Boolean = true): GradleBuildScriptManipulator<*> = when (file) { - is KtFile -> KotlinBuildScriptManipulator(file, preferNewSyntax) - is GroovyFile -> GroovyBuildScriptManipulator(file, preferNewSyntax) - else -> error("Unknown build script file type (${file::class.qualifiedName})!") - } - - val GROUP_ID = "org.jetbrains.kotlin" - val GRADLE_PLUGIN_ID = "kotlin-gradle-plugin" - - val CLASSPATH = "classpath \"$GROUP_ID:$GRADLE_PLUGIN_ID:\$kotlin_version\"" - - private val KOTLIN_BUILD_SCRIPT_NAME = "build.gradle.kts" - private val KOTLIN_SETTINGS_SCRIPT_NAME = "settings.gradle.kts" - - fun getGroovyDependencySnippet(artifactName: String, scope: String, withVersion: Boolean) = - "$scope \"org.jetbrains.kotlin:$artifactName${if (withVersion) ":\$kotlin_version" else ""}\"" - - fun getGroovyApplyPluginDirective(pluginName: String) = "apply plugin: '$pluginName'" - - fun addKotlinLibraryToModule(module: Module, scope: DependencyScope, libraryDescriptor: ExternalLibraryDescriptor) { - val buildScript = module.getBuildScriptPsiFile() ?: return - if (!canConfigureFile(buildScript)) { - return - } - - getManipulator(buildScript) - .addKotlinLibraryToModuleBuildScript(scope, libraryDescriptor, module.getBuildSystemType() == AndroidGradle) - - buildScript.virtualFile?.let { - createConfigureKotlinNotificationCollector(buildScript.project) - .addMessage(it.path + " was modified") - .showNotification() - } - } - - fun changeCoroutineConfiguration(module: Module, coroutineOption: String): PsiElement? = changeBuildGradle(module) { - getManipulator(it).changeCoroutineConfiguration(coroutineOption) - } - - fun changeLanguageVersion(module: Module, languageVersion: String?, apiVersion: String?, forTests: Boolean) = - changeBuildGradle(module) { buildScriptFile -> - val manipulator = getManipulator(buildScriptFile) - var result: PsiElement? = null - if (languageVersion != null) { - result = manipulator.changeLanguageVersion(languageVersion, forTests) - } - - if (apiVersion != null) { - result = manipulator.changeApiVersion(apiVersion, forTests) - } - - result - } - - private fun changeBuildGradle(module: Module, body: (PsiFile) -> PsiElement?): PsiElement? { - val buildScriptFile = module.getBuildScriptPsiFile() - if (buildScriptFile != null && canConfigureFile(buildScriptFile)) { - return buildScriptFile.project.executeWriteCommand("Change build.gradle configuration", null) { - body(buildScriptFile) - } - } - return null - } - - fun getKotlinStdlibVersion(module: Module): String? { - return module.getBuildScriptPsiFile()?.let { - getManipulator(it).getKotlinStdlibVersion() - } - } - - private fun canConfigureFile(file: PsiFile): Boolean = WritingAccessProvider.isPotentiallyWritable(file.virtualFile, null) - - private fun Module.getBuildScriptPsiFile() = - getBuildScriptFile(GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(project) - - fun Module.getBuildScriptSettingsPsiFile() = - getBuildScriptSettingsFile(GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) - - private fun Project.getTopLevelBuildScriptPsiFile() = basePath?.let { - findBuildGradleFile(it, GradleConstants.DEFAULT_SCRIPT_NAME, KOTLIN_BUILD_SCRIPT_NAME)?.getPsiFile(this) - } - - fun Module.getTopLevelBuildScriptSettingsPsiFile() = - ExternalSystemApiUtil.getExternalRootProjectPath(this)?.let { externalProjectPath -> - findBuildGradleFile(externalProjectPath, GradleConstants.SETTINGS_FILE_NAME, KOTLIN_SETTINGS_SCRIPT_NAME)?.getPsiFile(project) - } - - private fun Module.getBuildScriptFile(vararg fileNames: String): File? { - val moduleDir = File(moduleFilePath).parent - findBuildGradleFile(moduleDir, *fileNames)?.let { - return it - } - - ModuleRootManager.getInstance(this).contentRoots.forEach { root -> - findBuildGradleFile(root.path, *fileNames)?.let { - return it - } - } - - ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> - findBuildGradleFile(externalProjectPath, *fileNames)?.let { - return it - } - } - - return null - } - - private fun Module.getBuildScriptSettingsFile(vararg fileNames: String): File? { - ExternalSystemApiUtil.getExternalProjectPath(this)?.let { externalProjectPath -> - return generateSequence(externalProjectPath) { - PathUtil.getParentPath(it).let { if (it.isBlank()) null else it } - }.mapNotNull { - findBuildGradleFile(it, *fileNames) - }.firstOrNull() - } - - return null - } - - private fun findBuildGradleFile(path: String, vararg fileNames: String): File? = - fileNames.asSequence().map { File(path + "/" + it) }.firstOrNull { it.exists() } - - private fun File.getPsiFile(project: Project) = VfsUtil.findFileByIoFile(this, true)?.let { - PsiManager.getInstance(project).findFile(it) - } - - private fun showErrorMessage(project: Project, message: String?) { - Messages.showErrorDialog( - project, - "Couldn't configure kotlin-gradle plugin automatically.
" + - (if (message != null) message + "
" else "") + - "
See manual installation instructions here.", - "Configure Kotlin-Gradle Plugin" - ) - } - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt index c7f7ca18acb..00b8def9508 100644 --- a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt @@ -251,7 +251,7 @@ fun parseCompilerArgumentsToFacet( arguments: List, defaultArguments: List, kotlinFacet: KotlinFacet, - modelsProvider: IdeModifiableModelsProvider + modelsProvider: IdeModifiableModelsProvider? ) { with(kotlinFacet.configuration.settings) { val compilerArguments = this.compilerArguments ?: return @@ -267,7 +267,8 @@ fun parseCompilerArgumentsToFacet( // Retain only fields exposed (and not explicitly ignored) in facet configuration editor. // The rest is combined into string and stored in CompilerSettings.additionalArguments - kotlinFacet.module.configureSdkIfPossible(compilerArguments, modelsProvider) + if (modelsProvider != null) + kotlinFacet.module.configureSdkIfPossible(compilerArguments, modelsProvider) val primaryFields = compilerArguments.primaryFields val ignoredFields = compilerArguments.ignoredFields diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt.as31 b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt.as31 deleted file mode 100644 index 00b8def9508..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt.as31 +++ /dev/null @@ -1,302 +0,0 @@ -/* - * 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.idea.facet - -import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider -import com.intellij.openapi.module.Module -import com.intellij.openapi.project.Project -import com.intellij.openapi.projectRoots.JavaSdk -import com.intellij.openapi.projectRoots.JavaSdkVersion -import com.intellij.openapi.projectRoots.ProjectJdkTable -import com.intellij.openapi.roots.ModuleRootManager -import com.intellij.openapi.roots.ModuleRootModel -import com.intellij.openapi.util.io.FileUtil -import com.intellij.openapi.util.text.StringUtil -import org.jetbrains.kotlin.cli.common.arguments.* -import org.jetbrains.kotlin.compilerRunner.ArgumentUtils -import org.jetbrains.kotlin.config.* -import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumentsHolder -import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder -import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder -import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings -import org.jetbrains.kotlin.idea.configuration.externalCompilerVersion -import org.jetbrains.kotlin.idea.framework.KotlinSdkType -import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.idea.versions.* -import kotlin.reflect.KProperty1 - -private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?): TargetPlatformKind<*> { - for (platform in TargetPlatformKind.ALL_PLATFORMS) { - if (getRuntimeLibraryVersions(module, rootModel, platform).isNotEmpty()) { - return platform - } - } - - val sdk = ((rootModel ?: ModuleRootManager.getInstance(module))).sdk - val sdkVersion = (sdk?.sdkType as? JavaSdk)?.getVersion(sdk!!) - return when { - sdkVersion == null || sdkVersion >= JavaSdkVersion.JDK_1_8 -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_8] - else -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6] - } -} - -fun KotlinFacetSettings.initializeIfNeeded( - module: Module, - rootModel: ModuleRootModel?, - platformKind: TargetPlatformKind<*>? = null, // if null, detect by module dependencies - compilerVersion: String? = null -) { - val project = module.project - - val shouldInferLanguageLevel = languageLevel == null - val shouldInferAPILevel = apiLevel == null - - if (compilerSettings == null) { - compilerSettings = KotlinCompilerSettings.getInstance(project).settings - } - - val commonArguments = KotlinCommonCompilerArgumentsHolder.getInstance(module.project).settings - - if (compilerArguments == null) { - val targetPlatformKind = platformKind ?: getDefaultTargetPlatform(module, rootModel) - compilerArguments = targetPlatformKind.createCompilerArguments { - targetPlatformKind.getPlatformCompilerArgumentsByProject(module.project)?.let { mergeBeans(it, this) } - mergeBeans(commonArguments, this) - } - } - - if (shouldInferLanguageLevel) { - languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null) - ?: getDefaultLanguageLevel(module, compilerVersion) - } - - if (shouldInferAPILevel) { - apiLevel = if (useProjectSettings) { - LanguageVersion.fromVersionString(commonArguments.apiVersion) ?: languageLevel - } else { - languageLevel!!.coerceAtMost(getLibraryLanguageLevel(module, rootModel, targetPlatformKind)) - } - } -} - -fun TargetPlatformKind<*>.getPlatformCompilerArgumentsByProject(project: Project): CommonCompilerArguments? { - return when (this) { - is TargetPlatformKind.Jvm -> Kotlin2JvmCompilerArgumentsHolder.getInstance(project).settings - is TargetPlatformKind.JavaScript -> Kotlin2JsCompilerArgumentsHolder.getInstance(project).settings - else -> null - } -} - -val TargetPlatformKind<*>.mavenLibraryIds: List - get() = when (this) { - is TargetPlatformKind.Jvm -> listOf( - MAVEN_STDLIB_ID, - MAVEN_STDLIB_ID_JRE7, - MAVEN_STDLIB_ID_JDK7, - MAVEN_STDLIB_ID_JRE8, - MAVEN_STDLIB_ID_JDK8 - ) - is TargetPlatformKind.JavaScript -> listOf(MAVEN_JS_STDLIB_ID, MAVEN_OLD_JS_STDLIB_ID) - is TargetPlatformKind.Common -> listOf(MAVEN_COMMON_STDLIB_ID) - } - -val mavenLibraryIdToPlatform: Map> by lazy { - TargetPlatformKind.ALL_PLATFORMS - .flatMap { platform -> platform.mavenLibraryIds.map { it to platform } } - .sortedByDescending { it.first.length } - .toMap() -} - -fun Module.getOrCreateFacet( - modelsProvider: IdeModifiableModelsProvider, - useProjectSettings: Boolean, - commitModel: Boolean = false -): KotlinFacet { - val facetModel = modelsProvider.getModifiableFacetModel(this) - - val facet = facetModel.findFacet(KotlinFacetType.TYPE_ID, KotlinFacetType.INSTANCE.defaultFacetName) - ?: with(KotlinFacetType.INSTANCE) { createFacet(this@getOrCreateFacet, defaultFacetName, createDefaultConfiguration(), null) } - .apply { facetModel.addFacet(this) } - facet.configuration.settings.useProjectSettings = useProjectSettings - if (commitModel) { - runWriteAction { - facetModel.commit() - } - } - return facet -} - -fun KotlinFacet.configureFacet( - compilerVersion: String, - coroutineSupport: LanguageFeature.State, - platformKind: TargetPlatformKind<*>?, // if null, detect by module dependencies - modelsProvider: IdeModifiableModelsProvider -) { - val module = module - with(configuration.settings) { - compilerArguments = null - compilerSettings = null - initializeIfNeeded( - module, - modelsProvider.getModifiableRootModel(module), - platformKind, - compilerVersion - ) - val apiLevel = apiLevel - val languageLevel = languageLevel - if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) { - this.apiLevel = languageLevel - } - this.coroutineSupport = coroutineSupport - } - - module.externalCompilerVersion = compilerVersion -} - -fun KotlinFacet.noVersionAutoAdvance() { - configuration.settings.compilerArguments?.let { - it.autoAdvanceLanguageVersion = false - it.autoAdvanceApiVersion = false - } -} - -// "Primary" fields are written to argument beans directly and thus not presented in the "additional arguments" string -// Update these lists when facet/project settings UI changes -val commonUIExposedFields = listOf( - CommonCompilerArguments::languageVersion.name, - CommonCompilerArguments::apiVersion.name, - CommonCompilerArguments::suppressWarnings.name, - CommonCompilerArguments::coroutinesState.name -) -private val commonUIHiddenFields = listOf( - CommonCompilerArguments::pluginClasspaths.name, - CommonCompilerArguments::pluginOptions.name -) -private val commonPrimaryFields = commonUIExposedFields + commonUIHiddenFields - -private val jvmSpecificUIExposedFields = listOf( - K2JVMCompilerArguments::jvmTarget.name, - K2JVMCompilerArguments::destination.name, - K2JVMCompilerArguments::classpath.name -) -val jvmUIExposedFields = commonUIExposedFields + jvmSpecificUIExposedFields -private val jvmPrimaryFields = commonPrimaryFields + jvmSpecificUIExposedFields - -private val jsSpecificUIExposedFields = listOf( - K2JSCompilerArguments::sourceMap.name, - K2JSCompilerArguments::sourceMapPrefix.name, - K2JSCompilerArguments::sourceMapEmbedSources.name, - K2JSCompilerArguments::outputPrefix.name, - K2JSCompilerArguments::outputPostfix.name, - K2JSCompilerArguments::moduleKind.name -) -val jsUIExposedFields = commonUIExposedFields + jsSpecificUIExposedFields -private val jsPrimaryFields = commonPrimaryFields + jsSpecificUIExposedFields - -private val metadataSpecificUIExposedFields = listOf( - K2MetadataCompilerArguments::destination.name, - K2MetadataCompilerArguments::classpath.name -) -val metadataUIExposedFields = commonUIExposedFields + metadataSpecificUIExposedFields -private val metadataPrimaryFields = commonPrimaryFields + metadataSpecificUIExposedFields - -private val CommonCompilerArguments.primaryFields: List - get() = when (this) { - is K2JVMCompilerArguments -> jvmPrimaryFields - is K2JSCompilerArguments -> jsPrimaryFields - is K2MetadataCompilerArguments -> metadataPrimaryFields - else -> commonPrimaryFields - } - -private val CommonCompilerArguments.ignoredFields: List - get() = when (this) { - is K2JVMCompilerArguments -> listOf(K2JVMCompilerArguments::noJdk.name, K2JVMCompilerArguments::jdkHome.name) - else -> emptyList() - } - -private fun Module.configureSdkIfPossible(compilerArguments: CommonCompilerArguments, modelsProvider: IdeModifiableModelsProvider) { - val allSdks = ProjectJdkTable.getInstance().allJdks - val sdk = if (compilerArguments is K2JVMCompilerArguments) { - val jdkHome = compilerArguments.jdkHome ?: return - allSdks.firstOrNull { it.sdkType is JavaSdk && FileUtil.comparePaths(it.homePath, jdkHome) == 0 } ?: return - } else { - allSdks.firstOrNull { it.sdkType is KotlinSdkType } - ?: modelsProvider - .modifiableModuleModel - .modules - .asSequence() - .mapNotNull { modelsProvider.getModifiableRootModel(it).sdk } - .firstOrNull { it.sdkType is KotlinSdkType } - ?: KotlinSdkType.INSTANCE.createSdkWithUniqueName(allSdks.toList()) - } - - modelsProvider.getModifiableRootModel(this).sdk = sdk -} - -fun parseCompilerArgumentsToFacet( - arguments: List, - defaultArguments: List, - kotlinFacet: KotlinFacet, - modelsProvider: IdeModifiableModelsProvider? -) { - with(kotlinFacet.configuration.settings) { - val compilerArguments = this.compilerArguments ?: return - - val defaultCompilerArguments = compilerArguments::class.java.newInstance() - parseCommandLineArguments(defaultArguments, defaultCompilerArguments) - defaultCompilerArguments.convertPathsToSystemIndependent() - - parseCommandLineArguments(arguments, compilerArguments) - - compilerArguments.convertPathsToSystemIndependent() - - // Retain only fields exposed (and not explicitly ignored) in facet configuration editor. - // The rest is combined into string and stored in CompilerSettings.additionalArguments - - if (modelsProvider != null) - kotlinFacet.module.configureSdkIfPossible(compilerArguments, modelsProvider) - - val primaryFields = compilerArguments.primaryFields - val ignoredFields = compilerArguments.ignoredFields - - fun exposeAsAdditionalArgument(property: KProperty1) = - property.name !in primaryFields && property.get(compilerArguments) != property.get(defaultCompilerArguments) - - val additionalArgumentsString = with(compilerArguments::class.java.newInstance()) { - copyFieldsSatisfying(compilerArguments, this) { exposeAsAdditionalArgument(it) && it.name !in ignoredFields } - ArgumentUtils.convertArgumentsToStringList(this).joinToString(separator = " ") { - if (StringUtil.containsWhitespaces(it) || it.startsWith('"')) { - StringUtil.wrapWithDoubleQuote(StringUtil.escapeQuotes(it)) - } else it - } - } - compilerSettings?.additionalArguments = - if (additionalArgumentsString.isNotEmpty()) additionalArgumentsString else CompilerSettings.DEFAULT_ADDITIONAL_ARGUMENTS - - with(compilerArguments::class.java.newInstance()) { - copyFieldsSatisfying(this, compilerArguments) { exposeAsAdditionalArgument(it) || it.name in ignoredFields } - } - - val languageLevel = languageLevel - val apiLevel = apiLevel - if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) { - this.apiLevel = languageLevel - } - - updateMergedArguments() - } -} diff --git a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt.as32 b/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt.as32 deleted file mode 100644 index 00b8def9508..00000000000 --- a/idea/src/org/jetbrains/kotlin/idea/facet/facetUtils.kt.as32 +++ /dev/null @@ -1,302 +0,0 @@ -/* - * 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.idea.facet - -import com.intellij.openapi.externalSystem.service.project.IdeModifiableModelsProvider -import com.intellij.openapi.module.Module -import com.intellij.openapi.project.Project -import com.intellij.openapi.projectRoots.JavaSdk -import com.intellij.openapi.projectRoots.JavaSdkVersion -import com.intellij.openapi.projectRoots.ProjectJdkTable -import com.intellij.openapi.roots.ModuleRootManager -import com.intellij.openapi.roots.ModuleRootModel -import com.intellij.openapi.util.io.FileUtil -import com.intellij.openapi.util.text.StringUtil -import org.jetbrains.kotlin.cli.common.arguments.* -import org.jetbrains.kotlin.compilerRunner.ArgumentUtils -import org.jetbrains.kotlin.config.* -import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JsCompilerArgumentsHolder -import org.jetbrains.kotlin.idea.compiler.configuration.Kotlin2JvmCompilerArgumentsHolder -import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCommonCompilerArgumentsHolder -import org.jetbrains.kotlin.idea.compiler.configuration.KotlinCompilerSettings -import org.jetbrains.kotlin.idea.configuration.externalCompilerVersion -import org.jetbrains.kotlin.idea.framework.KotlinSdkType -import org.jetbrains.kotlin.idea.util.application.runWriteAction -import org.jetbrains.kotlin.idea.versions.* -import kotlin.reflect.KProperty1 - -private fun getDefaultTargetPlatform(module: Module, rootModel: ModuleRootModel?): TargetPlatformKind<*> { - for (platform in TargetPlatformKind.ALL_PLATFORMS) { - if (getRuntimeLibraryVersions(module, rootModel, platform).isNotEmpty()) { - return platform - } - } - - val sdk = ((rootModel ?: ModuleRootManager.getInstance(module))).sdk - val sdkVersion = (sdk?.sdkType as? JavaSdk)?.getVersion(sdk!!) - return when { - sdkVersion == null || sdkVersion >= JavaSdkVersion.JDK_1_8 -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_8] - else -> TargetPlatformKind.Jvm[JvmTarget.JVM_1_6] - } -} - -fun KotlinFacetSettings.initializeIfNeeded( - module: Module, - rootModel: ModuleRootModel?, - platformKind: TargetPlatformKind<*>? = null, // if null, detect by module dependencies - compilerVersion: String? = null -) { - val project = module.project - - val shouldInferLanguageLevel = languageLevel == null - val shouldInferAPILevel = apiLevel == null - - if (compilerSettings == null) { - compilerSettings = KotlinCompilerSettings.getInstance(project).settings - } - - val commonArguments = KotlinCommonCompilerArgumentsHolder.getInstance(module.project).settings - - if (compilerArguments == null) { - val targetPlatformKind = platformKind ?: getDefaultTargetPlatform(module, rootModel) - compilerArguments = targetPlatformKind.createCompilerArguments { - targetPlatformKind.getPlatformCompilerArgumentsByProject(module.project)?.let { mergeBeans(it, this) } - mergeBeans(commonArguments, this) - } - } - - if (shouldInferLanguageLevel) { - languageLevel = (if (useProjectSettings) LanguageVersion.fromVersionString(commonArguments.languageVersion) else null) - ?: getDefaultLanguageLevel(module, compilerVersion) - } - - if (shouldInferAPILevel) { - apiLevel = if (useProjectSettings) { - LanguageVersion.fromVersionString(commonArguments.apiVersion) ?: languageLevel - } else { - languageLevel!!.coerceAtMost(getLibraryLanguageLevel(module, rootModel, targetPlatformKind)) - } - } -} - -fun TargetPlatformKind<*>.getPlatformCompilerArgumentsByProject(project: Project): CommonCompilerArguments? { - return when (this) { - is TargetPlatformKind.Jvm -> Kotlin2JvmCompilerArgumentsHolder.getInstance(project).settings - is TargetPlatformKind.JavaScript -> Kotlin2JsCompilerArgumentsHolder.getInstance(project).settings - else -> null - } -} - -val TargetPlatformKind<*>.mavenLibraryIds: List - get() = when (this) { - is TargetPlatformKind.Jvm -> listOf( - MAVEN_STDLIB_ID, - MAVEN_STDLIB_ID_JRE7, - MAVEN_STDLIB_ID_JDK7, - MAVEN_STDLIB_ID_JRE8, - MAVEN_STDLIB_ID_JDK8 - ) - is TargetPlatformKind.JavaScript -> listOf(MAVEN_JS_STDLIB_ID, MAVEN_OLD_JS_STDLIB_ID) - is TargetPlatformKind.Common -> listOf(MAVEN_COMMON_STDLIB_ID) - } - -val mavenLibraryIdToPlatform: Map> by lazy { - TargetPlatformKind.ALL_PLATFORMS - .flatMap { platform -> platform.mavenLibraryIds.map { it to platform } } - .sortedByDescending { it.first.length } - .toMap() -} - -fun Module.getOrCreateFacet( - modelsProvider: IdeModifiableModelsProvider, - useProjectSettings: Boolean, - commitModel: Boolean = false -): KotlinFacet { - val facetModel = modelsProvider.getModifiableFacetModel(this) - - val facet = facetModel.findFacet(KotlinFacetType.TYPE_ID, KotlinFacetType.INSTANCE.defaultFacetName) - ?: with(KotlinFacetType.INSTANCE) { createFacet(this@getOrCreateFacet, defaultFacetName, createDefaultConfiguration(), null) } - .apply { facetModel.addFacet(this) } - facet.configuration.settings.useProjectSettings = useProjectSettings - if (commitModel) { - runWriteAction { - facetModel.commit() - } - } - return facet -} - -fun KotlinFacet.configureFacet( - compilerVersion: String, - coroutineSupport: LanguageFeature.State, - platformKind: TargetPlatformKind<*>?, // if null, detect by module dependencies - modelsProvider: IdeModifiableModelsProvider -) { - val module = module - with(configuration.settings) { - compilerArguments = null - compilerSettings = null - initializeIfNeeded( - module, - modelsProvider.getModifiableRootModel(module), - platformKind, - compilerVersion - ) - val apiLevel = apiLevel - val languageLevel = languageLevel - if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) { - this.apiLevel = languageLevel - } - this.coroutineSupport = coroutineSupport - } - - module.externalCompilerVersion = compilerVersion -} - -fun KotlinFacet.noVersionAutoAdvance() { - configuration.settings.compilerArguments?.let { - it.autoAdvanceLanguageVersion = false - it.autoAdvanceApiVersion = false - } -} - -// "Primary" fields are written to argument beans directly and thus not presented in the "additional arguments" string -// Update these lists when facet/project settings UI changes -val commonUIExposedFields = listOf( - CommonCompilerArguments::languageVersion.name, - CommonCompilerArguments::apiVersion.name, - CommonCompilerArguments::suppressWarnings.name, - CommonCompilerArguments::coroutinesState.name -) -private val commonUIHiddenFields = listOf( - CommonCompilerArguments::pluginClasspaths.name, - CommonCompilerArguments::pluginOptions.name -) -private val commonPrimaryFields = commonUIExposedFields + commonUIHiddenFields - -private val jvmSpecificUIExposedFields = listOf( - K2JVMCompilerArguments::jvmTarget.name, - K2JVMCompilerArguments::destination.name, - K2JVMCompilerArguments::classpath.name -) -val jvmUIExposedFields = commonUIExposedFields + jvmSpecificUIExposedFields -private val jvmPrimaryFields = commonPrimaryFields + jvmSpecificUIExposedFields - -private val jsSpecificUIExposedFields = listOf( - K2JSCompilerArguments::sourceMap.name, - K2JSCompilerArguments::sourceMapPrefix.name, - K2JSCompilerArguments::sourceMapEmbedSources.name, - K2JSCompilerArguments::outputPrefix.name, - K2JSCompilerArguments::outputPostfix.name, - K2JSCompilerArguments::moduleKind.name -) -val jsUIExposedFields = commonUIExposedFields + jsSpecificUIExposedFields -private val jsPrimaryFields = commonPrimaryFields + jsSpecificUIExposedFields - -private val metadataSpecificUIExposedFields = listOf( - K2MetadataCompilerArguments::destination.name, - K2MetadataCompilerArguments::classpath.name -) -val metadataUIExposedFields = commonUIExposedFields + metadataSpecificUIExposedFields -private val metadataPrimaryFields = commonPrimaryFields + metadataSpecificUIExposedFields - -private val CommonCompilerArguments.primaryFields: List - get() = when (this) { - is K2JVMCompilerArguments -> jvmPrimaryFields - is K2JSCompilerArguments -> jsPrimaryFields - is K2MetadataCompilerArguments -> metadataPrimaryFields - else -> commonPrimaryFields - } - -private val CommonCompilerArguments.ignoredFields: List - get() = when (this) { - is K2JVMCompilerArguments -> listOf(K2JVMCompilerArguments::noJdk.name, K2JVMCompilerArguments::jdkHome.name) - else -> emptyList() - } - -private fun Module.configureSdkIfPossible(compilerArguments: CommonCompilerArguments, modelsProvider: IdeModifiableModelsProvider) { - val allSdks = ProjectJdkTable.getInstance().allJdks - val sdk = if (compilerArguments is K2JVMCompilerArguments) { - val jdkHome = compilerArguments.jdkHome ?: return - allSdks.firstOrNull { it.sdkType is JavaSdk && FileUtil.comparePaths(it.homePath, jdkHome) == 0 } ?: return - } else { - allSdks.firstOrNull { it.sdkType is KotlinSdkType } - ?: modelsProvider - .modifiableModuleModel - .modules - .asSequence() - .mapNotNull { modelsProvider.getModifiableRootModel(it).sdk } - .firstOrNull { it.sdkType is KotlinSdkType } - ?: KotlinSdkType.INSTANCE.createSdkWithUniqueName(allSdks.toList()) - } - - modelsProvider.getModifiableRootModel(this).sdk = sdk -} - -fun parseCompilerArgumentsToFacet( - arguments: List, - defaultArguments: List, - kotlinFacet: KotlinFacet, - modelsProvider: IdeModifiableModelsProvider? -) { - with(kotlinFacet.configuration.settings) { - val compilerArguments = this.compilerArguments ?: return - - val defaultCompilerArguments = compilerArguments::class.java.newInstance() - parseCommandLineArguments(defaultArguments, defaultCompilerArguments) - defaultCompilerArguments.convertPathsToSystemIndependent() - - parseCommandLineArguments(arguments, compilerArguments) - - compilerArguments.convertPathsToSystemIndependent() - - // Retain only fields exposed (and not explicitly ignored) in facet configuration editor. - // The rest is combined into string and stored in CompilerSettings.additionalArguments - - if (modelsProvider != null) - kotlinFacet.module.configureSdkIfPossible(compilerArguments, modelsProvider) - - val primaryFields = compilerArguments.primaryFields - val ignoredFields = compilerArguments.ignoredFields - - fun exposeAsAdditionalArgument(property: KProperty1) = - property.name !in primaryFields && property.get(compilerArguments) != property.get(defaultCompilerArguments) - - val additionalArgumentsString = with(compilerArguments::class.java.newInstance()) { - copyFieldsSatisfying(compilerArguments, this) { exposeAsAdditionalArgument(it) && it.name !in ignoredFields } - ArgumentUtils.convertArgumentsToStringList(this).joinToString(separator = " ") { - if (StringUtil.containsWhitespaces(it) || it.startsWith('"')) { - StringUtil.wrapWithDoubleQuote(StringUtil.escapeQuotes(it)) - } else it - } - } - compilerSettings?.additionalArguments = - if (additionalArgumentsString.isNotEmpty()) additionalArgumentsString else CompilerSettings.DEFAULT_ADDITIONAL_ARGUMENTS - - with(compilerArguments::class.java.newInstance()) { - copyFieldsSatisfying(this, compilerArguments) { exposeAsAdditionalArgument(it) || it.name in ignoredFields } - } - - val languageLevel = languageLevel - val apiLevel = apiLevel - if (languageLevel != null && apiLevel != null && apiLevel > languageLevel) { - this.apiLevel = languageLevel - } - - updateMergedArguments() - } -}