From cc1be5f559436afbd336bebe79725dfa23b62db4 Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Tue, 25 Sep 2018 18:18:34 +0200 Subject: [PATCH] Introduce SourceType and use KotlinFacetSettings.isTestModule Refactor dealing with production/test roots Remove ad-hoc code in KotlinMultiplatformRunLocationsProvider --- .../idea/caches/project/IdeaModuleInfos.kt | 9 +++++-- .../idea/caches/project/ModuleIndexCache.kt | 23 +++++++++--------- .../idea/caches/project/multiplatformUtil.kt | 24 +++++++++++++------ .../kotlin/idea/core/fileIndexUtils.kt | 18 ++++++++++---- ...KotlinMultiplatformRunLocationsProvider.kt | 18 ++++++-------- 5 files changed, 55 insertions(+), 37 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt index 0bc2857d3c7..ae334061448 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/IdeaModuleInfos.kt @@ -210,8 +210,6 @@ data class ModuleTestSourceInfo internal constructor(override val module: Module override fun createCachedValueProvider(f: () -> CachedValueProvider.Result) = CachedValueProvider { f() } } -internal fun ModuleSourceInfo.isTests() = this is ModuleTestSourceInfo - fun Module.productionSourceInfo(): ModuleProductionSourceInfo? = if (hasProductionRoots()) ModuleProductionSourceInfo(this) else null fun Module.testSourceInfo(): ModuleTestSourceInfo? = if (hasTestRoots()) ModuleTestSourceInfo(this) else null @@ -444,3 +442,10 @@ data class PlatformModuleInfo( fun IdeaModuleInfo.projectSourceModules(): List? = (this as? ModuleSourceInfo)?.let(::listOf) ?: (this as? PlatformModuleInfo)?.containedModules + +enum class SourceType { + PRODUCTION, + TEST +} + +internal val ModuleSourceInfo.sourceType get() = if (this is ModuleTestSourceInfo) SourceType.TEST else SourceType.PRODUCTION diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ModuleIndexCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ModuleIndexCache.kt index 8257b8bb2a1..eac3f58c798 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ModuleIndexCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/ModuleIndexCache.kt @@ -6,25 +6,24 @@ package org.jetbrains.kotlin.idea.caches.project import com.intellij.openapi.module.Module -import com.intellij.util.containers.MultiMap -import com.intellij.openapi.project.Project import com.intellij.openapi.module.ModuleManager -import com.intellij.openapi.roots.ModuleRootManager +import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ModuleOrderEntry -import gnu.trove.THashSet -import com.intellij.util.containers.Queue -import com.intellij.psi.util.CachedValuesManager -import com.intellij.psi.util.CachedValueProvider +import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ProjectRootModificationTracker -import java.util.HashSet +import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager +import com.intellij.util.containers.MultiMap +import com.intellij.util.containers.Queue +import gnu.trove.THashSet +import java.util.* //NOTE: this is an approximation that may contain more module infos then the exact solution fun ModuleSourceInfo.getDependentModules(): Set { val dependents = getDependents(module) - return if (isTests()) { - dependents.mapNotNullTo(HashSet(), Module::testSourceInfo) - } else { - dependents.flatMapTo(HashSet()) { it.correspondingModuleInfos() } + return when (sourceType) { + SourceType.TEST -> dependents.mapNotNullTo(HashSet(), Module::testSourceInfo) + SourceType.PRODUCTION -> dependents.flatMapTo(HashSet()) { it.correspondingModuleInfos() } } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/multiplatformUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/multiplatformUtil.kt index 8bab4f82c58..b09baf888ff 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/multiplatformUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/project/multiplatformUtil.kt @@ -16,6 +16,8 @@ import com.intellij.psi.util.CachedValueProvider import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.caches.resolve.KotlinCacheService import org.jetbrains.kotlin.descriptors.ModuleDescriptor +import org.jetbrains.kotlin.idea.caches.project.SourceType.PRODUCTION +import org.jetbrains.kotlin.idea.caches.project.SourceType.TEST import org.jetbrains.kotlin.idea.facet.KotlinFacet import org.jetbrains.kotlin.idea.facet.KotlinFacetType import org.jetbrains.kotlin.idea.facet.KotlinFacetType.Companion.ID @@ -26,19 +28,24 @@ import org.jetbrains.kotlin.platform.impl.isCommon import org.jetbrains.kotlin.resolve.TargetPlatform val Module.isNewMPPModule: Boolean - get() = KotlinFacet.get(this)?.configuration?.settings?.kind?.isNewMPP ?: false + get() = facetSettings?.kind?.isNewMPP ?: false val Module.externalProjectId: String - get() = KotlinFacet.get(this)?.configuration?.settings?.externalProjectId ?: "" + get() = facetSettings?.externalProjectId ?: "" + +val Module.sourceType: SourceType? + get() = facetSettings?.isTestModule?.let { isTest -> if (isTest) SourceType.TEST else PRODUCTION } val Module.isMPPModule: Boolean get() { - val settings = KotlinFacet.get(this)?.configuration?.settings ?: return false + val settings = facetSettings ?: return false return settings.platform.isCommon || settings.implementedModuleNames.isNotEmpty() || settings.kind.isNewMPP } +private val Module.facetSettings get() = KotlinFacet.get(this)?.configuration?.settings + val Module.implementingModules: List get() = cached(CachedValueProvider { val moduleManager = ModuleManager.getInstance(project) @@ -87,12 +94,15 @@ val ModuleDescriptor.implementingDescriptors: List return listOf(this) } val moduleSourceInfo = moduleInfo as? ModuleSourceInfo ?: return emptyList() - val implementingModuleInfos = moduleSourceInfo.module.implementingModules.mapNotNull { it.toInfo(moduleSourceInfo.isTests()) } + val implementingModuleInfos = moduleSourceInfo.module.implementingModules.mapNotNull { it.toInfo(moduleSourceInfo.sourceType) } return implementingModuleInfos.mapNotNull { it.toDescriptor() } } -private fun Module.toInfo(isTests: Boolean): ModuleSourceInfo? = - if (isTests) testSourceInfo() else productionSourceInfo() +private fun Module.toInfo(type: SourceType): ModuleSourceInfo? = when (type) { + PRODUCTION -> productionSourceInfo() + TEST -> testSourceInfo() +} + val ModuleDescriptor.implementedDescriptors: List get() { @@ -112,7 +122,7 @@ fun PsiElement.getPlatformModuleInfo(desiredPlatform: TargetPlatform): PlatformM val moduleInfo = getModuleInfo() as? ModuleSourceInfo ?: return null return when (moduleInfo.platform) { TargetPlatform.Common -> { - val correspondingImplementingModule = moduleInfo.module.implementingModules.map { it.toInfo(moduleInfo.isTests()) } + val correspondingImplementingModule = moduleInfo.module.implementingModules.map { it.toInfo(moduleInfo.sourceType) } .firstOrNull { it?.platform == desiredPlatform } ?: return null PlatformModuleInfo(correspondingImplementingModule, correspondingImplementingModule.expectedBy) } diff --git a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt index 427fa2cf4b7..7d1ca89ed8c 100644 --- a/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt +++ b/idea/idea-core/src/org/jetbrains/kotlin/idea/core/fileIndexUtils.kt @@ -12,12 +12,20 @@ import org.jetbrains.jps.model.java.JavaSourceRootType import org.jetbrains.jps.model.module.JpsModuleSourceRootType import org.jetbrains.kotlin.config.KotlinResourceRootType import org.jetbrains.kotlin.config.KotlinSourceRootType +import org.jetbrains.kotlin.idea.caches.project.SourceType +import org.jetbrains.kotlin.idea.util.isInSourceContentWithoutInjected private val testRootTypes: Set> = setOf( - JavaSourceRootType.TEST_SOURCE, - JavaResourceRootType.TEST_RESOURCE, - KotlinSourceRootType.TestSource, - KotlinResourceRootType.TestResource + JavaSourceRootType.TEST_SOURCE, + JavaResourceRootType.TEST_RESOURCE, + KotlinSourceRootType.TestSource, + KotlinResourceRootType.TestResource ) -fun FileIndex.isInTestSourceContentKotlinAware(fileOrDir: VirtualFile) = isUnderSourceRootOfType(fileOrDir, testRootTypes) \ No newline at end of file +fun FileIndex.isInTestSourceContentKotlinAware(fileOrDir: VirtualFile) = isUnderSourceRootOfType(fileOrDir, testRootTypes) + +fun FileIndex.getSourceType(fileOrDir: VirtualFile): SourceType? = when { + isInTestSourceContentKotlinAware(fileOrDir) -> SourceType.TEST + isInSourceContentWithoutInjected(fileOrDir) -> SourceType.PRODUCTION + else -> null +} \ No newline at end of file diff --git a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/multiplatform/KotlinMultiplatformRunLocationsProvider.kt b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/multiplatform/KotlinMultiplatformRunLocationsProvider.kt index 293f022b629..1967959dee3 100644 --- a/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/multiplatform/KotlinMultiplatformRunLocationsProvider.kt +++ b/idea/idea-jvm/src/org/jetbrains/kotlin/idea/run/multiplatform/KotlinMultiplatformRunLocationsProvider.kt @@ -9,13 +9,14 @@ import com.intellij.execution.Location import com.intellij.execution.PsiLocation import com.intellij.execution.actions.MultipleRunLocationsProvider import com.intellij.openapi.module.Module -import com.intellij.openapi.module.ModuleManager import com.intellij.openapi.roots.ModuleRootManager import org.jetbrains.kotlin.config.KotlinModuleKind +import org.jetbrains.kotlin.idea.caches.project.SourceType import org.jetbrains.kotlin.idea.caches.project.implementingModules import org.jetbrains.kotlin.idea.caches.project.isNewMPPModule +import org.jetbrains.kotlin.idea.caches.project.sourceType import org.jetbrains.kotlin.idea.configuration.toModuleGroup -import org.jetbrains.kotlin.idea.core.isInTestSourceContentKotlinAware +import org.jetbrains.kotlin.idea.core.getSourceType import org.jetbrains.kotlin.idea.facet.KotlinFacet class KotlinMultiplatformRunLocationsProvider : MultipleRunLocationsProvider() { @@ -27,8 +28,8 @@ class KotlinMultiplatformRunLocationsProvider : MultipleRunLocationsProvider() { override fun getAlternativeLocations(originalLocation: Location<*>): List> { val originalModule = originalLocation.module ?: return emptyList() val virtualFile = originalLocation.virtualFile ?: return emptyList() - val shouldRunAsTest = ModuleRootManager.getInstance(originalModule).fileIndex.isInTestSourceContentKotlinAware(virtualFile) - return modulesToRunFrom(originalModule, shouldRunAsTest).map { PsiLocation(originalLocation.project, it, originalLocation.psiElement) } + val sourceType = ModuleRootManager.getInstance(originalModule).fileIndex.getSourceType(virtualFile) ?: return emptyList() + return modulesToRunFrom(originalModule, sourceType).map { PsiLocation(originalLocation.project, it, originalLocation.psiElement) } } } @@ -43,17 +44,12 @@ private fun compactedGradleProjectId(module: Module): String? { private fun modulesToRunFrom( originalModule: Module, - shouldRunAsTest: Boolean + originalSourceType: SourceType ): List { val modules = originalModule.implementingModules if (!originalModule.isNewMPPModule) return modules val compilations = modules.filter { KotlinFacet.get(it)?.configuration?.settings?.kind == KotlinModuleKind.COMPILATION_AND_SOURCE_SET_HOLDER } - - val project = originalModule.project - // TODO: more robust way to get test/production compilations - val baseName = originalModule.toModuleGroup().baseModule.name - val commonTests = ModuleManager.getInstance(project).findModuleByName(baseName + "_commonTest") ?: return compilations - return compilations.filter { ModuleRootManager.getInstance(it).isDependsOn(commonTests) == shouldRunAsTest } + return compilations.filter { it.sourceType == originalSourceType } } \ No newline at end of file