From 10c62b8d773f6e7326264672bbbc1d540e82ad86 Mon Sep 17 00:00:00 2001 From: Dmitry Gridin Date: Wed, 17 Jun 2020 21:13:25 +0700 Subject: [PATCH] ImportOptimizer: add cases for unresolved references Part of #KT-31331 --- .../idea/imports/KotlinImportOptimizer.kt | 26 ++++++++++++------- .../common/IteratorFunction.kt | 1 + .../common/IteratorFunction2.kt | 11 ++++++++ .../common/IteratorFunction2.kt.after | 10 +++++++ .../JsOptimizeImportsTestGenerated.java | 5 ++++ .../JvmOptimizeImportsTestGenerated.java | 5 ++++ .../importStatement/importWithKeywords.java | 5 +++- .../importStatement/importWithKeywords.kt | 7 +++-- 8 files changed, 58 insertions(+), 12 deletions(-) create mode 100644 idea/testData/editor/optimizeImports/common/IteratorFunction2.kt create mode 100644 idea/testData/editor/optimizeImports/common/IteratorFunction2.kt.after diff --git a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt index 5f1d35bfddb..bffbeb332d9 100644 --- a/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt +++ b/idea/src/org/jetbrains/kotlin/idea/imports/KotlinImportOptimizer.kt @@ -28,10 +28,12 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.resolve.BindingContext 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.lazy.BodyResolveMode import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope import org.jetbrains.kotlin.resolve.scopes.utils.* +import org.jetbrains.kotlin.types.error.ErrorSimpleFunctionDescriptorImpl class KotlinImportOptimizer : ImportOptimizer { override fun supports(file: PsiFile) = file is KtFile @@ -145,17 +147,27 @@ class KotlinImportOptimizer : ImportOptimizer { } 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 abstractRefs.add(AbstractReferenceImpl(reference)) val names = reference.resolvesByNames - var isResolved = false + if (!isResolved) { + unresolvedNames += names + } - val bindingContext = element.analyze(BodyResolveMode.PARTIAL) for (target in reference.targets(bindingContext)) { - isResolved = true - val importableDescriptor = target.getImportableDescriptor() val importableFqName = target.importableFqName ?: continue val parentFqName = importableFqName.parent() @@ -171,11 +183,7 @@ class KotlinImportOptimizer : ImportOptimizer { namesToImport.getOrPut(importableFqName) { hashSetOf() } += descriptorNames descriptorsToImport += importableDescriptor } - - if (!isResolved && reference is KtSimpleNameReference) unresolvedNames += names } - - super.visitKtElement(element) } private fun isAccessibleAsMember(target: DeclarationDescriptor, place: KtElement, bindingContext: BindingContext): Boolean { diff --git a/idea/testData/editor/optimizeImports/common/IteratorFunction.kt b/idea/testData/editor/optimizeImports/common/IteratorFunction.kt index c2013ae8128..f0ca73195bb 100644 --- a/idea/testData/editor/optimizeImports/common/IteratorFunction.kt +++ b/idea/testData/editor/optimizeImports/common/IteratorFunction.kt @@ -1,5 +1,6 @@ import test1.MyClass import test1.iterator +import test2.iterator fun foo() { val s = MyClass() diff --git a/idea/testData/editor/optimizeImports/common/IteratorFunction2.kt b/idea/testData/editor/optimizeImports/common/IteratorFunction2.kt new file mode 100644 index 00000000000..973ebd7cdc6 --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/IteratorFunction2.kt @@ -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) {} +} diff --git a/idea/testData/editor/optimizeImports/common/IteratorFunction2.kt.after b/idea/testData/editor/optimizeImports/common/IteratorFunction2.kt.after new file mode 100644 index 00000000000..67b13a4700b --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/IteratorFunction2.kt.after @@ -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) {} +} diff --git a/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java index 415484a69cc..e4419306d6d 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java @@ -133,6 +133,11 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes 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") public void testKT11640() throws Exception { runTest("idea/testData/editor/optimizeImports/common/KT11640.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java index 35e1ceff041..e3da075e714 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java @@ -331,6 +331,11 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT 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") public void testKT11640() throws Exception { runTest("idea/testData/editor/optimizeImports/common/KT11640.kt"); diff --git a/nj2k/testData/newJ2k/importStatement/importWithKeywords.java b/nj2k/testData/newJ2k/importStatement/importWithKeywords.java index 9a6d9c0a4b8..db4b0c8263f 100644 --- a/nj2k/testData/newJ2k/importStatement/importWithKeywords.java +++ b/nj2k/testData/newJ2k/importStatement/importWithKeywords.java @@ -2,5 +2,8 @@ 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; -class Test {} +class Test { + public void foo(as a) { } +} diff --git a/nj2k/testData/newJ2k/importStatement/importWithKeywords.kt b/nj2k/testData/newJ2k/importStatement/importWithKeywords.kt index 928b01efa3b..27fba6e3a1b 100644 --- a/nj2k/testData/newJ2k/importStatement/importWithKeywords.kt +++ b/nj2k/testData/newJ2k/importStatement/importWithKeywords.kt @@ -1,6 +1,9 @@ // ERROR: Unresolved reference: `as` +// ERROR: Unresolved reference: `as` 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`?) {} +} \ No newline at end of file