From d0f318d7dbc0481b7bed1f6207685225a39b3367 Mon Sep 17 00:00:00 2001 From: Valentin Kipyatkov Date: Sat, 17 Oct 2015 02:51:56 +0300 Subject: [PATCH] Fixed bug in completion with double insertion of "::class.java" --- .../kotlin/idea/completion/CompletionUtils.kt | 2 +- .../handlers/BaseDeclarationInsertHandler.kt | 14 +++--------- .../handlers/CastReceiverInsertHandler.kt | 6 ++--- .../handlers/KotlinFunctionInsertHandler.kt | 22 ++++++++++++++----- .../idea/completion/smart/StaticMembers.kt | 21 +++++++++--------- .../smart/TypeInstantiationItems.kt | 11 ++++++---- .../handlers/smart/ConcreteJavaClass2.kt | 8 +++++++ .../smart/ConcreteJavaClass2.kt.after | 8 +++++++ .../SmartCompletionHandlerTestGenerated.java | 6 +++++ 9 files changed, 61 insertions(+), 37 deletions(-) create mode 100644 idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt create mode 100644 idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt.after diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt index 65f13fc0bcd..6bb90227a00 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/CompletionUtils.kt @@ -89,7 +89,7 @@ fun LookupElement.withReceiverCast(): LookupElement { return object: LookupElementDecorator(this) { override fun handleInsert(context: InsertionContext) { super.handleInsert(context) - CastReceiverInsertHandler.handleInsert(context, getDelegate()) + CastReceiverInsertHandler.postHandleInsert(context, delegate) } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt index c5e97cceca3..9edda9d0a48 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/BaseDeclarationInsertHandler.kt @@ -19,22 +19,14 @@ package org.jetbrains.kotlin.idea.completion.handlers import com.intellij.codeInsight.completion.InsertHandler import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement -import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.idea.core.completion.DeclarationLookupObject -import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.renderer.render open class BaseDeclarationInsertHandler : InsertHandler { override fun handleInsert(context: InsertionContext, item: LookupElement) { - val name = (item.getObject() as? DeclarationLookupObject)?.name - if (name != null) { - val nameInCode = name.render() - val document = context.getDocument() - val needEscaping = nameInCode != name.asString() - // we check that text inserted matches the name because something else can be inserted by custom insert handler - if (needEscaping && document.getText(TextRange(context.getStartOffset(), context.getTailOffset())) == name.asString()) { - document.replaceString(context.getStartOffset(), context.getTailOffset(), nameInCode) - } + val name = (item.`object` as? DeclarationLookupObject)?.name + if (name != null && !name.isSpecial) { + context.document.replaceString(context.startOffset, context.tailOffset, name.render()) } } } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/CastReceiverInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/CastReceiverInsertHandler.kt index 7fdcf59652d..0b9a34d2464 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/CastReceiverInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/CastReceiverInsertHandler.kt @@ -26,10 +26,8 @@ import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.ShortenReferences import org.jetbrains.kotlin.psi.* -object CastReceiverInsertHandler : KotlinCallableInsertHandler() { - override fun handleInsert(context: InsertionContext, item: LookupElement) { - super.handleInsert(context, item) - +object CastReceiverInsertHandler { + fun postHandleInsert(context: InsertionContext, item: LookupElement) { val expression = PsiTreeUtil.findElementOfClassAtOffset(context.getFile(), context.getStartOffset(), javaClass(), false) val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass(), true) if (qualifiedExpression != null) { diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt index 93235a6378c..22cd3cd45de 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinFunctionInsertHandler.kt @@ -33,15 +33,14 @@ import org.jetbrains.kotlin.types.JetType class GenerateLambdaInfo(val lambdaType: JetType, val explicitParameters: Boolean) -sealed class KotlinFunctionInsertHandler( - -) : KotlinCallableInsertHandler() { +sealed class KotlinFunctionInsertHandler : KotlinCallableInsertHandler() { class Normal( val inputTypeArguments: Boolean, val inputValueArguments: Boolean, val argumentText: String = "", - val lambdaInfo: GenerateLambdaInfo? = null + val lambdaInfo: GenerateLambdaInfo? = null, + val argumentsOnly: Boolean = false ) : KotlinFunctionInsertHandler() { init { if (lambdaInfo != null) { @@ -49,8 +48,19 @@ sealed class KotlinFunctionInsertHandler( } } - public override fun handleInsert(context: InsertionContext, item: LookupElement) { - super.handleInsert(context, item) + //TODO: add 'data' or special annotation when supported + fun copy( + inputTypeArguments: Boolean = this.inputTypeArguments, + inputValueArguments: Boolean = this.inputValueArguments, + argumentText: String = this.argumentText, + lambdaInfo: GenerateLambdaInfo? = this.lambdaInfo, + argumentsOnly: Boolean = this.argumentsOnly + ) = Normal(inputTypeArguments, inputValueArguments, argumentText, lambdaInfo, argumentsOnly) + + override fun handleInsert(context: InsertionContext, item: LookupElement) { + if (!argumentsOnly) { + super.handleInsert(context, item) + } val psiDocumentManager = PsiDocumentManager.getInstance(context.project) psiDocumentManager.commitAllDocuments() diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt index ba08f232747..8be97474891 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/StaticMembers.kt @@ -16,10 +16,12 @@ package org.jetbrains.kotlin.idea.completion.smart +import com.intellij.codeInsight.completion.CompletionInitializationContext import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementDecorator import com.intellij.codeInsight.lookup.LookupElementPresentation +import com.intellij.psi.PsiDocumentManager import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.idea.completion.ExpectedInfo import org.jetbrains.kotlin.idea.completion.LookupElementFactory @@ -30,7 +32,6 @@ import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers import org.jetbrains.kotlin.idea.util.fuzzyReturnType import org.jetbrains.kotlin.psi.JetSimpleNameExpression import org.jetbrains.kotlin.renderer.DescriptorRenderer -import org.jetbrains.kotlin.renderer.render import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.DescriptorUtils import org.jetbrains.kotlin.resolve.descriptorUtil.isExtension @@ -109,9 +110,7 @@ class StaticMembers( return lookupElements.map { object: LookupElementDecorator(it) { - override fun getAllLookupStrings(): Set { - return setOf(it.lookupString, qualifierPresentation) - } + override fun getAllLookupStrings() = setOf(delegate.lookupString, qualifierPresentation) override fun renderElement(presentation: LookupElementPresentation) { getDelegate().renderElement(presentation) @@ -132,16 +131,16 @@ class StaticMembers( } override fun handleInsert(context: InsertionContext) { - var text = qualifierText + "." + memberDescriptor.getName().render() + val prefix = qualifierText + "." - context.getDocument().replaceString(context.getStartOffset(), context.getTailOffset(), text) - context.setTailOffset(context.getStartOffset() + text.length()) + val offset = context.startOffset + context.document.insertString(offset, prefix) + context.offsetMap.addOffset(CompletionInitializationContext.START_OFFSET, offset + prefix.length) - if (memberDescriptor is FunctionDescriptor) { - getDelegate().handleInsert(context) - } + shortenReferences(context, offset, offset + prefix.length) + PsiDocumentManager.getInstance(context.project).doPostponedOperationsAndUnblockDocument(context.document) - shortenReferences(context, context.getStartOffset(), context.getTailOffset()) + super.handleInsert(context) } }.assignSmartCompletionPriority(SmartCompletionItemPriority.STATIC_MEMBER) } diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt index 3f79d482cfe..2d42a476011 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/smart/TypeInstantiationItems.kt @@ -202,10 +202,13 @@ class TypeInstantiationItems( else -> "(...)" } - val baseInsertHandler = when (visibleConstructors.size()) { - 0 -> KotlinFunctionInsertHandler.Normal(inputTypeArguments = false, inputValueArguments = false) - 1 -> lookupElementFactory.insertHandlerProvider.insertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler.Normal - else -> KotlinFunctionInsertHandler.Normal(inputTypeArguments = false, inputValueArguments = true) + val baseInsertHandler = when (visibleConstructors.size) { + 0 -> KotlinFunctionInsertHandler.Normal(inputTypeArguments = false, inputValueArguments = false, argumentsOnly = true) + + 1 -> (lookupElementFactory.insertHandlerProvider.insertHandler(visibleConstructors.single()) as KotlinFunctionInsertHandler.Normal) + .copy(argumentsOnly = true) + + else -> KotlinFunctionInsertHandler.Normal(inputTypeArguments = false, inputValueArguments = true, argumentsOnly = true) } insertHandler = object : InsertHandler { diff --git a/idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt b/idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt new file mode 100644 index 00000000000..c6d79e4466c --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt @@ -0,0 +1,8 @@ +fun foo(klass: Class) {} + +fun bar() { + foo() +} + +// ELEMENT: "String::class.java" + diff --git a/idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt.after b/idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt.after new file mode 100644 index 00000000000..d7c838a578a --- /dev/null +++ b/idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt.after @@ -0,0 +1,8 @@ +fun foo(klass: Class) {} + +fun bar() { + foo(String::class.java) +} + +// ELEMENT: "String::class.java" + diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java index 54b70c481cd..ffdefa076f9 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/SmartCompletionHandlerTestGenerated.java @@ -269,6 +269,12 @@ public class SmartCompletionHandlerTestGenerated extends AbstractSmartCompletion doTest(fileName); } + @TestMetadata("ConcreteJavaClass2.kt") + public void testConcreteJavaClass2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/ConcreteJavaClass2.kt"); + doTest(fileName); + } + @TestMetadata("ConcreteKClass.kt") public void testConcreteKClass() throws Exception { String fileName = JetTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/smart/ConcreteKClass.kt");