diff --git a/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt b/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt index 726d4f273d5..9c1d758715a 100644 --- a/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt +++ b/compiler/psi/src/org/jetbrains/kotlin/psi/KtFile.kt @@ -174,6 +174,10 @@ open class KtFile(viewProvider: FileViewProvider, val isCompiled: Boolean) : fun findImportByAlias(name: String): KtImportDirective? = importDirectives.firstOrNull { name == it.aliasName } + fun findAliasByFqName(fqName: FqName): KtImportAlias? = importDirectives.firstOrNull { + fqName == it.importedFqName + }?.alias + @Deprecated("") // getPackageFqName should be used instead override fun getPackageName(): String { return packageFqName.asString() diff --git a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt index 837be9ab754..9bcc61eec85 100644 --- a/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt +++ b/idea/src/org/jetbrains/kotlin/idea/actions/KotlinAddImportAction.kt @@ -45,6 +45,7 @@ import org.jetbrains.kotlin.idea.core.ImportableFqNameClassifier import org.jetbrains.kotlin.idea.imports.importableFqName import org.jetbrains.kotlin.idea.references.KtSimpleNameReference import org.jetbrains.kotlin.idea.references.mainReference +import org.jetbrains.kotlin.idea.references.resolveMainReferenceToDescriptors import org.jetbrains.kotlin.idea.util.ImportInsertHelper import org.jetbrains.kotlin.idea.util.application.executeWriteCommand import org.jetbrains.kotlin.name.FqName @@ -195,7 +196,8 @@ class KotlinAddImportAction internal constructor( } private fun addImport(variant: AutoImportVariant) { - PsiDocumentManager.getInstance(project).commitAllDocuments() + val psiDocumentManager = PsiDocumentManager.getInstance(project) + psiDocumentManager.commitAllDocuments() project.executeWriteCommand(QuickFixBundle.message("add.import")) { if (!element.isValid) return@executeWriteCommand @@ -207,15 +209,27 @@ class KotlinAddImportAction internal constructor( StatisticsManager.getInstance().incUseCount(PsiProximityComparator.STATISTICS_KEY, it, location) } - for (descriptor in variant.descriptorsToImport) { + variant.descriptorsToImport.forEach { descriptor -> // for class or package we use ShortenReferences because we not necessary insert an import but may want to // insert partly qualified name - if (descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) { + + val importAlias = descriptor.importableFqName?.let { file.findAliasByFqName(it) } + if (importAlias != null || descriptor is ClassDescriptor || descriptor is PackageViewDescriptor) { if (element is KtSimpleNameExpression) { - element.mainReference.bindToFqName( - descriptor.importableFqName!!, - KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING - ) + if (importAlias != null) { + importAlias.nameIdentifier?.copy()?.let { element.getIdentifier()?.replace(it) } + val resultDescriptor = element.resolveMainReferenceToDescriptors().firstOrNull() + if (resultDescriptor == descriptor) { + return@forEach + } + } + + descriptor.importableFqName?.let { + element.mainReference.bindToFqName( + it, + KtSimpleNameReference.ShorteningMode.FORCED_SHORTENING + ) + } } } else { ImportInsertHelper.getInstance(project).importDescriptor(file, descriptor) @@ -289,8 +303,10 @@ internal interface AutoImportVariant { DescriptorToSourceUtilsIde.getAnyDeclaration(project, descriptorsToImport.first()) } -private class GroupedImportVariant(val autoImportDescription: String, val descriptors: Collection) : - AutoImportVariant { +private class GroupedImportVariant( + val autoImportDescription: String, + val descriptors: Collection +) : AutoImportVariant { override val excludeFqNameCheck: FqName = descriptors.first().importableFqName!!.parent() override val descriptorsToImport: Collection get() = descriptors override val hint: String get() = "$autoImportDescription from $excludeFqNameCheck" diff --git a/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.after.kt b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.after.kt new file mode 100644 index 00000000000..e503f302639 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.after.kt @@ -0,0 +1,7 @@ +// "Import" "true" +// ERROR: Unresolved reference: ImportedClass + +import editor.completion.apx.ImportedClass as Class2 +fun context() { + val c: Class2 +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Dependency.kt b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Dependency.kt new file mode 100644 index 00000000000..dc88b66df6a --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Dependency.kt @@ -0,0 +1,2 @@ +package editor.completion.apx +class ImportedClass \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Main.kt b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Main.kt new file mode 100644 index 00000000000..481ef6948da --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Main.kt @@ -0,0 +1,7 @@ +// "Import" "true" +// ERROR: Unresolved reference: ImportedClass + +import editor.completion.apx.ImportedClass as Class2 +fun context() { + val c: ImportedClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.after.kt b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.after.kt new file mode 100644 index 00000000000..5064a567a00 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.after.kt @@ -0,0 +1,8 @@ +// "Import" "true" +// ERROR: Unresolved reference: ImportedClass + +import editor.completion.apx.ImportedClass as Class2 +fun context() { + class Class2 + val c: editor.completion.apx.ImportedClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Dependency.kt b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Dependency.kt new file mode 100644 index 00000000000..dc88b66df6a --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Dependency.kt @@ -0,0 +1,2 @@ +package editor.completion.apx +class ImportedClass \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt new file mode 100644 index 00000000000..edf66f82bdc --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt @@ -0,0 +1,8 @@ +// "Import" "true" +// ERROR: Unresolved reference: ImportedClass + +import editor.completion.apx.ImportedClass as Class2 +fun context() { + class Class2 + val c: ImportedClass +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.after.kt b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.after.kt new file mode 100644 index 00000000000..610ec520e32 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.after.kt @@ -0,0 +1,8 @@ +// "Import" "true" +// ERROR: Unresolved reference: importedFunA + +import editor.completion.apx.importedFunA as funA +fun context() { + val funA = 42 + funA() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.before.Dependency.kt b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.before.Dependency.kt new file mode 100644 index 00000000000..a02b16b92e0 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.before.Dependency.kt @@ -0,0 +1,2 @@ +package editor.completion.apx +fun importedFunA() {} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.before.Main.kt b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.before.Main.kt new file mode 100644 index 00000000000..50e579efde6 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.before.Main.kt @@ -0,0 +1,8 @@ +// "Import" "true" +// ERROR: Unresolved reference: importedFunA + +import editor.completion.apx.importedFunA as funA +fun context() { + val funA = 42 + importedFunA() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.after.kt b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.after.kt new file mode 100644 index 00000000000..e30b6b0302e --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.after.kt @@ -0,0 +1,8 @@ +// "Import" "true" +// ERROR: Unresolved reference: importedFunA + +import editor.completion.apx.importedFunA as funA +fun context() { + fun funA() {} + editor.completion.apx.importedFunA() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Dependency.kt b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Dependency.kt new file mode 100644 index 00000000000..a02b16b92e0 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Dependency.kt @@ -0,0 +1,2 @@ +package editor.completion.apx +fun importedFunA() {} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt new file mode 100644 index 00000000000..8969df0cd88 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt @@ -0,0 +1,8 @@ +// "Import" "true" +// ERROR: Unresolved reference: importedFunA + +import editor.completion.apx.importedFunA as funA +fun context() { + fun funA() {} + importedFunA() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasLetAlreadyExists.kt b/idea/testData/quickfix/autoImports/importAliasLetAlreadyExists.kt new file mode 100644 index 00000000000..cce7cc05d02 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasLetAlreadyExists.kt @@ -0,0 +1,10 @@ +// "Import" "true" +// WITH_RUNTIME + +import kotlin.let as let1 + +fun main() { + 1.let { + println(it) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasLetAlreadyExists.kt.after b/idea/testData/quickfix/autoImports/importAliasLetAlreadyExists.kt.after new file mode 100644 index 00000000000..4f128a0e498 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasLetAlreadyExists.kt.after @@ -0,0 +1,10 @@ +// "Import" "true" +// WITH_RUNTIME + +import kotlin.let as let1 + +fun main() { + 1.let1 { + println(it) + } +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.after.kt b/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.after.kt new file mode 100644 index 00000000000..0e8d89c92d4 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.after.kt @@ -0,0 +1,7 @@ +// "Import" "true" +// ERROR: Unresolved reference: importedValA + +import editor.completion.apx.importedValA as valA +fun context() { + valA() +} \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.before.Dependency.kt b/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.before.Dependency.kt new file mode 100644 index 00000000000..946c4f116a3 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.before.Dependency.kt @@ -0,0 +1,2 @@ +package editor.completion.apx +val importedValA = "" \ No newline at end of file diff --git a/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.before.Main.kt b/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.before.Main.kt new file mode 100644 index 00000000000..4b5b7c046a6 --- /dev/null +++ b/idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.before.Main.kt @@ -0,0 +1,7 @@ +// "Import" "true" +// ERROR: Unresolved reference: importedValA + +import editor.completion.apx.importedValA as valA +fun context() { + importedValA() +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java index e710e33462b..ab20cc68312 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixMultiFileTestGenerated.java @@ -595,6 +595,31 @@ public class QuickFixMultiFileTestGenerated extends AbstractQuickFixMultiFileTes runTest("idea/testData/quickfix/autoImports/functionImport.before.Main.kt"); } + @TestMetadata("importAliasClassAlreadyExists.before.Main.kt") + public void testImportAliasClassAlreadyExists() throws Exception { + runTest("idea/testData/quickfix/autoImports/importAliasClassAlreadyExists.before.Main.kt"); + } + + @TestMetadata("importAliasClassAlreadyExistsCollision.before.Main.kt") + public void testImportAliasClassAlreadyExistsCollision() throws Exception { + runTest("idea/testData/quickfix/autoImports/importAliasClassAlreadyExistsCollision.before.Main.kt"); + } + + @TestMetadata("importAliasFunctionAlreadyExists.before.Main.kt") + public void testImportAliasFunctionAlreadyExists() throws Exception { + runTest("idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExists.before.Main.kt"); + } + + @TestMetadata("importAliasFunctionAlreadyExistsCollision.before.Main.kt") + public void testImportAliasFunctionAlreadyExistsCollision() throws Exception { + runTest("idea/testData/quickfix/autoImports/importAliasFunctionAlreadyExistsCollision.before.Main.kt"); + } + + @TestMetadata("importAliasPropertyAlreadyExists.before.Main.kt") + public void testImportAliasPropertyAlreadyExists() throws Exception { + runTest("idea/testData/quickfix/autoImports/importAliasPropertyAlreadyExists.before.Main.kt"); + } + @TestMetadata("importInFirstPartInQualifiedExpression.before.Main.kt") public void testImportInFirstPartInQualifiedExpression() throws Exception { runTest("idea/testData/quickfix/autoImports/importInFirstPartInQualifiedExpression.before.Main.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index 0f34dccf2fb..a3a43a0802a 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -1670,6 +1670,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { runTest("idea/testData/quickfix/autoImports/excludedFromImport.kt"); } + @TestMetadata("importAliasLetAlreadyExists.kt") + public void testImportAliasLetAlreadyExists() throws Exception { + runTest("idea/testData/quickfix/autoImports/importAliasLetAlreadyExists.kt"); + } + @TestMetadata("inPrimaryConstructor.kt") public void testInPrimaryConstructor() throws Exception { runTest("idea/testData/quickfix/autoImports/inPrimaryConstructor.kt");