[LL FIR] KT-58257 Invalidate script sessions globally (as a workaround)

- Until the IDE module dependents provider has been implemented for
  script dependents (see KTIJ-25620), we must assume that any script
  modification may lead to any other script session being out of date.
  Hence, script modification now leads to the removal of all script
  sessions.
- Because the IDE module dependents provider doesn't provide script
  dependents for libraries yet, library modification must also lead to
  global script session invalidation.
This commit is contained in:
Marco Pennekamp
2023-07-03 15:28:43 +02:00
committed by Space Team
parent efabd55646
commit bb92d19b47
2 changed files with 30 additions and 9 deletions
@@ -109,6 +109,26 @@ class LLFirSessionCache(private val project: Project) {
storage.clear()
}
// Removing script sessions is only needed temporarily until KTIJ-25620 has been implemented.
fun removeAllScriptSessions() {
ApplicationManager.getApplication().assertWriteAccessAllowed()
removeAllScriptSessionsFrom(sourceCache)
removeAllScriptSessionsFrom(binaryCache)
}
private fun removeAllScriptSessionsFrom(storage: SessionStorage) {
// `ConcurrentSoftValueHashMap` (the implementation used by `storage`) does not back its entry set but rather creates a copy, which
// is in violation of the contract of `Map.entrySet`, and thus changes to the entry set are not reflected in `storage`. Because this
// function is executed in a write action, we do not need the weak consistency guarantees made by `ConcurrentMap`'s iterator, so a
// "collect and remove" approach also works.
val scriptEntries = storage.entries.filter { (module, _) -> module is KtScriptModule || module is KtScriptDependencyModule }
for ((module, session) in scriptEntries) {
session.isValid = false
storage.remove(module)
}
}
private fun createSession(module: KtModule): LLFirSession {
val sessionFactory = createPlatformAwareSessionFactory(module)
return when (module) {
@@ -8,16 +8,9 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.sessions
import com.intellij.openapi.Disposable
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.project.structure.KotlinModuleDependentsProvider
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.analysis.project.structure.*
import org.jetbrains.kotlin.analysis.providers.analysisMessageBus
import org.jetbrains.kotlin.analysis.providers.topics.KotlinGlobalModuleStateModificationListener
import org.jetbrains.kotlin.analysis.providers.topics.KotlinGlobalOutOfBlockModificationListener
import org.jetbrains.kotlin.analysis.providers.topics.KotlinGlobalSourceModuleStateModificationListener
import org.jetbrains.kotlin.analysis.providers.topics.KotlinGlobalSourceOutOfBlockModificationListener
import org.jetbrains.kotlin.analysis.providers.topics.KotlinTopics
import org.jetbrains.kotlin.analysis.providers.topics.KotlinModuleOutOfBlockModificationListener
import org.jetbrains.kotlin.analysis.providers.topics.KotlinModuleStateModificationListener
import org.jetbrains.kotlin.analysis.providers.topics.*
/**
* [LLFirSessionInvalidationService] listens to [modification events][KotlinTopics] and invalidates [LLFirSession]s which depend on the
@@ -81,6 +74,14 @@ class LLFirSessionInvalidationService(private val project: Project) : Disposable
if (!didSessionExist) return
KotlinModuleDependentsProvider.getInstance(project).getTransitiveDependents(module).forEach(sessionCache::removeSession)
// Due to a missing IDE implementation for script dependents (see KTIJ-25620), script sessions need to be invalidated globally:
// - A script may include other scripts, so a script modification may affect any other script.
// - Script dependencies are also not linked via dependents yet, so any script dependency modification may affect any script.
// - Scripts may depend on libraries, and the IDE module dependents provider doesn't provide script dependents for libraries yet.
if (module is KtScriptModule || module is KtScriptDependencyModule || module is KtLibraryModule) {
sessionCache.removeAllScriptSessions()
}
}
private fun invalidateAll(includeBinaryModules: Boolean) {