ImportOptimizer: basic support for removing unresolved imports

#KT-32409 Fixed
Part of #KT-31331
This commit is contained in:
Dmitry Gridin
2020-06-17 16:10:21 +07:00
parent 8faced9192
commit 4de582564c
21 changed files with 165 additions and 16 deletions
@@ -53,7 +53,8 @@ class OptimizedImportsBuilder(
class InputData(
val descriptorsToImport: Set<DeclarationDescriptor>,
val namesToImport: Map<FqName, Set<Name>>,
val references: Collection<AbstractReference>
val references: Collection<AbstractReference>,
val unresolvedNames: Set<Name>,
)
class Options(
@@ -81,9 +82,8 @@ class OptimizedImportsBuilder(
fun buildOptimizedImports(): List<ImportPath>? {
val facade = file.getResolutionFacade()
file.importDirectives
.filterNot { it.canResolve(facade) }
.mapNotNull(KtImportDirective::getImportPath)
.mapTo(importRules) { ImportRule.Add(it) }
.filter { it.isAllUnder && data.unresolvedNames.isNotEmpty() || it.importedName in data.unresolvedNames && !it.canResolve(facade) }
.mapNotNullTo(importRules) { it.importPath?.let { path -> ImportRule.Add(path) } }
while (true) {
ProgressManager.checkCanceled()
@@ -106,7 +106,7 @@ class OptimizedImportsBuilder(
}
private fun tryBuildOptimizedImports(): List<ImportPath>? {
val importsToGenerate = HashSet<ImportPath>()
val importsToGenerate = hashSetOf<ImportPath>()
importRules.filterIsInstance<ImportRule.Add>().mapTo(importsToGenerate) { it.importPath }
val descriptorsByParentFqName = HashMap<FqName, MutableSet<DeclarationDescriptor>>()
@@ -120,15 +120,14 @@ class OptimizedImportsBuilder(
val parentFqName = fqName.parent()
if (alias == null && canUseStarImport(descriptor, fqName) && ImportPath(parentFqName, true).isAllowedByRules()) {
descriptorsByParentFqName.getOrPut(parentFqName) { LinkedHashSet() }.add(descriptor)
descriptorsByParentFqName.getOrPut(parentFqName) { hashSetOf() }.add(descriptor)
} else {
importsToGenerate.add(explicitImportPath)
}
}
}
val classNamesToCheck = HashSet<FqName>()
val classNamesToCheck = hashSetOf<FqName>()
for (parentFqName in descriptorsByParentFqName.keys) {
ProgressManager.checkCanceled()
@@ -120,12 +120,14 @@ class KotlinImportOptimizer : ImportOptimizer {
private val descriptorsToImport = hashSetOf<DeclarationDescriptor>()
private val namesToImport = hashMapOf<FqName, MutableSet<Name>>()
private val abstractRefs = ArrayList<OptimizedImportsBuilder.AbstractReference>()
private val unresolvedNames = hashSetOf<Name>()
val data: OptimizedImportsBuilder.InputData
get() = OptimizedImportsBuilder.InputData(
descriptorsToImport,
namesToImport,
abstractRefs,
unresolvedNames,
)
override fun visitElement(element: PsiElement) {
@@ -148,12 +150,13 @@ class KotlinImportOptimizer : ImportOptimizer {
abstractRefs.add(AbstractReferenceImpl(reference))
val names = reference.resolvesByNames
var isResolved = false
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val targets = reference.targets(bindingContext)
for (target in targets) {
val importableDescriptor = target.getImportableDescriptor()
for (target in reference.targets(bindingContext)) {
isResolved = true
val importableDescriptor = target.getImportableDescriptor()
val importableFqName = target.importableFqName ?: continue
val parentFqName = importableFqName.parent()
if (target is PackageViewDescriptor && parentFqName == FqName.ROOT) continue // no need to import top-level packages
@@ -168,6 +171,8 @@ class KotlinImportOptimizer : ImportOptimizer {
namesToImport.getOrPut(importableFqName) { hashSetOf() } += descriptorNames
descriptorsToImport += importableDescriptor
}
if (!isResolved && reference is KtSimpleNameReference) unresolvedNames += names
}
super.visitKtElement(element)
@@ -0,0 +1,9 @@
package srt
import srt.A
const val A = 4
fun test(a: A) {
}
@@ -0,0 +1,7 @@
package srt
const val A = 4
fun test(a: A) {
}
@@ -0,0 +1,9 @@
package srt
import srt.*
const val A = 4
fun test(b: A) {
}
@@ -0,0 +1,9 @@
package srt
import srt.*
const val A = 4
fun test(b: A) {
}
@@ -0,0 +1,7 @@
package a.b
import a.*
class Foo(
val bar: Bar
)
@@ -0,0 +1,7 @@
package a.b
import a.*
class Foo(
val bar: Bar
)
@@ -1,7 +1,6 @@
import pack1.Class4
import pack1.Example
import pack2.*
import pack3.Ggd
fun method(a: Class4) {
Example()
@@ -0,0 +1,4 @@
package pack1
class Example
class Class4
@@ -0,0 +1,9 @@
import pack1.Class4
import pack1.Example
import pack2.*
import pack3.Ggd
import pack4.Gga as Arrr
fun method(a: Class4) {
Example()
}
@@ -0,0 +1,6 @@
import pack1.Class4
import pack1.Example
fun method(a: Class4) {
Example()
}
@@ -7,7 +7,7 @@ import java.io.File
import java.io.PrintStream
import dependency.*
fun foo(c: C) {
fun foo(c: Int) {
val v = HashMap<File, ArrayList<Int>>()
"".extFun()
"".extFun(1)
@@ -5,7 +5,7 @@ import dependency.extFun
import java.io.File
import java.util.*
fun foo(c: C) {
fun foo(c: Int) {
val v = HashMap<File, ArrayList<Int>>()
"".extFun()
"".extFun(1)
@@ -0,0 +1,4 @@
package dependency
fun String.extFun() {}
fun String.extFun(p: Int) {}
@@ -0,0 +1,14 @@
// NAME_COUNT_TO_USE_STAR_IMPORT: 2
package ppp
import java.util.HashMap
import java.util.ArrayList
import java.io.File
import java.io.PrintStream
import dependency.*
fun foo(c: C) {
val v = HashMap<File, ArrayList<Int>>()
"".extFun()
"".extFun(1)
}
@@ -0,0 +1,12 @@
// NAME_COUNT_TO_USE_STAR_IMPORT: 2
package ppp
import dependency.*
import java.io.File
import java.util.*
fun foo(c: C) {
val v = HashMap<File, ArrayList<Int>>()
"".extFun()
"".extFun(1)
}
@@ -3,4 +3,6 @@
<caret>import kotlin.collections.*
val (a, b, c) = Triple(1, 2, 3)
fun test() {
val (a, b, c) = Triple(1, 2, 3)
}
@@ -1,4 +1,6 @@
// "Optimize imports" "true"
// WITH_RUNTIME
val (a, b, c) = Triple(1, 2, 3)
fun test() {
val (a, b, c) = Triple(1, 2, 3)
}
@@ -73,6 +73,16 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes
runTest("idea/testData/editor/optimizeImports/common/ConflictWithAlias2.kt");
}
@TestMetadata("ConflictWithUnresolvedName.kt")
public void testConflictWithUnresolvedName() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/ConflictWithUnresolvedName.kt");
}
@TestMetadata("ConflictWithUnresolvedName2.kt")
public void testConflictWithUnresolvedName2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/ConflictWithUnresolvedName2.kt");
}
@TestMetadata("CurrentPackage.kt")
public void testCurrentPackage() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/CurrentPackage.kt");
@@ -158,6 +168,11 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes
runTest("idea/testData/editor/optimizeImports/common/Kt2709.kt");
}
@TestMetadata("Kt32409.kt")
public void testKt32409() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/Kt32409.kt");
}
@TestMetadata("MemberImports.kt")
public void testMemberImports() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/MemberImports.kt");
@@ -198,6 +213,11 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes
runTest("idea/testData/editor/optimizeImports/common/UnresolvedImport.kt");
}
@TestMetadata("UnresolvedImport2.kt")
public void testUnresolvedImport2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/UnresolvedImport2.kt");
}
@TestMetadata("WithAlias.kt")
public void testWithAlias() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/WithAlias.kt");
@@ -217,6 +217,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
runTest("idea/testData/editor/optimizeImports/jvm/allUnderImports/NameCountSetting.kt");
}
@TestMetadata("NameCountSettingWithUnresolvedReference.kt")
public void testNameCountSettingWithUnresolvedReference() throws Exception {
runTest("idea/testData/editor/optimizeImports/jvm/allUnderImports/NameCountSettingWithUnresolvedReference.kt");
}
@TestMetadata("PackagesToUseStarImport.kt")
public void testPackagesToUseStarImport() throws Exception {
runTest("idea/testData/editor/optimizeImports/jvm/allUnderImports/PackagesToUseStarImport.kt");
@@ -266,6 +271,16 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
runTest("idea/testData/editor/optimizeImports/common/ConflictWithAlias2.kt");
}
@TestMetadata("ConflictWithUnresolvedName.kt")
public void testConflictWithUnresolvedName() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/ConflictWithUnresolvedName.kt");
}
@TestMetadata("ConflictWithUnresolvedName2.kt")
public void testConflictWithUnresolvedName2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/ConflictWithUnresolvedName2.kt");
}
@TestMetadata("CurrentPackage.kt")
public void testCurrentPackage() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/CurrentPackage.kt");
@@ -351,6 +366,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
runTest("idea/testData/editor/optimizeImports/common/Kt2709.kt");
}
@TestMetadata("Kt32409.kt")
public void testKt32409() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/Kt32409.kt");
}
@TestMetadata("MemberImports.kt")
public void testMemberImports() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/MemberImports.kt");
@@ -391,6 +411,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
runTest("idea/testData/editor/optimizeImports/common/UnresolvedImport.kt");
}
@TestMetadata("UnresolvedImport2.kt")
public void testUnresolvedImport2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/UnresolvedImport2.kt");
}
@TestMetadata("WithAlias.kt")
public void testWithAlias() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/WithAlias.kt");