Cache result of collectModulesFromIdeaModel

Cache base module infos from idea model until next root modification
Calculate platform specific module infos (see PlatformModuleInfo)
    on demand based on cached module infos from idea model

 #KT-24144 Fixed
This commit is contained in:
Pavel V. Talanov
2018-04-27 17:05:33 +02:00
parent 406a3888c7
commit 607fab994c
4 changed files with 55 additions and 19 deletions
@@ -94,10 +94,6 @@ private fun orderEntryToModuleInfo(project: Project, orderEntry: OrderEntry, for
} }
} }
fun <T> Module.cached(provider: CachedValueProvider<T>): T {
return CachedValuesManager.getManager(project).getCachedValue(this, provider)
}
private fun OrderEntry.acceptAsDependency(forProduction: Boolean): Boolean { private fun OrderEntry.acceptAsDependency(forProduction: Boolean): Boolean {
return this !is ExportableOrderEntry return this !is ExportableOrderEntry
|| !forProduction || !forProduction
@@ -0,0 +1,19 @@
/*
* Copyright 2010-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.caches.project
import com.intellij.openapi.module.Module
import com.intellij.openapi.project.Project
import com.intellij.psi.util.CachedValueProvider
import com.intellij.psi.util.CachedValuesManager
fun <T> Module.cached(provider: CachedValueProvider<T>): T {
return CachedValuesManager.getManager(project).getCachedValue(this, provider)
}
fun <T> Project.cached(provider: CachedValueProvider<T>): T {
return CachedValuesManager.getManager(this).getCachedValue(this, provider)
}
@@ -13,11 +13,37 @@ import com.intellij.openapi.projectRoots.Sdk
import com.intellij.openapi.roots.JdkOrderEntry import com.intellij.openapi.roots.JdkOrderEntry
import com.intellij.openapi.roots.LibraryOrderEntry import com.intellij.openapi.roots.LibraryOrderEntry
import com.intellij.openapi.roots.ModuleRootManager import com.intellij.openapi.roots.ModuleRootManager
import com.intellij.openapi.roots.ProjectRootModificationTracker
import com.intellij.psi.util.CachedValueProvider
import org.jetbrains.kotlin.resolve.TargetPlatform import org.jetbrains.kotlin.resolve.TargetPlatform
import java.util.concurrent.ConcurrentHashMap
fun collectAllModuleInfosFromIdeaModel(project: Project, platform: TargetPlatform): List<IdeaModuleInfo> { fun getModuleInfosFromIdeaModel(project: Project, platform: TargetPlatform): List<IdeaModuleInfo> {
val modelInfosCache = project.cached(CachedValueProvider {
CachedValueProvider.Result(collectModuleInfosFromIdeaModel(project), ProjectRootModificationTracker.getInstance(project))
})
return modelInfosCache.forPlatform(platform)
}
private class IdeaModelInfosCache(
val moduleSourceInfos: List<ModuleSourceInfo>,
val libraryInfos: List<LibraryInfo>,
val sdkInfos: List<SdkInfo>
) {
private val resultByPlatform = ConcurrentHashMap<TargetPlatform, List<IdeaModuleInfo>>()
fun forPlatform(platform: TargetPlatform): List<IdeaModuleInfo> {
return resultByPlatform.getOrPut(platform) {
mergePlatformModules(moduleSourceInfos, platform) + libraryInfos + sdkInfos
}
}
}
private fun collectModuleInfosFromIdeaModel(
project: Project
): IdeaModelInfosCache {
val ideaModules = ModuleManager.getInstance(project).modules.toList() val ideaModules = ModuleManager.getInstance(project).modules.toList()
val modulesSourcesInfos = ideaModules.flatMap(Module::correspondingModuleInfos)
//TODO: (module refactoring) include libraries that are not among dependencies of any module //TODO: (module refactoring) include libraries that are not among dependencies of any module
val ideaLibraries = ideaModules.flatMap { val ideaLibraries = ideaModules.flatMap {
@@ -26,33 +52,28 @@ fun collectAllModuleInfosFromIdeaModel(project: Project, platform: TargetPlatfor
} }
}.filterNotNull().toSet() }.filterNotNull().toSet()
val librariesInfos = ideaLibraries.map { LibraryInfo(project, it) }
val sdksFromModulesDependencies = ideaModules.flatMap { val sdksFromModulesDependencies = ideaModules.flatMap {
ModuleRootManager.getInstance(it).orderEntries.filterIsInstance<JdkOrderEntry>().map { ModuleRootManager.getInstance(it).orderEntries.filterIsInstance<JdkOrderEntry>().map {
it.jdk it.jdk
} }
} }
val sdksInfos = (sdksFromModulesDependencies + getAllProjectSdks()).filterNotNull().toSet().map { return IdeaModelInfosCache(
SdkInfo( moduleSourceInfos = ideaModules.flatMap(Module::correspondingModuleInfos),
project, libraryInfos = ideaLibraries.map { LibraryInfo(project, it) },
it sdkInfos = (sdksFromModulesDependencies + getAllProjectSdks()).filterNotNull().toSet().map { SdkInfo(project, it) }
) )
}
return mergePlatformModules(modulesSourcesInfos, platform) + librariesInfos + sdksInfos
} }
private fun mergePlatformModules( private fun mergePlatformModules(
allModules: List<IdeaModuleInfo>, allModules: List<ModuleSourceInfo>,
platform: TargetPlatform platform: TargetPlatform
): List<IdeaModuleInfo> { ): List<IdeaModuleInfo> {
if (platform == TargetPlatform.Common) return allModules if (platform == TargetPlatform.Common) return allModules
val platformModules = val platformModules =
allModules.flatMap { module -> allModules.flatMap { module ->
if (module is ModuleSourceInfo && module.platform == platform && module.expectedBy.isNotEmpty()) if (module.platform == platform && module.expectedBy.isNotEmpty())
listOf(module to module.expectedBy) listOf(module to module.expectedBy)
else emptyList() else emptyList()
}.map { (module, expectedBys) -> }.map { (module, expectedBys) ->
@@ -104,7 +104,7 @@ internal class ProjectResolutionFacade(
globalContext globalContext
) )
val allModuleInfos = (allModules ?: collectAllModuleInfosFromIdeaModel(project, settings.platform)).toMutableSet() val allModuleInfos = (allModules ?: getModuleInfosFromIdeaModel(project, settings.platform)).toMutableSet()
val syntheticFilesByModule = syntheticFiles.groupBy(KtFile::getModuleInfo) val syntheticFilesByModule = syntheticFiles.groupBy(KtFile::getModuleInfo)
val syntheticFilesModules = syntheticFilesByModule.keys val syntheticFilesModules = syntheticFilesByModule.keys