[Analysis API FIR] fix invalid usages of CachedValue

it should not cache map as values are stored on soft references
diff --git a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/CachingKtAnalysisSessionProvider.kt b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/CachingKtAnalysisSessionProvider.kt
index fe3275f..f88f19c 100644
--- a/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/CachingKtAnalysisSessionProvider.kt
+++ b/analysis/analysis-api-impl-base/src/org/jetbrains/kotlin/analysis/api/impl/base/CachingKtAnalysisSessionProvider.kt
@@ -7,21 +7,18 @@
 
 import com.intellij.openapi.project.Project
 import com.intellij.openapi.roots.ProjectRootModificationTracker
-import com.intellij.psi.util.CachedValueProvider
-import com.intellij.psi.util.CachedValuesManager
 import com.intellij.psi.util.PsiModificationTracker
 import org.jetbrains.annotations.TestOnly
 import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
-import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
 import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
-import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider
-import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
-import org.jetbrains.kotlin.analysis.project.structure.KtModule
-import org.jetbrains.kotlin.analysis.project.structure.getKtModule
 import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeToken
 import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenFactory
+import org.jetbrains.kotlin.analysis.api.session.KtAnalysisSessionProvider
+import org.jetbrains.kotlin.analysis.project.structure.KtModule
+import org.jetbrains.kotlin.analysis.project.structure.getKtModule
+import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
+import org.jetbrains.kotlin.analysis.utils.caches.SoftCachedMap
 import org.jetbrains.kotlin.psi.KtElement
-import java.util.concurrent.ConcurrentHashMap
 import kotlin.reflect.KClass
 
 @KtAnalysisApiInternals
@@ -47,10 +44,6 @@
         }
     }
 
-    private fun getCachedAnalysisSession(firResolveSession: State, token: KtLifetimeToken): KtAnalysisSession? {
-        return cache.getCachedAnalysisSession(firResolveSession to token::class)
-    }
-
     @TestOnly
     final override fun clearCaches() {
         cache.clear()
@@ -58,23 +51,24 @@
 }
 
 private class KtAnalysisSessionCache(project: Project) {
-    private val cache = CachedValuesManager.getManager(project).createCachedValue {
-        CachedValueProvider.Result(
-            ConcurrentHashMap<Pair<KtModule, KClass<out KtLifetimeToken>>, KtAnalysisSession>(),
+    private val cache = SoftCachedMap.create<Pair<KtModule, KClass<out KtLifetimeToken>>, KtAnalysisSession>(
+        project,
+        SoftCachedMap.Kind.STRONG_KEYS_SOFT_VALUES,
+        listOf(
             PsiModificationTracker.MODIFICATION_COUNT,
             ProjectRootModificationTracker.getInstance(project),
             project.createProjectWideOutOfBlockModificationTracker()
         )
-    }
+    )
 
     @TestOnly
     fun clear() {
-        cache.value.clear()
+        cache.clear()
     }
 
-    inline fun getAnalysisSession(key: Pair<KtModule, KClass<out KtLifetimeToken>>, create: () -> KtAnalysisSession): KtAnalysisSession =
-        cache.value.getOrPut(key) { create() }
-
-    fun getCachedAnalysisSession(key: KEY): KtAnalysisSession? =
-        cache.value[key]
+    fun getAnalysisSession(
+        key: Pair<KtModule, KClass<out KtLifetimeToken>>,
+        create: () -> KtAnalysisSession
+    ): KtAnalysisSession =
+        cache.getOrPut(key) { create() }
 }
\ No newline at end of file
diff --git a/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/caches/SoftCachedMap.kt b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/caches/SoftCachedMap.kt
new file mode 100644
index 0000000..de3038e
--- /dev/null
+++ b/analysis/analysis-internal-utils/src/org/jetbrains/kotlin/analysis/utils/caches/SoftCachedMap.kt
@@ -0,0 +1,75 @@
+/*
+ * Copyright 2010-2022 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.utils.caches
+
+import com.intellij.openapi.project.Project
+import com.intellij.psi.util.CachedValue
+import com.intellij.psi.util.CachedValueProvider
+import com.intellij.psi.util.CachedValuesManager
+import com.intellij.util.containers.ContainerUtil
+import org.jetbrains.annotations.TestOnly
+import java.util.concurrent.ConcurrentHashMap
+
+public abstract class SoftCachedMap<K : Any, V : Any> {
+    public abstract fun getOrPut(key: K, create: () -> V): V
+
+    @TestOnly
+    public abstract fun clear()
+
+    public companion object {
+        public fun <K : Any, V : Any> create(
+            project: Project,
+            kind: Kind,
+            trackers: List<Any>
+        ): SoftCachedMap<K, V> = when {
+            trackers.isEmpty() -> SoftCachedMapWithoutTrackers(kind)
+            else -> SoftCachedMapWithTrackers(project, kind, trackers.toTypedArray())
+        }
+    }
+
+    public enum class Kind {
+        SOFT_KEYS_SOFT_VALUES,
+        STRONG_KEYS_SOFT_VALUES
+    }
+}
+
+private class SoftCachedMapWithTrackers<K : Any, V : Any>(
+    private val project: Project,
+    kind: Kind,
+    private val trackers: Array<Any>
+) : SoftCachedMap<K, V>() {
+    private val cache = when (kind) {
+        Kind.SOFT_KEYS_SOFT_VALUES -> ContainerUtil.createConcurrentSoftMap<K, CachedValue<V>>()
+        Kind.STRONG_KEYS_SOFT_VALUES -> ConcurrentHashMap<K, CachedValue<V>>()
+    }
+
+    override fun clear() {
+        cache.clear()
+    }
+
+    override fun getOrPut(key: K, create: () -> V): V {
+        return cache.getOrPut(key) {
+            CachedValuesManager.getManager(project).createCachedValue {
+                CachedValueProvider.Result(create(), *trackers)
+            }
+        }.value
+    }
+}
+
+private class SoftCachedMapWithoutTrackers<K : Any, V : Any>(kind: Kind) : SoftCachedMap<K, V>() {
+    private val cache = when (kind) {
+        Kind.SOFT_KEYS_SOFT_VALUES -> ContainerUtil.createConcurrentSoftKeySoftValueMap<K, V>()
+        Kind.STRONG_KEYS_SOFT_VALUES -> ContainerUtil.createSoftValueMap<K, V>()
+    }
+
+    override fun clear() {
+        cache.clear()
+    }
+
+    override fun getOrPut(key: K, create: () -> V): V {
+        return cache.getOrPut(key, create)
+    }
+}
\ No newline at end of file
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt
index f7e4672..b108aa9 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveSessionDepended.kt
@@ -41,13 +41,14 @@
     override val useSiteKtModule: KtModule get() = originalFirResolveSession.useSiteKtModule
     override val useSiteFirSession get() = originalFirResolveSession.useSiteFirSession
 
-    private val scopeSessionProviderCache by softCachedValue(
+    private val scopeSessionProviderCache = SoftCachedMap.create<FirSession, LLFirScopeSessionProvider>(
         project,
-        PsiModificationTracker.MODIFICATION_COUNT,
-        ProjectRootModificationTracker.getInstance(project),
-    ) {
-        ConcurrentHashMap<FirSession, LLFirScopeSessionProvider>()
-    }
+        SoftCachedMap.Kind.SOFT_KEYS_SOFT_VALUES,
+        listOf(
+            PsiModificationTracker.MODIFICATION_COUNT,
+            ProjectRootModificationTracker.getInstance(project)
+        )
+    )
 
     override fun getScopeSessionFor(firSession: FirSession): ScopeSession {
         return scopeSessionProviderCache
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt
index b4a8b3d..30ebaa8 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/LLFirResolveStateService.kt
@@ -8,6 +8,7 @@
 import com.intellij.openapi.components.ServiceManager
 import com.intellij.openapi.project.Project
 import com.intellij.openapi.roots.ProjectRootModificationTracker
+import com.intellij.psi.util.PsiModificationTracker
 import org.jetbrains.annotations.TestOnly
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.LLFirResolveSession
 import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
@@ -19,33 +20,23 @@
 import org.jetbrains.kotlin.analysis.low.level.api.fir.util.errorWithFirSpecificEntries
 import org.jetbrains.kotlin.analysis.project.structure.*
 import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker
-import org.jetbrains.kotlin.analysis.utils.caches.getValue
-import org.jetbrains.kotlin.analysis.utils.caches.softCachedValue
-import java.util.concurrent.locks.ReentrantReadWriteLock
-import kotlin.concurrent.withLock
+import org.jetbrains.kotlin.analysis.utils.caches.SoftCachedMap
 
 internal class LLFirResolveSessionService(project: Project) {
     private val sessionProviderStorage = LLFirSessionProviderStorage(project)
 
-    private val stateCache by softCachedValue(
+    private val cache = SoftCachedMap.create<KtModule, LLFirResolvableResolveSession>(
         project,
-        project.createProjectWideOutOfBlockModificationTracker(),
-        ProjectRootModificationTracker.getInstance(project),
-    ) {
-        mutableMapOf<KtModule, LLFirResolvableResolveSession>()
-    }
-
-    private val cacheLock = ReentrantReadWriteLock()
+        SoftCachedMap.Kind.STRONG_KEYS_SOFT_VALUES,
+        listOf(
+            ProjectRootModificationTracker.getInstance(project),
+            project.createProjectWideOutOfBlockModificationTracker(),
+        )
+    )
 
     fun getFirResolveSession(module: KtModule): LLFirResolvableResolveSession {
-        cacheLock.readLock().withLock {
-            stateCache[module]?.let { return it }
-        }
-        cacheLock.writeLock().withLock {
-            stateCache[module]?.let { return it }
-            val session = createFirResolveSessionFor(module, sessionProviderStorage)
-            stateCache[module] = session
-            return session
+        return cache.getOrPut(module) {
+            createFirResolveSessionFor(module, sessionProviderStorage)
         }
     }
 
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt
index f16a40f..c3bd72e 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/providers/LLFirIdePredicateBasedProvider.kt
@@ -9,6 +9,7 @@
 import kotlinx.collections.immutable.persistentListOf
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.getFirResolveSession
 import org.jetbrains.kotlin.analysis.low.level.api.fir.api.resolveToFirSymbol
+import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSourcesSession
 import org.jetbrains.kotlin.analysis.low.level.api.fir.util.getContainingFile
 import org.jetbrains.kotlin.analysis.providers.KotlinAnnotationsResolver
 import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider
@@ -40,7 +41,7 @@
  * PSI index based implementation of [FirPredicateBasedProvider].
  */
 internal class LLFirIdePredicateBasedProvider(
-    private val session: FirSession,
+    private val session: LLFirSourcesSession,
     private val annotationsResolver: KotlinAnnotationsResolver,
     private val declarationProvider: KotlinDeclarationProvider,
 ) : FirPredicateBasedProvider() {
diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirScopeSessionProvider.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirScopeSessionProvider.kt
index f848e98..e867697 100644
--- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirScopeSessionProvider.kt
+++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/util/LLFirScopeSessionProvider.kt
@@ -6,10 +6,7 @@
 package org.jetbrains.kotlin.analysis.low.level.api.fir.util
 
 import com.intellij.openapi.project.Project
-import com.intellij.openapi.roots.ProjectRootModificationTracker
-import com.intellij.psi.util.PsiModificationTracker
-import org.jetbrains.kotlin.analysis.utils.caches.getValue
-import org.jetbrains.kotlin.analysis.utils.caches.softCachedValue
+import org.jetbrains.kotlin.analysis.utils.caches.SoftCachedMap
 import org.jetbrains.kotlin.fir.resolve.ScopeSession
 import java.util.concurrent.ConcurrentHashMap
 
@@ -28,12 +25,11 @@
 private class LLFirInvalidatableScopeSessionProvider(project: Project, invalidationTrackers: List<Any>) : LLFirScopeSessionProvider() {
     // ScopeSession is thread-local, so we use Thread id as a key
     // We cannot use thread locals here as it may lead to memory leaks
-    private val cache by softCachedValue(
+    private val cache = SoftCachedMap.create<Long, ScopeSession>(
         project,
-        *invalidationTrackers.toTypedArray(),
-    ) {
-        ConcurrentHashMap<Long, ScopeSession>()
-    }
+        SoftCachedMap.Kind.STRONG_KEYS_SOFT_VALUES,
+        invalidationTrackers
+    )
 
     override fun getScopeSession(): ScopeSession {
         return cache.getOrPut(Thread.currentThread().id) { ScopeSession() }