Add modCounter to invalidate synthetic file cache

#KT-35186 Fixed
This commit is contained in:
Vladimir Dolzhenko
2020-01-03 16:20:26 +01:00
parent 7329a1641a
commit 6352cded1b
2 changed files with 25 additions and 41 deletions
@@ -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
)
@@ -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<ASTNode>): Boolean {
private fun inBlockModifications(elements: Array<ASTNode>): List<KtElement> {
// 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<KtElement>()
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<Long>("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