From 7ed16690502aef254f8d3adb7375860985c0866c Mon Sep 17 00:00:00 2001 From: Simon Ogorodnik Date: Tue, 18 Jul 2017 02:28:03 +0300 Subject: [PATCH] KT-19011: Fix import optimizing when extension functional type is used It should check is extension functional type imported from companion is actually called on companion instance #KT-19011 fixed --- .../kotlin/idea/references/referenceUtil.kt | 9 +++++++-- .../idea/codeInliner/CodeToInlineBuilder.kt | 2 +- .../KotlinCopyPasteReferenceProcessor.kt | 2 +- .../idea/imports/KotlinImportOptimizer.kt | 2 +- ...nalTypeValFromCompanionObject.dependency.kt | 7 +++++++ ...sionFunctionalTypeValFromCompanionObject.kt | 7 +++++++ ...nctionalTypeValFromCompanionObject.kt.after | 7 +++++++ ...ompanionObjectCallOnCompanion.dependency.kt | 7 +++++++ ...ypeValFromCompanionObjectCallOnCompanion.kt | 8 ++++++++ ...FromCompanionObjectCallOnCompanion.kt.after | 8 ++++++++ ...FromCompanionObjectNonExtCall.dependency.kt | 7 +++++++ ...onalTypeValFromCompanionObjectNonExtCall.kt | 7 +++++++ ...peValFromCompanionObjectNonExtCall.kt.after | 7 +++++++ .../JsOptimizeImportsTestGenerated.java | 18 ++++++++++++++++++ .../JvmOptimizeImportsTestGenerated.java | 18 ++++++++++++++++++ 15 files changed, 111 insertions(+), 5 deletions(-) create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.dependency.kt create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt.after create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.dependency.kt create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt.after create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.dependency.kt create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt create mode 100644 idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt.after diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt index c59304ccea6..4bd5d3961d9 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/references/referenceUtil.kt @@ -24,7 +24,6 @@ import org.jetbrains.kotlin.descriptors.DeclarationDescriptorWithSource import org.jetbrains.kotlin.descriptors.PropertyDescriptor import org.jetbrains.kotlin.idea.caches.resolve.analyze import org.jetbrains.kotlin.idea.caches.resolve.resolveImportReference -import org.jetbrains.kotlin.idea.codeInsight.DescriptorToSourceUtilsIde import org.jetbrains.kotlin.idea.imports.canBeReferencedViaImport import org.jetbrains.kotlin.idea.intentions.OperatorToFunctionIntention import org.jetbrains.kotlin.idea.kdoc.KDocReference @@ -34,7 +33,9 @@ import org.jetbrains.kotlin.kdoc.psi.impl.KDocName import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.psi.* import org.jetbrains.kotlin.psi.psiUtil.* +import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.calls.callUtil.getResolvedCall +import org.jetbrains.kotlin.resolve.calls.model.VariableAsFunctionResolvedCall import org.jetbrains.kotlin.resolve.calls.model.isReallySuccess import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension import org.jetbrains.kotlin.resolve.lazy.BodyResolveMode @@ -254,7 +255,7 @@ fun KtExpression.readWriteAccess(useResolveForReadWrite: Boolean): ReferenceAcce ReferenceAccess.READ } -fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor): Boolean { +fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor, bindingContext: BindingContext): Boolean { if (!target.canBeReferencedViaImport()) return false if (this is KDocReference) return element.getQualifiedName().size == 1 @@ -267,6 +268,10 @@ fun KtReference.canBeResolvedViaImport(target: DeclarationDescriptor): Boolean { if (callTypeAndReceiver.receiver != null) { if (target !is PropertyDescriptor || !target.type.isExtensionFunctionType) return false if (callTypeAndReceiver !is CallTypeAndReceiver.DOT && callTypeAndReceiver !is CallTypeAndReceiver.SAFE) return false + + val resolvedCall = bindingContext[BindingContext.CALL, referenceExpression].getResolvedCall(bindingContext) + as? VariableAsFunctionResolvedCall ?: return false + if (resolvedCall.variableCall.explicitReceiverKind.isDispatchReceiver) return false } if (element.parent is KtThisExpression || element.parent is KtSuperExpression) return false // TODO: it's a bad design of PSI tree, we should change it diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt index ab2f7bd7051..56f85033e15 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInliner/CodeToInlineBuilder.kt @@ -143,7 +143,7 @@ class CodeToInlineBuilder( val target = bindingContext[BindingContext.REFERENCE_TARGET, expression] ?: return@forEachDescendantOfType //TODO: other types of references ('[]' etc) - if (expression.mainReference.canBeResolvedViaImport(target)) { + if (expression.mainReference.canBeResolvedViaImport(target, bindingContext)) { codeToInline.fqNamesToImport.add(target.importableFqName!!) } diff --git a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt index 61f143db061..9089f88b4e7 100644 --- a/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt +++ b/idea/src/org/jetbrains/kotlin/idea/codeInsight/KotlinCopyPasteReferenceProcessor.kt @@ -167,7 +167,7 @@ class KotlinCopyPasteReferenceProcessor : CopyPastePostProcessor Unit = TODO() + } +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt new file mode 100644 index 00000000000..3b9d9529fd0 --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt @@ -0,0 +1,7 @@ +package p2 + +import p1.Foo + +fun test() { + Foo.COMPANION_VAL +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt.after b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt.after new file mode 100644 index 00000000000..3b9d9529fd0 --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt.after @@ -0,0 +1,7 @@ +package p2 + +import p1.Foo + +fun test() { + Foo.COMPANION_VAL +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.dependency.kt b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.dependency.kt new file mode 100644 index 00000000000..6f8db3343bc --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.dependency.kt @@ -0,0 +1,7 @@ +package p1 + +class Foo { + companion object { + val COMPANION_VAL: Any.() -> Unit = TODO() + } +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt new file mode 100644 index 00000000000..e161cf8651a --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt @@ -0,0 +1,8 @@ +package p2 + +import p1.Foo +import p1.Foo.Companion.COMPANION_VAL + +fun test() { + Foo.COMPANION_VAL() +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt.after b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt.after new file mode 100644 index 00000000000..e161cf8651a --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt.after @@ -0,0 +1,8 @@ +package p2 + +import p1.Foo +import p1.Foo.Companion.COMPANION_VAL + +fun test() { + Foo.COMPANION_VAL() +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.dependency.kt b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.dependency.kt new file mode 100644 index 00000000000..6f8db3343bc --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.dependency.kt @@ -0,0 +1,7 @@ +package p1 + +class Foo { + companion object { + val COMPANION_VAL: Any.() -> Unit = TODO() + } +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt new file mode 100644 index 00000000000..978817b8c99 --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt @@ -0,0 +1,7 @@ +package p2 + +import p1.Foo + +fun test() { + Foo.COMPANION_VAL("") +} \ No newline at end of file diff --git a/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt.after b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt.after new file mode 100644 index 00000000000..978817b8c99 --- /dev/null +++ b/idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt.after @@ -0,0 +1,7 @@ +package p2 + +import p1.Foo + +fun test() { + Foo.COMPANION_VAL("") +} \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java index cf93f88ebfb..9cbd76e5962 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/imports/JsOptimizeImportsTestGenerated.java @@ -89,6 +89,24 @@ public class JsOptimizeImportsTestGenerated extends AbstractJsOptimizeImportsTes doTest(fileName); } + @TestMetadata("ExtensionFunctionalTypeValFromCompanionObject.kt") + public void testExtensionFunctionalTypeValFromCompanionObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt"); + doTest(fileName); + } + + @TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt") + public void testExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt"); + doTest(fileName); + } + + @TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt") + public void testExtensionFunctionalTypeValFromCompanionObjectNonExtCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt"); + doTest(fileName); + } + @TestMetadata("InvokeFunction.kt") public void testInvokeFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/InvokeFunction.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java index e605e7ed59d..d94f18b4953 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/imports/JvmOptimizeImportsTestGenerated.java @@ -290,6 +290,24 @@ public class JvmOptimizeImportsTestGenerated extends AbstractJvmOptimizeImportsT doTest(fileName); } + @TestMetadata("ExtensionFunctionalTypeValFromCompanionObject.kt") + public void testExtensionFunctionalTypeValFromCompanionObject() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObject.kt"); + doTest(fileName); + } + + @TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt") + public void testExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectCallOnCompanion.kt"); + doTest(fileName); + } + + @TestMetadata("ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt") + public void testExtensionFunctionalTypeValFromCompanionObjectNonExtCall() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/ExtensionFunctionalTypeValFromCompanionObjectNonExtCall.kt"); + doTest(fileName); + } + @TestMetadata("InvokeFunction.kt") public void testInvokeFunction() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/editor/optimizeImports/common/InvokeFunction.kt");