ImportOptimizer: add cases for unresolved references

Part of #KT-31331
This commit is contained in:
Dmitry Gridin
2020-06-17 21:13:25 +07:00
parent 4de582564c
commit 10c62b8d77
8 changed files with 58 additions and 12 deletions
@@ -28,10 +28,12 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.ImportPath import org.jetbrains.kotlin.resolve.ImportPath
import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall
import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor import org.jetbrains.kotlin.resolve.descriptorUtil.getImportableDescriptor
import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode
import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope
import org.jetbrains.kotlin.resolve.scopes.utils.* import org.jetbrains.kotlin.resolve.scopes.utils.*
import org.jetbrains.kotlin.types.error.ErrorSimpleFunctionDescriptorImpl
class KotlinImportOptimizer : ImportOptimizer { class KotlinImportOptimizer : ImportOptimizer {
override fun supports(file: PsiFile) = file is KtFile override fun supports(file: PsiFile) = file is KtFile
@@ -145,17 +147,27 @@ class KotlinImportOptimizer : ImportOptimizer {
} }
override fun visitKtElement(element: KtElement) { override fun visitKtElement(element: KtElement) {
for (reference in element.references) { super.visitKtElement(element)
val references = element.references.ifEmpty { return }
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
val isResolved = if (element is KtCallElement)
element.getResolvedCall(bindingContext) != null
else
element.mainReference?.resolveToDescriptors(bindingContext)?.let { descriptors ->
descriptors.isNotEmpty() && descriptors.none { it is ErrorSimpleFunctionDescriptorImpl }
} == true
for (reference in references) {
if (reference !is KtReference) continue if (reference !is KtReference) continue
abstractRefs.add(AbstractReferenceImpl(reference)) abstractRefs.add(AbstractReferenceImpl(reference))
val names = reference.resolvesByNames val names = reference.resolvesByNames
var isResolved = false if (!isResolved) {
unresolvedNames += names
}
val bindingContext = element.analyze(BodyResolveMode.PARTIAL)
for (target in reference.targets(bindingContext)) { for (target in reference.targets(bindingContext)) {
isResolved = true
val importableDescriptor = target.getImportableDescriptor() val importableDescriptor = target.getImportableDescriptor()
val importableFqName = target.importableFqName ?: continue val importableFqName = target.importableFqName ?: continue
val parentFqName = importableFqName.parent() val parentFqName = importableFqName.parent()
@@ -171,11 +183,7 @@ class KotlinImportOptimizer : ImportOptimizer {
namesToImport.getOrPut(importableFqName) { hashSetOf() } += descriptorNames namesToImport.getOrPut(importableFqName) { hashSetOf() } += descriptorNames
descriptorsToImport += importableDescriptor descriptorsToImport += importableDescriptor
} }
if (!isResolved && reference is KtSimpleNameReference) unresolvedNames += names
} }
super.visitKtElement(element)
} }
private fun isAccessibleAsMember(target: DeclarationDescriptor, place: KtElement, bindingContext: BindingContext): Boolean { private fun isAccessibleAsMember(target: DeclarationDescriptor, place: KtElement, bindingContext: BindingContext): Boolean {
@@ -1,5 +1,6 @@
import test1.MyClass import test1.MyClass
import test1.iterator import test1.iterator
import test2.iterator
fun foo() { fun foo() {
val s = MyClass() val s = MyClass()
@@ -0,0 +1,11 @@
import test1.MyClass
import test1.iterator
import test2.iterator
import test3.notIterator
import test1.invoke
import test4.*
fun foo() {
val s = MyClass()
for (i in s) {}
}
@@ -0,0 +1,10 @@
import test1.MyClass
import test1.invoke
import test1.iterator
import test2.iterator
import test4.*
fun foo() {
val s = MyClass()
for (i in s) {}
}
@@ -133,6 +133,11 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes
runTest("idea/testData/editor/optimizeImports/common/IteratorFunction.kt"); runTest("idea/testData/editor/optimizeImports/common/IteratorFunction.kt");
} }
@TestMetadata("IteratorFunction2.kt")
public void testIteratorFunction2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/IteratorFunction2.kt");
}
@TestMetadata("KT11640.kt") @TestMetadata("KT11640.kt")
public void testKT11640() throws Exception { public void testKT11640() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/KT11640.kt"); runTest("idea/testData/editor/optimizeImports/common/KT11640.kt");
@@ -331,6 +331,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT
runTest("idea/testData/editor/optimizeImports/common/IteratorFunction.kt"); runTest("idea/testData/editor/optimizeImports/common/IteratorFunction.kt");
} }
@TestMetadata("IteratorFunction2.kt")
public void testIteratorFunction2() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/IteratorFunction2.kt");
}
@TestMetadata("KT11640.kt") @TestMetadata("KT11640.kt")
public void testKT11640() throws Exception { public void testKT11640() throws Exception {
runTest("idea/testData/editor/optimizeImports/common/KT11640.kt"); runTest("idea/testData/editor/optimizeImports/common/KT11640.kt");
@@ -2,5 +2,8 @@
package test; package test;
import as.type.val.var.fun.is.in.object.when.typeof; import as.type.val.var.fun.is.in.object.when.typeof;
import as.type.val.var.fun.is.in.object.when.typeof.as;
class Test {} class Test {
public void foo(as a) { }
}
+5 -2
View File
@@ -1,6 +1,9 @@
// ERROR: Unresolved reference: `as` // ERROR: Unresolved reference: `as`
// ERROR: Unresolved reference: `as`
package test package test
import `as`.type.`val`.`var`.`fun`.`is`.`in`.`object`.`when`.`typeof` import `as`.type.`val`.`var`.`fun`.`is`.`in`.`object`.`when`.`typeof`.`as`
internal class Test internal class Test {
fun foo(a: `as`?) {}
}