Fix ImportFixBase to compute suggestions not on EDT
This commit is contained in:
committed by
Simon Ogorodnik
parent
94b261d701
commit
ddcff3c96d
@@ -75,7 +75,6 @@ import org.jetbrains.kotlin.resolve.scopes.ExplicitImportsScope
|
|||||||
import org.jetbrains.kotlin.resolve.scopes.utils.addImportingScope
|
import org.jetbrains.kotlin.resolve.scopes.utils.addImportingScope
|
||||||
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
|
import org.jetbrains.kotlin.resolve.scopes.utils.collectFunctions
|
||||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||||
import org.jetbrains.kotlin.utils.CachedValueProperty
|
|
||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -89,10 +88,11 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
|||||||
|
|
||||||
private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(project).modificationCount
|
private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(project).modificationCount
|
||||||
|
|
||||||
protected val suggestions: Collection<FqName> by CachedValueProperty(
|
protected lateinit var suggestions: Collection<FqName>
|
||||||
calculator = { computeSuggestions() },
|
|
||||||
timestampCalculator = { PsiModificationTracker.SERVICE.getInstance(project).modificationCount }
|
fun computeSuggestions() {
|
||||||
)
|
suggestions = collectSuggestions()
|
||||||
|
}
|
||||||
|
|
||||||
protected open fun getSupportedErrors() = factory.supportedErrors
|
protected open fun getSupportedErrors() = factory.supportedErrors
|
||||||
|
|
||||||
@@ -133,7 +133,7 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
|||||||
return createSingleImportAction(project, editor, element, suggestions)
|
return createSingleImportAction(project, editor, element, suggestions)
|
||||||
}
|
}
|
||||||
|
|
||||||
fun computeSuggestions(): Collection<FqName> {
|
fun collectSuggestions(): Collection<FqName> {
|
||||||
val element = element ?: return emptyList()
|
val element = element ?: return emptyList()
|
||||||
if (!element.isValid) return emptyList()
|
if (!element.isValid) return emptyList()
|
||||||
if (element.containingFile !is KtFile) return emptyList()
|
if (element.containingFile !is KtFile) return emptyList()
|
||||||
@@ -145,13 +145,13 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
|||||||
if (importNames.isEmpty()) return emptyList()
|
if (importNames.isEmpty()) return emptyList()
|
||||||
|
|
||||||
return importNames
|
return importNames
|
||||||
.flatMap { computeSuggestionsForName(it, callTypeAndReceiver) }
|
.flatMap { collectSuggestionsForName(it, callTypeAndReceiver) }
|
||||||
.distinct()
|
.distinct()
|
||||||
.map { it.fqNameSafe }
|
.map { it.fqNameSafe }
|
||||||
.distinct()
|
.distinct()
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun computeSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection<DeclarationDescriptor> {
|
private fun collectSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection<DeclarationDescriptor> {
|
||||||
val element = element ?: return emptyList()
|
val element = element ?: return emptyList()
|
||||||
val nameStr = name.asString()
|
val nameStr = name.asString()
|
||||||
if (nameStr.isEmpty()) return emptyList()
|
if (nameStr.isEmpty()) return emptyList()
|
||||||
@@ -222,7 +222,20 @@ internal abstract class ImportFixBase<T : KtExpression> protected constructor(
|
|||||||
val supportedErrors: Collection<DiagnosticFactory<*>> by lazy { QuickFixes.getInstance().getDiagnostics(this) }
|
val supportedErrors: Collection<DiagnosticFactory<*>> by lazy { QuickFixes.getInstance().getDiagnostics(this) }
|
||||||
|
|
||||||
override fun isApplicableForCodeFragment() = true
|
override fun isApplicableForCodeFragment() = true
|
||||||
|
|
||||||
|
abstract fun createImportAction(diagnostic: Diagnostic): ImportFixBase<*>?
|
||||||
|
|
||||||
|
open fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<ImportFixBase<*>> = emptyList()
|
||||||
|
|
||||||
|
override final fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
||||||
|
return createImportAction(diagnostic)?.apply { computeSuggestions() }
|
||||||
|
}
|
||||||
|
|
||||||
|
override final fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<IntentionAction> {
|
||||||
|
return createImportActionsForAllProblems(sameTypeDiagnostics).onEach { it.computeSuggestions() }
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
internal abstract class OrdinaryImportFixBase<T : KtExpression>(expression: T, factory: Factory) : ImportFixBase<T>(expression, factory) {
|
internal abstract class OrdinaryImportFixBase<T : KtExpression>(expression: T, factory: Factory) : ImportFixBase<T>(expression, factory) {
|
||||||
@@ -319,10 +332,8 @@ internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFix
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object MyFactory : Factory() {
|
companion object MyFactory : Factory() {
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
override fun createImportAction(diagnostic: Diagnostic) =
|
||||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let {
|
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportFix)
|
||||||
ImportFix(it).apply { computeSuggestions() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -346,10 +357,8 @@ internal class ImportConstructorReferenceFix(expression: KtSimpleNameExpression)
|
|||||||
override val importNames = element?.mainReference?.resolvesByNames ?: emptyList()
|
override val importNames = element?.mainReference?.resolvesByNames ?: emptyList()
|
||||||
|
|
||||||
companion object MyFactory : Factory() {
|
companion object MyFactory : Factory() {
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
override fun createImportAction(diagnostic: Diagnostic) =
|
||||||
(diagnostic.psiElement as? KtSimpleNameExpression)?.let {
|
(diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportConstructorReferenceFix)
|
||||||
ImportConstructorReferenceFix(it).apply { computeSuggestions() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,10 +368,8 @@ internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase
|
|||||||
override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.OPERATOR(it) }
|
override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.OPERATOR(it) }
|
||||||
|
|
||||||
companion object MyFactory : Factory() {
|
companion object MyFactory : Factory() {
|
||||||
override fun createAction(diagnostic: Diagnostic) =
|
override fun createImportAction(diagnostic: Diagnostic) =
|
||||||
(diagnostic.psiElement as? KtExpression)?.let {
|
(diagnostic.psiElement as? KtExpression)?.let(::InvokeImportFix)
|
||||||
InvokeImportFix(it).apply { computeSuggestions() }
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -385,13 +392,13 @@ internal open class ArrayAccessorImportFix(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtArrayAccessExpression>? {
|
override fun createImportAction(diagnostic: Diagnostic): ArrayAccessorImportFix? {
|
||||||
val factory = diagnostic.factory
|
val factory = diagnostic.factory
|
||||||
assert(factory == Errors.NO_GET_METHOD || factory == Errors.NO_SET_METHOD)
|
assert(factory == Errors.NO_GET_METHOD || factory == Errors.NO_SET_METHOD)
|
||||||
|
|
||||||
val element = diagnostic.psiElement
|
val element = diagnostic.psiElement
|
||||||
if (element is KtArrayAccessExpression && element.arrayExpression != null) {
|
if (element is KtArrayAccessExpression && element.arrayExpression != null) {
|
||||||
return ArrayAccessorImportFix(element, listOf(importName(diagnostic)), true).apply { computeSuggestions() }
|
return ArrayAccessorImportFix(element, listOf(importName(diagnostic)), true)
|
||||||
}
|
}
|
||||||
|
|
||||||
return null
|
return null
|
||||||
@@ -426,13 +433,13 @@ internal class DelegateAccessorsImportFix(
|
|||||||
}.distinct()
|
}.distinct()
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtExpression>? {
|
override fun createImportAction(diagnostic: Diagnostic) =
|
||||||
return (diagnostic.psiElement as? KtExpression)?.let {
|
(diagnostic.psiElement as? KtExpression)?.let {
|
||||||
DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false).apply { computeSuggestions() }
|
DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<IntentionAction> {
|
|
||||||
|
override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<DelegateAccessorsImportFix> {
|
||||||
val element = sameTypeDiagnostics.first().psiElement
|
val element = sameTypeDiagnostics.first().psiElement
|
||||||
val names = importNames(sameTypeDiagnostics)
|
val names = importNames(sameTypeDiagnostics)
|
||||||
return listOfNotNull((element as? KtExpression)?.let { DelegateAccessorsImportFix(it, names, true) })
|
return listOfNotNull((element as? KtExpression)?.let { DelegateAccessorsImportFix(it, names, true) })
|
||||||
@@ -460,13 +467,12 @@ internal class ComponentsImportFix(
|
|||||||
private fun importNames(diagnostics: Collection<Diagnostic>) =
|
private fun importNames(diagnostics: Collection<Diagnostic>) =
|
||||||
diagnostics.map { Name.identifier(Errors.COMPONENT_FUNCTION_MISSING.cast(it).a.identifier) }
|
diagnostics.map { Name.identifier(Errors.COMPONENT_FUNCTION_MISSING.cast(it).a.identifier) }
|
||||||
|
|
||||||
override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction<KtExpression>? {
|
override fun createImportAction(diagnostic: Diagnostic) =
|
||||||
return (diagnostic.psiElement as? KtExpression)?.let {
|
(diagnostic.psiElement as? KtExpression)?.let {
|
||||||
ComponentsImportFix(it, importNames(listOf(diagnostic)), false).apply { computeSuggestions() }
|
ComponentsImportFix(it, importNames(listOf(diagnostic)), false)
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
override fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<IntentionAction> {
|
override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection<Diagnostic>): List<ComponentsImportFix> {
|
||||||
val element = sameTypeDiagnostics.first().psiElement
|
val element = sameTypeDiagnostics.first().psiElement
|
||||||
val names = importNames(sameTypeDiagnostics)
|
val names = importNames(sameTypeDiagnostics)
|
||||||
val solveSeveralProblems = sameTypeDiagnostics.size > 1
|
val solveSeveralProblems = sameTypeDiagnostics.size > 1
|
||||||
@@ -552,17 +558,17 @@ internal class ImportForMismatchingArgumentsFix(
|
|||||||
}
|
}
|
||||||
|
|
||||||
companion object MyFactory : Factory() {
|
companion object MyFactory : Factory() {
|
||||||
override fun createAction(diagnostic: Diagnostic): ImportForMismatchingArgumentsFix? {
|
override fun createImportAction(diagnostic: Diagnostic): ImportForMismatchingArgumentsFix? {
|
||||||
//TODO: not only KtCallExpression
|
//TODO: not only KtCallExpression
|
||||||
val callExpression = diagnostic.psiElement.getStrictParentOfType<KtCallExpression>() ?: return null
|
val callExpression = diagnostic.psiElement.getStrictParentOfType<KtCallExpression>() ?: return null
|
||||||
val nameExpression = callExpression.calleeExpression as? KtNameReferenceExpression ?: return null
|
val nameExpression = callExpression.calleeExpression as? KtNameReferenceExpression ?: return null
|
||||||
return ImportForMismatchingArgumentsFix(nameExpression).apply { computeSuggestions() }
|
return ImportForMismatchingArgumentsFix(nameExpression)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
object ImportForMissingOperatorFactory : KotlinSingleIntentionActionFactory() {
|
internal object ImportForMissingOperatorFactory : ImportFixBase.Factory() {
|
||||||
override fun createAction(diagnostic: Diagnostic): IntentionAction? {
|
override fun createImportAction(diagnostic: Diagnostic): ImportFixBase<*>? {
|
||||||
val element = diagnostic.psiElement as? KtExpression ?: return null
|
val element = diagnostic.psiElement as? KtExpression ?: return null
|
||||||
val operatorDescriptor = Errors.OPERATOR_MODIFIER_REQUIRED.cast(diagnostic).a
|
val operatorDescriptor = Errors.OPERATOR_MODIFIER_REQUIRED.cast(diagnostic).a
|
||||||
val name = operatorDescriptor.name
|
val name = operatorDescriptor.name
|
||||||
|
|||||||
@@ -87,7 +87,7 @@ class KotlinReferenceImporter : ReferenceImporter {
|
|||||||
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
val bindingContext = analyze(BodyResolveMode.PARTIAL)
|
||||||
if (mainReference.resolveToDescriptors(bindingContext).isNotEmpty()) return false
|
if (mainReference.resolveToDescriptors(bindingContext).isNotEmpty()) return false
|
||||||
|
|
||||||
val suggestions = ImportFix(this).computeSuggestions()
|
val suggestions = ImportFix(this).collectSuggestions()
|
||||||
if (suggestions.size != 1) return false
|
if (suggestions.size != 1) return false
|
||||||
val descriptors = file.resolveImportReference(suggestions.single())
|
val descriptors = file.resolveImportReference(suggestions.single())
|
||||||
|
|
||||||
|
|||||||
Reference in New Issue
Block a user