Fix import quickfix if import has import alias

#KT-30669 Fixed
 #KT-7380 Fixed
 #KT-30663 Fixed
This commit is contained in:
Dmitry Gridin
2019-04-03 19:26:05 +07:00
parent 6caf6858fa
commit 4f8e29ad23
21 changed files with 165 additions and 9 deletions
@@ -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()
@@ -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<DeclarationDescriptor>) :
AutoImportVariant {
private class GroupedImportVariant(
val autoImportDescription: String,
val descriptors: Collection<DeclarationDescriptor>
) : AutoImportVariant {
override val excludeFqNameCheck: FqName = descriptors.first().importableFqName!!.parent()
override val descriptorsToImport: Collection<DeclarationDescriptor> get() = descriptors
override val hint: String get() = "$autoImportDescription from $excludeFqNameCheck"
@@ -0,0 +1,7 @@
// "Import" "true"
// ERROR: Unresolved reference: ImportedClass
import editor.completion.apx.ImportedClass as Class2
fun context() {
val c: Class2
}
@@ -0,0 +1,2 @@
package editor.completion.apx
class ImportedClass
@@ -0,0 +1,7 @@
// "Import" "true"
// ERROR: Unresolved reference: ImportedClass
import editor.completion.apx.ImportedClass as Class2
fun context() {
val c: <caret>ImportedClass
}
@@ -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
}
@@ -0,0 +1,2 @@
package editor.completion.apx
class ImportedClass
@@ -0,0 +1,8 @@
// "Import" "true"
// ERROR: Unresolved reference: ImportedClass
import editor.completion.apx.ImportedClass as Class2
fun context() {
class Class2
val c: <caret>ImportedClass
}
@@ -0,0 +1,8 @@
// "Import" "true"
// ERROR: Unresolved reference: importedFunA
import editor.completion.apx.importedFunA as funA
fun context() {
val funA = 42
funA()
}
@@ -0,0 +1,2 @@
package editor.completion.apx
fun importedFunA() {}
@@ -0,0 +1,8 @@
// "Import" "true"
// ERROR: Unresolved reference: importedFunA
import editor.completion.apx.importedFunA as funA
fun context() {
val funA = 42
<caret>importedFunA()
}
@@ -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()
}
@@ -0,0 +1,2 @@
package editor.completion.apx
fun importedFunA() {}
@@ -0,0 +1,8 @@
// "Import" "true"
// ERROR: Unresolved reference: importedFunA
import editor.completion.apx.importedFunA as funA
fun context() {
fun funA() {}
<caret>importedFunA()
}
@@ -0,0 +1,10 @@
// "Import" "true"
// WITH_RUNTIME
import kotlin.let as let1
fun main() {
1.<caret>let {
println(it)
}
}
@@ -0,0 +1,10 @@
// "Import" "true"
// WITH_RUNTIME
import kotlin.let as let1
fun main() {
1.let1 {
println(it)
}
}
@@ -0,0 +1,7 @@
// "Import" "true"
// ERROR: Unresolved reference: importedValA
import editor.completion.apx.importedValA as valA
fun context() {
valA()
}
@@ -0,0 +1,2 @@
package editor.completion.apx
val importedValA = ""
@@ -0,0 +1,7 @@
// "Import" "true"
// ERROR: Unresolved reference: importedValA
import editor.completion.apx.importedValA as valA
fun context() {
<caret>importedValA()
}
@@ -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");
@@ -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");