From e135b6ae967a46a0b91068b50e6306f1827c162d Mon Sep 17 00:00:00 2001 From: "Pavel V. Talanov" Date: Thu, 2 Jul 2015 18:03:31 +0300 Subject: [PATCH] Recompute KotlinResolveCache for synthetic files on project structure modification Since computed KotlinResolveCache depends on corresponding synthetic files location (namely, moduleFilter), it should be recomputed in this case The STR for this issue provided by Alexander Udalov: 1. Open a library source, wait for it to be analyzed. In this case library sources are files in the project under core/builtins/src/. 2. Go to project settings and remove the source from the library. 3. Exception now on each file change, out of block doesn't seem to help. --- .../idea/caches/resolve/KotlinCacheService.kt | 123 ++++++++++-------- 1 file changed, 67 insertions(+), 56 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt index d3c016855c9..b22b6120619 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheService.kt @@ -21,6 +21,7 @@ import com.intellij.openapi.diagnostic.Logger import com.intellij.openapi.project.Project import com.intellij.openapi.roots.ProjectRootModificationTracker import com.intellij.psi.util.CachedValueProvider +import com.intellij.psi.util.CachedValuesManager import com.intellij.psi.util.PsiModificationTracker import com.intellij.util.containers.SLRUCache import org.jetbrains.kotlin.analyzer.AnalysisResult @@ -102,67 +103,77 @@ public class KotlinCacheService(val project: Project) { private fun getGlobalCache(platform: TargetPlatform) = globalCachesPerPlatform[platform]!!.modulesCache private fun getGlobalLibrariesCache(platform: TargetPlatform) = globalCachesPerPlatform[platform]!!.librariesCache - private val syntheticFileCaches = object : SLRUCache, KotlinResolveCache>(2, 3) { - override fun createValue(files: Set): KotlinResolveCache { - // we assume that all files come from the same module - val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single() - val syntheticFileModule = files.map { it.getModuleInfo() }.toSet().single() - val dependenciesForSyntheticFileCache = listOf( - PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, - KotlinOutOfBlockCompletionModificationTracker.getInstance(project) - ) - return when { - syntheticFileModule is ModuleSourceInfo -> { - val dependentModules = syntheticFileModule.getDependentModules() - KotlinResolveCache( - project, - globalResolveSessionProvider( - targetPlatform, - syntheticFiles = files, - reuseDataFromCache = getGlobalCache(targetPlatform), - moduleFilter = { it in dependentModules }, - dependencies = dependenciesForSyntheticFileCache - ) - ) - } - - syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> { - KotlinResolveCache( - project, - globalResolveSessionProvider( - targetPlatform, - syntheticFiles = files, - reuseDataFromCache = getGlobalLibrariesCache(targetPlatform), - moduleFilter = { it == syntheticFileModule }, - dependencies = dependenciesForSyntheticFileCache - ) - ) - } - - syntheticFileModule.isLibraryClasses() -> { - //NOTE: this code should not be called for sdk or library classes - // currently the only known scenario is when we cannot determine that file is a library source - // (file under both classes and sources root) - LOG.warn("Creating cache with synthetic files ($files) in classes of library $syntheticFileModule") - KotlinResolveCache( - project, - globalResolveSessionProvider( - targetPlatform, - syntheticFiles = files, - moduleFilter = { true }, - dependencies = dependenciesForSyntheticFileCache - ) - ) - } - - else -> throw IllegalStateException("Unknown IdeaModuleInfo ${syntheticFileModule.javaClass}") + private fun createCacheForSyntheticFiles(files: Set): KotlinResolveCache { + // we assume that all files come from the same module + val targetPlatform = files.map { TargetPlatformDetector.getPlatform(it) }.toSet().single() + val syntheticFileModule = files.map { it.getModuleInfo() }.toSet().single() + val dependenciesForSyntheticFileCache = listOf( + PsiModificationTracker.OUT_OF_CODE_BLOCK_MODIFICATION_COUNT, + KotlinOutOfBlockCompletionModificationTracker.getInstance(project) + ) + return when { + syntheticFileModule is ModuleSourceInfo -> { + val dependentModules = syntheticFileModule.getDependentModules() + KotlinResolveCache( + project, + globalResolveSessionProvider( + targetPlatform, + syntheticFiles = files, + reuseDataFromCache = getGlobalCache(targetPlatform), + moduleFilter = { it in dependentModules }, + dependencies = dependenciesForSyntheticFileCache + ) + ) } + + syntheticFileModule is LibrarySourceInfo || syntheticFileModule is NotUnderContentRootModuleInfo -> { + KotlinResolveCache( + project, + globalResolveSessionProvider( + targetPlatform, + syntheticFiles = files, + reuseDataFromCache = getGlobalLibrariesCache(targetPlatform), + moduleFilter = { it == syntheticFileModule }, + dependencies = dependenciesForSyntheticFileCache + ) + ) + } + + syntheticFileModule.isLibraryClasses() -> { + //NOTE: this code should not be called for sdk or library classes + // currently the only known scenario is when we cannot determine that file is a library source + // (file under both classes and sources root) + LOG.warn("Creating cache with synthetic files ($files) in classes of library $syntheticFileModule") + KotlinResolveCache( + project, + globalResolveSessionProvider( + targetPlatform, + syntheticFiles = files, + moduleFilter = { true }, + dependencies = dependenciesForSyntheticFileCache + ) + ) + } + + else -> throw IllegalStateException("Unknown IdeaModuleInfo ${syntheticFileModule.javaClass}") } } + private val syntheticFileCachesLock = Any() + + private val slruCacheProvider = CachedValueProvider { + CachedValueProvider.Result(object : SLRUCache, KotlinResolveCache>(2, 3) { + override fun createValue(files: Set): KotlinResolveCache { + return createCacheForSyntheticFiles(files) + } + }, LibraryModificationTracker.getInstance(project), ProjectRootModificationTracker.getInstance(project)) + } + private fun getCacheForSyntheticFiles(files: Set): KotlinResolveCache { - return synchronized(syntheticFileCaches) { - syntheticFileCaches[files] + return synchronized(syntheticFileCachesLock) { + //NOTE: computations inside createCacheForSyntheticFiles depend on project root structure + // so we additionally drop the whole slru cache on change + CachedValuesManager.getManager(project).getCachedValue(project, slruCacheProvider).get(files) } }