diff --git a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt index 3677ba9215a..ad390b00532 100644 --- a/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt +++ b/idea/idea-completion/src/org/jetbrains/kotlin/idea/completion/handlers/KotlinCallableInsertHandler.kt @@ -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) 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 b735d1a3ae5..4e2a2cfe96e 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 @@ -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() + ?.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) diff --git a/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2-1.kt b/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2-1.kt new file mode 100644 index 00000000000..261ca171968 --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2-1.kt @@ -0,0 +1,7 @@ +package a + +class Goo { + fun x() { + foo + } +} \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2-2.kt b/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2-2.kt new file mode 100644 index 00000000000..4f393b98705 --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2-2.kt @@ -0,0 +1,5 @@ +package a.b + +val Foo.foo: Int get() = 123 +fun foo(i: (Int, Int) -> Unit) {} +class Foo {} \ No newline at end of file diff --git a/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2.kt.after b/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2.kt.after new file mode 100644 index 00000000000..1650180339e --- /dev/null +++ b/idea/idea-completion/testData/handlers/multifile/PropertyFunctionConflict2.kt.after @@ -0,0 +1,9 @@ +package a + +import a.b.foo + +class Goo { + fun x() { + foo { i, i2 -> } + } +} \ No newline at end of file diff --git a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt index cbcf9373bcd..db2d62d0ba0 100644 --- a/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt +++ b/idea/idea-completion/tests/org/jetbrains/kotlin/idea/completion/test/handlers/CompletionMultifileHandlerTest.kt @@ -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