[AA] Introduce `KotlinGlobalSearchScopeMerger` platform component

- The scope merger allows LL FIR to access scope merge logic provided by
  the Analysis API platform.

^KT-57733
diff --git a/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/declarations/KotlinDeclarationProviderFactory.kt b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/declarations/KotlinDeclarationProviderFactory.kt
index c9bded4..2baa55d 100644
--- a/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/declarations/KotlinDeclarationProviderFactory.kt
+++ b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/declarations/KotlinDeclarationProviderFactory.kt
@@ -38,6 +38,9 @@
  * Hence, [KotlinDeclarationProvider]s cannot just be combined by combining the scopes of all declaration providers and calling
  * [createDeclarationProvider]. [KotlinDeclarationProviderMerger] should implement proper merging logic that takes these concerns into
  * account.
+ *
+ * The provider merger should consider merging scopes with [KotlinGlobalSearchScopeMerger][org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinGlobalSearchScopeMerger]
+ * if there is a useful implementation provided by the platform.
  */
 public interface KotlinDeclarationProviderMerger : KotlinComposableProviderMerger<KotlinDeclarationProvider>, KotlinPlatformComponent {
     public companion object {
diff --git a/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/packages/KotlinPackageProviderFactory.kt b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/packages/KotlinPackageProviderFactory.kt
index 5d1e13e..9b8fceb 100644
--- a/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/packages/KotlinPackageProviderFactory.kt
+++ b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/packages/KotlinPackageProviderFactory.kt
@@ -33,6 +33,9 @@
  *
  * Package providers should not be naively merged by combining scopes and calling [createPackageProvider], because there may be additional
  * package providers which do not operate based on scopes (e.g. resolve extension package providers).
+ *
+ * The provider merger should consider merging scopes with [KotlinGlobalSearchScopeMerger][org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinGlobalSearchScopeMerger]
+ * if there is a useful implementation provided by the platform.
  */
 public interface KotlinPackageProviderMerger : KotlinComposableProviderMerger<KotlinPackageProvider>, KotlinPlatformComponent {
     public companion object {
diff --git a/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/projectStructure/KotlinGlobalSearchScopeMerger.kt b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/projectStructure/KotlinGlobalSearchScopeMerger.kt
new file mode 100644
index 0000000..d7883fb
--- /dev/null
+++ b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/projectStructure/KotlinGlobalSearchScopeMerger.kt
@@ -0,0 +1,28 @@
+/*
+ * Copyright 2010-2024 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.analysis.api.platform.projectStructure
+
+import com.intellij.openapi.components.service
+import com.intellij.openapi.project.Project
+import com.intellij.psi.search.GlobalSearchScope
+import org.jetbrains.kotlin.analysis.api.platform.KotlinPlatformComponent
+
+/**
+ * Merges [GlobalSearchScope]s according to platform-specific strategies with the goal of creating an optimized combined scope. If possible,
+ * the merger should especially try to merge scopes which can be the basis of [KaModule.contentScope][org.jetbrains.kotlin.analysis.api.projectStructure.KaModule.contentScope]s.
+ *
+ * If there are no good scope merging strategies, [KotlinSimpleGlobalSearchScopeMerger] should be registered by the platform.
+ */
+public interface KotlinGlobalSearchScopeMerger : KotlinPlatformComponent {
+    /**
+     * Creates a merged [GlobalSearchScope] which represents a *union* of all [scopes].
+     */
+    public fun union(scopes: Collection<GlobalSearchScope>): GlobalSearchScope
+
+    public companion object {
+        public fun getInstance(project: Project): KotlinGlobalSearchScopeMerger = project.service()
+    }
+}
diff --git a/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/projectStructure/KotlinSimpleGlobalSearchScopeMerger.kt b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/projectStructure/KotlinSimpleGlobalSearchScopeMerger.kt
new file mode 100644
index 0000000..f68b886
--- /dev/null
+++ b/analysis/analysis-api-platform-interface/src/org/jetbrains/kotlin/analysis/api/platform/projectStructure/KotlinSimpleGlobalSearchScopeMerger.kt
@@ -0,0 +1,17 @@
+/*
+ * Copyright 2010-2024 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.analysis.api.platform.projectStructure
+
+import com.intellij.psi.search.GlobalSearchScope
+
+/**
+ * A non-optimizing [KotlinGlobalSearchScopeMerger] which simply creates naive union scopes. It may be registered if the platform cannot
+ * provide any scope merging strategies.
+ */
+public class KotlinSimpleGlobalSearchScopeMerger : KotlinGlobalSearchScopeMerger {
+    override fun union(scopes: Collection<GlobalSearchScope>): GlobalSearchScope =
+        GlobalSearchScope.union(scopes.toList())
+}
diff --git a/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/resources/META-INF/analysis-api/analysis-api-fir-standalone-base.xml b/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/resources/META-INF/analysis-api/analysis-api-fir-standalone-base.xml
index b589928..252a5d1 100644
--- a/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/resources/META-INF/analysis-api/analysis-api-fir-standalone-base.xml
+++ b/analysis/analysis-api-standalone/analysis-api-fir-standalone-base/resources/META-INF/analysis-api/analysis-api-fir-standalone-base.xml
@@ -6,6 +6,10 @@
         serviceInterface="org.jetbrains.kotlin.analysis.api.platform.declarations.KotlinDirectInheritorsProvider"
         serviceImplementation="org.jetbrains.kotlin.analysis.api.standalone.base.declarations.KotlinStandaloneFirDirectInheritorsProvider"
     />
+    <projectService
+        serviceInterface="org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinGlobalSearchScopeMerger"
+        serviceImplementation="org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinSimpleGlobalSearchScopeMerger"
+    />
     <applicationService serviceInterface="org.jetbrains.kotlin.analysis.decompiler.psi.BuiltinsVirtualFileProvider"
         serviceImplementation="org.jetbrains.kotlin.analysis.decompiler.psi.BuiltinsVirtualFileProviderCliImpl"/>
   </extensions>
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt
index 4e3d25f..7817dd7 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirCombinedJavaSymbolProvider.kt
@@ -6,7 +6,7 @@
 package org.jetbrains.kotlin.analysis.low.level.api.fir.providers
 
 import com.intellij.openapi.project.Project
-import com.intellij.psi.search.GlobalSearchScope
+import org.jetbrains.kotlin.analysis.api.platform.projectStructure.KotlinGlobalSearchScopeMerger
 import org.jetbrains.kotlin.analysis.low.level.api.fir.caches.NullableCaffeineCache
 import org.jetbrains.kotlin.fir.FirSession
 import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
@@ -93,7 +93,7 @@
     companion object {
         fun merge(session: FirSession, project: Project, providers: List<LLFirJavaSymbolProvider>): FirSymbolProvider? =
             if (providers.size > 1) {
-                val combinedScope = GlobalSearchScope.union(providers.map { it.searchScope })
+                val combinedScope = KotlinGlobalSearchScopeMerger.getInstance(project).union(providers.map { it.searchScope })
                 val javaClassFinder = project.createJavaClassFinder(combinedScope)
                 LLFirCombinedJavaSymbolProvider(session, project, providers, javaClassFinder)
             } else providers.singleOrNull()