diff --git a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt index 67bc061b09f..f3f3f6bc421 100644 --- a/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt +++ b/core/util.runtime/src/org/jetbrains/kotlin/utils/collections.kt @@ -55,6 +55,8 @@ inline fun MutableMap.getOrPutNullable(key: K, defaultValue: () -> inline fun > C.ifEmpty(body: () -> C): C = if (isEmpty()) body() else this +inline fun > M.ifEmpty(body: () -> M): M = if (isEmpty()) body() else this + inline fun Array.ifEmpty(body: () -> Array): Array = if (isEmpty()) body() else this fun MutableCollection.addIfNotNull(t: T?) { diff --git a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt index a947c277942..1071bfc4b9b 100644 --- a/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt +++ b/idea/idea-maven/src/org/jetbrains/kotlin/idea/maven/configuration/KotlinMavenConfigurator.kt @@ -48,7 +48,8 @@ abstract class KotlinMavenConfigurator override val name: String, override val presentableText: String) : KotlinProjectConfigurator { - override fun getStatus(module: Module): ConfigureKotlinStatus { + override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus { + val module = moduleSourceRootGroup.baseModule if (!KotlinPluginUtil.isMavenModule(module)) return ConfigureKotlinStatus.NON_APPLICABLE diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/ConfigureKotlinInProjectAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/ConfigureKotlinInProjectAction.kt index 22e221f9028..918e52cde47 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/ConfigureKotlinInProjectAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/ConfigureKotlinInProjectAction.kt @@ -26,7 +26,6 @@ import org.jetbrains.kotlin.idea.configuration.* import org.jetbrains.kotlin.idea.util.projectStructure.allModules import org.jetbrains.kotlin.js.resolve.JsPlatform import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform -import org.jetbrains.kotlin.utils.ifEmpty abstract class ConfigureKotlinInProjectAction : AnAction() { @@ -35,7 +34,7 @@ abstract class ConfigureKotlinInProjectAction : AnAction() { override fun actionPerformed(e: AnActionEvent) { val project = e.project ?: return - val modules = getConfigurableModulesWithKotlinFiles(project).ifEmpty { project.allModules() } + val modules = getConfigurableModules(project) if (modules.all(::isModuleConfigured)) { Messages.showInfoMessage("All modules with Kotlin files are configured", e.presentation.text!!) return diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt index 399adcd7e7d..7c72e039329 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ConfigureKotlinInProjectUtils.kt @@ -18,9 +18,7 @@ package org.jetbrains.kotlin.idea.configuration import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.extensions.Extensions -import com.intellij.openapi.externalSystem.util.ExternalSystemApiUtil import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.Project import com.intellij.openapi.roots.DependencyScope @@ -30,6 +28,7 @@ import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.idea.KotlinFileType import org.jetbrains.kotlin.idea.configuration.ui.notifications.ConfigureKotlinNotification +import org.jetbrains.kotlin.idea.util.application.runReadAction import org.jetbrains.kotlin.idea.util.projectStructure.allModules import org.jetbrains.kotlin.idea.versions.getKotlinJvmRuntimeMarkerClass import org.jetbrains.kotlin.idea.versions.hasKotlinJsKjsmFile @@ -96,9 +95,9 @@ fun getRepositoryForVersion(version: String): RepositoryDescription? = when { else -> null } -fun isModuleConfigured(module: Module): Boolean { +fun isModuleConfigured(moduleSourceRootGroup: ModuleSourceRootGroup): Boolean { return allConfigurators().any { - it.getStatus(module) == ConfigureKotlinStatus.CONFIGURED + it.getStatus(moduleSourceRootGroup) == ConfigureKotlinStatus.CONFIGURED } } @@ -107,57 +106,67 @@ fun getModulesWithKotlinFiles(project: Project): Collection { return emptyList() } - if (!FileTypeIndex.containsFileOfType(KotlinFileType.INSTANCE, GlobalSearchScope.projectScope(project))) { + if (!runReadAction { FileTypeIndex.containsFileOfType (KotlinFileType.INSTANCE, GlobalSearchScope.projectScope(project)) }) { return emptyList() } return project.allModules() .filter { module -> - FileTypeIndex.containsFileOfType(KotlinFileType.INSTANCE, module.getModuleScope(true)) + runReadAction { + FileTypeIndex.containsFileOfType(KotlinFileType.INSTANCE, module.getModuleScope(true)) + } } } -fun getConfigurableModulesWithKotlinFiles(project: Project): Collection { +fun getConfigurableModulesWithKotlinFiles(project: Project): List { val modules = getModulesWithKotlinFiles(project) - if (modules.isEmpty()) return modules + if (modules.isEmpty()) return emptyList() - val pathMap = ModuleManager.getInstance(project).modules.asList().buildExternalPathMap() - return modules.mapTo(HashSet()) { module -> - val externalPath = module.externalProjectPath - if (externalPath == null) module else (pathMap[externalPath] ?: module) - } + return ModuleSourceRootMap(project).groupByBaseModules(modules) } fun showConfigureKotlinNotificationIfNeeded(module: Module) { - if (isModuleConfigured(module)) return + val moduleGroup = ModuleSourceRootMap(module.project).toModuleGroup(module) + if (isModuleConfigured(moduleGroup)) return ConfigureKotlinNotificationManager.notify(module.project) } fun showConfigureKotlinNotificationIfNeeded(project: Project, excludeModules: List = emptyList()) { - ApplicationManager.getApplication().executeOnPooledThread { - val notificationString = DumbService.getInstance(project).runReadActionInSmartMode(Computable { - val modules = getConfigurableModulesWithKotlinFiles(project) - excludeModules - if (modules.all(::isModuleConfigured)) null else ConfigureKotlinNotification.getNotificationString(project, excludeModules) - }) - if (notificationString != null) { - ApplicationManager.getApplication().invokeLater { - ConfigureKotlinNotificationManager.notify(project, ConfigureKotlinNotification(project, excludeModules, notificationString)) - } + val notificationString = DumbService.getInstance(project).runReadActionInSmartMode(Computable { + val modules = getConfigurableModulesWithKotlinFiles(project).exclude(excludeModules) + if (modules.all(::isModuleConfigured)) + null + else + ConfigureKotlinNotification.getNotificationString(project, excludeModules) + }) + + if (notificationString != null) { + ApplicationManager.getApplication().invokeLater { + ConfigureKotlinNotificationManager.notify(project, ConfigureKotlinNotification(project, excludeModules, notificationString)) } } } fun getAbleToRunConfigurators(project: Project): Collection { - val modules = getConfigurableModulesWithKotlinFiles(project).ifEmpty { project.allModules() } + val modules = getConfigurableModules(project) return allConfigurators().filter { configurator -> - modules.any { module -> configurator.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED } + modules.any { configurator.getStatus(it) == ConfigureKotlinStatus.CAN_BE_CONFIGURED } + } +} + +fun getConfigurableModules(project: Project): List { + return getConfigurableModulesWithKotlinFiles(project).ifEmpty { + ModuleSourceRootMap(project).groupByBaseModules(project.allModules()) } } fun getAbleToRunConfigurators(module: Module): Collection { - return allConfigurators().filter { it.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED } + val moduleGroup = ModuleSourceRootMap(module.project).toModuleGroup(module) + return allConfigurators().filter { + it.getStatus(moduleGroup) == ConfigureKotlinStatus.CAN_BE_CONFIGURED + } } fun getConfiguratorByName(name: String): KotlinProjectConfigurator? { @@ -167,56 +176,26 @@ fun getConfiguratorByName(name: String): KotlinProjectConfigurator? { fun allConfigurators() = Extensions.getExtensions(KotlinProjectConfigurator.EP_NAME) fun getCanBeConfiguredModules(project: Project, configurator: KotlinProjectConfigurator): List { - return project.allModules() - .filter { module -> configurator.canConfigure(module) } - .excludeSourceRootModules() + return ModuleSourceRootMap(project).groupByBaseModules(project.allModules()) + .filter { configurator.canConfigure(it) } + .map { it.baseModule } } -private fun KotlinProjectConfigurator.canConfigure(module: Module) = - getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED && - (allConfigurators().toList() - this).none { it.getStatus(module) == ConfigureKotlinStatus.CONFIGURED } - -fun Collection.excludeSourceRootModules(): List { - val pathMap = buildExternalPathMap() - return filter { it.externalProjectId == null || it.externalProjectPath == null } + pathMap.values -} - -fun Collection.buildExternalPathMap(): Map { - val pathMap = mutableMapOf() - for (module in this) { - val externalId = module.externalProjectId - val externalPath = module.externalProjectPath - if (externalId != null && externalPath != null) { - val previousModule = pathMap[externalPath] - // the module without the source root suffix will have the shortest name - if (previousModule == null || isSourceRootPrefix(externalId, previousModule.externalProjectId!!)) { - pathMap[externalPath] = module - } - } - } - return pathMap -} - -private fun isSourceRootPrefix(externalId: String, previousModuleExternalId: String) - = externalId.length < previousModuleExternalId.length && previousModuleExternalId.startsWith(externalId) - -val Module.externalProjectId: String? - get() = ExternalSystemApiUtil.getExternalProjectId(this) - -val Module.externalProjectPath: String? - get() = ExternalSystemApiUtil.getExternalProjectPath(this) +private fun KotlinProjectConfigurator.canConfigure(moduleSourceRootGroup: ModuleSourceRootGroup) = + getStatus(moduleSourceRootGroup) == ConfigureKotlinStatus.CAN_BE_CONFIGURED && + (allConfigurators().toList() - this).none { it.getStatus(moduleSourceRootGroup) == ConfigureKotlinStatus.CONFIGURED } fun getCanBeConfiguredModulesWithKotlinFiles(project: Project, configurator: KotlinProjectConfigurator): List { val modules = getConfigurableModulesWithKotlinFiles(project) - return modules.filter { module -> configurator.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED } + return modules.filter { configurator.getStatus(it) == ConfigureKotlinStatus.CAN_BE_CONFIGURED }.map { it.baseModule } } fun getCanBeConfiguredModulesWithKotlinFiles(project: Project, excludeModules: Collection = emptyList()): Collection { - val modulesWithKotlinFiles = getConfigurableModulesWithKotlinFiles(project) - excludeModules + val modulesWithKotlinFiles = getConfigurableModulesWithKotlinFiles(project).exclude(excludeModules) val configurators = allConfigurators() - return modulesWithKotlinFiles.filter { module -> - configurators.any { it.getStatus(module) == ConfigureKotlinStatus.CAN_BE_CONFIGURED } - } + return modulesWithKotlinFiles.filter { moduleSourceRootGroup -> + configurators.any { it.getStatus(moduleSourceRootGroup) == ConfigureKotlinStatus.CAN_BE_CONFIGURED } + }.map { it.baseModule } } fun hasAnyKotlinRuntimeInScope(module: Module): Boolean { diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurator.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurator.kt index 95d3a0b5421..3ec933f3a9b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinProjectConfigurator.kt @@ -37,7 +37,7 @@ enum class ConfigureKotlinStatus { interface KotlinProjectConfigurator { - fun getStatus(module: Module): ConfigureKotlinStatus + fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus @JvmSuppressWildcards fun configure(project: Project, excludeModules: Collection) diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt index d40fddeb359..66d7762c623 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithGradleConfigurator.kt @@ -46,12 +46,13 @@ import java.util.* abstract class KotlinWithGradleConfigurator : KotlinProjectConfigurator { - override fun getStatus(module: Module): ConfigureKotlinStatus { + override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus { + val module = moduleSourceRootGroup.baseModule if (!isApplicable(module)) { return ConfigureKotlinStatus.NON_APPLICABLE } - if (hasAnyKotlinRuntimeInScope(module)) { + if (moduleSourceRootGroup.sourceRootModules.all(::hasAnyKotlinRuntimeInScope)) { return ConfigureKotlinStatus.CONFIGURED } diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithLibraryConfigurator.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithLibraryConfigurator.kt index dd441ea447e..b1308156d5b 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithLibraryConfigurator.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/KotlinWithLibraryConfigurator.kt @@ -51,7 +51,8 @@ abstract class KotlinWithLibraryConfigurator internal constructor() : KotlinProj protected val libraryKind: PersistentLibraryKind<*>? = libraryType?.kind - override fun getStatus(module: Module): ConfigureKotlinStatus { + override fun getStatus(moduleSourceRootGroup: ModuleSourceRootGroup): ConfigureKotlinStatus { + val module = moduleSourceRootGroup.baseModule if (!isApplicable(module)) { return ConfigureKotlinStatus.NON_APPLICABLE } diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ModuleSourceRootMap.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/ModuleSourceRootMap.kt new file mode 100644 index 00000000000..7cce80adc46 --- /dev/null +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ModuleSourceRootMap.kt @@ -0,0 +1,82 @@ +/* + * 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.externalSystem.util.ExternalSystemApiUtil +import com.intellij.openapi.module.Module +import com.intellij.openapi.project.Project +import org.jetbrains.kotlin.idea.util.projectStructure.allModules + +class ModuleSourceRootGroup(val baseModule: Module, + val sourceRootModules: List) + +class ModuleSourceRootMap(val modules: Collection) { + private val baseModuleByExternalPath: Map + private val allModulesByExternalPath: Map> + + constructor(project: Project): this(project.allModules()) + + init { + allModulesByExternalPath = modules + .filter { it.externalProjectPath != null && it.externalProjectId != null } + .groupBy { it.externalProjectPath!! } + + baseModuleByExternalPath = allModulesByExternalPath + .mapValues { (path, modules) -> + modules.reduce { m1, m2 -> + if (isSourceRootPrefix(m2.externalProjectId!!, m1.externalProjectId!!)) m2 else m1 + } + } + } + + fun groupByBaseModules(modules: Collection): List { + return modules + .groupBy { module -> + val externalPath = module.externalProjectPath + if (externalPath == null) module else (baseModuleByExternalPath[externalPath] ?: module) + } + .map { (module, sourceRootModules) -> + ModuleSourceRootGroup(module, + if (sourceRootModules.size > 1) sourceRootModules - module else sourceRootModules) + } + } + + fun toModuleGroup(module: Module): ModuleSourceRootGroup = groupByBaseModules(listOf(module)).single() +} + +private fun isSourceRootPrefix(externalId: String, previousModuleExternalId: String) + = externalId.length < previousModuleExternalId.length && previousModuleExternalId.startsWith(externalId) + +val Module.externalProjectId: String? + get() = ExternalSystemApiUtil.getExternalProjectId(this) + +val Module.externalProjectPath: String? + get() = ExternalSystemApiUtil.getExternalProjectPath(this) + +fun List.exclude(excludeModules: Collection): List { + return mapNotNull { + if (it.baseModule in excludeModules) + null + else { + val remainingSourceRootModules = it.sourceRootModules - excludeModules + if (remainingSourceRootModules.isEmpty()) + null + else + ModuleSourceRootGroup(it.baseModule, remainingSourceRootModules) + } + } +} \ No newline at end of file diff --git a/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinConfigurationCheckerComponent.kt b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinConfigurationCheckerComponent.kt index e53cb078394..e29ef894b09 100644 --- a/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinConfigurationCheckerComponent.kt +++ b/idea/src/org/jetbrains/kotlin/idea/configuration/ui/KotlinConfigurationCheckerComponent.kt @@ -23,13 +23,10 @@ import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.components.AbstractProjectComponent import com.intellij.openapi.project.DumbService import com.intellij.openapi.project.Project -import com.intellij.openapi.roots.ModuleRootAdapter import com.intellij.openapi.roots.ModuleRootEvent +import com.intellij.openapi.roots.ModuleRootListener import com.intellij.openapi.startup.StartupManager -import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinNotificationManager -import org.jetbrains.kotlin.idea.configuration.getModulesWithKotlinFiles -import org.jetbrains.kotlin.idea.configuration.isModuleConfigured -import org.jetbrains.kotlin.idea.configuration.showConfigureKotlinNotificationIfNeeded +import org.jetbrains.kotlin.idea.configuration.* import org.jetbrains.kotlin.idea.project.getAndCacheLanguageLevelByDependencies import org.jetbrains.kotlin.idea.versions.collectModulesWithOutdatedRuntime import org.jetbrains.kotlin.idea.versions.findOutdatedKotlinLibraries @@ -44,10 +41,11 @@ class KotlinConfigurationCheckerComponent(project: Project) : AbstractProjectCom NotificationsConfiguration.getNotificationsConfiguration().register(CONFIGURE_NOTIFICATION_GROUP_ID, NotificationDisplayType.STICKY_BALLOON, true) val connection = project.messageBus.connect() - connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootAdapter() { + connection.subscribe(ProjectTopics.PROJECT_ROOTS, object : ModuleRootListener { override fun rootsChanged(event: ModuleRootEvent?) { if (notificationPostponed && !isSyncing) { - DumbService.getInstance(myProject).smartInvokeLater { + ApplicationManager.getApplication().executeOnPooledThread { + DumbService.getInstance(myProject).waitForSmartMode() if (!isSyncing) { notificationPostponed = false showConfigureKotlinNotificationIfNeeded(myProject, @@ -59,7 +57,7 @@ class KotlinConfigurationCheckerComponent(project: Project) : AbstractProjectCom if (ConfigureKotlinNotificationManager.getVisibleNotifications(project).isNotEmpty()) { ApplicationManager.getApplication().executeOnPooledThread { DumbService.getInstance(myProject).waitForSmartMode() - if (getModulesWithKotlinFiles(project).all(::isModuleConfigured)) { + if (getConfigurableModulesWithKotlinFiles(project).all(::isModuleConfigured)) { ApplicationManager.getApplication().invokeLater { ConfigureKotlinNotificationManager.expireOldNotifications(project) } @@ -74,18 +72,22 @@ class KotlinConfigurationCheckerComponent(project: Project) : AbstractProjectCom super.projectOpened() StartupManager.getInstance(myProject).registerPostStartupActivity { - DumbService.getInstance(myProject).smartInvokeLater { + ApplicationManager.getApplication().executeOnPooledThread { + DumbService.getInstance(myProject).waitForSmartMode() + for (module in getModulesWithKotlinFiles(myProject)) { module.getAndCacheLanguageLevelByDependencies() } val libraries = findOutdatedKotlinLibraries(myProject) if (!libraries.isEmpty()) { - notifyOutdatedKotlinRuntime(myProject, libraries) + ApplicationManager.getApplication().invokeLater { + notifyOutdatedKotlinRuntime(myProject, libraries) + } } - if (syncDepth.get() == 0) { - showConfigureKotlinNotificationIfNeeded(myProject, - collectModulesWithOutdatedRuntime(libraries)) + if (!isSyncing) { + val excludeModules = collectModulesWithOutdatedRuntime(libraries) + showConfigureKotlinNotificationIfNeeded(myProject, excludeModules) } else { notificationPostponed = true diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt index 3952b525b7a..c84eef604c8 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleConfiguratorTest.kt @@ -60,11 +60,12 @@ class GradleConfiguratorTest : GradleImportingTestCase() { myProject.baseDir.createChildData(null, "build.gradle") val module = ModuleManager.getInstance(myProject).findModuleByName("app")!! + val moduleGroup = ModuleSourceRootMap(myProject).toModuleGroup(module) // We have a Kotlin runtime in build.gradle but not in the classpath, so it doesn't make sense // to suggest configuring it - assertEquals(ConfigureKotlinStatus.BROKEN, findGradleModuleConfigurator().getStatus(module)) + assertEquals(ConfigureKotlinStatus.BROKEN, findGradleModuleConfigurator().getStatus(moduleGroup)) // Don't offer the JS configurator if the JVM configuration exists but is broken - assertEquals(ConfigureKotlinStatus.BROKEN, findJsGradleModuleConfigurator().getStatus(module)) + assertEquals(ConfigureKotlinStatus.BROKEN, findJsGradleModuleConfigurator().getStatus(moduleGroup)) } } } @@ -212,6 +213,68 @@ class GradleConfiguratorTest : GradleImportingTestCase() { } } + @Test + fun testListNonConfiguredModules_Configured() { + createProjectSubFile("settings.gradle", "include ':app'") + createProjectSubFile("app/build.gradle", """ + buildscript { + repositories { + jcenter() + mavenCentral() + } + } + + apply plugin: 'java' + + repositories { + jcenter() + mavenCentral() + } + + dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib:1.1.3" + } + """.trimIndent()) + createProjectSubFile("app/src/main/java/foo.kt", "") + + importProject() + + runReadAction { + assertEmpty(getCanBeConfiguredModulesWithKotlinFiles(myProject)) + } + } + + @Test + fun testListNonConfiguredModules_ConfiguredOnlyTest() { + createProjectSubFile("settings.gradle", "include ':app'") + createProjectSubFile("app/build.gradle", """ + buildscript { + repositories { + jcenter() + mavenCentral() + } + } + + apply plugin: 'java' + + repositories { + jcenter() + mavenCentral() + } + + dependencies { + testCompile "org.jetbrains.kotlin:kotlin-stdlib:1.1.3" + } + """.trimIndent()) + createProjectSubFile("app/src/test/java/foo.kt", "") + + importProject() + + runReadAction { + assertEmpty(getCanBeConfiguredModulesWithKotlinFiles(myProject)) + } + } + @Test fun testAddNonKotlinLibraryGSK() { val buildScript = createProjectSubFile("build.gradle.kts", @@ -751,5 +814,4 @@ class GradleConfiguratorTest : GradleImportingTestCase() { } """.trimIndent(), LoadTextUtil.loadText(buildScript).toString()) } - } diff --git a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt index cdc8f1855f1..76a6a75ff34 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/codeInsight/gradle/GradleFacetImportTest.kt @@ -18,6 +18,7 @@ package org.jetbrains.kotlin.idea.codeInsight.gradle import com.intellij.openapi.application.Result import com.intellij.openapi.application.WriteAction +import com.intellij.openapi.application.runReadAction import com.intellij.openapi.projectRoots.JavaSdk import com.intellij.openapi.projectRoots.ProjectJdkTable import com.intellij.openapi.roots.LibraryOrderEntry @@ -27,9 +28,13 @@ import com.intellij.openapi.util.text.StringUtil import org.jetbrains.kotlin.cli.common.arguments.K2JSCompilerArguments import org.jetbrains.kotlin.cli.common.arguments.K2JVMCompilerArguments import org.jetbrains.kotlin.config.* +import org.jetbrains.kotlin.idea.configuration.ConfigureKotlinStatus +import org.jetbrains.kotlin.idea.configuration.ModuleSourceRootMap +import org.jetbrains.kotlin.idea.configuration.allConfigurators import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.idea.framework.CommonLibraryKind import org.jetbrains.kotlin.idea.framework.JSLibraryKind +import org.jetbrains.kotlin.idea.util.projectStructure.allModules import org.junit.Assert import org.junit.Test import java.io.File @@ -46,9 +51,6 @@ class GradleFacetImportTest : GradleImportingTestCase() { @Test fun testJvmImport() { createProjectSubFile("build.gradle", """ - group 'Again' - version '1.0-SNAPSHOT' - buildscript { repositories { mavenCentral() @@ -97,6 +99,48 @@ class GradleFacetImportTest : GradleImportingTestCase() { Assert.assertEquals("-Xdump-declarations-to=tmpTest", compilerSettings!!.additionalArguments) } + + assertAllModulesConfigured() + } + + @Test + fun testJvmImportWithPlugin() { + createProjectSubFile("build.gradle", """ +buildscript { + repositories { + mavenCentral() + } +} + +plugins { + id "org.jetbrains.kotlin.jvm" version "1.1.3" +} + +version '1.0-SNAPSHOT' + +apply plugin: 'java' + +sourceCompatibility = 1.8 + +repositories { + mavenCentral() +} + +dependencies { + compile "org.jetbrains.kotlin:kotlin-stdlib-jre8:1.1.3" + testCompile group: 'junit', name: 'junit', version: '4.12' +} + +compileKotlin { + kotlinOptions.jvmTarget = "1.8" +} +compileTestKotlin { + kotlinOptions.jvmTarget = "1.8" +} + """) + importProject() + + assertAllModulesConfigured() } @Test @@ -227,6 +271,8 @@ class GradleFacetImportTest : GradleImportingTestCase() { Assert.assertEquals("-Xdump-declarations-to=tmpTest", compilerSettings!!.additionalArguments) } + + assertAllModulesConfigured() } @Test @@ -436,6 +482,8 @@ class GradleFacetImportTest : GradleImportingTestCase() { val rootManager = ModuleRootManager.getInstance(getModule("project_main")) val stdlib = rootManager.orderEntries.filterIsInstance().single().library assertEquals(JSLibraryKind, (stdlib as LibraryEx).kind) + + assertAllModulesConfigured() } @Test @@ -511,6 +559,8 @@ class GradleFacetImportTest : GradleImportingTestCase() { Assert.assertEquals("-main callTest", compilerSettings!!.additionalArguments) } + + assertAllModulesConfigured() } @Test @@ -1160,4 +1210,15 @@ class GradleFacetImportTest : GradleImportingTestCase() { }.execute() } } + + private fun assertAllModulesConfigured() { + runReadAction { + for (moduleGroup in ModuleSourceRootMap(myProject).groupByBaseModules(myProject.allModules())) { + val configurator = allConfigurators().find { + it.getStatus(moduleGroup) == ConfigureKotlinStatus.CAN_BE_CONFIGURED + } + Assert.assertNull("Configurator $configurator tells that ${moduleGroup.baseModule} can be configured", configurator) + } + } + } }