[Analysis API] forbid providing custom KtLifetimeToken for every analyze call

^KT-60488 fixed
This commit is contained in:
Ilya Kirillov
2023-07-17 14:21:09 +02:00
committed by Space Team
parent b617b24d48
commit 4b523825be
7 changed files with 41 additions and 63 deletions
@@ -22,50 +22,40 @@ import org.jetbrains.kotlin.psi.KtFile
* Uses [useSiteKtElement] as an [KtElement] which containing module is a use-site module,
* i.e, the module from which perspective the project will be analyzed.
*
* [nonDefaultLifetimeTokenFactory] represents lifetime and accessibility guaranties
* which will be applied to the [org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeOwner] instances created during code analysis.
*
* @see KtAnalysisSession
* @see KtLifetimeTokenFactory
* @see analyzeWithReadAction
*/
public inline fun <R> analyze(
useSiteKtElement: KtElement,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory? = null,
action: KtAnalysisSession.() -> R
): R =
KtAnalysisSessionProvider.getInstance(useSiteKtElement.project)
.analyse(useSiteKtElement, nonDefaultLifetimeTokenFactory, action)
.analyse(useSiteKtElement, action)
/**
* Execute given [action] in [KtAnalysisSession] context
* Uses [useSiteKtModule] as use-site module, i.e, the module from which perspective the project will be analyzed.
*
* [nonDefaultLifetimeTokenFactory] represents lifetime and accessibility guaranties
* which will be applied to the [org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeOwner] instances created during code analysis.
*
* @see KtAnalysisSession
* @see KtLifetimeTokenFactory
*/
public inline fun <R> analyze(
useSiteKtModule: KtModule,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory? = null,
crossinline action: KtAnalysisSession.() -> R
): R {
val sessionProvider = KtAnalysisSessionProvider.getInstance(useSiteKtModule.project)
return sessionProvider.analyze(useSiteKtModule, nonDefaultLifetimeTokenFactory, action)
return sessionProvider.analyze(useSiteKtModule, action)
}
public inline fun <R> analyzeInDependedAnalysisSession(
originalFile: KtFile,
elementToReanalyze: KtElement,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory? = null,
action: KtAnalysisSession.() -> R
): R =
KtAnalysisSessionProvider.getInstance(originalFile.project)
.analyseInDependedAnalysisSession(originalFile, elementToReanalyze, nonDefaultLifetimeTokenFactory, action)
.analyseInDependedAnalysisSession(originalFile, elementToReanalyze, action)
/**
* Execute given [action] in [KtAnalysisSession] context like [analyze] does but execute it in read action
@@ -81,10 +71,9 @@ public inline fun <R> analyzeInDependedAnalysisSession(
*/
public inline fun <R> analyzeWithReadAction(
contextElement: KtElement,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory? = null,
crossinline action: KtAnalysisSession.() -> R
): R = ApplicationManager.getApplication().runReadAction(Computable {
analyze(contextElement, nonDefaultLifetimeTokenFactory, action)
analyze(contextElement, action)
})
/**
@@ -97,13 +86,12 @@ public inline fun <R> analyzeWithReadAction(
public inline fun <R> analyzeInModalWindow(
contextElement: KtElement,
windowTitle: String,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory? = null,
crossinline action: KtAnalysisSession.() -> R
): R {
ApplicationManager.getApplication().assertIsDispatchThread()
val task = object : Task.WithResult<R, Exception>(contextElement.project, windowTitle, /*canBeCancelled*/ true) {
override fun compute(indicator: ProgressIndicator): R =
analyzeWithReadAction(contextElement, nonDefaultLifetimeTokenFactory) { action() }
analyzeWithReadAction(contextElement) { action() }
}
task.queue()
return task.result
@@ -9,19 +9,19 @@ import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
@KtAnalysisApiInternals
public abstract class KtDefaultLifetimeTokenProvider {
public abstract fun getDefaultLifetimeTokenFactory(): KtLifetimeTokenFactory
public abstract class KtLifetimeTokenProvider {
public abstract fun getLifetimeTokenFactory(): KtLifetimeTokenFactory
public companion object {
@KtAnalysisApiInternals
public fun getService(project: Project): KtDefaultLifetimeTokenProvider =
project.getService(KtDefaultLifetimeTokenProvider::class.java)
public fun getService(project: Project): KtLifetimeTokenProvider =
project.getService(KtLifetimeTokenProvider::class.java)
}
}
@KtAnalysisApiInternals
public class KtReadActionConfinementDefaultLifetimeTokenProvider: KtDefaultLifetimeTokenProvider() {
override fun getDefaultLifetimeTokenFactory(): KtLifetimeTokenFactory {
public class KtReadActionConfinementLifetimeTokenProvider : KtLifetimeTokenProvider() {
override fun getLifetimeTokenFactory(): KtLifetimeTokenFactory {
return KtReadActionConfinementLifetimeTokenFactory
}
}
@@ -11,7 +11,7 @@ import org.jetbrains.annotations.TestOnly
import org.jetbrains.kotlin.analysis.api.KtAnalysisSession
import org.jetbrains.kotlin.analysis.api.KtAnalysisApiInternals
import org.jetbrains.kotlin.analysis.api.lifetime.impl.NoWriteActionInAnalyseCallChecker
import org.jetbrains.kotlin.analysis.api.lifetime.KtDefaultLifetimeTokenProvider
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenProvider
import org.jetbrains.kotlin.analysis.api.lifetime.KtLifetimeTokenFactory
import org.jetbrains.kotlin.analysis.project.structure.KtModule
import org.jetbrains.kotlin.psi.KtElement
@@ -21,63 +21,53 @@ import org.jetbrains.kotlin.psi.KtFile
* Provides [KtAnalysisSession] by [contextElement]
* Should not be used directly, consider using [analyse]/[analyzeWithReadAction]/[analyzeInModalWindow] instead
*/
@KtAnalysisApiInternals
@OptIn(KtAnalysisApiInternals::class)
public abstract class KtAnalysisSessionProvider(public val project: Project) : Disposable {
@KtAnalysisApiInternals
public val tokenFactory: KtLifetimeTokenFactory = KtLifetimeTokenProvider.getService(project).getLifetimeTokenFactory()
@Suppress("LeakingThis")
public val noWriteActionInAnalyseCallChecker: NoWriteActionInAnalyseCallChecker = NoWriteActionInAnalyseCallChecker(this)
public abstract fun getAnalysisSession(useSiteKtElement: KtElement, factory: KtLifetimeTokenFactory): KtAnalysisSession
public abstract fun getAnalysisSession(useSiteKtElement: KtElement): KtAnalysisSession
public abstract fun getAnalysisSessionByUseSiteKtModule(useSiteKtModule: KtModule, factory: KtLifetimeTokenFactory): KtAnalysisSession
public abstract fun getAnalysisSessionByUseSiteKtModule(useSiteKtModule: KtModule): KtAnalysisSession
public inline fun <R> analyseInDependedAnalysisSession(
originalFile: KtFile,
elementToReanalyze: KtElement,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory?,
action: KtAnalysisSession.() -> R
action: KtAnalysisSession.() -> R,
): R {
val factory =
nonDefaultLifetimeTokenFactory ?: KtDefaultLifetimeTokenProvider.getService(project).getDefaultLifetimeTokenFactory()
val originalAnalysisSession = getAnalysisSession(originalFile, factory)
val originalAnalysisSession = getAnalysisSession(originalFile)
val dependedAnalysisSession = originalAnalysisSession
.createContextDependentCopy(originalFile, elementToReanalyze)
return analyse(dependedAnalysisSession, factory, action)
return analyse(dependedAnalysisSession, action)
}
public inline fun <R> analyse(
useSiteKtElement: KtElement,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory?,
action: KtAnalysisSession.() -> R
action: KtAnalysisSession.() -> R,
): R {
val factory =
nonDefaultLifetimeTokenFactory ?: KtDefaultLifetimeTokenProvider.getService(project).getDefaultLifetimeTokenFactory()
return analyse(getAnalysisSession(useSiteKtElement, factory), factory, action)
return analyse(getAnalysisSession(useSiteKtElement), action)
}
public inline fun <R> analyze(
useSiteKtModule: KtModule,
nonDefaultLifetimeTokenFactory: KtLifetimeTokenFactory?,
action: KtAnalysisSession.() -> R
action: KtAnalysisSession.() -> R,
): R {
val factory =
nonDefaultLifetimeTokenFactory ?: KtDefaultLifetimeTokenProvider.getService(project).getDefaultLifetimeTokenFactory()
return analyse(getAnalysisSessionByUseSiteKtModule(useSiteKtModule, factory), factory, action)
return analyse(getAnalysisSessionByUseSiteKtModule(useSiteKtModule), action)
}
public inline fun <R> analyse(
analysisSession: KtAnalysisSession,
factory: KtLifetimeTokenFactory,
action: KtAnalysisSession.() -> R
action: KtAnalysisSession.() -> R,
): R {
noWriteActionInAnalyseCallChecker.beforeEnteringAnalysisContext()
factory.beforeEnteringAnalysisContext(analysisSession.token)
tokenFactory.beforeEnteringAnalysisContext(analysisSession.token)
return try {
analysisSession.action()
} finally {
factory.afterLeavingAnalysisContext(analysisSession.token)
tokenFactory.afterLeavingAnalysisContext(analysisSession.token)
noWriteActionInAnalyseCallChecker.afterLeavingAnalysisContext()
}
}