diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt index 10c60dcc586..eebc46bde57 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/PerFileAnalysisCache.kt @@ -165,6 +165,9 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone throw e } } + if (fileResult == null) { + file.clearInBlockModifications() + } return fileResult } @@ -228,6 +231,7 @@ internal class PerFileAnalysisCache(val file: KtFile, componentProvider: Compone return AnalysisResult.EMPTY } + moduleDescriptor.assertValid() try { return KotlinResolveDataProvider.analyze( project, diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt index 702a8201192..2e036fa2654 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/ProjectResolutionFacade.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.idea.caches.resolve +import com.intellij.openapi.diagnostic.ControlFlowException import com.intellij.openapi.progress.ProcessCanceledException import com.intellij.openapi.progress.ProgressManager import com.intellij.openapi.project.Project @@ -102,13 +103,8 @@ internal class ProjectResolutionFacade( private val resolverForProjectDependencies = dependencies + listOf(globalContext.exceptionTracker) private fun computeModuleResolverProvider(): ResolverForProject { - val delegateResolverForProject: ResolverForProject - - if (reuseDataFrom != null) { - delegateResolverForProject = reuseDataFrom.cachedResolverForProject - } else { - delegateResolverForProject = EmptyResolverForProject() - } + val delegateResolverForProject: ResolverForProject = + reuseDataFrom?.cachedResolverForProject ?: EmptyResolverForProject() val allModuleInfos = (allModules ?: getModuleInfosFromIdeaModel(project, (settings as? PlatformAnalysisSettingsImpl)?.platform)) .toMutableSet() @@ -154,13 +150,29 @@ internal class ProjectResolutionFacade( internal fun getAnalysisResultsForElements(elements: Collection): AnalysisResult { assert(elements.isNotEmpty()) { "elements collection should not be empty" } - val slruCache = analysisResultsSimpleLock.guarded { + val cache = analysisResultsSimpleLock.guarded { analysisResults.value!! } - val results = elements.map { - val perFileCache = slruCache[it.containingKtFile] - perFileCache.getAnalysisResults(it) - } + val results = + elements.map { + val containingKtFile = it.containingKtFile + val perFileCache = cache[containingKtFile] + try { + perFileCache.getAnalysisResults(it) + } catch (e: Throwable) { + if (e is ControlFlowException) { + throw e + } + val actualCache = analysisResultsSimpleLock.guarded { + analysisResults.upToDateOrNull?.get() + } + if (cache !== actualCache) { + throw IllegalStateException("Cache has been invalidated during performing analysis for $containingKtFile", e) + } + throw e + } + } + val withError = results.firstOrNull { it.isError() } val bindingContext = CompositeBindingContext.create(results.map { it.bindingContext }) if (withError != null) { diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt index 6a49adbc373..bfcd664d17c 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt @@ -8,10 +8,8 @@ package org.jetbrains.kotlin.idea.caches.trackers import com.intellij.openapi.project.Project import com.intellij.openapi.util.SimpleModificationTracker import com.intellij.pom.tree.TreeAspect -import com.intellij.psi.util.PsiModificationTracker import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.util.application.getServiceSafe -import org.jetbrains.kotlin.psi.KtFile /** * Tested in OutOfBlockModificationTestGenerated diff --git a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt index 9c6521beb74..72d1f2efb7d 100644 --- a/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt +++ b/idea/idea-frontend-independent/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt @@ -6,6 +6,7 @@ package org.jetbrains.kotlin.idea.caches.trackers import com.intellij.lang.ASTNode +import com.intellij.openapi.Disposable import com.intellij.openapi.project.Project import com.intellij.openapi.util.Key import com.intellij.openapi.util.ModificationTracker @@ -27,6 +28,8 @@ import com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.PROPERTY_CHANGE import com.intellij.psi.impl.PsiTreeChangePreprocessor import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.PsiTreeUtil +import org.jetbrains.kotlin.analyzer.ModuleDescriptorListener +import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.anyDescendantOfType @@ -39,7 +42,7 @@ val KOTLIN_CONSOLE_KEY = Key.create("kotlin.console") * Tested in OutOfBlockModificationTestGenerated */ // FIX ME WHEN BUNCH 193 REMOVED -abstract class KotlinCodeBlockModificationListenerCompat(protected val project: Project) : PsiTreeChangePreprocessor { +abstract class KotlinCodeBlockModificationListenerCompat(protected val project: Project) : PsiTreeChangePreprocessor, Disposable { protected val modificationTrackerImpl: PsiModificationTrackerImpl = PsiModificationTracker.SERVICE.getInstance(project) as PsiModificationTrackerImpl @@ -62,7 +65,7 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project: kotlinOutOfCodeBlockTrackerImpl = kotlinOutOfCodeBlockTrackerProducer() kotlinOutOfCodeBlockTracker = kotlinOutOfCodeBlockTrackerImpl val model = PomManager.getModel(project) - val messageBusConnection = project.messageBus.connect(project) + val messageBusConnection = project.messageBus.connect(this) model.addModelListener(object : PomModelListener { override fun isAspectChangeInteresting(aspect: PomModelAspect): Boolean { return aspect == treeAspect @@ -125,6 +128,10 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project: } } + override fun dispose() { + kotlinOutOfCodeBlockTrackerImpl.incModificationCount() + } + companion object { private fun isReplLine(file: VirtualFile): Boolean { return file.getUserData(KOTLIN_CONSOLE_KEY) == true @@ -176,7 +183,7 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project: // dirty scope for whitespaces and comments is the element itself if (element is PsiWhiteSpace || element is PsiComment || element is KDoc) return element - return getInsideCodeBlockModificationScope(element)?.blockDeclaration ?: null + return getInsideCodeBlockModificationScope(element)?.blockDeclaration } fun getInsideCodeBlockModificationScope(element: PsiElement): BlockModificationScopeElement? { @@ -267,7 +274,7 @@ abstract class KotlinCodeBlockModificationListenerCompat(protected val project: is KtSecondaryConstructor -> { blockDeclaration - ?.takeIf { + .takeIf { it.bodyExpression?.isAncestor(element) ?: false || it.getDelegationCallOrNull()?.isAncestor(element) ?: false }?.let { ktConstructor -> PsiTreeUtil.getParentOfType(blockDeclaration, KtClassOrObject::class.java)?.let {