New J2K : move resolve resolve out of EDT in shorten references processing
relates to #KT-31812
This commit is contained in:
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.idea.core
|
||||
|
||||
import com.intellij.openapi.application.runReadAction
|
||||
import com.intellij.openapi.util.TextRange
|
||||
import com.intellij.psi.PsiDocumentManager
|
||||
import com.intellij.psi.PsiElement
|
||||
@@ -19,7 +20,6 @@ import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport
|
||||
import org.jetbrains.kotlin.idea.imports.getImportableTargets
|
||||
import org.jetbrains.kotlin.idea.references.mainReference
|
||||
import org.jetbrains.kotlin.idea.util.*
|
||||
import org.jetbrains.kotlin.idea.util.application.runWriteAction
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.psi.*
|
||||
import org.jetbrains.kotlin.psi.psiUtil.*
|
||||
@@ -95,19 +95,31 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun process(element: KtElement, elementFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS }): KtElement {
|
||||
return process(listOf(element), elementFilter).single()
|
||||
fun process(
|
||||
element: KtElement,
|
||||
elementFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS },
|
||||
actionRunningMode: ActionRunningMode = ActionRunningMode.RUN_IN_CURRENT_THREAD
|
||||
): KtElement {
|
||||
return process(listOf(element), elementFilter, actionRunningMode).single()
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun process(file: KtFile, startOffset: Int, endOffset: Int, additionalFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS }) {
|
||||
val documentManager = PsiDocumentManager.getInstance(file.project)
|
||||
val document = file.viewProvider.document!!
|
||||
check(documentManager.isCommitted(document)) { "Document should be committed to shorten references in range" }
|
||||
|
||||
val rangeMarker = document.createRangeMarker(startOffset, endOffset)
|
||||
rangeMarker.isGreedyToLeft = true
|
||||
rangeMarker.isGreedyToRight = true
|
||||
fun process(
|
||||
file: KtFile,
|
||||
startOffset: Int,
|
||||
endOffset: Int,
|
||||
additionalFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS },
|
||||
actionRunningMode: ActionRunningMode = ActionRunningMode.RUN_IN_CURRENT_THREAD
|
||||
) {
|
||||
val rangeMarker = runReadAction {
|
||||
val documentManager = PsiDocumentManager.getInstance(file.project)
|
||||
val document = file.viewProvider.document!!
|
||||
check(documentManager.isCommitted(document)) { "Document should be committed to shorten references in range" }
|
||||
document.createRangeMarker(startOffset, endOffset).apply {
|
||||
isGreedyToLeft = true
|
||||
isGreedyToRight = true
|
||||
}
|
||||
}
|
||||
|
||||
val rangeFilter = { element: PsiElement ->
|
||||
if (rangeMarker.isValid) {
|
||||
@@ -136,11 +148,12 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
|
||||
}
|
||||
}
|
||||
try {
|
||||
process(listOf(file)) { element ->
|
||||
val filter = { element: PsiElement ->
|
||||
minOf(rangeFilter(element), additionalFilter(element))
|
||||
}
|
||||
process(listOf(file), filter, actionRunningMode)
|
||||
} finally {
|
||||
rangeMarker.dispose()
|
||||
runReadAction { rangeMarker.dispose() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -153,16 +166,18 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
|
||||
@JvmOverloads
|
||||
fun process(
|
||||
elements: Iterable<KtElement>,
|
||||
elementFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS }
|
||||
elementFilter: (PsiElement) -> FilterResult = { FilterResult.PROCESS },
|
||||
actionRunningMode: ActionRunningMode = ActionRunningMode.RUN_IN_CURRENT_THREAD
|
||||
): Collection<KtElement> {
|
||||
return elements.groupBy(KtElement::getContainingKtFile)
|
||||
.flatMap { shortenReferencesInFile(it.key, it.value, elementFilter) }
|
||||
return runReadAction { elements.groupBy(KtElement::getContainingKtFile) }
|
||||
.flatMap { shortenReferencesInFile(it.key, it.value, elementFilter, actionRunningMode) }
|
||||
}
|
||||
|
||||
private fun shortenReferencesInFile(
|
||||
file: KtFile,
|
||||
elements: List<KtElement>,
|
||||
elementFilter: (PsiElement) -> FilterResult
|
||||
elementFilter: (PsiElement) -> FilterResult,
|
||||
actionRunningMode: ActionRunningMode = ActionRunningMode.RUN_IN_CURRENT_THREAD
|
||||
): Collection<KtElement> {
|
||||
//TODO: that's not correct since we have options!
|
||||
val elementsToUse = dropNestedElements(elements)
|
||||
@@ -182,39 +197,45 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
|
||||
while (true) {
|
||||
// Processors order is important here so that enclosing elements are not shortened before their children are, e.g.
|
||||
// test.foo(this@A) -> foo(this)
|
||||
val processors: List<ShorteningProcessor<*>> = listOf(
|
||||
ShortenTypesProcessor(file, elementFilter, failedToImportDescriptors),
|
||||
ShortenThisExpressionsProcessor(file, elementFilter, failedToImportDescriptors),
|
||||
ShortenQualifiedExpressionsProcessor(file, elementFilter, failedToImportDescriptors),
|
||||
RemoveExplicitCompanionObjectReferenceProcessor(file, companionElementFilter, failedToImportDescriptors)
|
||||
)
|
||||
val processors: List<ShorteningProcessor<*>> = runReadAction {
|
||||
listOf(
|
||||
ShortenTypesProcessor(file, elementFilter, failedToImportDescriptors),
|
||||
ShortenThisExpressionsProcessor(file, elementFilter, failedToImportDescriptors),
|
||||
ShortenQualifiedExpressionsProcessor(file, elementFilter, failedToImportDescriptors),
|
||||
RemoveExplicitCompanionObjectReferenceProcessor(file, companionElementFilter, failedToImportDescriptors)
|
||||
)
|
||||
}
|
||||
|
||||
// step 1: collect qualified elements to analyze (no resolve at this step)
|
||||
val visitors = processors.map { it.collectElementsVisitor }
|
||||
for (visitor in visitors) {
|
||||
for (element in elementsToUse) {
|
||||
visitor.options = options(element)
|
||||
element.accept(visitor)
|
||||
runReadAction {
|
||||
for (visitor in visitors) {
|
||||
for (element in elementsToUse) {
|
||||
visitor.options = options(element)
|
||||
element.accept(visitor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// step 2: analyze collected elements with resolve and decide which can be shortened now and which need descriptors to be imported before shortening
|
||||
val allElementsToAnalyze = visitors.flatMap { visitor -> visitor.getElementsToAnalyze().map { it.element } }.toSet()
|
||||
val bindingContext = allowResolveInDispatchThread {
|
||||
file.getResolutionFacade().analyze(allElementsToAnalyze, BodyResolveMode.PARTIAL_WITH_CFA)
|
||||
}
|
||||
|
||||
processors.forEach { it.analyzeCollectedElements(bindingContext) }
|
||||
// step 2: analyze collected elements with resolve and decide which can be shortened now and which need descriptors to be imported before shortening
|
||||
val allElementsToAnalyze = visitors.flatMap { visitor -> visitor.getElementsToAnalyze().map { it.element } }.toSet()
|
||||
val bindingContext = allowResolveInDispatchThread {
|
||||
file.getResolutionFacade().analyze(allElementsToAnalyze, BodyResolveMode.PARTIAL_WITH_CFA)
|
||||
}
|
||||
|
||||
processors.forEach { it.analyzeCollectedElements(bindingContext) }
|
||||
}
|
||||
|
||||
// step 3: shorten elements that can be shortened right now
|
||||
runWriteAction {
|
||||
actionRunningMode.runAction {
|
||||
processors.forEach { it.shortenElements(elementSetToUpdate = elementsToUse, options = options) }
|
||||
}
|
||||
|
||||
// step 4: try to import descriptors needed to shorten other elements
|
||||
val descriptorsToImport = processors.flatMap { it.getDescriptorsToImport() }.toSet()
|
||||
var anyChange = false
|
||||
runWriteAction {
|
||||
// step 4: try to import descriptors needed to shorten other elements
|
||||
val descriptorsToImport = runReadAction {
|
||||
processors.flatMap { it.getDescriptorsToImport() }.toSet()
|
||||
}
|
||||
actionRunningMode.runAction {
|
||||
for (descriptor in descriptorsToImport) {
|
||||
assert(descriptor !in failedToImportDescriptors)
|
||||
|
||||
@@ -226,7 +247,10 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
|
||||
failedToImportDescriptors.add(descriptor)
|
||||
}
|
||||
}
|
||||
if (!anyChange) processors.forEach { it.removeRootPrefixes() }
|
||||
|
||||
if (!anyChange) {
|
||||
processors.forEach { it.removeRootPrefixes() }
|
||||
}
|
||||
}
|
||||
|
||||
if (!anyChange) break
|
||||
@@ -235,9 +259,9 @@ class ShortenReferences(val options: (KtElement) -> Options = { Options.DEFAULT
|
||||
return elementsToUse
|
||||
}
|
||||
|
||||
private fun dropNestedElements(elements: List<KtElement>): LinkedHashSet<KtElement> {
|
||||
private fun dropNestedElements(elements: List<KtElement>): LinkedHashSet<KtElement> = runReadAction {
|
||||
val elementSet = elements.toSet()
|
||||
return elementSet.filterTo(LinkedHashSet(elementSet.size)) { element ->
|
||||
elementSet.filterTo(LinkedHashSet(elementSet.size)) { element ->
|
||||
element.parents.none { it in elementSet }
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user