From b94e9e63c37b1b8c52833d9867aa8fe1797dca12 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Thu, 25 Dec 2014 18:39:18 +0300 Subject: [PATCH] KT-6534 Code completion of global function does not insert import in very specific context #KT-6534 Fixed --- .../jet/plugin/completion/CompletionUtils.kt | 15 ++++++++++++ .../handlers/KotlinCallableInsertHandler.kt | 5 ++-- .../handlers/KotlinClassInsertHandler.kt | 23 ++++--------------- .../GlobalFunctionImportInLambda-1.kt | 9 ++++++++ .../GlobalFunctionImportInLambda-2.kt | 3 +++ .../GlobalFunctionImportInLambda.kt.after | 11 +++++++++ .../CompletionMultifileHandlerTest.java | 4 ++++ 7 files changed, 50 insertions(+), 20 deletions(-) create mode 100644 idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-1.kt create mode 100644 idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-2.kt create mode 100644 idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda.kt.after diff --git a/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt b/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt index fbb95c63625..1a81c5dc3ec 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/CompletionUtils.kt @@ -44,6 +44,7 @@ import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue import org.jetbrains.jet.lang.psi.psiUtil.getReceiverExpression import org.jetbrains.jet.lang.resolve.scopes.receivers.ExpressionReceiver import org.jetbrains.jet.lang.types.expressions.ExpressionTypingUtils +import com.intellij.openapi.editor.Document enum class ItemPriority { MULTIPLE_ARGUMENTS_ITEM @@ -170,3 +171,17 @@ fun DeclarationDescriptorWithVisibility.isVisible( } return false } + +fun InsertionContext.isAfterDot(): Boolean { + var offset = getStartOffset() + val chars = getDocument().getCharsSequence() + while (offset > 0) { + offset-- + val c = chars.charAt(offset) + if (!Character.isWhitespace(c)) { + return c == '.' + } + } + return false +} + diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt index 54ca749dfef..dd08c9af8b7 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinCallableInsertHandler.kt @@ -47,6 +47,7 @@ import org.jetbrains.jet.plugin.completion.qualifiedNameForSourceCode import org.jetbrains.jet.lexer.JetTokens import org.jetbrains.jet.lang.psi.JetTypeArgumentList import com.intellij.codeInsight.lookup.Lookup +import org.jetbrains.jet.plugin.completion.isAfterDot public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler() { public override fun handleInsert(context: InsertionContext, item: LookupElement) { @@ -69,8 +70,8 @@ public abstract class KotlinCallableInsertHandler : BaseDeclarationInsertHandler if (file is JetFile && o is DeclarationDescriptorLookupObject) { val descriptor = o.descriptor as? CallableDescriptor if (descriptor != null) { - if (element.getStrictParentOfType() != null && - descriptor.getExtensionReceiverParameter() == null) { + // for completion after dot, import insertion may be required only for extensions + if (context.isAfterDot() && descriptor.getExtensionReceiverParameter() == null) { return@runReadAction } diff --git a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinClassInsertHandler.kt b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinClassInsertHandler.kt index 06dffb668d0..027a8b85294 100644 --- a/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinClassInsertHandler.kt +++ b/idea/src/org/jetbrains/jet/plugin/completion/handlers/KotlinClassInsertHandler.kt @@ -18,7 +18,6 @@ package org.jetbrains.jet.plugin.completion.handlers import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.openapi.editor.Document import com.intellij.psi.PsiDocumentManager import org.jetbrains.jet.lang.psi.JetFile import org.jetbrains.jet.plugin.codeInsight.ShortenReferences @@ -30,7 +29,7 @@ import org.jetbrains.jet.lang.psi.JetNameReferenceExpression import org.jetbrains.jet.plugin.caches.resolve.getResolutionFacade import org.jetbrains.jet.lang.resolve.BindingContext import org.jetbrains.jet.lang.resolve.lazy.BodyResolveMode -import org.jetbrains.jet.lang.descriptors.ClassKind +import org.jetbrains.jet.plugin.completion.isAfterDot public object KotlinClassInsertHandler : BaseDeclarationInsertHandler() { override fun handleInsert(context: InsertionContext, item: LookupElement) { @@ -38,12 +37,13 @@ public object KotlinClassInsertHandler : BaseDeclarationInsertHandler() { val file = context.getFile() if (file is JetFile) { - val startOffset = context.getStartOffset() - val document = context.getDocument() - if (!isAfterDot(document, startOffset)) { + if (!context.isAfterDot()) { val psiDocumentManager = PsiDocumentManager.getInstance(context.getProject()) psiDocumentManager.commitAllDocuments() + val startOffset = context.getStartOffset() + val document = context.getDocument() + val qualifiedName = qualifiedNameToInsert(item) // first try to resolve short name for faster handling @@ -88,17 +88,4 @@ public object KotlinClassInsertHandler : BaseDeclarationInsertHandler() { else -> error("Unknown object in LookupElement with KotlinClassInsertHandler: $lookupObject") } } - - private fun isAfterDot(document: Document, offset: Int): Boolean { - var curOffset = offset - val chars = document.getCharsSequence() - while (curOffset > 0) { - curOffset-- - val c = chars.charAt(curOffset) - if (!Character.isWhitespace(c)) { - return c == '.' - } - } - return false - } } diff --git a/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-1.kt b/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-1.kt new file mode 100644 index 00000000000..d6793e38555 --- /dev/null +++ b/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-1.kt @@ -0,0 +1,9 @@ +object XXX { + fun authorize(handler: String.() -> Unit) { } +} + +fun f() { + XXX.authorize { + globalFun + } +} diff --git a/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-2.kt b/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-2.kt new file mode 100644 index 00000000000..87ced45665e --- /dev/null +++ b/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda-2.kt @@ -0,0 +1,3 @@ +package ppp + +fun globalFun(){} \ No newline at end of file diff --git a/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda.kt.after b/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda.kt.after new file mode 100644 index 00000000000..084f27b1cf6 --- /dev/null +++ b/idea/testData/completion/handlers/multifile/GlobalFunctionImportInLambda.kt.after @@ -0,0 +1,11 @@ +import ppp.globalFun + +object XXX { + fun authorize(handler: String.() -> Unit) { } +} + +fun f() { + XXX.authorize { + globalFun() + } +} diff --git a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java index ec9614b024f..6c8a0bf02e8 100644 --- a/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java +++ b/idea/tests/org/jetbrains/jet/completion/handlers/CompletionMultifileHandlerTest.java @@ -66,6 +66,10 @@ public class CompletionMultifileHandlerTest extends KotlinCompletionTestCase { doTest(); } + public void testGlobalFunctionImportInLambda() throws Exception { + doTest(); + } + public void doTest() throws Exception { String fileName = getTestName(false);