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:
Alexander Udalov
2018-07-13 17:44:49 +02:00
parent ce34deb9af
commit f766b2c473
9 changed files with 87 additions and 2 deletions
@@ -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<DeclarationDescriptor>, descriptors2: Collection<DeclarationDescriptor>): 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 }
}
}