From 2d279c5f25d453b0757047b4f5eb5d1eeb0cb1be Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Thu, 22 Jun 2023 15:08:01 +0200 Subject: [PATCH] [AA] KT-58257 Remove timing guarantees of Kotlin modification events - Kotlin modification events are published before or after the modification, depending on the underlying cause. For example, PSI tree change events in the IDE can occur both before and after the change, so module and global out-of-block modification events must not make timing guarantees. Similarly, module state modification events published by the IDE can both happen before and after a module change, with most events happening before the change. --- .../providers/impl/KotlinGlobalModificationServiceBase.kt | 8 ++++---- .../topics/KotlinGlobalModuleStateModificationListener.kt | 6 +++--- .../topics/KotlinGlobalOutOfBlockModificationListener.kt | 5 +++-- .../KotlinGlobalSourceModuleStateModificationListener.kt | 6 +++--- .../KotlinGlobalSourceOutOfBlockModificationListener.kt | 6 +++--- .../topics/KotlinModuleOutOfBlockModificationListener.kt | 4 ++-- .../topics/KotlinModuleStateModificationListener.kt | 6 +++--- .../kotlin/analysis/providers/topics/KotlinTopics.kt | 6 ++++++ 8 files changed, 27 insertions(+), 20 deletions(-) diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinGlobalModificationServiceBase.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinGlobalModificationServiceBase.kt index 6d862f89a28..749834322fb 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinGlobalModificationServiceBase.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinGlobalModificationServiceBase.kt @@ -21,7 +21,7 @@ public abstract class KotlinGlobalModificationServiceBase(private val project: P ApplicationManager.getApplication().assertWriteAccessAllowed() incrementModificationTrackers(includeBinaryTrackers = true) - project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_MODULE_STATE_MODIFICATION).afterModification() + project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_MODULE_STATE_MODIFICATION).onModification() } @TestOnly @@ -29,7 +29,7 @@ public abstract class KotlinGlobalModificationServiceBase(private val project: P ApplicationManager.getApplication().assertWriteAccessAllowed() incrementModificationTrackers(includeBinaryTrackers = true) - project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_OUT_OF_BLOCK_MODIFICATION).afterModification() + project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_OUT_OF_BLOCK_MODIFICATION).onModification() } @TestOnly @@ -37,7 +37,7 @@ public abstract class KotlinGlobalModificationServiceBase(private val project: P ApplicationManager.getApplication().assertWriteAccessAllowed() incrementModificationTrackers(includeBinaryTrackers = false) - project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_SOURCE_MODULE_STATE_MODIFICATION).afterModification() + project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_SOURCE_MODULE_STATE_MODIFICATION).onModification() } @TestOnly @@ -45,6 +45,6 @@ public abstract class KotlinGlobalModificationServiceBase(private val project: P ApplicationManager.getApplication().assertWriteAccessAllowed() incrementModificationTrackers(includeBinaryTrackers = false) - project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_SOURCE_OUT_OF_BLOCK_MODIFICATION).afterModification() + project.analysisMessageBus.syncPublisher(KotlinTopics.GLOBAL_SOURCE_OUT_OF_BLOCK_MODIFICATION).onModification() } } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalModuleStateModificationListener.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalModuleStateModificationListener.kt index 223e23df573..b378ff094af 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalModuleStateModificationListener.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalModuleStateModificationListener.kt @@ -9,10 +9,10 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule public fun interface KotlinGlobalModuleStateModificationListener { /** - * [afterModification] is invoked in a write action after global modification of the module state of all [KtModule]s, including binary - * modules. + * [onModification] is invoked in a write action before or after global modification of the module state of all [KtModule]s, including + * binary modules. * * This event is published after SDK removal and to invalidate caches during/between tests. */ - public fun afterModification() + public fun onModification() } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalOutOfBlockModificationListener.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalOutOfBlockModificationListener.kt index 88bcd791ee5..5211b43d950 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalOutOfBlockModificationListener.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalOutOfBlockModificationListener.kt @@ -9,9 +9,10 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule public fun interface KotlinGlobalOutOfBlockModificationListener { /** - * [afterModification] is invoked in a write action after global out-of-block modification of all [KtModule]s, including binary modules. + * [onModification] is invoked in a write action before or after global out-of-block modification of all [KtModule]s, including binary + * modules. * * This event is published to invalidate caches during/between tests. */ - public fun afterModification() + public fun onModification() } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceModuleStateModificationListener.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceModuleStateModificationListener.kt index d567bf8dde8..31308f851de 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceModuleStateModificationListener.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceModuleStateModificationListener.kt @@ -9,10 +9,10 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule public fun interface KotlinGlobalSourceModuleStateModificationListener { /** - * [afterModification] is invoked in a write action after global modification of the module state of all source [KtModule]s, excluding - * binary modules. + * [onModification] is invoked in a write action before or after global modification of the module state of all source [KtModule]s, + * excluding binary modules. * * This event is published to invalidate caches during/between tests. */ - public fun afterModification() + public fun onModification() } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceOutOfBlockModificationListener.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceOutOfBlockModificationListener.kt index f47fd7d9efe..25b2865b026 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceOutOfBlockModificationListener.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinGlobalSourceOutOfBlockModificationListener.kt @@ -9,10 +9,10 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule public fun interface KotlinGlobalSourceOutOfBlockModificationListener { /** - * [afterModification] is invoked in a write action after global out-of-block modification of all source [KtModule]s, excluding binary - * modules. + * [onModification] is invoked in a write action before or after global out-of-block modification of all source [KtModule]s, excluding + * binary modules. * * This event is published on global PSI changes. */ - public fun afterModification() + public fun onModification() } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleOutOfBlockModificationListener.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleOutOfBlockModificationListener.kt index d008919fdd5..6b09916e7ed 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleOutOfBlockModificationListener.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleOutOfBlockModificationListener.kt @@ -10,7 +10,7 @@ import org.jetbrains.kotlin.analysis.providers.KotlinModificationTrackerFactory public fun interface KotlinModuleOutOfBlockModificationListener { /** - * [afterModification] is invoked in a write action after an out-of-block modification happened in [module]'s source code. + * [onModification] is invoked in a write action before or after an out-of-block modification happens in [module]'s source code. * * See [KotlinModificationTrackerFactory.createProjectWideOutOfBlockModificationTracker] for an explanation of out-of-block * modifications. @@ -18,5 +18,5 @@ public fun interface KotlinModuleOutOfBlockModificationListener { * This event may be published for any and all source code changes, not just out-of-block modifications, to simplify the implementation * of modification detection. */ - public fun afterModification(module: KtModule) + public fun onModification(module: KtModule) } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleStateModificationListener.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleStateModificationListener.kt index 52af0990549..2f3b315ce79 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleStateModificationListener.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinModuleStateModificationListener.kt @@ -9,8 +9,8 @@ import org.jetbrains.kotlin.analysis.project.structure.KtModule public fun interface KotlinModuleStateModificationListener { /** - * [afterModification] is invoked in a write action after the [module] was moved, removed, or its structure changed. [isRemoval] signals - * if the module was removed. + * [onModification] is invoked in a write action before or after the [module] is moved, removed, or its structure is changed. + * [isRemoval] signals if the event is a removal. */ - public fun afterModification(module: KtModule, isRemoval: Boolean) + public fun onModification(module: KtModule, isRemoval: Boolean) } diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinTopics.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinTopics.kt index 8cdd8e99285..aa60ba6b828 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinTopics.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/topics/KotlinTopics.kt @@ -13,6 +13,7 @@ import org.jetbrains.kotlin.analysis.providers.analysisMessageBus * message bus: [analysisMessageBus]. * * See the individual listener interfaces for documentation about the events described by these topics: + * * - [KotlinModuleStateModificationListener] * - [KotlinModuleOutOfBlockModificationListener] * - [KotlinGlobalModuleStateModificationListener] @@ -20,6 +21,11 @@ import org.jetbrains.kotlin.analysis.providers.analysisMessageBus * - [KotlinGlobalSourceModuleStateModificationListener] * - [KotlinGlobalSourceOutOfBlockModificationListener] * + * Modification events may be published before or after a modification, so subscribers should not assume that the modification has or hasn't + * happened yet. The reason for this design decision is that the underlying events (such as PSI tree changes or workspace model events) are + * sometimes published before and sometimes after a change, or even both. Modification events published before the modification should + * however be published close to the modification. + * * Care needs to be taken with the lack of interplay between different types of topics: Publishing a global modification event, for example, * does not imply the corresponding module-level event. Similarly, publishing a module state modification event does not imply out-of-block * modification.