diff --git a/analysis/analysis-api/build.gradle.kts b/analysis/analysis-api/build.gradle.kts index 6b82841070f..a21e5876eed 100644 --- a/analysis/analysis-api/build.gradle.kts +++ b/analysis/analysis-api/build.gradle.kts @@ -8,6 +8,7 @@ kotlin { } dependencies { + implementation(kotlinxCollectionsImmutable()) compileOnly(project(":kotlin-reflect-api")) compileOnly(project(":compiler:psi")) diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtLifetimeToken.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtLifetimeToken.kt index 9cc43296f10..72437ae58e7 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtLifetimeToken.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtLifetimeToken.kt @@ -22,8 +22,8 @@ public abstract class KtLifetimeTokenFactory { public abstract val identifier: KClass public abstract fun create(project: Project): KtLifetimeToken - public open fun beforeEnteringAnalysisContext() {} - public open fun afterLeavingAnalysisContext() {} + public open fun beforeEnteringAnalysisContext(token: KtLifetimeToken) {} + public open fun afterLeavingAnalysisContext(token: KtLifetimeToken) {} } diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtReadActionConfinementLifetimeToken.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtReadActionConfinementLifetimeToken.kt index 61f1739ec90..65ce991abb5 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtReadActionConfinementLifetimeToken.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/lifetime/KtReadActionConfinementLifetimeToken.kt @@ -9,10 +9,10 @@ package org.jetbrains.kotlin.analysis.api.lifetime import com.intellij.openapi.application.ApplicationManager import com.intellij.openapi.project.Project -import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker +import kotlinx.collections.immutable.PersistentList +import kotlinx.collections.immutable.persistentListOf import org.jetbrains.kotlin.analysis.api.* -import org.jetbrains.kotlin.analysis.api.KtAnalysisAllowanceManager - +import org.jetbrains.kotlin.analysis.providers.createProjectWideOutOfBlockModificationTracker import kotlin.reflect.KClass @OptIn(KtAllowAnalysisOnEdt::class) @@ -35,6 +35,7 @@ public class KtReadActionConfinementLifetimeToken(project: Project) : KtLifetime if (KtAnalysisAllowanceManager.resolveIsForbiddenInActionWithName.get() != null) return false if (!application.isReadAccessAllowed) return false if (!KtReadActionConfinementLifetimeTokenFactory.isInsideAnalysisContext()) return false + if (KtReadActionConfinementLifetimeTokenFactory.currentToken() != this) return false return true } @@ -46,6 +47,8 @@ public class KtReadActionConfinementLifetimeToken(project: Project) : KtLifetime return "Resolve is forbidden in $actionName" } if (!KtReadActionConfinementLifetimeTokenFactory.isInsideAnalysisContext()) return "Called outside analyse method" + if (KtReadActionConfinementLifetimeTokenFactory.currentToken() != this) return "Using KtLifetimeOwner from previous analysis" + error("Getting inaccessibility reason for validity token when it is accessible") } @@ -63,19 +66,24 @@ public object KtReadActionConfinementLifetimeTokenFactory : KtLifetimeTokenFacto override fun create(project: Project): KtLifetimeToken = KtReadActionConfinementLifetimeToken(project) - override fun beforeEnteringAnalysisContext() { - currentAnalysisContextEnteringCount.set(currentAnalysisContextEnteringCount.get() + 1) + override fun beforeEnteringAnalysisContext(token: KtLifetimeToken) { + lifetimeOwnersStack.set(lifetimeOwnersStack.get().add(token)) } - override fun afterLeavingAnalysisContext() { - currentAnalysisContextEnteringCount.set(currentAnalysisContextEnteringCount.get() - 1) + override fun afterLeavingAnalysisContext(token: KtLifetimeToken) { + val stack = lifetimeOwnersStack.get() + val last = stack.last() + check(last == token) + lifetimeOwnersStack.set(stack.removeAt(stack.lastIndex)) } - private val currentAnalysisContextEnteringCount = ThreadLocal.withInitial { 0 } + private val lifetimeOwnersStack = ThreadLocal.withInitial> { persistentListOf() } - internal fun isInsideAnalysisContext() = currentAnalysisContextEnteringCount.get() > 0 + internal fun isInsideAnalysisContext() = lifetimeOwnersStack.get().size > 0 + internal fun currentToken() = lifetimeOwnersStack.get().last() } + /** * * @see KtAnalysisSession diff --git a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/session/KtAnalysisSessionProvider.kt b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/session/KtAnalysisSessionProvider.kt index c4da0f01f51..1ed97aee6e6 100644 --- a/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/session/KtAnalysisSessionProvider.kt +++ b/analysis/analysis-api/src/org/jetbrains/kotlin/analysis/api/session/KtAnalysisSessionProvider.kt @@ -75,11 +75,11 @@ public abstract class KtAnalysisSessionProvider(public val project: Project) : D action: KtAnalysisSession.() -> R ): R { noWriteActionInAnalyseCallChecker.beforeEnteringAnalysisContext() - factory.beforeEnteringAnalysisContext() + factory.beforeEnteringAnalysisContext(analysisSession.token) return try { analysisSession.action() } finally { - factory.afterLeavingAnalysisContext() + factory.afterLeavingAnalysisContext(analysisSession.token) noWriteActionInAnalyseCallChecker.afterLeavingAnalysisContext() } }