Fixed bug in completion with double insertion of "::class.java"

This commit is contained in:
Valentin Kipyatkov
2015-10-17 02:51:56 +03:00
parent 499ca02615
commit d0f318d7db
9 changed files with 61 additions and 37 deletions
@@ -89,7 +89,7 @@ fun LookupElement.withReceiverCast(): LookupElement {
return object: LookupElementDecorator<LookupElement>(this) {
override fun handleInsert(context: InsertionContext) {
super.handleInsert(context)
CastReceiverInsertHandler.handleInsert(context, getDelegate())
CastReceiverInsertHandler.postHandleInsert(context, delegate)
}
}
}
@@ -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<LookupElement> {
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())
}
}
}
@@ -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<JetSimpleNameExpression>(), false)
val qualifiedExpression = PsiTreeUtil.getParentOfType(expression, javaClass<JetQualifiedExpression>(), true)
if (qualifiedExpression != null) {
@@ -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()
@@ -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<LookupElement>(it) {
override fun getAllLookupStrings(): Set<String> {
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)
}
@@ -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<LookupElement> {
@@ -0,0 +1,8 @@
fun <T> foo(klass: Class<T>) {}
fun bar() {
foo<String>(<caret>)
}
// ELEMENT: "String::class.java"
@@ -0,0 +1,8 @@
fun <T> foo(klass: Class<T>) {}
fun bar() {
foo<String>(String::class.java)<caret>
}
// ELEMENT: "String::class.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");