From 6352cded1b87b0f9208a12eeeddc9b197d2d8664 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Fri, 3 Jan 2020 16:20:26 +0100 Subject: [PATCH] Add modCounter to invalidate synthetic file cache #KT-35186 Fixed --- .../caches/resolve/KotlinCacheServiceImpl.kt | 13 ++--- .../KotlinCodeBlockModificationListener.kt | 53 ++++++++----------- 2 files changed, 25 insertions(+), 41 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt index 47d44ea9de3..03c8612fc92 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/resolve/KotlinCacheServiceImpl.kt @@ -44,7 +44,6 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.idea.caches.project.* import org.jetbrains.kotlin.idea.caches.project.IdeaModuleInfo import org.jetbrains.kotlin.idea.caches.resolve.util.contextWithCompositeExceptionTracker -import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener import org.jetbrains.kotlin.idea.caches.trackers.outOfBlockModificationCount import org.jetbrains.kotlin.idea.compiler.IDELanguageSettingsProvider import org.jetbrains.kotlin.idea.core.script.ScriptDependenciesModificationTracker @@ -255,13 +254,9 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { val settings = specialModuleInfo.platformSettings(specialModuleInfo.platform ?: targetPlatform) // Dummy files created e.g. by J2K do not receive events. - val dependenciesForSyntheticFileCache = if (files.all { it.originalFile != it }) { - emptyList() - } else { - listOf(ModificationTracker { - files.sumByLong { it.modificationStamp } - }) - } + val dependencyTrackerForSyntheticFileCache = if (files.all { it.originalFile != it }) { + ModificationTracker { files.sumByLong { it.outOfBlockModificationCount } } + } else ModificationTracker { files.sumByLong { it.modificationStamp } } val resolverDebugName = "$resolverForSpecialInfoName $specialModuleInfo for files ${files.joinToString { it.name }} for platform $targetPlatform" @@ -282,7 +277,7 @@ class KotlinCacheServiceImpl(val project: Project) : KotlinCacheService { syntheticFiles = files, reuseDataFrom = reuseDataFrom, moduleFilter = moduleFilter, - dependencies = dependenciesForSyntheticFileCache, + dependencies = listOf(dependencyTrackerForSyntheticFileCache), invalidateOnOOCB = true, allModules = allModules ) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt index 91cb953a929..9aa9dbfef93 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt @@ -92,20 +92,18 @@ class KotlinCodeBlockModificationListener( val changedElements = changeSet.changedElements // skip change if it contains only virtual/fake change - if (changedElements.isNotEmpty() && - // ignore formatting (whitespaces etc) change - (isFormattingChange(changeSet) || - // ignore comment change - isCommentChange(changeSet) || - changedElements.all { !it.psi.isPhysical }) - ) return + if (changedElements.isNotEmpty()) { + // ignore formatting (whitespaces etc) + if (isFormattingChange(changeSet) || isCommentChange(changeSet)) return + } - val inBlockChange = inBlockModifications(changedElements) + val inBlockElements = inBlockModifications(changedElements) - if (!inBlockChange) { + val physical = ktFile.isPhysical + if (inBlockElements.isEmpty()) { messageBusConnection.deliverImmediately() - if (ktFile.isPhysical && !isReplLine(ktFile.virtualFile)) { + if (physical && !isReplLine(ktFile.virtualFile)) { if (isLanguageTrackerEnabled) { kotlinOutOfCodeBlockTrackerImpl.incModificationCount() perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true) @@ -116,7 +114,9 @@ class KotlinCodeBlockModificationListener( } } - incOutOfBlockModificationCount(ktFile) + ktFile.incOutOfBlockModificationCount() + } else if (physical) { + inBlockElements.forEach { it.containingKtFile.addInBlockModifiedItem(it) } } } }) @@ -165,37 +165,20 @@ class KotlinCodeBlockModificationListener( return file.getUserData(KOTLIN_CONSOLE_KEY) == true } - private fun incOutOfBlockModificationCount(file: KtFile) { - file.clearInBlockModifications() - - val count = file.getUserData(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT) ?: 0 - file.putUserData(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT, count + 1) - } - private fun incFileModificationCount(file: KtFile) { val tracker = file.getUserData(PER_FILE_MODIFICATION_TRACKER) ?: file.putUserDataIfAbsent(PER_FILE_MODIFICATION_TRACKER, SimpleModificationTracker()) tracker.incModificationCount() } - private fun inBlockModifications(elements: Array): Boolean { + private fun inBlockModifications(elements: Array): List { // When a code fragment is reparsed, Intellij doesn't do an AST diff and considers the entire // contents to be replaced, which is represented in a POM event as an empty list of changed elements - if (elements.isEmpty()) return false - val inBlockElements = mutableSetOf() - for (element in elements) { - // skip fake PSI elements like `IntellijIdeaRulezzz$` - val psi = element.psi - if (!psi.isPhysical) continue - - val modificationScope = getInsideCodeBlockModificationScope(psi) ?: return false - - inBlockElements.add(modificationScope.blockDeclaration) + return elements.mapNotNull { element -> + val modificationScope = getInsideCodeBlockModificationScope(element.psi) ?: return emptyList() + modificationScope.blockDeclaration } - - inBlockElements.forEach { it.containingKtFile.addInBlockModifiedItem(it) } - return inBlockElements.isNotEmpty() } private fun isCommentChange(changeSet: TreeChangeEvent): Boolean = @@ -359,6 +342,12 @@ private val FILE_OUT_OF_BLOCK_MODIFICATION_COUNT = Key("FILE_OUT_OF_BLOCK_ val KtFile.outOfBlockModificationCount: Long by NotNullableUserDataProperty(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT, 0) +private fun KtFile.incOutOfBlockModificationCount() { + clearInBlockModifications() + + val count = getUserData(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT) ?: 0 + putUserData(FILE_OUT_OF_BLOCK_MODIFICATION_COUNT, count + 1) +} /** * inBlockModifications is a collection of block elements those have in-block modifications