Minor: refactor PerModulePackageCacheService

This commit is contained in:
Pavel V. Talanov
2017-05-11 21:04:29 +03:00
parent f750d08350
commit 77e611b2e7
2 changed files with 36 additions and 38 deletions
@@ -16,7 +16,7 @@
package org.jetbrains.kotlin.idea.caches package org.jetbrains.kotlin.idea.caches
import com.intellij.openapi.components.ServiceManager import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.Ref import com.intellij.openapi.util.Ref
@@ -57,13 +57,13 @@ class KotlinPackageContentModificationListener(
.filterNotNull() .filterNotNull()
.filter { it in scope } .filter { it in scope }
.forEach { file -> .forEach { file ->
PerModulePackageCacheService.notifyPackageChange(file, project) project.service<PerModulePackageCacheService>().notifyPackageChange(file)
} }
}) })
} }
} }
class KotlinPackageStatementPsiTreeChangePreprocessor : PsiTreeChangePreprocessor { class KotlinPackageStatementPsiTreeChangePreprocessor(private val project: Project) : PsiTreeChangePreprocessor {
override fun treeChanged(event: PsiTreeChangeEventImpl) { override fun treeChanged(event: PsiTreeChangeEventImpl) {
val file = event.file as? KtFile ?: return val file = event.file as? KtFile ?: return
@@ -71,7 +71,7 @@ class KotlinPackageStatementPsiTreeChangePreprocessor : PsiTreeChangePreprocesso
PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED, PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED, PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED, PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> { PsiTreeChangeEventImpl.PsiEventType.CHILD_ADDED, PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED, PsiTreeChangeEventImpl.PsiEventType.CHILD_REPLACED, PsiTreeChangeEventImpl.PsiEventType.CHILD_REMOVED -> {
val child = event.child ?: return val child = event.child ?: return
if (child.getParentOfType<KtPackageDirective>(false) != null) if (child.getParentOfType<KtPackageDirective>(false) != null)
PerModulePackageCacheService.notifyPackageChange(file) project.service<PerModulePackageCacheService>().notifyPackageChange(file)
} }
else -> { else -> {
} }
@@ -79,46 +79,43 @@ class KotlinPackageStatementPsiTreeChangePreprocessor : PsiTreeChangePreprocesso
} }
} }
class PerModulePackageCacheService { class PerModulePackageCacheService(private val project: Project) {
val cache = ContainerUtil.createConcurrentWeakMap<ModuleInfo, Ref<ConcurrentMap<FqName, Boolean>>>() private val cache = ContainerUtil.createConcurrentWeakMap<ModuleInfo, Ref<ConcurrentMap<FqName, Boolean>>>()
companion object { internal fun notifyPackageChange(file: VirtualFile) {
(getModuleInfoByVirtualFile(project, file) as? ModuleSourceInfo)?.let { onChangeInModuleSource(it) }
}
val PER_MODULE_PACKAGE_CACHE = Key.create<ConcurrentMap<ModuleInfo, Ref<ConcurrentMap<FqName, Boolean>>>>("per_module_package_cache") internal fun notifyPackageChange(file: KtFile) {
(file.getNullableModuleInfo() as? ModuleSourceInfo)?.let { onChangeInModuleSource(it) }
}
internal fun notifyPackageChange(file: KtFile): Unit { internal fun onChangeInModuleSource(moduleSourceInfo: ModuleSourceInfo) {
(file.getNullableModuleInfo() as? ModuleSourceInfo)?.let { onChangeInModuleSource(it, file.project) } cache[moduleSourceInfo]?.set(null)
}
fun packageExists(packageFqName: FqName, moduleInfo: ModuleSourceInfo): Boolean {
val module = moduleInfo.module
// Module own cache is a view on global cache. Since global cache based on WeakReferences when module
// gets disposed this soft map will be disposed too, leading to drop soft refs on ModuleInfo's, and then to
// disposing global cache entry
val moduleOwnCache = module.getUserData(PerModulePackageCacheService.PER_MODULE_PACKAGE_CACHE) ?: run {
ContainerUtil.createConcurrentSoftMap<ModuleInfo, Ref<ConcurrentMap<FqName, Boolean>>>()
.apply { module.putUserData(PerModulePackageCacheService.PER_MODULE_PACKAGE_CACHE, this) }
} }
val cached = moduleOwnCache.getOrPut(moduleInfo) { cache.getOrPut(moduleInfo) { Ref() } }
internal fun onChangeInModuleSource(moduleSourceInfo: ModuleSourceInfo, project: Project) = with(getInstance(project)) { .apply { if (isNull) set(ContainerUtil.createConcurrentSoftMap<FqName, Boolean>()) }
cache[moduleSourceInfo]?.set(null) .get()
}
internal fun notifyPackageChange(file: VirtualFile, project: Project): Unit {
(getModuleInfoByVirtualFile(project, file) as? ModuleSourceInfo)?.let { onChangeInModuleSource(it, project) }
}
fun getInstance(project: Project): PerModulePackageCacheService = ServiceManager.getService(project, PerModulePackageCacheService::class.java)
fun packageExists(packageFqName: FqName, moduleInfo: ModuleSourceInfo, project: Project): Boolean = with(getInstance(project)) {
val module = moduleInfo.module
// Module own cache is a view on global cache. Since global cache based on WeakReferences when module
// gets disposed this soft map will be disposed too, leading to drop soft refs on ModuleInfo's, and then to
// disposing global cache entry
val moduleOwnCache = module.getUserData(PerModulePackageCacheService.PER_MODULE_PACKAGE_CACHE) ?: run {
ContainerUtil.createConcurrentSoftMap<ModuleInfo, Ref<ConcurrentMap<FqName, Boolean>>>()
.apply { module.putUserData(PerModulePackageCacheService.PER_MODULE_PACKAGE_CACHE, this) }
}
val cached = moduleOwnCache.getOrPut(moduleInfo) { cache.getOrPut(moduleInfo) { Ref() } }
.apply { if (isNull) set(ContainerUtil.createConcurrentSoftMap<FqName, Boolean>()) }
.get()
return cached.getOrPut(packageFqName) { return cached.getOrPut(packageFqName) {
PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project) PackageIndexUtil.packageExists(packageFqName, moduleInfo.contentScope(), project)
}
} }
} }
companion object {
private val PER_MODULE_PACKAGE_CACHE = Key.create<ConcurrentMap<ModuleInfo, Ref<ConcurrentMap<FqName, Boolean>>>>("per_module_package_cache")
}
} }
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.stubindex.resolve package org.jetbrains.kotlin.idea.stubindex.resolve
import com.intellij.openapi.components.service
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import com.intellij.psi.search.GlobalSearchScope import com.intellij.psi.search.GlobalSearchScope
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
@@ -55,7 +56,7 @@ class PluginDeclarationProviderFactory(
private fun packageExists(name: FqName): Boolean { private fun packageExists(name: FqName): Boolean {
return if (moduleInfo is ModuleSourceInfo) return if (moduleInfo is ModuleSourceInfo)
PerModulePackageCacheService.packageExists(name, moduleInfo, project) project.service<PerModulePackageCacheService>().packageExists(name, moduleInfo)
else else
PackageIndexUtil.packageExists(name, indexedFilesScope, project) PackageIndexUtil.packageExists(name, indexedFilesScope, project)
} }