From ddcff3c96d31d25e507461d25307472145fbc930 Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Tue, 28 Mar 2017 23:16:45 +0300 Subject: [PATCH] Fix ImportFixBase to compute suggestions not on EDT --- .../kotlin/idea/quickfix/ImportFix.kt | 82 ++++++++++--------- .../idea/quickfix/KotlinReferenceImporter.kt | 2 +- 2 files changed, 45 insertions(+), 39 deletions(-) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt index b4e2ef00479..7ce52dbf7b4 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt @@ -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.collectFunctions import org.jetbrains.kotlin.util.OperatorNameConventions -import org.jetbrains.kotlin.utils.CachedValueProperty import java.util.* /** @@ -89,10 +88,11 @@ internal abstract class ImportFixBase protected constructor( private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(project).modificationCount - protected val suggestions: Collection by CachedValueProperty( - calculator = { computeSuggestions() }, - timestampCalculator = { PsiModificationTracker.SERVICE.getInstance(project).modificationCount } - ) + protected lateinit var suggestions: Collection + + fun computeSuggestions() { + suggestions = collectSuggestions() + } protected open fun getSupportedErrors() = factory.supportedErrors @@ -133,7 +133,7 @@ internal abstract class ImportFixBase protected constructor( return createSingleImportAction(project, editor, element, suggestions) } - fun computeSuggestions(): Collection { + fun collectSuggestions(): Collection { val element = element ?: return emptyList() if (!element.isValid) return emptyList() if (element.containingFile !is KtFile) return emptyList() @@ -145,13 +145,13 @@ internal abstract class ImportFixBase protected constructor( if (importNames.isEmpty()) return emptyList() return importNames - .flatMap { computeSuggestionsForName(it, callTypeAndReceiver) } + .flatMap { collectSuggestionsForName(it, callTypeAndReceiver) } .distinct() .map { it.fqNameSafe } .distinct() } - private fun computeSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection { + private fun collectSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection { val element = element ?: return emptyList() val nameStr = name.asString() if (nameStr.isEmpty()) return emptyList() @@ -222,7 +222,20 @@ internal abstract class ImportFixBase protected constructor( val supportedErrors: Collection> by lazy { QuickFixes.getInstance().getDiagnostics(this) } override fun isApplicableForCodeFragment() = true + + abstract fun createImportAction(diagnostic: Diagnostic): ImportFixBase<*>? + + open fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection): List> = emptyList() + + override final fun createAction(diagnostic: Diagnostic): IntentionAction? { + return createImportAction(diagnostic)?.apply { computeSuggestions() } + } + + override final fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection): List { + return createImportActionsForAllProblems(sameTypeDiagnostics).onEach { it.computeSuggestions() } + } } + } internal abstract class OrdinaryImportFixBase(expression: T, factory: Factory) : ImportFixBase(expression, factory) { @@ -319,10 +332,8 @@ internal class ImportFix(expression: KtSimpleNameExpression) : OrdinaryImportFix } companion object MyFactory : Factory() { - override fun createAction(diagnostic: Diagnostic) = - (diagnostic.psiElement as? KtSimpleNameExpression)?.let { - ImportFix(it).apply { computeSuggestions() } - } + override fun createImportAction(diagnostic: Diagnostic) = + (diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportFix) } } @@ -346,10 +357,8 @@ internal class ImportConstructorReferenceFix(expression: KtSimpleNameExpression) override val importNames = element?.mainReference?.resolvesByNames ?: emptyList() companion object MyFactory : Factory() { - override fun createAction(diagnostic: Diagnostic) = - (diagnostic.psiElement as? KtSimpleNameExpression)?.let { - ImportConstructorReferenceFix(it).apply { computeSuggestions() } - } + override fun createImportAction(diagnostic: Diagnostic) = + (diagnostic.psiElement as? KtSimpleNameExpression)?.let(::ImportConstructorReferenceFix) } } @@ -359,10 +368,8 @@ internal class InvokeImportFix(expression: KtExpression) : OrdinaryImportFixBase override fun getCallTypeAndReceiver() = element?.let { CallTypeAndReceiver.OPERATOR(it) } companion object MyFactory : Factory() { - override fun createAction(diagnostic: Diagnostic) = - (diagnostic.psiElement as? KtExpression)?.let { - InvokeImportFix(it).apply { computeSuggestions() } - } + override fun createImportAction(diagnostic: Diagnostic) = + (diagnostic.psiElement as? KtExpression)?.let(::InvokeImportFix) } } @@ -385,13 +392,13 @@ internal open class ArrayAccessorImportFix( } } - override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { + override fun createImportAction(diagnostic: Diagnostic): ArrayAccessorImportFix? { val factory = diagnostic.factory assert(factory == Errors.NO_GET_METHOD || factory == Errors.NO_SET_METHOD) val element = diagnostic.psiElement 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 @@ -426,13 +433,13 @@ internal class DelegateAccessorsImportFix( }.distinct() } - override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { - return (diagnostic.psiElement as? KtExpression)?.let { - DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false).apply { computeSuggestions() } - } - } + override fun createImportAction(diagnostic: Diagnostic) = + (diagnostic.psiElement as? KtExpression)?.let { + DelegateAccessorsImportFix(it, importNames(listOf(diagnostic)), false) + } - override fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection): List { + + override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection): List { val element = sameTypeDiagnostics.first().psiElement val names = importNames(sameTypeDiagnostics) return listOfNotNull((element as? KtExpression)?.let { DelegateAccessorsImportFix(it, names, true) }) @@ -460,13 +467,12 @@ internal class ComponentsImportFix( private fun importNames(diagnostics: Collection) = diagnostics.map { Name.identifier(Errors.COMPONENT_FUNCTION_MISSING.cast(it).a.identifier) } - override fun createAction(diagnostic: Diagnostic): KotlinQuickFixAction? { - return (diagnostic.psiElement as? KtExpression)?.let { - ComponentsImportFix(it, importNames(listOf(diagnostic)), false).apply { computeSuggestions() } - } - } + override fun createImportAction(diagnostic: Diagnostic) = + (diagnostic.psiElement as? KtExpression)?.let { + ComponentsImportFix(it, importNames(listOf(diagnostic)), false) + } - override fun doCreateActionsForAllProblems(sameTypeDiagnostics: Collection): List { + override fun createImportActionsForAllProblems(sameTypeDiagnostics: Collection): List { val element = sameTypeDiagnostics.first().psiElement val names = importNames(sameTypeDiagnostics) val solveSeveralProblems = sameTypeDiagnostics.size > 1 @@ -552,17 +558,17 @@ internal class ImportForMismatchingArgumentsFix( } companion object MyFactory : Factory() { - override fun createAction(diagnostic: Diagnostic): ImportForMismatchingArgumentsFix? { + override fun createImportAction(diagnostic: Diagnostic): ImportForMismatchingArgumentsFix? { //TODO: not only KtCallExpression val callExpression = diagnostic.psiElement.getStrictParentOfType() ?: return null val nameExpression = callExpression.calleeExpression as? KtNameReferenceExpression ?: return null - return ImportForMismatchingArgumentsFix(nameExpression).apply { computeSuggestions() } + return ImportForMismatchingArgumentsFix(nameExpression) } } } -object ImportForMissingOperatorFactory : KotlinSingleIntentionActionFactory() { - override fun createAction(diagnostic: Diagnostic): IntentionAction? { +internal object ImportForMissingOperatorFactory : ImportFixBase.Factory() { + override fun createImportAction(diagnostic: Diagnostic): ImportFixBase<*>? { val element = diagnostic.psiElement as? KtExpression ?: return null val operatorDescriptor = Errors.OPERATOR_MODIFIER_REQUIRED.cast(diagnostic).a val name = operatorDescriptor.name diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt index 23e0447c7e1..bd8eba38d2a 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt @@ -87,7 +87,7 @@ class KotlinReferenceImporter : ReferenceImporter { val bindingContext = analyze(BodyResolveMode.PARTIAL) if (mainReference.resolveToDescriptors(bindingContext).isNotEmpty()) return false - val suggestions = ImportFix(this).computeSuggestions() + val suggestions = ImportFix(this).collectSuggestions() if (suggestions.size != 1) return false val descriptors = file.resolveImportReference(suggestions.single())