Reworked resolve references in background thread in PlainTextPasteImportResolver
Relates to #KT-16774
This commit is contained in:
+51
-59
@@ -44,6 +44,8 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
|||||||
private val project = targetFile.project
|
private val project = targetFile.project
|
||||||
|
|
||||||
private val importList = file.importList!!
|
private val importList = file.importList!!
|
||||||
|
|
||||||
|
// keep access to deprecated PsiElementFactory.SERVICE for bwc with <= 191
|
||||||
private val psiElementFactory = PsiElementFactory.SERVICE.getInstance(project)
|
private val psiElementFactory = PsiElementFactory.SERVICE.getInstance(project)
|
||||||
|
|
||||||
private val bindingContext by lazy { targetFile.analyzeWithContent() }
|
private val bindingContext by lazy { targetFile.analyzeWithContent() }
|
||||||
@@ -64,17 +66,17 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
|||||||
&& descriptor.isVisible(targetFile, null, bindingContext, resolutionFacade)
|
&& descriptor.isVisible(targetFile, null, bindingContext, resolutionFacade)
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun addImport(addImportData: AddImportData) {
|
private fun addImport(importStatement: PsiImportStatementBase, shouldAddToTarget: Boolean = false) {
|
||||||
importList.add(addImportData.importStatement)
|
importList.add(importStatement)
|
||||||
if (addImportData.shouldAddToTarget)
|
if (shouldAddToTarget)
|
||||||
addedImports.add(addImportData.importStatement)
|
addedImports.add(importStatement)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun addImportsFromTargetFile() {
|
fun addImportsFromTargetFile() {
|
||||||
if (importList in dataForConversion.elementsAndTexts.toList()) return
|
if (importList in dataForConversion.elementsAndTexts.toList()) return
|
||||||
|
|
||||||
val task = {
|
val task = {
|
||||||
val addImportList = mutableListOf<AddImportData>()
|
val addImportList = mutableListOf<PsiImportStatementBase>()
|
||||||
|
|
||||||
fun tryConvertKotlinImport(importDirective: KtImportDirective) {
|
fun tryConvertKotlinImport(importDirective: KtImportDirective) {
|
||||||
val importPath = importDirective.importPath
|
val importPath = importDirective.importPath
|
||||||
@@ -98,27 +100,19 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
|||||||
if (importPath.isAllUnder) {
|
if (importPath.isAllUnder) {
|
||||||
when {
|
when {
|
||||||
isClassReceiver ->
|
isClassReceiver ->
|
||||||
addImportList.add(
|
addImportList.add(psiElementFactory.createImportStaticStatement(receiver as PsiClass, "*"))
|
||||||
AddImportData(psiElementFactory.createImportStaticStatement(receiver as PsiClass, "*"))
|
|
||||||
)
|
|
||||||
isPackageReceiver ->
|
isPackageReceiver ->
|
||||||
addImportList.add(
|
addImportList.add(psiElementFactory.createImportStatementOnDemand((receiver as PsiPackage).qualifiedName))
|
||||||
AddImportData(psiElementFactory.createImportStatementOnDemand((receiver as PsiPackage).qualifiedName))
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
when {
|
when {
|
||||||
isClassSelector ->
|
isClassSelector ->
|
||||||
addImportList.add(
|
addImportList.add(psiElementFactory.createImportStatement(selector as PsiClass))
|
||||||
AddImportData(psiElementFactory.createImportStatement(selector as PsiClass))
|
|
||||||
)
|
|
||||||
isClassReceiver ->
|
isClassReceiver ->
|
||||||
addImportList.add(
|
addImportList.add(
|
||||||
AddImportData(
|
psiElementFactory.createImportStaticStatement(
|
||||||
psiElementFactory.createImportStaticStatement(
|
receiver as PsiClass,
|
||||||
receiver as PsiClass,
|
importPath.importedName!!.asString()
|
||||||
importPath.importedName!!.asString()
|
|
||||||
)
|
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
@@ -144,63 +138,69 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
private data class AddImportData(val importStatement: PsiImportStatementBase, val shouldAddToTarget: Boolean = false)
|
|
||||||
|
|
||||||
fun tryResolveReferences() {
|
fun tryResolveReferences() {
|
||||||
val task = {
|
val task = {
|
||||||
val addImportList = mutableListOf<AddImportData>()
|
fun performWriteAction(block: () -> Unit) {
|
||||||
|
ApplicationManager.getApplication().invokeAndWait { runWriteAction { block() } }
|
||||||
|
}
|
||||||
|
|
||||||
fun tryResolveReference(reference: PsiQualifiedReference): Boolean {
|
fun tryResolveReference(reference: PsiQualifiedReference): Boolean {
|
||||||
if (reference.resolve() != null) return true
|
if (runReadAction { reference.resolve() } != null) return true
|
||||||
val referenceName = reference.referenceName ?: return false
|
val referenceName = runReadAction { reference.referenceName } ?: return false
|
||||||
if (referenceName in failedToResolveReferenceNames) return false
|
if (referenceName in failedToResolveReferenceNames) return false
|
||||||
if (reference.qualifier != null) return false
|
if (runReadAction { reference.qualifier } != null) return false
|
||||||
val classes = shortNameCache.getClassesByName(referenceName, scope)
|
|
||||||
.mapNotNull { psiClass ->
|
val classes = runReadAction {
|
||||||
val containingFile = psiClass.containingFile
|
shortNameCache.getClassesByName(referenceName, scope)
|
||||||
if (ProjectRootsUtil.isInProjectOrLibraryContent(containingFile)) {
|
.mapNotNull { psiClass ->
|
||||||
psiClass to psiClass.getJavaMemberDescriptor() as? ClassDescriptor
|
val containingFile = psiClass.containingFile
|
||||||
} else null
|
if (ProjectRootsUtil.isInProjectOrLibraryContent(containingFile)) {
|
||||||
}.filter { canBeImported(it.second) }
|
psiClass to psiClass.getJavaMemberDescriptor() as? ClassDescriptor
|
||||||
|
} else null
|
||||||
|
}.filter { canBeImported(it.second) }
|
||||||
|
}
|
||||||
|
|
||||||
classes.find { (_, descriptor) ->
|
classes.find { (_, descriptor) ->
|
||||||
JavaToKotlinClassMap.mapPlatformClass(descriptor!!).isNotEmpty()
|
JavaToKotlinClassMap.mapPlatformClass(descriptor!!).isNotEmpty()
|
||||||
}?.let { (psiClass, _) ->
|
}?.let { (psiClass, _) ->
|
||||||
addImportList.add(AddImportData(psiElementFactory.createImportStatement(psiClass)))
|
performWriteAction { addImport(psiElementFactory.createImportStatement(psiClass)) }
|
||||||
}
|
}
|
||||||
if (reference.resolve() != null) return true
|
if (runReadAction { reference.resolve() } != null) return true
|
||||||
|
|
||||||
classes.singleOrNull()?.let { (psiClass, _) ->
|
classes.singleOrNull()?.let { (psiClass, _) ->
|
||||||
addImportList.add(AddImportData(psiElementFactory.createImportStatement(psiClass), true))
|
performWriteAction { addImport(psiElementFactory.createImportStatement(psiClass), true) }
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
when {
|
||||||
reference.resolve() != null -> return true
|
runReadAction { reference.resolve() } != null -> return true
|
||||||
classes.isNotEmpty() -> {
|
classes.isNotEmpty() -> {
|
||||||
ambiguityInResolution = true
|
ambiguityInResolution = true
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val members = (shortNameCache.getMethodsByName(referenceName, scope).asList() +
|
val members = runReadAction {
|
||||||
shortNameCache.getFieldsByName(referenceName, scope).asList())
|
(shortNameCache.getMethodsByName(referenceName, scope).asList() +
|
||||||
.asSequence()
|
shortNameCache.getFieldsByName(referenceName, scope).asList())
|
||||||
.map { it as PsiMember }
|
.asSequence()
|
||||||
.filter { it.getNullableModuleInfo() != null }
|
.map { it as PsiMember }
|
||||||
.map { it to it.getJavaMemberDescriptor(resolutionFacade) as? DeclarationDescriptorWithVisibility }
|
.filter { it.getNullableModuleInfo() != null }
|
||||||
.filter { canBeImported(it.second) }
|
.map { it to it.getJavaMemberDescriptor(resolutionFacade) as? DeclarationDescriptorWithVisibility }
|
||||||
.toList()
|
.filter { canBeImported(it.second) }
|
||||||
|
.toList()
|
||||||
|
}
|
||||||
|
|
||||||
members.singleOrNull()?.let { (psiMember, _) ->
|
members.singleOrNull()?.let { (psiMember, _) ->
|
||||||
addImportList.add(
|
performWriteAction {
|
||||||
AddImportData(
|
addImport(
|
||||||
psiElementFactory.createImportStaticStatement(psiMember.containingClass!!, psiMember.name!!),
|
psiElementFactory.createImportStaticStatement(psiMember.containingClass!!, psiMember.name!!),
|
||||||
true
|
true
|
||||||
)
|
)
|
||||||
)
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
when {
|
when {
|
||||||
reference.resolve() != null -> return false
|
runReadAction { reference.resolve() } != null -> return false
|
||||||
members.isNotEmpty() -> ambiguityInResolution = true
|
members.isNotEmpty() -> ambiguityInResolution = true
|
||||||
else -> couldNotResolve = true
|
else -> couldNotResolve = true
|
||||||
}
|
}
|
||||||
@@ -220,17 +220,9 @@ class PlainTextPasteImportResolver(private val dataForConversion: DataForConvers
|
|||||||
reversed.forEachIndexed { index, value ->
|
reversed.forEachIndexed { index, value ->
|
||||||
ProgressManager.getInstance().progressIndicator?.fraction = 1.0 * index / reversed.size
|
ProgressManager.getInstance().progressIndicator?.fraction = 1.0 * index / reversed.size
|
||||||
val reference = value.reference as PsiQualifiedReference
|
val reference = value.reference as PsiQualifiedReference
|
||||||
addImportList.clear()
|
if (!tryResolveReference(reference)) {
|
||||||
val tryResolveReference = runReadAction { tryResolveReference(reference) }
|
runReadAction { reference.referenceName }?.let {
|
||||||
if (!tryResolveReference) {
|
failedToResolveReferenceNames += it
|
||||||
ApplicationManager.getApplication().invokeAndWait {
|
|
||||||
runWriteAction {
|
|
||||||
addImportList.forEach { addImport(it) }
|
|
||||||
val referenceName = reference.referenceName
|
|
||||||
if (referenceName != null) {
|
|
||||||
failedToResolveReferenceNames += referenceName
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user