Don't delete import from stdlib if alias exists and used
#KT-31414 Fixed
This commit is contained in:
@@ -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) {
|
||||
|
||||
+9
@@ -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 {}
|
||||
+9
@@ -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())
|
||||
|
||||
+20
@@ -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)
|
||||
|
||||
+20
@@ -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)
|
||||
|
||||
Reference in New Issue
Block a user