KT-8529 Code completion for parameter name and type together replaces wrong range on Tab
#KT-8529 Fixed
This commit is contained in:
+12
-4
@@ -108,9 +108,9 @@ class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
?: DEFAULT_DUMMY_IDENTIFIER
|
?: DEFAULT_DUMMY_IDENTIFIER
|
||||||
}
|
}
|
||||||
|
|
||||||
if (context.completionType == CompletionType.SMART && !isAtEndOfLine(offset, context.editor.document) /* do not use parent expression if we are at the end of line - it's probably parsed incorrectly */) {
|
val tokenAt = psiFile.findElementAt(Math.max(0, offset))
|
||||||
val tokenAt = psiFile.findElementAt(Math.max(0, offset))
|
if (tokenAt != null) {
|
||||||
if (tokenAt != null) {
|
if (context.completionType == CompletionType.SMART && !isAtEndOfLine(offset, context.editor.document) /* do not use parent expression if we are at the end of line - it's probably parsed incorrectly */) {
|
||||||
var parent = tokenAt.parent
|
var parent = tokenAt.parent
|
||||||
if (parent is KtExpression && parent !is KtBlockExpression) {
|
if (parent is KtExpression && parent !is KtBlockExpression) {
|
||||||
// search expression to be replaced - go up while we are the first child of parent expression
|
// search expression to be replaced - go up while we are the first child of parent expression
|
||||||
@@ -131,11 +131,19 @@ class KotlinCompletionContributor : CompletionContributor() {
|
|||||||
val argumentList = (expression.parent as? KtValueArgument)?.parent as? KtValueArgumentList
|
val argumentList = (expression.parent as? KtValueArgument)?.parent as? KtValueArgumentList
|
||||||
if (argumentList != null) {
|
if (argumentList != null) {
|
||||||
context.offsetMap.addOffset(SmartCompletion.MULTIPLE_ARGUMENTS_REPLACEMENT_OFFSET,
|
context.offsetMap.addOffset(SmartCompletion.MULTIPLE_ARGUMENTS_REPLACEMENT_OFFSET,
|
||||||
argumentList.rightParenthesis?.textRange?.startOffset ?: argumentList.endOffset)
|
argumentList.rightParenthesis?.textRange?.startOffset ?: argumentList.endOffset)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
if (tokenAt.node.elementType == KtTokens.IDENTIFIER) {
|
||||||
|
val parameter = tokenAt.parent as? KtParameter
|
||||||
|
if (parameter != null) {
|
||||||
|
context.offsetMap.addOffset(ParameterNameAndTypeCompletion.REPLACEMENT_OFFSET, parameter.endOffset)
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun replacementOffsetByExpression(expression: KtExpression): Int {
|
private fun replacementOffsetByExpression(expression: KtExpression): Int {
|
||||||
|
|||||||
+24
-6
@@ -16,10 +16,7 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.idea.completion
|
package org.jetbrains.kotlin.idea.completion
|
||||||
|
|
||||||
import com.intellij.codeInsight.completion.CompletionInitializationContext
|
import com.intellij.codeInsight.completion.*
|
||||||
import com.intellij.codeInsight.completion.CompletionParameters
|
|
||||||
import com.intellij.codeInsight.completion.InsertionContext
|
|
||||||
import com.intellij.codeInsight.completion.PrefixMatcher
|
|
||||||
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
|
import com.intellij.codeInsight.completion.impl.CamelHumpMatcher
|
||||||
import com.intellij.codeInsight.lookup.*
|
import com.intellij.codeInsight.lookup.*
|
||||||
import com.intellij.openapi.progress.ProgressManager
|
import com.intellij.openapi.progress.ProgressManager
|
||||||
@@ -30,9 +27,12 @@ import com.intellij.psi.codeStyle.CodeStyleSettingsManager
|
|||||||
import com.intellij.psi.codeStyle.NameUtil
|
import com.intellij.psi.codeStyle.NameUtil
|
||||||
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassifierDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.idea.completion.handlers.isCharAt
|
||||||
|
import org.jetbrains.kotlin.idea.completion.handlers.skipSpaces
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
import org.jetbrains.kotlin.idea.core.KotlinIndicesHelper
|
||||||
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
import org.jetbrains.kotlin.idea.core.KotlinNameSuggester
|
||||||
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
|
||||||
|
import org.jetbrains.kotlin.idea.quickfix.moveCaret
|
||||||
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
import org.jetbrains.kotlin.idea.resolve.ResolutionFacade
|
||||||
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
import org.jetbrains.kotlin.idea.util.IdeDescriptorRenderers
|
||||||
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
import org.jetbrains.kotlin.idea.util.getResolutionScope
|
||||||
@@ -206,6 +206,22 @@ class ParameterNameAndTypeCompletion(
|
|||||||
}
|
}
|
||||||
|
|
||||||
override fun handleInsert(context: InsertionContext) {
|
override fun handleInsert(context: InsertionContext) {
|
||||||
|
if (context.completionChar == Lookup.REPLACE_SELECT_CHAR) {
|
||||||
|
val replacementOffset = context.offsetMap.getOffset(REPLACEMENT_OFFSET)
|
||||||
|
if (replacementOffset != -1) {
|
||||||
|
val tailOffset = context.tailOffset
|
||||||
|
context.document.deleteString(tailOffset, replacementOffset)
|
||||||
|
|
||||||
|
val chars = context.document.charsSequence
|
||||||
|
var offset = chars.skipSpaces(tailOffset)
|
||||||
|
if (chars.isCharAt(offset, ',')) {
|
||||||
|
offset++
|
||||||
|
offset = chars.skipSpaces(offset)
|
||||||
|
context.editor.moveCaret(offset)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
val settings = CodeStyleSettingsManager.getInstance(context.project).currentSettings.getCustomSettings(KotlinCodeStyleSettings::class.java)
|
val settings = CodeStyleSettingsManager.getInstance(context.project).currentSettings.getCustomSettings(KotlinCodeStyleSettings::class.java)
|
||||||
val spaceBefore = if (settings.SPACE_BEFORE_TYPE_COLON) " " else ""
|
val spaceBefore = if (settings.SPACE_BEFORE_TYPE_COLON) " " else ""
|
||||||
val spaceAfter = if (settings.SPACE_AFTER_TYPE_COLON) " " else ""
|
val spaceAfter = if (settings.SPACE_AFTER_TYPE_COLON) " " else ""
|
||||||
@@ -224,8 +240,10 @@ class ParameterNameAndTypeCompletion(
|
|||||||
override fun hashCode() = parameterName.hashCode()
|
override fun hashCode() = parameterName.hashCode()
|
||||||
}
|
}
|
||||||
|
|
||||||
private companion object {
|
companion object {
|
||||||
val PRIORITY_KEY = Key<Int>("ParameterNameAndTypeCompletion.PRIORITY_KEY")
|
private val PRIORITY_KEY = Key<Int>("ParameterNameAndTypeCompletion.PRIORITY_KEY")
|
||||||
|
|
||||||
|
val REPLACEMENT_OFFSET = OffsetKey.create("ParameterNameAndTypeCompletion.REPLACEMENT_OFFSET")
|
||||||
}
|
}
|
||||||
|
|
||||||
object Weigher : LookupElementWeigher("kotlin.parameterNameAndTypePriority") {
|
object Weigher : LookupElementWeigher("kotlin.parameterNameAndTypePriority") {
|
||||||
|
|||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
class FooBar
|
||||||
|
|
||||||
|
fun f(b<caret>pp: (Int, Char) -> String)
|
||||||
|
|
||||||
|
// ELEMENT_TEXT: bar: FooBar
|
||||||
|
// CHAR: '\t'
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
class FooBar
|
||||||
|
|
||||||
|
fun f(bar: FooBar<caret>)
|
||||||
|
|
||||||
|
// ELEMENT_TEXT: bar: FooBar
|
||||||
|
// CHAR: '\t'
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
class FooBar
|
||||||
|
|
||||||
|
fun f(b<caret>pp: Int, c: Char)
|
||||||
|
|
||||||
|
// ELEMENT_TEXT: bar: FooBar
|
||||||
|
// CHAR: '\t'
|
||||||
+6
@@ -0,0 +1,6 @@
|
|||||||
|
class FooBar
|
||||||
|
|
||||||
|
fun f(bar: FooBar, <caret>c: Char)
|
||||||
|
|
||||||
|
// ELEMENT_TEXT: bar: FooBar
|
||||||
|
// CHAR: '\t'
|
||||||
+12
@@ -562,6 +562,18 @@ public class BasicCompletionHandlerTestGenerated extends AbstractBasicCompletion
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TabReplace1.kt")
|
||||||
|
public void testTabReplace1() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace1.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("TabReplace2.kt")
|
||||||
|
public void testTabReplace2() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/parameterNameAndType/TabReplace2.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("TypeParameter.kt")
|
@TestMetadata("TypeParameter.kt")
|
||||||
public void testTypeParameter() throws Exception {
|
public void testTypeParameter() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/parameterNameAndType/TypeParameter.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("idea/idea-completion/testData/handlers/basic/parameterNameAndType/TypeParameter.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user