FIR IDE: introduce analyseInModalWindow function

This commit is contained in:
Ilya Kirillov
2020-08-26 18:36:20 +03:00
parent 81be230541
commit fcc7db5224
3 changed files with 66 additions and 6 deletions
@@ -9,6 +9,7 @@ import com.intellij.codeInsight.completion.*
import com.intellij.patterns.PlatformPatterns import com.intellij.patterns.PlatformPatterns
import com.intellij.patterns.PsiJavaPatterns import com.intellij.patterns.PsiJavaPatterns
import com.intellij.util.ProcessingContext import com.intellij.util.ProcessingContext
import org.jetbrains.kotlin.idea.frontend.api.InvalidWayOfUsingAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.getAnalysisSessionFor import org.jetbrains.kotlin.idea.frontend.api.getAnalysisSessionFor
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol
@@ -62,6 +63,7 @@ private object KotlinHighLevelApiContributor : CompletionProvider<CompletionPara
private object KotlinAvailableScopesCompletionContributor { private object KotlinAvailableScopesCompletionContributor {
private val lookupElementFactory = HighLevelApiLookupElementFactory() private val lookupElementFactory = HighLevelApiLookupElementFactory()
@OptIn(InvalidWayOfUsingAnalysisSession::class)
fun collectCompletions(parameters: CompletionParameters, result: CompletionResultSet) { fun collectCompletions(parameters: CompletionParameters, result: CompletionResultSet) {
val originalFile = parameters.originalFile as? KtFile ?: return val originalFile = parameters.originalFile as? KtFile ?: return
@@ -5,29 +5,85 @@
package org.jetbrains.kotlin.idea.frontend.api package org.jetbrains.kotlin.idea.frontend.api
import com.intellij.openapi.application.ApplicationManager
import com.intellij.openapi.components.service import com.intellij.openapi.components.service
import com.intellij.openapi.diagnostic.Logger
import com.intellij.openapi.progress.ProgressIndicator
import com.intellij.openapi.progress.Task
import org.jetbrains.kotlin.idea.frontend.api.types.render
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.utils.PrintingLogger
@RequiresOptIn("To use analysis session, consider using analyze/analyzeWithReadAction/analyseInModalWindow methods")
annotation class InvalidWayOfUsingAnalysisSession
/**
* Provides [KtAnalysisSession] by [contextElement]
* Should not be used directly, consider using [analyze]/[analyzeWithReadAction]/[analyseInModalWindow] instead
*/
@InvalidWayOfUsingAnalysisSession
abstract class KtAnalysisSessionProvider { abstract class KtAnalysisSessionProvider {
@InvalidWayOfUsingAnalysisSession
abstract fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession abstract fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession
} }
@Suppress("DeprecatedCallableAddReplaceWith") @InvalidWayOfUsingAnalysisSession
@Deprecated(
"Should not be directly used as it is not allowed to store KtAnalysisSession in a variable, consider using `analyze` instead",
level = DeprecationLevel.WARNING,
)
fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession = fun getAnalysisSessionFor(contextElement: KtElement): KtAnalysisSession =
contextElement.project.service<KtAnalysisSessionProvider>().getAnalysisSessionFor(contextElement) contextElement.project.service<KtAnalysisSessionProvider>().getAnalysisSessionFor(contextElement)
@Suppress("DEPRECATION") /**
* Execute given [action] in [KtAnalysisSession] context
* Uses [contextElement] to get a module from which you would like to see the other modules
* Usually [contextElement] is some element form the module you currently analysing now
*
* Should not be called from EDT thread
* Should be called from read action
* To analyse something from EDT thread, consider using [analyseInModalWindow]
*
* @see KtAnalysisSession
* @see analyzeWithReadAction
*/
@OptIn(InvalidWayOfUsingAnalysisSession::class)
inline fun <R> analyze(contextElement: KtElement, action: KtAnalysisSession.() -> R): R = inline fun <R> analyze(contextElement: KtElement, action: KtAnalysisSession.() -> R): R =
getAnalysisSessionFor(contextElement).action() getAnalysisSessionFor(contextElement).action()
/**
* Execute given [action] in [KtAnalysisSession] context like [analyze] does but execute it in read action
* Uses [contextElement] to get a module from which you would like to see the other modules
* Usually [contextElement] is some element form the module you currently analysing now
*
* Should be called from read action
* To analyse something from EDT thread, consider using [analyseInModalWindow]
* If you are already in read action, consider using [analyze]
*
* @see KtAnalysisSession
* @see analyze
*/
inline fun <R> analyzeWithReadAction( inline fun <R> analyzeWithReadAction(
contextElement: KtElement, contextElement: KtElement,
crossinline action: KtAnalysisSession.() -> R crossinline action: KtAnalysisSession.() -> R
): R = runReadAction { ): R = runReadAction {
analyze(contextElement, action) analyze(contextElement, action)
}
/**
* Show a modal window with a progress bar and specified [windowTitle]
* and execute given [action] task with [KtAnalysisSession] context
* If [action] throws some exception, then [analyseInModalWindow] will rethrow it
* Should be executed from EDT only
* If you want to analyse something from non-EDT thread, consider using [analyze]/[analyzeWithReadAction]
*/
inline fun <R> analyseInModalWindow(
contextElement: KtElement,
windowTitle: String,
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) { action() }
}
task.queue()
return task.result
} }
@@ -11,12 +11,14 @@ import com.intellij.psi.util.CachedValuesManager
import com.intellij.psi.util.PsiModificationTracker import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.analyzer.ModuleInfo import org.jetbrains.kotlin.analyzer.ModuleInfo
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
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.KtAnalysisSessionProvider import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSessionProvider
import org.jetbrains.kotlin.idea.frontend.api.assertIsValid import org.jetbrains.kotlin.idea.frontend.api.assertIsValid
import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtElement
import java.util.concurrent.ConcurrentHashMap import java.util.concurrent.ConcurrentHashMap
@OptIn(InvalidWayOfUsingAnalysisSession::class)
class KtFirAnalysisSessionProvider(project: Project) : KtAnalysisSessionProvider() { class KtFirAnalysisSessionProvider(project: Project) : KtAnalysisSessionProvider() {
private val analysisSessionByModuleInfoCache = private val analysisSessionByModuleInfoCache =
CachedValuesManager.getManager(project).createCachedValue { CachedValuesManager.getManager(project).createCachedValue {