ImportOptimizer: basic support for removing unresolved imports
#KT-32409 Fixed Part of #KT-31331
This commit is contained in:
@@ -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) {
|
||||
|
||||
}
|
||||
+7
@@ -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) {
|
||||
|
||||
}
|
||||
+9
@@ -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()
|
||||
}
|
||||
+1
-1
@@ -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)
|
||||
|
||||
+1
-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)
|
||||
|
||||
+4
@@ -0,0 +1,4 @@
|
||||
package dependency
|
||||
|
||||
fun String.extFun() {}
|
||||
fun String.extFun(p: Int) {}
|
||||
Vendored
+14
@@ -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)
|
||||
}
|
||||
+12
@@ -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)
|
||||
}
|
||||
|
||||
+20
@@ -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");
|
||||
|
||||
+25
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user