diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt index 412021c3b43..12097480415 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ReadActionConfinementValidityToken.kt @@ -13,21 +13,30 @@ class ReadActionConfinementValidityToken(project: Project) : ValidityToken() { private val modificationTracker = project.createProjectWideOutOfBlockModificationTracker() private val onCreatedTimeStamp = modificationTracker.modificationCount - @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) override fun isValid(): Boolean { - val application = ApplicationManager.getApplication() - if (application.isDispatchThread && !allowOnEdt.get()) return false - if (!application.isReadAccessAllowed) return false return onCreatedTimeStamp == modificationTracker.modificationCount } @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) override fun getInvalidationReason(): String { + if (onCreatedTimeStamp != modificationTracker.modificationCount) return "PSI has changed since creation" + error("Getting invalidation reason for valid validity token") + } + + @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) + override fun isAccessible(): Boolean { + val application = ApplicationManager.getApplication() + if (application.isDispatchThread && !allowOnEdt.get()) return false + if (!application.isReadAccessAllowed) return false + return true + } + + @OptIn(HackToForceAllowRunningAnalyzeOnEDT::class) + override fun getInaccessibilityReason(): String { val application = ApplicationManager.getApplication() if (application.isDispatchThread && !allowOnEdt.get()) return "Called in EDT thread" if (!application.isReadAccessAllowed) return "Called outside read action" - if (onCreatedTimeStamp != modificationTracker.modificationCount) return "PSI has changed since creation" - error("Getting invalidation reason for valid validity token") + error("Getting inaccessibility reason for validity token when it is accessible") } companion object { diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityToken.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityToken.kt index 69f23509aa7..f8d37e1d82e 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityToken.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityToken.kt @@ -8,14 +8,23 @@ package org.jetbrains.kotlin.idea.frontend.api abstract class ValidityToken { abstract fun isValid(): Boolean abstract fun getInvalidationReason(): String + + abstract fun isAccessible(): Boolean + abstract fun getInaccessibilityReason(): String } @Suppress("NOTHING_TO_INLINE") -inline fun ValidityToken.assertIsValid() { +inline fun ValidityToken.assertIsValidAndAccessible() { if (!isValid()) { - throw InvalidEntityAccessException("Access to invalid $this, invalidation reason is ${getInvalidationReason()}") + throw InvalidEntityAccessException("Access to invalid $this: ${getInvalidationReason()}") + } + if (!isAccessible()) { + throw InaccessibleEntityAccessException("$this is inaccessible: ${getInaccessibilityReason()}") } } -class InvalidEntityAccessException(override val message: String): IllegalStateException() +abstract class BadEntityAccessException(): IllegalStateException() + +class InvalidEntityAccessException(override val message: String) : BadEntityAccessException() +class InaccessibleEntityAccessException(override val message: String): BadEntityAccessException() diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityTokenOwner.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityTokenOwner.kt index cdd9c6f54a4..4971336c579 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityTokenOwner.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/ValidityTokenOwner.kt @@ -9,12 +9,14 @@ interface ValidityTokenOwner { val token: ValidityToken } +fun ValidityTokenOwner.isValid(): Boolean = token.isValid() + @Suppress("NOTHING_TO_INLINE") -inline fun ValidityTokenOwner.assertIsValid() { - token.assertIsValid() +inline fun ValidityTokenOwner.assertIsValidAndAccessible() { + token.assertIsValidAndAccessible() } inline fun ValidityTokenOwner.withValidityAssertion(action: () -> R): R { - assertIsValid() + assertIsValidAndAccessible() return action() } \ No newline at end of file diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt index 38669123b8c..06e7dd58545 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSession.kt @@ -15,7 +15,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.getResolveState import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.ReadActionConfinementValidityToken import org.jetbrains.kotlin.idea.frontend.api.ValidityToken -import org.jetbrains.kotlin.idea.frontend.api.assertIsValid +import org.jetbrains.kotlin.idea.frontend.api.assertIsValidAndAccessible import org.jetbrains.kotlin.idea.frontend.api.components.* import org.jetbrains.kotlin.idea.frontend.api.fir.components.* import org.jetbrains.kotlin.idea.frontend.api.fir.symbols.KtFirSymbolProvider @@ -35,7 +35,7 @@ private constructor( val context: KtFirAnalysisSessionContext, ) : KtAnalysisSession(token) { init { - assertIsValid() + assertIsValidAndAccessible() } internal val towerDataContextProvider: TowerDataContextProvider = TowerDataContextProvider(this) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSessionProvider.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSessionProvider.kt index 3497ef52c73..93c0f1fc93c 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSessionProvider.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/KtFirAnalysisSessionProvider.kt @@ -17,7 +17,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState import org.jetbrains.kotlin.idea.frontend.api.InvalidWayOfUsingAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProvider -import org.jetbrains.kotlin.idea.frontend.api.assertIsValid +import org.jetbrains.kotlin.idea.frontend.api.assertIsValidAndAccessible import org.jetbrains.kotlin.psi.KtElement import java.util.concurrent.ConcurrentHashMap @@ -37,7 +37,7 @@ class KtFirAnalysisSessionProvider(project: Project) : KtAnalysisSessionProvider @Suppress("DEPRECATION") KtFirAnalysisSession.createForElement(contextElement) }.apply { - assertIsValid() + assertIsValidAndAccessible() } } diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt index 7cdd54c9b03..8f01aa91139 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirCallResolver.kt @@ -89,10 +89,11 @@ internal class KtFirCallResolver( val target = when (val calleeReference = calleeReference) { is FirResolvedNamedReference -> calleeReference.getKtFunctionOrConstructorSymbol()?.let { KtSuccessCallTarget(it) } is FirErrorNamedReference -> calleeReference.createErrorCallTarget() - is FirSimpleNamedReference -> error( - "Looks like FirFunctionCall was not resolved to BODY_RESOLVE phase, " + - "consider resolving it containing declaration before starting resolve calls" - ) + is FirSimpleNamedReference -> + error( + "Looks like FirFunctionCall was not resolved to BODY_RESOLVE phase, " + + "consider resolving it containing declaration before starting resolve calls" + ) else -> error("Unexpected call reference ${calleeReference::class.simpleName}") } ?: return null return KtFunctionCall(target) diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSubtyppingComponent.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSubtyppingComponent.kt index f3ea0ceb07f..34586ab1b9a 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSubtyppingComponent.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/components/KtFirSubtyppingComponent.kt @@ -6,7 +6,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.components import org.jetbrains.kotlin.idea.frontend.api.ValidityToken -import org.jetbrains.kotlin.idea.frontend.api.assertIsValid +import org.jetbrains.kotlin.idea.frontend.api.assertIsValidAndAccessible import org.jetbrains.kotlin.idea.frontend.api.components.KtSubtypingComponent import org.jetbrains.kotlin.idea.frontend.api.fir.KtFirAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.fir.types.KtFirType @@ -20,7 +20,7 @@ internal class KtFirSubtypingComponent( override val token: ValidityToken, ) : KtSubtypingComponent(), KtFirAnalysisSessionComponent { override fun isEqualTo(first: KtType, second: KtType): Boolean = withValidityAssertion { - second.assertIsValid() + second.assertIsValidAndAccessible() check(first is KtFirType) check(second is KtFirType) return AbstractTypeChecker.equalTypes( @@ -31,7 +31,7 @@ internal class KtFirSubtypingComponent( } override fun isSubTypeOf(subType: KtType, superType: KtType): Boolean = withValidityAssertion { - superType.assertIsValid() + superType.assertIsValidAndAccessible() check(subType is KtFirType) check(superType is KtFirType) return AbstractTypeChecker.isSubtypeOf( diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/FirRefWithValidityCheck.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/FirRefWithValidityCheck.kt index 0b41fc42de2..43e6c915848 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/FirRefWithValidityCheck.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/FirRefWithValidityCheck.kt @@ -9,11 +9,10 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.fir.declarations.FirDeclaration import org.jetbrains.kotlin.fir.declarations.FirResolvePhase import org.jetbrains.kotlin.idea.fir.low.level.api.api.FirModuleResolveState -import org.jetbrains.kotlin.idea.fir.low.level.api.api.resolvedFirToPhase import org.jetbrains.kotlin.idea.fir.low.level.api.api.withFirDeclaration import org.jetbrains.kotlin.idea.frontend.api.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner -import org.jetbrains.kotlin.idea.frontend.api.assertIsValid +import org.jetbrains.kotlin.idea.frontend.api.assertIsValidAndAccessible import java.lang.ref.WeakReference internal class FirRefWithValidityCheck(fir: D, resolveState: FirModuleResolveState, val token: ValidityToken) { @@ -25,7 +24,7 @@ internal class FirRefWithValidityCheck(fir: D, resolveSt firWeakRef.get() == null && resolveStateWeakRef.get() == null inline fun withFir(phase: FirResolvePhase = FirResolvePhase.RAW_FIR, crossinline action: (fir: D) -> R): R { - token.assertIsValid() + token.assertIsValidAndAccessible() val fir = firWeakRef.get() ?: throw EntityWasGarbageCollectedException("FirElement") val resolveState = resolveStateWeakRef.get() diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/ValidityAwareCachedValue.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/ValidityAwareCachedValue.kt index e7ef4b87f6b..40f1dfed2ea 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/ValidityAwareCachedValue.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/utils/ValidityAwareCachedValue.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.frontend.api.fir.utils import org.jetbrains.kotlin.idea.frontend.api.ValidityToken import org.jetbrains.kotlin.idea.frontend.api.ValidityTokenOwner -import org.jetbrains.kotlin.idea.frontend.api.assertIsValid +import org.jetbrains.kotlin.idea.frontend.api.assertIsValidAndAccessible import kotlin.properties.ReadOnlyProperty import kotlin.reflect.KProperty @@ -22,7 +22,7 @@ class ValidityAwareCachedValue( @Suppress("UNCHECKED_CAST") override fun getValue(thisRef: Any, property: KProperty<*>): T { - token.assertIsValid() + token.assertIsValidAndAccessible() return lazyValue.value } }