diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionProviderStorage.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionProviderStorage.kt index e72bf246b58..bd6454f6234 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionProviderStorage.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionProviderStorage.kt @@ -15,6 +15,7 @@ import org.jetbrains.kotlin.idea.caches.project.ModuleSourceInfo import org.jetbrains.kotlin.idea.fir.low.level.api.FirPhaseRunner import org.jetbrains.kotlin.idea.fir.low.level.api.FirTransformerProvider import org.jetbrains.kotlin.idea.fir.low.level.api.trackers.KotlinFirOutOfBlockModificationTrackerFactory +import org.jetbrains.kotlin.idea.fir.low.level.api.util.addValueFor import org.jetbrains.kotlin.idea.fir.low.level.api.util.executeWithoutPCE import java.util.concurrent.ConcurrentHashMap @@ -71,36 +72,42 @@ private class FromModuleViewSessionCache( @OptIn(ExperimentalStdlibApi::class) private fun getSessions(): Map = buildMap { val sessions = mappings.values - val sessionToValidity = hashMapOf() + val wasSessionInvalidated = sessions.associateWithTo(hashMapOf()) { false } - var isValid = true - fun dfs(session: FirSessionWithModificationTracker) { - sessionToValidity[session]?.let { valid -> - if (!valid) isValid = false + val reversedDependencies = sessions.reversedDependencies { session -> + session.firSession.dependencies.mapNotNull { mappings[it] } + } + + fun markAsInvalidWithDfs(session: FirSessionWithModificationTracker) { + if (wasSessionInvalidated.getValue(session)) { + // we already was in that branch return } - sessionToValidity[session] = session.isValid - session.firSession.dependencies.forEach { dependency -> - mappings[dependency]?.let(::dfs) - } - if (!session.isValid) { - isValid = false - } - if (!isValid) { - sessionToValidity[session] = false + wasSessionInvalidated[session] = true + reversedDependencies[session]?.forEach { dependsOn -> + markAsInvalidWithDfs(dependsOn) } } for (session in sessions) { - if (session !in sessionToValidity) { - isValid = true - dfs(session) + if (!session.isValid) { + markAsInvalidWithDfs(session) } } - return sessionToValidity.entries - .mapNotNull { (session, valid) -> session.takeIf { valid } } + return wasSessionInvalidated.entries + .mapNotNull { (session, wasInvalidated) -> session.takeUnless { wasInvalidated } } .associate { session -> session.firSession.moduleInfo to session.firSession } } + + private fun Collection.reversedDependencies(getDependencies: (T) -> List): Map> { + val result = hashMapOf>() + forEach { from -> + getDependencies(from).forEach { to -> + result.addValueFor(to, from) + } + } + return result + } } private class FirSessionWithModificationTracker(