Improve "optimize imports" behavior on default imports
Optimize imports to classes when there's an import of a type alias to that class with the same name. This results in "java.lang.*" imports being optimized in favor of the corresponding type aliases in "kotlin.*" which are imported by default
This commit is contained in:
@@ -20,6 +20,8 @@ import org.jetbrains.annotations.TestOnly
|
|||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
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.analysis.analyzeAsReplacement
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
import org.jetbrains.kotlin.idea.caches.resolve.analyze
|
||||||
import org.jetbrains.kotlin.idea.caches.resolve.getResolutionFacade
|
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 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 {
|
private fun DeclarationDescriptor.nameCountToUseStar(): Int {
|
||||||
val isMember = containingDeclaration is ClassDescriptor
|
val isMember = containingDeclaration is ClassDescriptor
|
||||||
return if (isMember)
|
return if (isMember)
|
||||||
@@ -316,8 +321,23 @@ class OptimizedImportsBuilder(
|
|||||||
|
|
||||||
private fun areTargetsEqual(descriptors1: Collection<DeclarationDescriptor>, descriptors2: Collection<DeclarationDescriptor>): Boolean {
|
private fun areTargetsEqual(descriptors1: Collection<DeclarationDescriptor>, descriptors2: Collection<DeclarationDescriptor>): Boolean {
|
||||||
return descriptors1.size == descriptors2.size &&
|
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 }
|
private fun ImportPath.isAllowedByRules(): Boolean = importRules.none { it is ImportRule.DoNotAdd && it.importPath == this }
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -0,0 +1,10 @@
|
|||||||
|
import java.lang.IllegalArgumentException
|
||||||
|
import kotlin.run
|
||||||
|
|
||||||
|
fun main(args: Array<String>) {
|
||||||
|
run {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun type(): IllegalArgumentException? = null
|
||||||
@@ -0,0 +1,7 @@
|
|||||||
|
fun main(args: Array<String>) {
|
||||||
|
run {
|
||||||
|
throw IllegalArgumentException()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun type(): IllegalArgumentException? = null
|
||||||
@@ -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()
|
||||||
|
}
|
||||||
+5
@@ -0,0 +1,5 @@
|
|||||||
|
package dep1
|
||||||
|
|
||||||
|
class A
|
||||||
|
|
||||||
|
class B
|
||||||
+7
@@ -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
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import dep1.A
|
||||||
|
import dep1.B
|
||||||
|
import dep2.*
|
||||||
|
|
||||||
|
fun test(
|
||||||
|
a: A,
|
||||||
|
b: B,
|
||||||
|
bbb: BBB
|
||||||
|
) {}
|
||||||
@@ -0,0 +1,9 @@
|
|||||||
|
import dep1.A
|
||||||
|
import dep1.B
|
||||||
|
import dep2.BBB
|
||||||
|
|
||||||
|
fun test(
|
||||||
|
a: A,
|
||||||
|
b: B,
|
||||||
|
bbb: BBB
|
||||||
|
) {}
|
||||||
+10
@@ -61,6 +61,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
|
|||||||
runTest("idea/testData/editor/optimizeImports/jvm/DuplicatedImports.kt");
|
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")
|
@TestMetadata("FromCompanionObject.kt")
|
||||||
public void testFromCompanionObject() throws Exception {
|
public void testFromCompanionObject() throws Exception {
|
||||||
runTest("idea/testData/editor/optimizeImports/jvm/FromCompanionObject.kt");
|
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");
|
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")
|
@TestMetadata("UnusedImports.kt")
|
||||||
public void testUnusedImports() throws Exception {
|
public void testUnusedImports() throws Exception {
|
||||||
runTest("idea/testData/editor/optimizeImports/jvm/UnusedImports.kt");
|
runTest("idea/testData/editor/optimizeImports/jvm/UnusedImports.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user