From 1cc58518c01e746fa20f1e031e8e16f835d30773 Mon Sep 17 00:00:00 2001 From: Vladimir Dolzhenko Date: Wed, 22 Apr 2020 21:36:36 +0200 Subject: [PATCH] Compatify KotlinCodeBlockModificationListener p.2 Relates to #KT-38443 --- .../KotlinCodeBlockModificationListener.kt | 83 ++++ ...KotlinCodeBlockModificationListener.kt.201 | 356 ++---------------- ...tlinCodeBlockModificationListenerCompat.kt | 80 +--- .../KotlinChangeLocalityDetector.kt | 2 +- .../idea/project/ResolveElementCache.kt | 3 +- .../CompletionBindingContextProvider.kt | 3 +- .../jetbrains/kotlin/idea/resolve/compat.kt | 7 +- 7 files changed, 131 insertions(+), 403 deletions(-) create mode 100644 idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt 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 new file mode 100644 index 00000000000..f135e8565e3 --- /dev/null +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt @@ -0,0 +1,83 @@ +/* + * Copyright 2010-2020 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + + +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.impl.PsiTreeChangeEventImpl +import org.jetbrains.kotlin.idea.KotlinLanguage + +/** + * Tested in OutOfBlockModificationTestGenerated + */ +// BUNCH: 193 +class KotlinCodeBlockModificationListener( + project: Project, + treeAspect: TreeAspect +) : KotlinCodeBlockModificationListenerCompat(project) { + + @Suppress("UnstableApiUsage") + private val isLanguageTrackerEnabled = modificationTrackerImpl.isEnableLanguageTrackerCompat + + // BUNCH: 191 + // When there're we no per-language trackers we had to increment global tracker first and process result afterward + private val customIncrement = if (isLanguageTrackerEnabled) 0 else 1 + + init { + init( + treeAspect, + incOCBCounter = { ktFile -> + if (isLanguageTrackerEnabled) { + kotlinOutOfCodeBlockTrackerImpl.incModificationCount() + perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true) + } else { + perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, false) + // Increment counter and process changes in PsiModificationTracker.Listener + modificationTrackerImpl.incCounter() + } + }, + kotlinOutOfCodeBlockTrackerProducer = { + if (isLanguageTrackerEnabled) { + SimpleModificationTracker() + } else { + object : SimpleModificationTracker() { + override fun getModificationCount(): Long { + @Suppress("DEPRECATION") + return modificationTrackerImpl.outOfCodeBlockModificationCount + } + } + } + }, + psiModificationTrackerListener = { + @Suppress("UnstableApiUsage") + if (isLanguageTrackerEnabled) { + val kotlinTrackerInternalIDECount = + modificationTrackerImpl.forLanguage(KotlinLanguage.INSTANCE).modificationCount + if (kotlinModificationTracker == kotlinTrackerInternalIDECount) { + // Some update that we are not sure is from Kotlin language, as Kotlin language tracker wasn't changed + kotlinOutOfCodeBlockTrackerImpl.incModificationCount() + } else { + kotlinModificationTracker = kotlinTrackerInternalIDECount + } + } + + perModuleOutOfCodeBlockTrackerUpdater.onPsiModificationTrackerUpdate(customIncrement) + } + ) + } + + override fun treeChanged(event: PsiTreeChangeEventImpl) { + assert(isLanguageTrackerEnabled) + super.treeChanged(event) + } + + companion object { + fun getInstance(project: Project): KotlinCodeBlockModificationListener = + project.getComponent(KotlinCodeBlockModificationListener::class.java) + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt.201 b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt.201 index 37e7b00b205..1b977f893a0 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt.201 +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListener.kt.201 @@ -5,358 +5,46 @@ package org.jetbrains.kotlin.idea.caches.trackers -import com.intellij.lang.ASTNode import com.intellij.openapi.project.Project -import com.intellij.openapi.util.Key -import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.SimpleModificationTracker -import com.intellij.openapi.vfs.VirtualFile -import com.intellij.pom.PomManager -import com.intellij.pom.PomModelAspect -import com.intellij.pom.event.PomModelEvent -import com.intellij.pom.event.PomModelListener import com.intellij.pom.tree.TreeAspect -import com.intellij.pom.tree.events.TreeChangeEvent -import com.intellij.pom.tree.events.impl.ChangeInfoImpl -import com.intellij.psi.* -import com.intellij.psi.impl.PsiManagerImpl -import com.intellij.psi.impl.PsiModificationTrackerImpl -import com.intellij.psi.impl.PsiTreeChangeEventImpl -import com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.CHILD_MOVED -import com.intellij.psi.impl.PsiTreeChangeEventImpl.PsiEventType.PROPERTY_CHANGED -import com.intellij.psi.impl.PsiTreeChangePreprocessor import com.intellij.psi.util.PsiModificationTracker -import com.intellij.psi.util.PsiTreeUtil import org.jetbrains.kotlin.idea.KotlinLanguage import org.jetbrains.kotlin.idea.util.application.getServiceSafe -import org.jetbrains.kotlin.kdoc.psi.api.KDoc -import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentOfType -import org.jetbrains.kotlin.psi.psiUtil.isAncestor - -val KOTLIN_CONSOLE_KEY = Key.create("kotlin.console") +import org.jetbrains.kotlin.psi.KtFile /** * Tested in OutOfBlockModificationTestGenerated */ // BUNCH: 193 -class KotlinCodeBlockModificationListener(project: Project) : PsiTreeChangePreprocessor { - private val treeAspect: TreeAspect = TreeAspect.getInstance(project) - - private val modificationTrackerImpl: PsiModificationTrackerImpl = - PsiModificationTracker.SERVICE.getInstance(project) as PsiModificationTrackerImpl - - @Volatile - private var kotlinModificationTracker: Long = 0 - - private val kotlinOutOfCodeBlockTrackerImpl: SimpleModificationTracker = SimpleModificationTracker() - - val kotlinOutOfCodeBlockTracker: ModificationTracker = kotlinOutOfCodeBlockTrackerImpl - - internal val perModuleOutOfCodeBlockTrackerUpdater = KotlinModuleOutOfCodeBlockModificationTracker.Updater(project) +class KotlinCodeBlockModificationListener(project: Project) : KotlinCodeBlockModificationListenerCompat(project) { init { - val model = PomManager.getModel(project) - val messageBusConnection = project.messageBus.connect(project) - - val psiManager = PsiManager.getInstance(project) as PsiManagerImpl - psiManager.addTreeChangePreprocessor(this) - - model.addModelListener(object : PomModelListener { - override fun isAspectChangeInteresting(aspect: PomModelAspect): Boolean { - return aspect == treeAspect - } - - override fun modelChanged(event: PomModelEvent) { - val changeSet = event.getChangeSet(treeAspect) as TreeChangeEvent? ?: return - val ktFile = changeSet.rootElement.psi.containingFile as? KtFile ?: return - - incFileModificationCount(ktFile) - - val changedElements = changeSet.changedElements - - // skip change if it contains only virtual/fake change - if (changedElements.isNotEmpty()) { - // ignore formatting (whitespaces etc) - if (isFormattingChange(changeSet) || isCommentChange(changeSet)) return - } - - val inBlockElements = inBlockModifications(changedElements) - - val physical = ktFile.isPhysical - if (inBlockElements.isEmpty()) { - messageBusConnection.deliverImmediately() - - if (physical && !isReplLine(ktFile.virtualFile) && ktFile !is KtTypeCodeFragment) { - kotlinOutOfCodeBlockTrackerImpl.incModificationCount() - perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true) - } - - ktFile.incOutOfBlockModificationCount() - } else if (physical) { - inBlockElements.forEach { it.containingKtFile.addInBlockModifiedItem(it) } - } - } - }) - - @Suppress("UnstableApiUsage") - messageBusConnection.subscribe(PsiModificationTracker.TOPIC, PsiModificationTracker.Listener { - val kotlinTrackerInternalIDECount = - modificationTrackerImpl.forLanguage(KotlinLanguage.INSTANCE).modificationCount - if (kotlinModificationTracker == kotlinTrackerInternalIDECount) { - // Some update that we are not sure is from Kotlin language, as Kotlin language tracker wasn't changed + init( + TreeAspect.getInstance(project), + incOCBCounter = { ktFile -> kotlinOutOfCodeBlockTrackerImpl.incModificationCount() - } else { - kotlinModificationTracker = kotlinTrackerInternalIDECount + perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true) + }, + kotlinOutOfCodeBlockTrackerProducer = { + SimpleModificationTracker() + }, + psiModificationTrackerListener = { + val kotlinTrackerInternalIDECount = + modificationTrackerImpl.forLanguage(KotlinLanguage.INSTANCE).modificationCount + if (kotlinModificationTracker == kotlinTrackerInternalIDECount) { + // Some update that we are not sure is from Kotlin language, as Kotlin language tracker wasn't changed + kotlinOutOfCodeBlockTrackerImpl.incModificationCount() + } else { + kotlinModificationTracker = kotlinTrackerInternalIDECount + } + + perModuleOutOfCodeBlockTrackerUpdater.onPsiModificationTrackerUpdate() } - - perModuleOutOfCodeBlockTrackerUpdater.onPsiModificationTrackerUpdate() - }) - } - - override fun treeChanged(event: PsiTreeChangeEventImpl) { - if (!PsiModificationTrackerImpl.canAffectPsi(event)) { - return - } - - // Copy logic from PsiModificationTrackerImpl.treeChanged(). Some out-of-code-block events are written to language modification - // tracker in PsiModificationTrackerImpl but don't have correspondent PomModelEvent. Increase kotlinOutOfCodeBlockTracker - // manually if needed. - val outOfCodeBlock = when (event.code) { - PROPERTY_CHANGED -> - event.propertyName === PsiTreeChangeEvent.PROP_UNLOADED_PSI || event.propertyName === PsiTreeChangeEvent.PROP_ROOTS - CHILD_MOVED -> event.oldParent is PsiDirectory || event.newParent is PsiDirectory - else -> event.parent is PsiDirectory - } - - if (outOfCodeBlock) { - kotlinOutOfCodeBlockTrackerImpl.incModificationCount() - } + ) } companion object { - private fun isReplLine(file: VirtualFile): Boolean { - return file.getUserData(KOTLIN_CONSOLE_KEY) == true - } - - 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): 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 - - return elements.map { element -> - val modificationScope = getInsideCodeBlockModificationScope(element.psi) ?: return emptyList() - modificationScope.blockDeclaration - } - } - - private fun isSpecificChange(changeSet: TreeChangeEvent, precondition: (ASTNode?) -> Boolean): Boolean = - changeSet.changedElements.all { changedElement -> - val changesByElement = changeSet.getChangesByElement(changedElement) - changesByElement.affectedChildren.all { affectedChild -> - if (!precondition(affectedChild)) return@all false - val changeByChild = changesByElement.getChangeByChild(affectedChild) - return@all if (changeByChild is ChangeInfoImpl) { - val oldChild = changeByChild.oldChild - precondition(oldChild) - } else false - } - } - - private fun isCommentChange(changeSet: TreeChangeEvent): Boolean = - isSpecificChange(changeSet) { it is PsiComment || it is KDoc } - - private fun isFormattingChange(changeSet: TreeChangeEvent): Boolean = - isSpecificChange(changeSet) { it is PsiWhiteSpace } - - /** - * Has to be aligned with [getInsideCodeBlockModificationScope] : - * - * result of analysis has to be reflected in dirty scope, - * the only difference is whitespaces and comments - */ - fun getInsideCodeBlockModificationDirtyScope(element: PsiElement): PsiElement? { - if (!element.isPhysical) return null - // 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 - } - - fun getInsideCodeBlockModificationScope(element: PsiElement): BlockModificationScopeElement? { - val lambda = element.getTopmostParentOfType() - if (lambda is KtLambdaExpression) { - lambda.getTopmostParentOfType()?.getTopmostParentOfType()?.let { - return BlockModificationScopeElement(it, it) - } - } - - val blockDeclaration = - KtPsiUtil.getTopmostParentOfTypes(element, *BLOCK_DECLARATION_TYPES) as? KtDeclaration ?: return null -// KtPsiUtil.getTopmostParentOfType(element) as? KtDeclaration ?: return null - - // should not be local declaration - if (KtPsiUtil.isLocal(blockDeclaration)) - return null - - when (blockDeclaration) { - is KtNamedFunction -> { -// if (blockDeclaration.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE) { -// topClassLikeDeclaration(blockDeclaration)?.let { -// return BlockModificationScopeElement(it, it) -// } -// } - if (blockDeclaration.hasBlockBody()) { - // case like `fun foo(): String {......}` - return blockDeclaration.bodyExpression - ?.takeIf { it.isAncestor(element) } - ?.let { BlockModificationScopeElement(blockDeclaration, it) } - } else if (blockDeclaration.hasDeclaredReturnType()) { - // case like `fun foo(): String = blabla` - return blockDeclaration.initializer - ?.takeIf { it.isAncestor(element) } - ?.let { BlockModificationScopeElement(blockDeclaration, it) } - } - } - - is KtProperty -> { -// if (blockDeclaration.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE) { -// topClassLikeDeclaration(blockDeclaration)?.let { -// return BlockModificationScopeElement(it, it) -// } -// } - if (blockDeclaration.typeReference != null) { - val accessors = - blockDeclaration.accessors.map { it.initializer ?: it.bodyExpression } + blockDeclaration.initializer - for (accessor in accessors) { - accessor?.takeIf { - it.isAncestor(element) && - // adding annotations to accessor is the same as change contract of property - (element !is KtAnnotated || element.annotationEntries.isEmpty()) - } - ?.let { expression -> - val declaration = - KtPsiUtil.getTopmostParentOfTypes(blockDeclaration, KtClassOrObject::class.java) as? KtElement ?: - // ktFile to check top level property declarations - return null - return BlockModificationScopeElement(declaration, expression) - } - } - } - } - - is KtScriptInitializer -> { - return (blockDeclaration.body as? KtCallExpression) - ?.lambdaArguments - ?.lastOrNull() - ?.getLambdaExpression() - ?.takeIf { it.isAncestor(element) } - ?.let { BlockModificationScopeElement(blockDeclaration, it) } - } - - is KtClassInitializer -> { - blockDeclaration - .takeIf { it.isAncestor(element) } - ?.let { ktClassInitializer -> - (PsiTreeUtil.getParentOfType(blockDeclaration, KtClassOrObject::class.java))?.let { - return BlockModificationScopeElement(it, ktClassInitializer) - } - } - } - - is KtSecondaryConstructor -> { - blockDeclaration - ?.takeIf { - it.bodyExpression?.isAncestor(element) ?: false || it.getDelegationCallOrNull()?.isAncestor(element) ?: false - }?.let { ktConstructor -> - PsiTreeUtil.getParentOfType(blockDeclaration, KtClassOrObject::class.java)?.let { - return BlockModificationScopeElement(it, ktConstructor) - } - } - } -// is KtClassOrObject -> { -// return when (element) { -// is KtProperty, is KtNamedFunction -> { -// if ((element as? KtModifierListOwner)?.visibilityModifierType()?.toVisibility() == Visibilities.PRIVATE) -// BlockModificationScopeElement(blockDeclaration, blockDeclaration) else null -// } -// else -> null -// } -// } - - else -> throw IllegalStateException() - } - - return null - } - - data class BlockModificationScopeElement(val blockDeclaration: KtElement, val element: KtElement) - - fun isBlockDeclaration(declaration: KtDeclaration): Boolean { - return BLOCK_DECLARATION_TYPES.any { it.isInstance(declaration) } - } - - private val BLOCK_DECLARATION_TYPES = arrayOf>( - KtProperty::class.java, - KtNamedFunction::class.java, - KtClassInitializer::class.java, - KtSecondaryConstructor::class.java, - KtScriptInitializer::class.java - ) - fun getInstance(project: Project): KotlinCodeBlockModificationListener = project.getServiceSafe() } -} - -private val PER_FILE_MODIFICATION_TRACKER = Key("FILE_OUT_OF_BLOCK_MODIFICATION_COUNT") - -val KtFile.perFileModificationTracker: ModificationTracker - get() = putUserDataIfAbsent(PER_FILE_MODIFICATION_TRACKER, SimpleModificationTracker()) - -private val FILE_OUT_OF_BLOCK_MODIFICATION_COUNT = Key("FILE_OUT_OF_BLOCK_MODIFICATION_COUNT") - -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 - */ -private val IN_BLOCK_MODIFICATIONS = Key>("IN_BLOCK_MODIFICATIONS") -private val FILE_IN_BLOCK_MODIFICATION_COUNT = Key("FILE_IN_BLOCK_MODIFICATION_COUNT") - -val KtFile.inBlockModificationCount: Long by NotNullableUserDataProperty(FILE_IN_BLOCK_MODIFICATION_COUNT, 0) - -val KtFile.inBlockModifications: Collection - get() { - val collection = getUserData(IN_BLOCK_MODIFICATIONS) - return collection ?: emptySet() - } - -private fun KtFile.addInBlockModifiedItem(element: KtElement) { - val collection = putUserDataIfAbsent(IN_BLOCK_MODIFICATIONS, mutableSetOf()) - synchronized(collection) { - collection.add(element) - } - val count = getUserData(FILE_IN_BLOCK_MODIFICATION_COUNT) ?: 0 - putUserData(FILE_IN_BLOCK_MODIFICATION_COUNT, count + 1) -} - -fun KtFile.clearInBlockModifications() { - val collection = getUserData(IN_BLOCK_MODIFICATIONS) - collection?.let { - synchronized(it) { - it.clear() - } - } } \ No newline at end of file diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt index 8c26226500a..e380efdd1d7 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/caches/trackers/KotlinCodeBlockModificationListenerCompat.kt @@ -27,7 +27,6 @@ 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.idea.KotlinLanguage import org.jetbrains.kotlin.kdoc.psi.api.KDoc import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.getTopmostParentOfType @@ -39,46 +38,30 @@ val KOTLIN_CONSOLE_KEY = Key.create("kotlin.console") * Tested in OutOfBlockModificationTestGenerated */ // BUNCH: 193 -class KotlinCodeBlockModificationListener( - modificationTracker: PsiModificationTracker, - project: Project, - private val treeAspect: TreeAspect -) : PsiTreeChangePreprocessor { - private val modificationTrackerImpl = modificationTracker as PsiModificationTrackerImpl - - @Suppress("UnstableApiUsage") - private val isLanguageTrackerEnabled = modificationTrackerImpl.isEnableLanguageTrackerCompat - - // BUNCH: 191 - // When there're we no per-language trackers we had to increment global tracker first and process result afterward - private val customIncrement = if (isLanguageTrackerEnabled) 0 else 1 +abstract class KotlinCodeBlockModificationListenerCompat(protected val project: Project) : PsiTreeChangePreprocessor { + protected val modificationTrackerImpl: PsiModificationTrackerImpl = + PsiModificationTracker.SERVICE.getInstance(project) as PsiModificationTrackerImpl @Volatile - private var kotlinModificationTracker: Long = 0 + protected var kotlinModificationTracker: Long = 0 - private val kotlinOutOfCodeBlockTrackerImpl: SimpleModificationTracker = if (isLanguageTrackerEnabled) { - SimpleModificationTracker() - } else { - object : SimpleModificationTracker() { - override fun getModificationCount(): Long { - @Suppress("DEPRECATION") - return modificationTracker.outOfCodeBlockModificationCount - } - } - } + protected lateinit var kotlinOutOfCodeBlockTrackerImpl: SimpleModificationTracker - val kotlinOutOfCodeBlockTracker: ModificationTracker = kotlinOutOfCodeBlockTrackerImpl + lateinit var kotlinOutOfCodeBlockTracker: ModificationTracker internal val perModuleOutOfCodeBlockTrackerUpdater = KotlinModuleOutOfCodeBlockModificationTracker.Updater(project) - init { + protected fun init( + treeAspect: TreeAspect, + incOCBCounter: (KtFile) -> Unit, + psiModificationTrackerListener: PsiModificationTracker.Listener, + kotlinOutOfCodeBlockTrackerProducer: () -> SimpleModificationTracker, + isLanguageTrackerEnabled: Boolean = true, + ) { + kotlinOutOfCodeBlockTrackerImpl = kotlinOutOfCodeBlockTrackerProducer() + kotlinOutOfCodeBlockTracker = kotlinOutOfCodeBlockTrackerImpl val model = PomManager.getModel(project) val messageBusConnection = project.messageBus.connect(project) - - if (isLanguageTrackerEnabled) { - (PsiManager.getInstance(project) as PsiManagerImpl).addTreeChangePreprocessor(this) - } - model.addModelListener(object : PomModelListener { override fun isAspectChangeInteresting(aspect: PomModelAspect): Boolean { return aspect == treeAspect @@ -105,14 +88,7 @@ class KotlinCodeBlockModificationListener( messageBusConnection.deliverImmediately() if (physical && !isReplLine(ktFile.virtualFile) && ktFile !is KtTypeCodeFragment) { - if (isLanguageTrackerEnabled) { - kotlinOutOfCodeBlockTrackerImpl.incModificationCount() - perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, true) - } else { - perModuleOutOfCodeBlockTrackerUpdater.onKotlinPhysicalFileOutOfBlockChange(ktFile, false) - // Increment counter and process changes in PsiModificationTracker.Listener - modificationTrackerImpl.incCounter() - } + incOCBCounter(ktFile) } ktFile.incOutOfBlockModificationCount() @@ -122,26 +98,13 @@ class KotlinCodeBlockModificationListener( } }) - @Suppress("UnstableApiUsage") - messageBusConnection.subscribe(PsiModificationTracker.TOPIC, PsiModificationTracker.Listener { - if (isLanguageTrackerEnabled) { - val kotlinTrackerInternalIDECount = - modificationTrackerImpl.forLanguage(KotlinLanguage.INSTANCE).modificationCount - if (kotlinModificationTracker == kotlinTrackerInternalIDECount) { - // Some update that we are not sure is from Kotlin language, as Kotlin language tracker wasn't changed - kotlinOutOfCodeBlockTrackerImpl.incModificationCount() - } else { - kotlinModificationTracker = kotlinTrackerInternalIDECount - } - } - - perModuleOutOfCodeBlockTrackerUpdater.onPsiModificationTrackerUpdate(customIncrement) - }) + if (isLanguageTrackerEnabled) { + (PsiManager.getInstance(project) as PsiManagerImpl).addTreeChangePreprocessor(this) + } + messageBusConnection.subscribe(PsiModificationTracker.TOPIC, psiModificationTrackerListener) } override fun treeChanged(event: PsiTreeChangeEventImpl) { - assert(isLanguageTrackerEnabled) - if (!PsiModificationTrackerImpl.canAffectPsi(event)) { return } @@ -335,9 +298,6 @@ class KotlinCodeBlockModificationListener( KtSecondaryConstructor::class.java, KtScriptInitializer::class.java ) - - fun getInstance(project: Project): KotlinCodeBlockModificationListener = - project.getComponent(KotlinCodeBlockModificationListener::class.java) } } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt index 9a62a2f1e08..6b5f14ba33f 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/highlighter/KotlinChangeLocalityDetector.kt @@ -18,7 +18,7 @@ package org.jetbrains.kotlin.idea.highlighter import com.intellij.codeInsight.daemon.ChangeLocalityDetector import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener.Companion.getInsideCodeBlockModificationDirtyScope +import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListenerCompat.Companion.getInsideCodeBlockModificationDirtyScope class KotlinChangeLocalityDetector : ChangeLocalityDetector { override fun getChangeHighlightingDirtyScopeFor(element: PsiElement): PsiElement? { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt index bf3b74fd136..ca7638622be 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/project/ResolveElementCache.kt @@ -23,6 +23,7 @@ import org.jetbrains.kotlin.frontend.di.createContainerForBodyResolve import org.jetbrains.kotlin.idea.caches.resolve.CodeFragmentAnalyzer import org.jetbrains.kotlin.idea.caches.resolve.util.analyzeControlFlow import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener +import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListenerCompat import org.jetbrains.kotlin.idea.caches.trackers.inBlockModificationCount import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.platform.TargetPlatform @@ -58,7 +59,7 @@ class ResolveElementCache( // data on any modification of the file !file.isPhysical -> file.modificationStamp - resolveElement is KtDeclaration && KotlinCodeBlockModificationListener.isBlockDeclaration(resolveElement) -> resolveElement.getModificationStamp() + resolveElement is KtDeclaration && KotlinCodeBlockModificationListenerCompat.isBlockDeclaration(resolveElement) -> resolveElement.getModificationStamp() resolveElement is KtSuperTypeList -> resolveElement.modificationStamp else -> null } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionBindingContextProvider.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionBindingContextProvider.kt index c4d4fa2a91c..a58c75353c5 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionBindingContextProvider.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionBindingContextProvider.kt @@ -18,6 +18,7 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.descriptors.ModuleDescriptor import org.jetbrains.kotlin.idea.analysis.analyzeInContext import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener +import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListenerCompat import org.jetbrains.kotlin.idea.resolve.ResolutionFacade import org.jetbrains.kotlin.idea.util.application.getServiceSafe import org.jetbrains.kotlin.idea.util.getResolutionScope @@ -95,7 +96,7 @@ class CompletionBindingContextProvider(project: Project) { val inStatement = position.findStatementInBlock() val block = inStatement?.parent as KtBlockExpression? val prevStatement = inStatement?.siblings(forward = false, withItself = false)?.firstIsInstanceOrNull() - val modificationScope = inStatement?.let { KotlinCodeBlockModificationListener.getInsideCodeBlockModificationScope(it)?.element } + val modificationScope = inStatement?.let { KotlinCodeBlockModificationListenerCompat.getInsideCodeBlockModificationScope(it)?.element } val psiElementsBeforeAndAfter = modificationScope?.let { collectPsiElementsBeforeAndAfter(modificationScope, inStatement) } diff --git a/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt b/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt index 2d78799a363..7b7285977c6 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt +++ b/idea/tests/org/jetbrains/kotlin/idea/resolve/compat.kt @@ -8,17 +8,12 @@ package org.jetbrains.kotlin.idea.resolve import com.intellij.mock.MockProject import com.intellij.pom.PomModel import com.intellij.pom.tree.TreeAspect -import com.intellij.psi.util.PsiModificationTracker import org.jetbrains.kotlin.idea.caches.trackers.KotlinCodeBlockModificationListener internal fun createAndRegisterKotlinCodeBlockModificationListener(project: MockProject, pomModel: PomModel, treeAspect: TreeAspect) { project.registerService(PomModel::class.java, pomModel) project.picoContainer.registerComponentInstance( - KotlinCodeBlockModificationListener( - PsiModificationTracker.SERVICE.getInstance(project), - project, - treeAspect - ) + KotlinCodeBlockModificationListener(project, treeAspect) ) }