FIR IDE: add validity check of analysis component that it is valid only in analysis context
This commit is contained in:
+2
-2
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile
|
|||||||
import org.jetbrains.kotlin.idea.frontend.api.InvalidWayOfUsingAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.InvalidWayOfUsingAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.components.KtScopeContext
|
import org.jetbrains.kotlin.idea.frontend.api.components.KtScopeContext
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.getAnalysisSessionFor
|
import org.jetbrains.kotlin.idea.frontend.api.analyseInFakeAnalysisSession
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtCompositeScope
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtCompositeScope
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter
|
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter
|
||||||
@@ -133,7 +133,7 @@ private class KotlinCommonCompletionProvider(
|
|||||||
|
|
||||||
val explicitReceiver = nameExpression.getReceiverExpression()
|
val explicitReceiver = nameExpression.getReceiverExpression()
|
||||||
|
|
||||||
with(getAnalysisSessionFor(originalFile).createContextDependentCopy(originalFile, nameExpression)) {
|
analyseInFakeAnalysisSession(originalFile, nameExpression) {
|
||||||
val expectedType = nameExpression.getExpectedType()
|
val expectedType = nameExpression.getExpectedType()
|
||||||
|
|
||||||
val scopesContext = originalFile.getScopeContextForPosition(nameExpression)
|
val scopesContext = originalFile.getScopeContextForPosition(nameExpression)
|
||||||
|
|||||||
+39
-5
@@ -11,10 +11,14 @@ import com.intellij.openapi.progress.ProgressIndicator
|
|||||||
import com.intellij.openapi.progress.Task
|
import com.intellij.openapi.progress.Task
|
||||||
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
import org.jetbrains.kotlin.idea.util.application.runReadAction
|
||||||
import org.jetbrains.kotlin.psi.KtElement
|
import org.jetbrains.kotlin.psi.KtElement
|
||||||
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
|
||||||
@RequiresOptIn("To use analysis session, consider using analyze/analyzeWithReadAction/analyseInModalWindow methods")
|
@RequiresOptIn("To use analysis session, consider using analyze/analyzeWithReadAction/analyseInModalWindow methods")
|
||||||
annotation class InvalidWayOfUsingAnalysisSession
|
annotation class InvalidWayOfUsingAnalysisSession
|
||||||
|
|
||||||
|
@RequiresOptIn
|
||||||
|
annotation class KtAnalysisSessionProviderInternals
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Provides [KtAnalysisSession] by [contextElement]
|
* Provides [KtAnalysisSession] by [contextElement]
|
||||||
* Should not be used directly, consider using [analyse]/[analyseWithReadAction]/[analyseInModalWindow] instead
|
* Should not be used directly, consider using [analyse]/[analyseWithReadAction]/[analyseInModalWindow] instead
|
||||||
@@ -23,11 +27,38 @@ annotation class InvalidWayOfUsingAnalysisSession
|
|||||||
abstract class KtAnalysisSessionProvider {
|
abstract class KtAnalysisSessionProvider {
|
||||||
@InvalidWayOfUsingAnalysisSession
|
@InvalidWayOfUsingAnalysisSession
|
||||||
abstract fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession
|
abstract fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession
|
||||||
}
|
|
||||||
|
|
||||||
@InvalidWayOfUsingAnalysisSession
|
@InvalidWayOfUsingAnalysisSession
|
||||||
fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession =
|
inline fun <R> analyseInFakeAnalysisSession(originalFile: KtFile, fakeExpresion: KtElement, action: KtAnalysisSession.() -> R): R {
|
||||||
contextElement.project.service<KtAnalysisSessionProvider>().getAnalysisSessionFor(contextElement)
|
val fakeAnalysisSession = getAnalysisSessionFor(originalFile).createContextDependentCopy(originalFile, fakeExpresion)
|
||||||
|
return analyse(fakeAnalysisSession, action)
|
||||||
|
}
|
||||||
|
|
||||||
|
@InvalidWayOfUsingAnalysisSession
|
||||||
|
inline fun <R> analyse(contextElement: KtElement, action: KtAnalysisSession.() -> R): R =
|
||||||
|
analyse(getAnalysisSessionFor(contextElement), action)
|
||||||
|
|
||||||
|
@OptIn(KtAnalysisSessionProviderInternals::class)
|
||||||
|
@InvalidWayOfUsingAnalysisSession
|
||||||
|
inline fun <R> analyse(analysisSession: KtAnalysisSession, action: KtAnalysisSession.() -> R): R {
|
||||||
|
currentAnalysisContextEnteringCount.set(currentAnalysisContextEnteringCount.get() + 1)
|
||||||
|
return try {
|
||||||
|
analysisSession.action()
|
||||||
|
} finally {
|
||||||
|
currentAnalysisContextEnteringCount.set(currentAnalysisContextEnteringCount.get() - 1)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
companion object {
|
||||||
|
@KtAnalysisSessionProviderInternals
|
||||||
|
val currentAnalysisContextEnteringCount = object : ThreadLocal<Int>() {
|
||||||
|
override fun initialValue() = 0
|
||||||
|
}
|
||||||
|
|
||||||
|
@OptIn(KtAnalysisSessionProviderInternals::class)
|
||||||
|
fun isInsideAnalysisContext() = currentAnalysisContextEnteringCount.get() > 0
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute given [action] in [KtAnalysisSession] context
|
* Execute given [action] in [KtAnalysisSession] context
|
||||||
@@ -43,8 +74,11 @@ fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession =
|
|||||||
*/
|
*/
|
||||||
@OptIn(InvalidWayOfUsingAnalysisSession::class)
|
@OptIn(InvalidWayOfUsingAnalysisSession::class)
|
||||||
inline fun <R> analyse(contextElement: KtElement, action: KtAnalysisSession.() -> R): R =
|
inline fun <R> analyse(contextElement: KtElement, action: KtAnalysisSession.() -> R): R =
|
||||||
getAnalysisSessionFor(contextElement).action()
|
contextElement.project.service<KtAnalysisSessionProvider>().analyse(contextElement, action)
|
||||||
|
|
||||||
|
@OptIn(InvalidWayOfUsingAnalysisSession::class)
|
||||||
|
inline fun <R> analyseInFakeAnalysisSession(originalFile: KtFile, fakeExpresion: KtElement, action: KtAnalysisSession.() -> R): R =
|
||||||
|
originalFile.project.service<KtAnalysisSessionProvider>().analyseInFakeAnalysisSession(originalFile, fakeExpresion, action)
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Execute given [action] in [KtAnalysisSession] context like [analyse] does but execute it in read action
|
* Execute given [action] in [KtAnalysisSession] context like [analyse] does but execute it in read action
|
||||||
|
|||||||
+4
-2
@@ -23,16 +23,17 @@ class ReadActionConfinementValidityToken(project: Project) : ValidityToken() {
|
|||||||
error("Getting invalidation reason for valid validity token")
|
error("Getting invalidation reason for valid validity token")
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class, ForbidKtResolveInternals::class)
|
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class, ForbidKtResolveInternals::class, InvalidWayOfUsingAnalysisSession::class)
|
||||||
override fun isAccessible(): Boolean {
|
override fun isAccessible(): Boolean {
|
||||||
val application = ApplicationManager.getApplication()
|
val application = ApplicationManager.getApplication()
|
||||||
if (application.isDispatchThread && !allowOnEdt.get()) return false
|
if (application.isDispatchThread && !allowOnEdt.get()) return false
|
||||||
if (ForbidKtResolve.resovleIsForbidenInActionWithName.get() != null) return false
|
if (ForbidKtResolve.resovleIsForbidenInActionWithName.get() != null) return false
|
||||||
if (!application.isReadAccessAllowed) return false
|
if (!application.isReadAccessAllowed) return false
|
||||||
|
if (!KtAnalysisSessionProvider.isInsideAnalysisContext()) return false
|
||||||
return true
|
return true
|
||||||
}
|
}
|
||||||
|
|
||||||
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class, ForbidKtResolveInternals::class)
|
@OptIn(HackToForceAllowRunningAnalyzeOnEDT::class, ForbidKtResolveInternals::class, InvalidWayOfUsingAnalysisSession::class)
|
||||||
override fun getInaccessibilityReason(): String {
|
override fun getInaccessibilityReason(): String {
|
||||||
val application = ApplicationManager.getApplication()
|
val application = ApplicationManager.getApplication()
|
||||||
if (application.isDispatchThread && !allowOnEdt.get()) return "Called in EDT thread"
|
if (application.isDispatchThread && !allowOnEdt.get()) return "Called in EDT thread"
|
||||||
@@ -40,6 +41,7 @@ class ReadActionConfinementValidityToken(project: Project) : ValidityToken() {
|
|||||||
ForbidKtResolve.resovleIsForbidenInActionWithName.get()?.let { actionName ->
|
ForbidKtResolve.resovleIsForbidenInActionWithName.get()?.let { actionName ->
|
||||||
return "Resolve is forbidden in $actionName"
|
return "Resolve is forbidden in $actionName"
|
||||||
}
|
}
|
||||||
|
if (!KtAnalysisSessionProvider.isInsideAnalysisContext()) return "Called outside analyse method"
|
||||||
error("Getting inaccessibility reason for validity token when it is accessible")
|
error("Getting inaccessibility reason for validity token when it is accessible")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
-3
@@ -34,9 +34,6 @@ private constructor(
|
|||||||
token: ValidityToken,
|
token: ValidityToken,
|
||||||
val context: KtFirAnalysisSessionContext,
|
val context: KtFirAnalysisSessionContext,
|
||||||
) : KtAnalysisSession(token) {
|
) : KtAnalysisSession(token) {
|
||||||
init {
|
|
||||||
assertIsValidAndAccessible()
|
|
||||||
}
|
|
||||||
|
|
||||||
override val smartCastProviderImpl = KtFirSmartcastProvider(this, token)
|
override val smartCastProviderImpl = KtFirSmartcastProvider(this, token)
|
||||||
|
|
||||||
|
|||||||
-2
@@ -38,8 +38,6 @@ class KtFirAnalysisSessionProvider(project: Project) : KtAnalysisSessionProvider
|
|||||||
return analysisSessionByModuleInfoCache.value.getOrPut(contextElement.getModuleInfo()) {
|
return analysisSessionByModuleInfoCache.value.getOrPut(contextElement.getModuleInfo()) {
|
||||||
@Suppress("DEPRECATION")
|
@Suppress("DEPRECATION")
|
||||||
KtFirAnalysisSession.createForElement(contextElement)
|
KtFirAnalysisSession.createForElement(contextElement)
|
||||||
}.apply {
|
|
||||||
assertIsValidAndAccessible()
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+4
-2
@@ -60,8 +60,10 @@ abstract class AbstractResolveCallTest : @Suppress("DEPRECATION") LightCodeInsig
|
|||||||
buildString {
|
buildString {
|
||||||
append(textWithoutLatestComments)
|
append(textWithoutLatestComments)
|
||||||
append("\n\n")
|
append("\n\n")
|
||||||
callInfos.joinTo(this, separator = "\n") { info ->
|
analyse(file as KtFile) {
|
||||||
"// CALL: ${info?.stringRepresentation()}"
|
callInfos.joinTo(this@buildString, separator = "\n") { info ->
|
||||||
|
"// CALL: ${info?.stringRepresentation()}"
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user