diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index de2cb0676aa..6a1f728a7a7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -39,6 +39,7 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptor import org.jetbrains.kotlin.descriptors.PackageViewDescriptor import org.jetbrains.kotlin.idea.KotlinBundle import org.jetbrains.kotlin.idea.KotlinDescriptorIconProvider +import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.core.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.imports.importableFqName @@ -52,15 +53,17 @@ import org.jetbrains.kotlin.psi.KtElement import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtSimpleNameExpression -internal fun createSingleImportAction(project: Project, - editor: Editor, - element: KtElement, - descriptors: Collection): KotlinAddImportAction { +internal fun createSingleImportAction( + project: Project, + editor: Editor, + element: KtElement, + fqNames: Collection +): KotlinAddImportAction { + val file = element.getContainingKtFile() val prioritizer = Prioritizer(element.getContainingKtFile()) - val variants = descriptors - .groupBy { it.importableFqName!! } - .map { - val (fqName, sameFqNameDescriptors) = it + val variants = fqNames + .map { fqName -> + val sameFqNameDescriptors = file.resolveImportReference(fqName) val priority = sameFqNameDescriptors.map { prioritizer.priority(it) }.min()!! Prioritizer.VariantWithPriority(SingleImportVariant(fqName, sameFqNameDescriptors), priority) } @@ -70,25 +73,29 @@ internal fun createSingleImportAction(project: Project, return KotlinAddImportAction(project, editor, element, variants) } -internal fun createGroupedImportsAction(project: Project, - editor: Editor, - element: KtElement, - autoImportDescription: String, - descriptors: Collection): KotlinAddImportAction { +internal fun createGroupedImportsAction( + project: Project, + editor: Editor, + element: KtElement, + autoImportDescription: String, + fqNames: Collection +): KotlinAddImportAction { val prioritizer = DescriptorGroupPrioritizer(element.getContainingKtFile()) - val variants = descriptors - .groupBy { it.importableFqName!!.parentOrNull() ?: FqName.ROOT } + val file = element.getContainingKtFile() + val variants = fqNames + .groupBy { it.parentOrNull() ?: FqName.ROOT } .map { - val samePackageDescriptors = it.value - val variant = if (samePackageDescriptors.size > 1) { - GroupedImportVariant(autoImportDescription, samePackageDescriptors) + val samePackageFqNames = it.value + val descriptors = samePackageFqNames.flatMap { file.resolveImportReference(it) } + val variant = if (samePackageFqNames.size > 1) { + GroupedImportVariant(autoImportDescription, descriptors) } else { - SingleImportVariant(samePackageDescriptors.first().importableFqName!!, samePackageDescriptors) + SingleImportVariant(samePackageFqNames.first(), descriptors) } - val priority = prioritizer.priority(samePackageDescriptors) + val priority = prioritizer.priority(descriptors) DescriptorGroupPrioritizer.VariantWithPriority(variant, priority) } .sortedBy { diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt index f2e48477fc4..b17c600cc51 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/ImportFix.kt @@ -56,6 +56,7 @@ import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.idea.util.CallTypeAndReceiver import org.jetbrains.kotlin.idea.util.getResolutionScope import org.jetbrains.kotlin.incremental.components.NoLookupLocation +import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.KtPsiUtil.isSelectorInQualified @@ -64,7 +65,6 @@ import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelectorOrThis import org.jetbrains.kotlin.psi.psiUtil.getStrictParentOfType import org.jetbrains.kotlin.psi.psiUtil.isImportDirectiveExpression import org.jetbrains.kotlin.resolve.BindingContext -import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoAfter import org.jetbrains.kotlin.resolve.bindingContextUtil.getDataFlowInfoBefore import org.jetbrains.kotlin.resolve.calls.callUtil.getParentCall import org.jetbrains.kotlin.resolve.calls.context.ContextDependency @@ -91,8 +91,8 @@ internal abstract class ImportFixBase protected constructor( private val modificationCountOnCreate = PsiModificationTracker.SERVICE.getInstance(project).modificationCount - private val suggestionCount: Int by CachedValueProperty( - calculator = { computeSuggestions().size }, + protected val suggestions: Collection by CachedValueProperty( + calculator = { computeSuggestions() }, timestampCalculator = { PsiModificationTracker.SERVICE.getInstance(project).modificationCount } ) @@ -108,7 +108,7 @@ internal abstract class ImportFixBase protected constructor( if (ApplicationManager.getApplication().isUnitTestMode && HintManager.getInstance().hasShownHintsThatWillHideByOtherHint(true)) return false - if (suggestionCount == 0) return false + if (suggestions.isEmpty()) return false return createAction(project, editor, element).showHint() } @@ -118,7 +118,7 @@ internal abstract class ImportFixBase protected constructor( override fun getFamilyName() = KotlinBundle.message("import.fix") override fun isAvailable(project: Project, editor: Editor?, file: PsiFile) - = element != null && super.isAvailable(project, editor, file) && suggestionCount > 0 + = element != null && super.isAvailable(project, editor, file) && suggestions.isNotEmpty() override fun invoke(project: Project, editor: Editor?, file: KtFile) { val element = element ?: return @@ -132,10 +132,10 @@ internal abstract class ImportFixBase protected constructor( private fun isOutdated() = modificationCountOnCreate != PsiModificationTracker.SERVICE.getInstance(project).modificationCount protected open fun createAction(project: Project, editor: Editor, element: KtExpression): KotlinAddImportAction { - return createSingleImportAction(project, editor, element, computeSuggestions()) + return createSingleImportAction(project, editor, element, suggestions) } - fun computeSuggestions(): Collection { + fun computeSuggestions(): Collection { val element = element ?: return emptyList() if (!element.isValid) return emptyList() if (element.containingFile !is KtFile) return emptyList() @@ -146,9 +146,11 @@ internal abstract class ImportFixBase protected constructor( if (importNames.isEmpty()) return emptyList() - return importNames.flatMapTo(LinkedHashSet()) { - computeSuggestionsForName(it, callTypeAndReceiver) - } + return importNames + .flatMap { computeSuggestionsForName(it, callTypeAndReceiver) } + .distinct() + .map { it.fqNameSafe } + .distinct() } private fun computeSuggestionsForName(name: Name, callTypeAndReceiver: CallTypeAndReceiver<*, *>): Collection { @@ -323,7 +325,7 @@ internal class DelegateAccessorsImportFix( override fun createAction(project: Project, editor: Editor, element: KtExpression): KotlinAddImportAction { if (solveSeveralProblems) { - return createGroupedImportsAction(project, editor, element, "Delegate accessors", computeSuggestions()) + return createGroupedImportsAction(project, editor, element, "Delegate accessors", suggestions) } return super.createAction(project, editor, element) @@ -364,7 +366,7 @@ internal class ComponentsImportFix( override fun createAction(project: Project, editor: Editor, element: KtExpression): KotlinAddImportAction { if (solveSeveralProblems) { - return createGroupedImportsAction(project, editor, element, "Component functions", computeSuggestions()) + return createGroupedImportsAction(project, editor, element, "Component functions", suggestions) } return super.createAction(project, editor, element) diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt index 31ab090bd42..23e0447c7e1 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/KotlinReferenceImporter.kt @@ -26,8 +26,8 @@ import com.intellij.psi.PsiFile import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.idea.actions.createSingleImportAction import org.jetbrains.kotlin.idea.caches.resolve.analyze +import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference import org.jetbrains.kotlin.idea.core.targetDescriptors -import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.psi.KtSimpleNameExpression @@ -88,11 +88,11 @@ class KotlinReferenceImporter : ReferenceImporter { if (mainReference.resolveToDescriptors(bindingContext).isNotEmpty()) return false val suggestions = ImportFix(this).computeSuggestions() - - if (suggestions.distinctBy { it.importableFqName!! }.size != 1) return false + if (suggestions.size != 1) return false + val descriptors = file.resolveImportReference(suggestions.single()) // we do not auto-import nested classes because this will probably add qualification into the text and this will confuse the user - if (suggestions.any { it is ClassDescriptor && it.containingDeclaration is ClassDescriptor }) return false + if (descriptors.any { it is ClassDescriptor && it.containingDeclaration is ClassDescriptor }) return false var result = false CommandProcessor.getInstance().runUndoTransparentAction {