Completion: fix shortening of fully qualified name for case of conflicts between property and function

#KT-31902 Fixed
#KT-33937 Fixed
This commit is contained in:
Dmitry Gridin
2019-09-26 17:58:26 +07:00
parent 589094377e
commit c185cecb40
6 changed files with 61 additions and 21 deletions
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.resolve.DescriptorUtils
abstract class KotlinCallableInsertHandler(val callType: CallType<*>) : BaseDeclarationInsertHandler() {
companion object {
private val shortenReferences = ShortenReferences { ShortenReferences.Options.DEFAULT.copy(dropBracesInStringTemplates = false) }
val SHORTEN_REFERENCES = ShortenReferences { ShortenReferences.Options.DEFAULT.copy(dropBracesInStringTemplates = false) }
}
override fun handleInsert(context: InsertionContext, item: LookupElement) {
@@ -54,7 +54,7 @@ abstract class KotlinCallableInsertHandler(val callType: CallType<*>) : BaseDecl
psiDocumentManager.commitAllDocuments()
shortenReferences.process(file, context.startOffset, context.tailOffset - 1)
SHORTEN_REFERENCES.process(file, context.startOffset, context.tailOffset - 1)
psiDocumentManager.doPostponedOperationsAndUnblockDocument(context.document)
@@ -1,17 +1,6 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.completion.handlers
@@ -29,9 +18,12 @@ import org.jetbrains.kotlin.idea.completion.LambdaSignatureTemplates
import org.jetbrains.kotlin.idea.core.formatter.KotlinCodeStyleSettings
import org.jetbrains.kotlin.idea.util.CallType
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.KtTypeArgumentList
import org.jetbrains.kotlin.psi.psiUtil.createSmartPointer
import org.jetbrains.kotlin.psi.psiUtil.endOffset
import org.jetbrains.kotlin.psi.psiUtil.getLastParentOfTypeInRow
import org.jetbrains.kotlin.types.KotlinType
class GenerateLambdaInfo(val lambdaType: KotlinType, val explicitParameters: Boolean)
@@ -79,6 +71,18 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
val element = context.file.findElementAt(startOffset) ?: return
addArguments(context, element)
// hack for KT-31902
if (callType == CallType.DEFAULT) {
context.file
.findElementAt(startOffset)
?.parent?.getLastParentOfTypeInRow<KtDotQualifiedExpression>()
?.createSmartPointer()?.let {
psiDocumentManager.commitDocument(document)
val dotQualifiedExpression = it.element ?: return@let
SHORTEN_REFERENCES.process(dotQualifiedExpression)
}
}
}
private fun addArguments(context: InsertionContext, offsetElement: PsiElement) {
@@ -104,11 +108,12 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
var insertTypeArguments = inputTypeArguments && (isNormalCompletion || isReplaceCompletion || isSmartEnterCompletion)
val psiDocumentManager = PsiDocumentManager.getInstance(project)
if (isReplaceCompletion) {
val offset1 = chars.skipSpaces(offset)
if (offset1 < chars.length) {
if (chars[offset1] == '<') {
PsiDocumentManager.getInstance(project).commitDocument(document)
psiDocumentManager.commitDocument(document)
val token = context.file.findElementAt(offset1)!!
if (token.node.elementType == KtTokens.LT) {
val parent = token.parent
@@ -159,7 +164,7 @@ sealed class KotlinFunctionInsertHandler(callType: CallType<*>) : KotlinCallable
document.insertString(offset, "()")
}
}
PsiDocumentManager.getInstance(project).commitDocument(document)
psiDocumentManager.commitDocument(document)
openingBracketOffset = document.charsSequence.indexOfSkippingSpace(openingBracket, offset)!!
closeBracketOffset = document.charsSequence.indexOfSkippingSpace(closingBracket, openingBracketOffset + 1)
@@ -0,0 +1,7 @@
package a
class Goo {
fun x() {
foo<caret>
}
}
@@ -0,0 +1,5 @@
package a.b
val Foo.foo: Int get() = 123
fun foo(i: (Int, Int) -> Unit) {}
class Foo {}
@@ -0,0 +1,9 @@
package a
import a.b.foo
class Goo {
fun x() {
foo { i, i2 -> }
}
}
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.idea.completion.test.handlers
import com.intellij.codeInsight.lookup.LookupElementPresentation
import org.jetbrains.kotlin.idea.completion.test.COMPLETION_TEST_DATA_BASE_PATH
import org.jetbrains.kotlin.idea.completion.test.KotlinCompletionTestCase
import org.jetbrains.kotlin.test.JUnit3WithIdeaConfigurationRunner
@@ -73,6 +74,10 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
doTest()
}
fun testPropertyFunctionConflict2() {
doTest(tailText = " { Int, Int -> ... } (i: (Int, Int) -> Unit) (a.b)")
}
fun testExclCharInsertImport() {
doTest('!')
}
@@ -105,17 +110,26 @@ class CompletionMultiFileHandlerTest : KotlinCompletionTestCase() {
doTest()
}
fun doTest(completionChar: Char = '\n', vararg extraFileNames: String) {
fun doTest(completionChar: Char = '\n', vararg extraFileNames: String, tailText: String? = null) {
val fileName = getTestName(false)
configureByFiles(null, *extraFileNames)
configureByFiles(null, fileName + "-1.kt", fileName + "-2.kt")
configureByFiles(null, "$fileName-1.kt", "$fileName-2.kt")
complete(2)
if (myItems != null) {
val item = myItems.singleOrNull() ?: error("Multiple items in completion")
val item = if (tailText == null)
myItems.singleOrNull() ?: error("Multiple items in completion")
else {
val presentation = LookupElementPresentation()
myItems.first {
it.renderElement(presentation)
presentation.tailText == tailText
} ?: error("Tail text not found")
}
selectItem(item, completionChar)
}
checkResultByFile(fileName + ".kt.after")
checkResultByFile("$fileName.kt.after")
}
override fun getTestDataPath() = File(COMPLETION_TEST_DATA_BASE_PATH, "/handlers/multifile/").path + File.separator