fixup! [LL] WIP - Java package sets

- Parent packages are now only considered for `hasPackage`. For example,
  the `kotlin` package was considered to be part of the combined symbol
  provider, which is not good, as only `kotlin.collections` and
  `kotlin.jvm.internal` contain Java classes.
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/LLFirJavaSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/LLFirJavaSymbolProvider.kt
index c6da2fc..ef2aa5f 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/LLFirJavaSymbolProvider.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/LLFirJavaSymbolProvider.kt
@@ -52,6 +52,10 @@
         }
     )
 
+    private val packageNamesWithParentPackages by lazy(LazyThreadSafetyMode.PUBLICATION) {
+        symbolNamesProvider.getPackageNames()?.let { computePackageNamesWithParentPackages(it) }
+    }
+
     // TODO: Hacky!
     override val symbolNamesProvider: FirSymbolNamesProvider = FirDelegatingCachedSymbolNamesProvider(
         session,
@@ -73,15 +77,15 @@
         return getClassLikeSymbolByClassId(classId, null)
     }
 
-    /**
-     * [KotlinJavaDeclarationNamesProvider] provides *exact* package sets (including parent packages), so we can decide [hasPackage] without
-     * querying the Java facade.
-     */
     override fun hasPackage(fqName: FqName): Boolean {
-        val packageNames = symbolNamesProvider.getPackageNames()
-            ?: return super.hasPackage(fqName)
+        val packageNames = packageNamesWithParentPackages
 
-        return fqName.asString() in packageNames
+        return if (packageNames != null) {
+            // The package set from Java symbol providers is *exact* if it can be computed, so we can decide `hasPackage` directly.
+            fqName.asString() in packageNames
+        } else {
+            super.hasPackage(fqName)
+        }
     }
 
     @LLModuleSpecificSymbolProviderAccess
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/combined/LLCombinedJavaSymbolProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/combined/LLCombinedJavaSymbolProvider.kt
index e7da78b..22d3ab2 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/combined/LLCombinedJavaSymbolProvider.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/combined/LLCombinedJavaSymbolProvider.kt
@@ -11,6 +11,7 @@
 import org.jetbrains.kotlin.analysis.api.platform.caches.withStatsCounter
 import org.jetbrains.kotlin.analysis.low.level.api.fir.statistics.LLStatisticsService
 import org.jetbrains.kotlin.analysis.low.level.api.fir.symbolProviders.LLFirJavaSymbolProvider
+import org.jetbrains.kotlin.analysis.low.level.api.fir.symbolProviders.computePackageNamesWithParentPackages
 import org.jetbrains.kotlin.fir.FirSession
 import org.jetbrains.kotlin.fir.java.JavaSymbolProvider
 import org.jetbrains.kotlin.fir.java.hasMetadataAnnotation
@@ -58,6 +59,10 @@
             .withStatsCounter(LLStatisticsService.getInstance(project)?.symbolProviders?.combinedSymbolProviderClassCacheStatsCounter)
     }
 
+    private val packageNamesWithParentPackages by lazy(LazyThreadSafetyMode.PUBLICATION) {
+        symbolNamesProvider.getPackageNames()?.let { computePackageNamesWithParentPackages(it) }
+    }
+
     override val symbolNamesProvider: FirSymbolNamesProvider = FirCompositeCachedSymbolNamesProvider.fromSymbolProviders(session, providers)
 
     override fun getClassLikeSymbolByClassId(classId: ClassId): FirClassLikeSymbol<*>? {
@@ -95,11 +100,14 @@
     }
 
     override fun hasPackage(fqName: FqName): Boolean {
-        // The package set from Java symbol providers is *exact* if it can be computed.
-        val packageNames = symbolNamesProvider.getPackageNames()
-            ?: return providers.any { it.hasPackage(fqName) }
+        val packageNames = packageNamesWithParentPackages
 
-        return fqName.asString() in packageNames
+        return if (packageNames != null) {
+            // The package set from Java symbol providers is *exact* if it can be computed, so we can decide `hasPackage` directly.
+            fqName.asString() in packageNames
+        } else {
+            providers.any { it.hasPackage(fqName) }
+        }
     }
 
     override fun estimateSymbolCacheSize(): Long = classCache.estimatedSize
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/utils.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/utils.kt
index 8db8c83..7b40570 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/utils.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/symbolProviders/utils.kt
@@ -28,6 +28,22 @@
 
 internal fun String.isKotlinPackage(): Boolean = startsWith(KOTLIN_PACKAGE_PREFIX)
 
+internal fun computePackageNamesWithParentPackages(packageNames: Set<String>): Set<String> {
+    if (packageNames.isEmpty()) return emptySet()
+
+    return buildSet {
+        add("")
+
+        packageNames.forEach { packageName ->
+            var currentPackage = packageName
+            while (currentPackage.isNotEmpty()) {
+                add(currentPackage)
+                currentPackage = currentPackage.substringBeforeLast(".", missingDelimiterValue = "")
+            }
+        }
+    }
+}
+
 /**
  * Checks if this [FirBasedSymbol] has the given PSI element as a source.
  *