Don't delete import from stdlib if alias exists and used

#KT-31414 Fixed
This commit is contained in:
Dmitry Gridin
2019-05-14 15:09:50 +07:00
parent 32298522dd
commit 3914530fa8
23 changed files with 239 additions and 17 deletions
@@ -60,7 +60,8 @@ class OptimizedImportsBuilder(
}
data class InputData(
val descriptorsToImport: Map<DeclarationDescriptor, Set<Name>>,
val descriptorsToImport: Set<DeclarationDescriptor>,
val namesToImport: Map<FqName, Set<Name>>,
val references: Collection<AbstractReference>
)
@@ -119,9 +120,9 @@ class OptimizedImportsBuilder(
.mapTo(importsToGenerate) { it.importPath }
val descriptorsByParentFqName = HashMap<FqName, MutableSet<DeclarationDescriptor>>()
for ((descriptor, names) in data.descriptorsToImport) {
for (name in names) {
val fqName = descriptor.importableFqName!!
for (descriptor in data.descriptorsToImport) {
val fqName = descriptor.importableFqName!!
for (name in data.namesToImport.getValue(fqName)) {
val alias = if (name != fqName.shortName()) name else null
val explicitImportPath = ImportPath(fqName, false, alias)
@@ -149,16 +150,16 @@ class OptimizedImportsBuilder(
|| !starImportPath.isAllowedByRules()
if (useExplicitImports) {
fqNames
.filter { !isImportedByDefault(it) }
.filter(this::needExplicitImport)
.mapTo(importsToGenerate) { ImportPath(it, false) }
} else {
descriptors
.asSequence()
.filterIsInstance<ClassDescriptor>()
.map { it.importableFqName!! }
.filterTo(classNamesToCheck) { !isImportedByDefault(it) }
.filterTo(classNamesToCheck, this::needExplicitImport)
if (!fqNames.all(this::isImportedByDefault)) {
if (fqNames.all(this::needExplicitImport)) {
importsToGenerate.add(starImportPath)
}
}
@@ -205,7 +206,7 @@ class OptimizedImportsBuilder(
(oldTargets + newTargets).forEach {
lockImportForDescriptor(
it,
data.descriptorsToImport.getOrElse(it) { listOf(it.name) }.intersect(names)
data.namesToImport.getOrElse(it.importableFqName!!) { listOf(it.name) }.intersect(names)
)
}
}
@@ -321,6 +322,12 @@ class OptimizedImportsBuilder(
}
}
private fun needExplicitImport(fqName: FqName): Boolean = hasAlias(fqName) || !isImportedByDefault(fqName)
private fun hasAlias(fqName: FqName) = data.namesToImport[fqName]?.let {
it.singleOrNull() == null
} ?: false
private fun isImportedByDefault(fqName: FqName) = importInsertHelper.isImportedWithDefault(ImportPath(fqName, false), file)
private fun isImportedByLowPriorityDefault(fqName: FqName) =
@@ -79,11 +79,12 @@ class KotlinImportOptimizer : ImportOptimizer {
.mapNotNull { it.importPath }
.groupBy(keySelector = { it.fqName }, valueTransform = { it.importedName as Name })
private val descriptorsToImport = LinkedHashMap<DeclarationDescriptor, HashSet<Name>>()
private val descriptorsToImport = LinkedHashSet<DeclarationDescriptor>()
private val namesToImport = LinkedHashMap<FqName, HashSet<Name>>()
private val abstractRefs = ArrayList<OptimizedImportsBuilder.AbstractReference>()
val data: OptimizedImportsBuilder.InputData
get() = OptimizedImportsBuilder.InputData(descriptorsToImport, abstractRefs)
get() = OptimizedImportsBuilder.InputData(descriptorsToImport, namesToImport, abstractRefs)
override fun visitElement(element: PsiElement) {
ProgressIndicatorProvider.checkCanceled()
@@ -119,7 +120,8 @@ class KotlinImportOptimizer : ImportOptimizer {
if (isAccessibleAsMember(importableDescriptor, element, bindingContext)) continue
val descriptorNames = (aliases[importableFqName].orEmpty() + importableFqName.shortName()).intersect(names)
descriptorsToImport.getOrPut(importableDescriptor) { LinkedHashSet() } += descriptorNames
namesToImport.getOrPut(importableFqName) { LinkedHashSet() } += descriptorNames
descriptorsToImport += importableDescriptor
}
}
@@ -49,7 +49,6 @@ import org.jetbrains.kotlin.idea.imports.OptimizedImportsBuilder
import org.jetbrains.kotlin.idea.imports.importableFqName
import org.jetbrains.kotlin.idea.util.ProjectRootsUtil
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtCodeFragment
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtImportDirective
@@ -75,12 +74,10 @@ class KotlinUnusedImportInspection : AbstractKotlinInspection() {
.map { it.fqName }
.toSet()
val fqNames = HashMap<FqName, Set<Name>>()
val fqNames = optimizerData.namesToImport
val parentFqNames = HashSet<FqName>()
for ((descriptor, names) in optimizerData.descriptorsToImport) {
for (descriptor in optimizerData.descriptorsToImport) {
val fqName = descriptor.importableFqName!!
fqNames.compute(fqName) { _, u -> u?.plus(names) ?: names }
if (fqName !in explicitlyImportedFqNames) { // we don't add parents of explicitly imported fq-names because such imports are not needed
val parentFqName = fqName.parent()
if (!parentFqName.isRoot) {
@@ -0,0 +1,9 @@
package pack1
fun a() {
}
fun Int.a() {
}
@@ -0,0 +1,15 @@
import pack1.a
import pack1.a as a1
import kotlin.collections.List
import kotlin.collections.List as List1
import kotlin.run as run1
import kotlin.run
fun foo() {
run {}
run1 {}
List<String>(1) {}
List1<String>(1) {}
a()
a1()
}
@@ -0,0 +1,15 @@
import pack1.a
import kotlin.collections.List
import kotlin.run
import pack1.a as a1
import kotlin.collections.List as List1
import kotlin.run as run1
fun foo() {
run {}
run1 {}
List<String>(1) {}
List1<String>(1) {}
a()
a1()
}
@@ -0,0 +1,37 @@
Additional checking of reference Getter: List
Additional checking of reference KtSimpleNameReference: List
Additional checking of reference Getter: List1
Additional checking of reference KtSimpleNameReference: List1
Changed resolve of KtSimpleNameReference: List1
Additional checking of reference Getter: a1
Additional checking of reference KtSimpleNameReference: a1
Changed resolve of KtSimpleNameReference: a1
Additional checking of reference Getter: run
Additional checking of reference KtSimpleNameReference: run
Additional checking of reference Getter: run1
Additional checking of reference KtSimpleNameReference: run1
Changed resolve of KtSimpleNameReference: run1
Additional checking of reference KtInvokeFunctionReference: List1<String>(1) {}
Additional checking of reference KtInvokeFunctionReference: List<String>(1) {}
Additional checking of reference KtInvokeFunctionReference: a1()
Additional checking of reference KtInvokeFunctionReference: run {}
Additional checking of reference KtInvokeFunctionReference: run1 {}
Trying to build import list again with import rules: +pack1.a as a1, +kotlin.collections.List as List1, +kotlin.run as run1
Additional checking of reference Getter: List
Additional checking of reference KtSimpleNameReference: List
Additional checking of reference Getter: List1
Additional checking of reference KtSimpleNameReference: List1
Changed resolve of KtSimpleNameReference: List1
Additional checking of reference Getter: a1
Additional checking of reference KtSimpleNameReference: a1
Changed resolve of KtSimpleNameReference: a1
Additional checking of reference Getter: run
Additional checking of reference KtSimpleNameReference: run
Additional checking of reference Getter: run1
Additional checking of reference KtSimpleNameReference: run1
Changed resolve of KtSimpleNameReference: run1
Additional checking of reference KtInvokeFunctionReference: List1<String>(1) {}
Additional checking of reference KtInvokeFunctionReference: List<String>(1) {}
Additional checking of reference KtInvokeFunctionReference: a1()
Additional checking of reference KtInvokeFunctionReference: run {}
Additional checking of reference KtInvokeFunctionReference: run1 {}
@@ -0,0 +1,9 @@
package pack1
fun a() {
}
fun Int.a() {
}
@@ -0,0 +1,10 @@
import pack1.a
import pack1.a as a1
import kotlin.run as run1
import kotlin.run
fun foo() {
run1 {}
a()
42.a1()
}
@@ -0,0 +1,9 @@
import pack1.a
import pack1.a as a1
import kotlin.run as run1
fun foo() {
run1 {}
a()
42.a1()
}
@@ -0,0 +1,17 @@
Additional checking of reference Getter: a1
Additional checking of reference KtSimpleNameReference: a1
Changed resolve of KtSimpleNameReference: a1
Additional checking of reference Getter: run1
Additional checking of reference KtSimpleNameReference: run1
Changed resolve of KtSimpleNameReference: run1
Additional checking of reference KtInvokeFunctionReference: a1()
Additional checking of reference KtInvokeFunctionReference: run1 {}
Trying to build import list again with import rules: +pack1.a as a1, +kotlin.run as run1
Additional checking of reference Getter: a1
Additional checking of reference KtSimpleNameReference: a1
Changed resolve of KtSimpleNameReference: a1
Additional checking of reference Getter: run1
Additional checking of reference KtSimpleNameReference: run1
Changed resolve of KtSimpleNameReference: run1
Additional checking of reference KtInvokeFunctionReference: a1()
Additional checking of reference KtInvokeFunctionReference: run1 {}
@@ -1,5 +1,5 @@
// NAME_COUNT_TO_USE_STAR_IMPORT: 2
import p1.A
import p1.*
import p2.A
fun f() {
@@ -6,3 +6,4 @@ Additional checking of reference KtSimpleNameReference: A
Changed resolve of KtSimpleNameReference: A
Additional checking of reference KtInvokeFunctionReference: A("")
Additional checking of reference KtInvokeFunctionReference: A(1)
Trying to build import list again with import rules: +p2.A, +p1.*
@@ -0,0 +1,9 @@
package pack1
fun a() {
}
fun Int.a() {
}
@@ -0,0 +1,6 @@
import pack1.a
import pack1.a as a1
fun foo() {
42.a1()
}
@@ -0,0 +1,5 @@
import pack1.a as a1
fun foo() {
42.a1()
}
@@ -0,0 +1,9 @@
Additional checking of reference Getter: a1
Additional checking of reference KtSimpleNameReference: a1
Changed resolve of KtSimpleNameReference: a1
Additional checking of reference KtInvokeFunctionReference: a1()
Trying to build import list again with import rules: +pack1.a as a1
Additional checking of reference Getter: a1
Additional checking of reference KtSimpleNameReference: a1
Changed resolve of KtSimpleNameReference: a1
Additional checking of reference KtInvokeFunctionReference: a1()
@@ -0,0 +1,9 @@
package pack1
fun a() {
}
fun Int.a() {
}
@@ -0,0 +1,6 @@
import pack1.a
import pack1.a as a1
fun foo() {
a()
}
@@ -0,0 +1,5 @@
import pack1.a
fun foo() {
a()
}
@@ -2,3 +2,8 @@ Additional checking of reference Getter: JavaFile
Additional checking of reference KtSimpleNameReference: JavaFile
Changed resolve of KtSimpleNameReference: JavaFile
Additional checking of reference KtInvokeFunctionReference: JavaFile(StringBuilder().append("Hello").toString())
Trying to build import list again with import rules: +java.io.File as JavaFile
Additional checking of reference Getter: JavaFile
Additional checking of reference KtSimpleNameReference: JavaFile
Changed resolve of KtSimpleNameReference: JavaFile
Additional checking of reference KtInvokeFunctionReference: JavaFile(StringBuilder().append("Hello").toString())
@@ -79,6 +79,16 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes
runTest("idea/testData/editor/optimizeImports/common/CurrentPackage.kt");
}
@TestMetadata("DefaultImportAndAlias.kt")
public void testDefaultImportAndAlias() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/DefaultImportAndAlias.kt");
}
@TestMetadata("DefaultImportAndAlias2.kt")
public void testDefaultImportAndAlias2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/DefaultImportAndAlias2.kt");
}
@TestMetadata("DefaultObjectReference.kt")
public void testDefaultObjectReference() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/DefaultObjectReference.kt");
@@ -179,6 +189,16 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes
runTest("idea/testData/editor/optimizeImports/common/UnresolvedImport.kt");
}
@TestMetadata("WithAlias.kt")
public void testWithAlias() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/WithAlias.kt");
}
@TestMetadata("WithAlias2.kt")
public void testWithAlias2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/WithAlias2.kt");
}
@TestMetadata("idea/testData/editor/optimizeImports/common/kt21515")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
@@ -272,6 +272,16 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
runTest("idea/testData/editor/optimizeImports/common/CurrentPackage.kt");
}
@TestMetadata("DefaultImportAndAlias.kt")
public void testDefaultImportAndAlias() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/DefaultImportAndAlias.kt");
}
@TestMetadata("DefaultImportAndAlias2.kt")
public void testDefaultImportAndAlias2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/DefaultImportAndAlias2.kt");
}
@TestMetadata("DefaultObjectReference.kt")
public void testDefaultObjectReference() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/DefaultObjectReference.kt");
@@ -372,6 +382,16 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
runTest("idea/testData/editor/optimizeImports/common/UnresolvedImport.kt");
}
@TestMetadata("WithAlias.kt")
public void testWithAlias() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/WithAlias.kt");
}
@TestMetadata("WithAlias2.kt")
public void testWithAlias2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/WithAlias2.kt");
}
@TestMetadata("idea/testData/editor/optimizeImports/common/kt21515")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)