diff --git a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt index f3ca8c680a8..dcf4dc78a78 100644 --- a/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt +++ b/idea/ide-common/src/org/jetbrains/kotlin/idea/util/OptimizedImportsBuilder.kt @@ -20,6 +20,8 @@ import org.jetbrains.annotations.TestOnly import org.jetbrains.kotlin.descriptors.ClassDescriptor import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor +import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor import org.jetbrains.kotlin.idea.analysis.analyzeAsReplacement import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade @@ -306,6 +308,9 @@ class OptimizedImportsBuilder( private fun isImportedByDefault(fqName: FqName) = importInsertHelper.isImportedWithDefault(ImportPath(fqName, false), file) + private fun isImportedByLowPriorityDefault(fqName: FqName) = + importInsertHelper.isImportedWithLowPriorityDefaultImport(ImportPath(fqName, false), file) + private fun DeclarationDescriptor.nameCountToUseStar(): Int { val isMember = containingDeclaration is ClassDescriptor return if (isMember) @@ -316,8 +321,23 @@ class OptimizedImportsBuilder( private fun areTargetsEqual(descriptors1: Collection, descriptors2: Collection): Boolean { return descriptors1.size == descriptors2.size && - descriptors1.zip(descriptors2).all { it.first.importableFqName == it.second.importableFqName } //TODO: can have different order? + descriptors1.zip(descriptors2).all { (first, second) -> areTargetsEqual(first, second) } //TODO: can have different order? } + private fun areTargetsEqual(first: DeclarationDescriptor, second: DeclarationDescriptor): Boolean { + if (first == second) return true + + val firstFqName = first.importableFqName + val secondFqName = second.importableFqName + + return firstFqName == secondFqName || + (first.isAliasTo(second) && secondFqName != null && isImportedByLowPriorityDefault(secondFqName)) || + (second.isAliasTo(first) && firstFqName != null && isImportedByLowPriorityDefault(firstFqName)) + } + + private fun DeclarationDescriptor.isAliasTo(other: DeclarationDescriptor): Boolean = + this is TypeAliasDescriptor && classDescriptor == other || + this is TypeAliasConstructorDescriptor && underlyingConstructorDescriptor == other + private fun ImportPath.isAllowedByRules(): Boolean = importRules.none { it is ImportRule.DoNotAdd && it.importPath == this } -} \ No newline at end of file +} diff --git a/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt b/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt new file mode 100644 index 00000000000..25acbad08a7 --- /dev/null +++ b/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt @@ -0,0 +1,10 @@ +import java.lang.IllegalArgumentException +import kotlin.run + +fun main(args: Array) { + run { + throw IllegalArgumentException() + } +} + +fun type(): IllegalArgumentException? = null diff --git a/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt.after b/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt.after new file mode 100644 index 00000000000..9c44674c6f8 --- /dev/null +++ b/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt.after @@ -0,0 +1,7 @@ +fun main(args: Array) { + run { + throw IllegalArgumentException() + } +} + +fun type(): IllegalArgumentException? = null diff --git a/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt.log b/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt.log new file mode 100644 index 00000000000..cd0d6fcbc05 --- /dev/null +++ b/idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt.log @@ -0,0 +1,8 @@ +Additional checking of reference Getter: IllegalArgumentException +Additional checking of reference KtSimpleNameReference: IllegalArgumentException +Additional checking of reference Getter: run +Additional checking of reference KtSimpleNameReference: run +Additional checking of reference KtInvokeFunctionReference: IllegalArgumentException() +Additional checking of reference KtInvokeFunctionReference: run { + throw IllegalArgumentException() + } diff --git a/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.dependency1.kt b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.dependency1.kt new file mode 100644 index 00000000000..a3fab36424d --- /dev/null +++ b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.dependency1.kt @@ -0,0 +1,5 @@ +package dep1 + +class A + +class B diff --git a/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.dependency2.kt b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.dependency2.kt new file mode 100644 index 00000000000..414461992bc --- /dev/null +++ b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.dependency2.kt @@ -0,0 +1,7 @@ +package dep2 + +// Type alias with the same name +typealias A = dep1.A + +// Type alias with a different name +typealias BBB = dep2.B diff --git a/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt new file mode 100644 index 00000000000..7d867298b52 --- /dev/null +++ b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt @@ -0,0 +1,9 @@ +import dep1.A +import dep1.B +import dep2.* + +fun test( + a: A, + b: B, + bbb: BBB +) {} diff --git a/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt.after b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt.after new file mode 100644 index 00000000000..920da7bf25c --- /dev/null +++ b/idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt.after @@ -0,0 +1,9 @@ +import dep1.A +import dep1.B +import dep2.BBB + +fun test( + a: A, + b: B, + bbb: BBB +) {} diff --git a/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java index 76b43ca460a..7a86e4aae19 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java @@ -61,6 +61,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT runTest("idea/testData/editor/optimizeImports/jvm/DuplicatedImports.kt"); } + @TestMetadata("ExplicitImportOfDefault.kt") + public void testExplicitImportOfDefault() throws Exception { + runTest("idea/testData/editor/optimizeImports/jvm/ExplicitImportOfDefault.kt"); + } + @TestMetadata("FromCompanionObject.kt") public void testFromCompanionObject() throws Exception { runTest("idea/testData/editor/optimizeImports/jvm/FromCompanionObject.kt"); @@ -141,6 +146,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT runTest("idea/testData/editor/optimizeImports/jvm/TrivialAlias.kt"); } + @TestMetadata("TypeAliasVsUnderlyingClass.kt") + public void testTypeAliasVsUnderlyingClass() throws Exception { + runTest("idea/testData/editor/optimizeImports/jvm/TypeAliasVsUnderlyingClass.kt"); + } + @TestMetadata("UnusedImports.kt") public void testUnusedImports() throws Exception { runTest("idea/testData/editor/optimizeImports/jvm/UnusedImports.kt");