From 0f13359229ad904df1f60a72ff8ea51ad50f0120 Mon Sep 17 00:00:00 2001 From: Ilya Kirillov Date: Wed, 26 May 2021 20:04:05 +0200 Subject: [PATCH] FIR IDE: implement completion in where clause --- .../KotlinFirCompletionContributor.kt | 5 ++ .../context/FirPositionCompletionContext.kt | 15 +++++- .../FirKeywordCompletionContributor.kt | 5 ++ ...tNameInWhereClauseCompletionContributor.kt | 54 +++++++++++++++++++ .../helpers/FirSuperEntriesProvider.kt | 2 +- .../contributors/helpers/completionHelpers.kt | 8 +-- .../PackagePartLookupElementFactory.kt | 4 +- 7 files changed, 84 insertions(+), 9 deletions(-) create mode 100644 idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirTypeParameterConstraintNameInWhereClauseCompletionContributor.kt diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt index b702fa29bae..4b06500d143 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/KotlinFirCompletionContributor.kt @@ -69,6 +69,7 @@ private object KotlinFirCompletionProvider : CompletionProvider { @@ -103,6 +104,10 @@ private object KotlinFirCompletionProvider : CompletionProvider { + complete(typeParameterConstraintNameInWhereClauseContributor, positionContext) + } + is FirUnknownPositionContext -> { complete(keywordContributor, positionContext) } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt index c2a2c8a85f6..a25802a8add 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/context/FirPositionCompletionContext.kt @@ -19,6 +19,11 @@ internal sealed class FirRawPositionCompletionContext { abstract val position: PsiElement } +internal class FirTypeConstraintNameInWhereClausePositionContext( + override val position: PsiElement, + val typeParametersOwner: KtTypeParameterListOwner +) : FirRawPositionCompletionContext() + internal sealed class FirNameReferencePositionContext : FirRawPositionCompletionContext() { abstract val reference: KtSimpleNameReference abstract val nameExpression: KtSimpleNameExpression @@ -40,7 +45,6 @@ internal class FirPackageDirectivePositionContext( ) : FirNameReferencePositionContext() - internal class FirTypeNameReferencePositionContext( override val position: PsiElement, override val reference: KtSimpleNameReference, @@ -108,6 +112,10 @@ internal object FirPositionCompletionContextDetector { explicitReceiver, ) } + parent is KtTypeConstraint -> FirTypeConstraintNameInWhereClausePositionContext( + position, + position.parentOfType()!!, + ) else -> { FirExpressionNameReferencePositionContext(position, reference, nameExpression, explicitReceiver) } @@ -169,7 +177,10 @@ internal object FirPositionCompletionContextDetector { positionContext.nameExpression, action ) - is FirUnknownPositionContext, is FirImportDirectivePositionContext, is FirPackageDirectivePositionContext -> { + is FirUnknownPositionContext, + is FirImportDirectivePositionContext, + is FirPackageDirectivePositionContext, + is FirTypeConstraintNameInWhereClausePositionContext -> { analyse(basicContext.originalKtFile, action) } } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt index 06467d3ddf1..d4767fab73e 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirKeywordCompletionContributor.kt @@ -9,9 +9,11 @@ import com.intellij.codeInsight.lookup.LookupElement import com.intellij.openapi.module.Module import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.completion.* +import org.jetbrains.kotlin.idea.completion.context.* import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.context.FirNameReferencePositionContext import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext +import org.jetbrains.kotlin.idea.completion.context.FirTypeConstraintNameInWhereClausePositionContext import org.jetbrains.kotlin.idea.completion.context.FirUnknownPositionContext import org.jetbrains.kotlin.idea.completion.contributors.keywords.OverrideKeywordHandler import org.jetbrains.kotlin.idea.completion.contributors.keywords.ReturnKeywordHandler @@ -44,6 +46,9 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC else -> reference.expression } } + is FirTypeConstraintNameInWhereClausePositionContext -> { + error("keyword completion should not be called for FirTypeConstraintNameInWhereClausePositionContext") + } is FirUnknownPositionContext -> null } completeWithResolve(expression ?: positionContext.position, expression) diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirTypeParameterConstraintNameInWhereClauseCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirTypeParameterConstraintNameInWhereClauseCompletionContributor.kt new file mode 100644 index 00000000000..62f0fb2088c --- /dev/null +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirTypeParameterConstraintNameInWhereClauseCompletionContributor.kt @@ -0,0 +1,54 @@ +/* + * Copyright 2010-2021 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.contributors + +import com.intellij.codeInsight.completion.InsertHandler +import com.intellij.codeInsight.completion.InsertionContext +import com.intellij.codeInsight.lookup.LookupElement +import com.intellij.codeInsight.lookup.LookupElementBuilder +import org.jetbrains.kotlin.idea.completion.KotlinFirIconProvider.getIconFor +import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext +import org.jetbrains.kotlin.idea.completion.context.FirTypeConstraintNameInWhereClausePositionContext +import org.jetbrains.kotlin.idea.completion.contributors.helpers.addSymbolAndInvokeCompletion +import org.jetbrains.kotlin.idea.completion.lookups.KotlinLookupObject +import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession +import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtSymbolWithTypeParameters +import org.jetbrains.kotlin.name.Name +import org.jetbrains.kotlin.renderer.render + +internal class FirTypeParameterConstraintNameInWhereClauseCompletionContributor( + basicContext: FirBasicCompletionContext +) : FirCompletionContributorBase(basicContext) { + + override fun KtAnalysisSession.complete(positionContext: FirTypeConstraintNameInWhereClausePositionContext) { + val ownerSymbol = positionContext.typeParametersOwner.getSymbol() as? KtSymbolWithTypeParameters ?: return + ownerSymbol.typeParameters.forEach { typeParameter -> + val name = typeParameter.name + val icon = getIconFor(typeParameter) + LookupElementBuilder.create(TypeParameterInWhenClauseILookupObject(name), name.asString()) + .withTailText(" : ") + .withInsertHandler(TypeParameterInWhenClauseInsertionHandler) + .withPsiElement(typeParameter.psi) + .withIcon(icon) + .let(result::addElement) + } + } +} + +private class TypeParameterInWhenClauseILookupObject(override val shortName: Name) : KotlinLookupObject + + +private object TypeParameterInWhenClauseInsertionHandler : InsertHandler { + override fun handleInsert(context: InsertionContext, item: LookupElement) { + val lookupElement = item.`object` as TypeParameterInWhenClauseILookupObject + val name = lookupElement.shortName.render() + context.document.replaceString(context.startOffset, context.tailOffset, name) + context.commitDocument() + context.addSymbolAndInvokeCompletion(symbol = " : ") + } +} + + diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/FirSuperEntriesProvider.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/FirSuperEntriesProvider.kt index 8254d8f9d63..c81245f5358 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/FirSuperEntriesProvider.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/FirSuperEntriesProvider.kt @@ -34,7 +34,7 @@ internal object SuperCallInsertionHandler : InsertHandler { val lookupObject = item.`object` as SuperCallLookupObject replaceWithClassIdAndShorten(lookupObject, context) - context.addDotAndInvokeCompletion() + context.addSymbolAndInvokeCompletion(symbol = ".") } private fun replaceWithClassIdAndShorten( diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/completionHelpers.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/completionHelpers.kt index 415b70a93b1..e0efa77680b 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/completionHelpers.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/helpers/completionHelpers.kt @@ -10,8 +10,8 @@ import com.intellij.codeInsight.completion.CompletionType import com.intellij.codeInsight.completion.InsertionContext import com.intellij.openapi.application.ApplicationManager -internal fun InsertionContext.addDotAndInvokeCompletion() { - addDotToCompletion(this) +internal fun InsertionContext.addSymbolAndInvokeCompletion(symbol: String) { + addSymbolToCompletion(this, symbol) invokeCompletion(this) } @@ -22,8 +22,8 @@ private fun invokeCompletion(context: InsertionContext) { } } -private fun addDotToCompletion(context: InsertionContext) { - context.document.insertString(context.tailOffset, ".") +private fun addSymbolToCompletion(context: InsertionContext, symbol: String) { + context.document.insertString(context.tailOffset, symbol) context.commitDocument() context.editor.caretModel.moveToOffset(context.tailOffset) } \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/PackagePartLookupElementFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/PackagePartLookupElementFactory.kt index 815d238e94d..bc9ac066f1b 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/PackagePartLookupElementFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/PackagePartLookupElementFactory.kt @@ -10,7 +10,7 @@ import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.icons.AllIcons -import org.jetbrains.kotlin.idea.completion.contributors.helpers.addDotAndInvokeCompletion +import org.jetbrains.kotlin.idea.completion.contributors.helpers.addSymbolAndInvokeCompletion import org.jetbrains.kotlin.idea.completion.lookups.KotlinLookupObject import org.jetbrains.kotlin.miniStdLib.letIf import org.jetbrains.kotlin.name.FqName @@ -41,7 +41,7 @@ private object PackagePartInsertionHandler : InsertHandler { val name = lookupElement.shortName.render() context.document.replaceString(context.startOffset, context.tailOffset, name) context.commitDocument() - context.addDotAndInvokeCompletion() + context.addSymbolAndInvokeCompletion(symbol = ".") } }