[Analysis API] Move 'KtCodeFragment' import modification subscription

Subscribing from service constructors may be dangerous, as services are
initialized lazily. It's unlikely for that code fragment import
modification to happen before 'LLFirDeclarationModificationService' is
created, but it still looks error-prone.

The new place, 'LLFirSessionInvalidationService', is called for code
fragments from 'LLFirDeclarationModificationService', so there should
not be any differences in behavior.
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/LLFirDeclarationModificationService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/LLFirDeclarationModificationService.kt
index 9f14088..9319495 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/LLFirDeclarationModificationService.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/file/structure/LLFirDeclarationModificationService.kt
@@ -35,7 +35,6 @@
 import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
 import org.jetbrains.kotlin.idea.KotlinLanguage
 import org.jetbrains.kotlin.psi
-import org.jetbrains.kotlin.psi.KotlinCodeFragmentImportModificationListener
 import org.jetbrains.kotlin.psi.KtAnnotated
 import org.jetbrains.kotlin.psi.KtBlockExpression
 import org.jetbrains.kotlin.psi.KtCodeFragment
@@ -70,11 +69,6 @@
             },
             this,
         )
-
-        project.messageBus.connect(this).subscribe(
-            KtCodeFragment.IMPORT_MODIFICATION,
-            KotlinCodeFragmentImportModificationListener { codeFragment -> outOfBlockModification(codeFragment) }
-        )
     }
 
     private var inBlockModificationQueue: MutableSet<ChangeType.InBlock>? = null
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 7dcd7f1..384f9ab 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
@@ -13,6 +13,8 @@
 import org.jetbrains.kotlin.analysis.providers.KotlinAnchorModuleProvider
 import org.jetbrains.kotlin.analysis.providers.analysisMessageBus
 import org.jetbrains.kotlin.analysis.providers.topics.*
+import org.jetbrains.kotlin.psi.KotlinCodeFragmentImportModificationListener
+import org.jetbrains.kotlin.psi.KtCodeFragment
 
 /**
  * [LLFirSessionInvalidationService] listens to [modification events][KotlinTopics] and invalidates [LLFirSession]s which depend on the
@@ -64,6 +66,12 @@
             PsiModificationTracker.TOPIC,
             PsiModificationTracker.Listener { invalidateUnstableDanglingFileSessions() }
         )
+
+        // 'KtCodeFragment' doesn't have access to 'analysisMessageBus' and always uses the project message bus
+        project.messageBus.connect(this).subscribe(
+            KtCodeFragment.IMPORT_MODIFICATION,
+            KotlinCodeFragmentImportModificationListener { codeFragment -> invalidateCodeFragment(codeFragment) }
+        )
     }
 
     /**
@@ -116,6 +124,11 @@
         sessionCache.removeAllSessions(includeLibraryModules)
     }
 
+    private fun invalidateCodeFragment(codeFragment: KtCodeFragment) {
+        val module = ProjectStructureProvider.getModule(project, codeFragment, contextualModule = null)
+        invalidateContextualDanglingFileSessions(module)
+    }
+
     private fun invalidateContextualDanglingFileSessions(contextModule: KtModule) {
         sessionCache.removeContextualDanglingFileSessions(contextModule)
     }