diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinAnchorModuleProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinAnchorModuleProvider.kt index 0597ac1e467..a10634add6e 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinAnchorModuleProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/KotlinAnchorModuleProvider.kt @@ -10,17 +10,22 @@ import org.jetbrains.kotlin.analysis.project.structure.KtLibraryModule import org.jetbrains.kotlin.analysis.project.structure.KtSourceModule /** - * Provide module which contains dependencies of the library. + * [KotlinAnchorModuleProvider] provides modules which contain dependencies of libraries. * - * Is required for navigation in IJ monorepo from kotlin compiler library sources to IJ platform sources. - * Kotlin compiler depends on platform but this dependency is not represented as jars in monorepo - * but should be replaced with given sources. + * In the IJ monorepo, anchor modules are required for navigation from Kotlin compiler library sources to IJ platform sources. The Kotlin + * compiler depends on the IJ platform, but this dependency is not represented as JARs in the monorepo, but rather by certain monorepo + * source modules, which are made visible to the Kotlin compiler library sources as dependencies via an anchor module. */ public interface KotlinAnchorModuleProvider { public fun getAnchorModule(libraryModule: KtLibraryModule): KtSourceModule? + /** + * Returns all anchor modules configured in the project. + */ + public fun getAllAnchorModules(): Collection + public companion object { public fun getInstance(project: Project): KotlinAnchorModuleProvider? = project.getService(KotlinAnchorModuleProvider::class.java) } -} \ No newline at end of file +} diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt index 6aa8171f831..5f8f97d41fe 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/sessions/LLFirSessionInvalidationService.kt @@ -9,6 +9,7 @@ import com.intellij.openapi.Disposable import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project import org.jetbrains.kotlin.analysis.project.structure.* +import org.jetbrains.kotlin.analysis.providers.KotlinAnchorModuleProvider import org.jetbrains.kotlin.analysis.providers.analysisMessageBus import org.jetbrains.kotlin.analysis.providers.topics.* @@ -87,6 +88,17 @@ class LLFirSessionInvalidationService(private val project: Project) : Disposable private fun invalidateAll(includeStableModules: Boolean) { ApplicationManager.getApplication().assertWriteAccessAllowed() + // When anchor modules are configured and `includeStableModules` is `false`, we get a situation where the anchor module session will + // be invalidated (because it is a source session), while its library dependents won't be invalidated (because they are sessions of + // stable modules). But such library sessions also need to be invalidated because they depend on the anchor module. + // + // Invalidating anchor modules before all source sessions has the advantage that `invalidate`'s session existence check will work, + // so we do not have to invalidate dependent sessions if the anchor module does not exist in the first place. + if (!includeStableModules) { + val anchorModules = KotlinAnchorModuleProvider.getInstance(project)?.getAllAnchorModules() + anchorModules?.forEach(::invalidate) + } + LLFirSessionCache.getInstance(project).removeAllSessions(includeStableModules) }