FIR IDE: implement completion in where clause

This commit is contained in:
Ilya Kirillov
2021-05-26 20:04:05 +02:00
committed by TeamCityServer
parent 5b5bbdd113
commit 0f13359229
7 changed files with 84 additions and 9 deletions
@@ -69,6 +69,7 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
val annotationsContributor = FirAnnotationCompletionContributor(basicContext)
val packageCompletionContributor = FirPackageCompletionContributor(basicContext)
val importDirectivePackageMembersCompletionContributor = FirImportDirectivePackageMembersCompletionContributor(basicContext)
val typeParameterConstraintNameInWhereClauseContributor = FirTypeParameterConstraintNameInWhereClauseCompletionContributor(basicContext)
when (positionContext) {
is FirExpressionNameReferencePositionContext -> {
@@ -103,6 +104,10 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
complete(packageCompletionContributor, positionContext)
}
is FirTypeConstraintNameInWhereClausePositionContext -> {
complete(typeParameterConstraintNameInWhereClauseContributor, positionContext)
}
is FirUnknownPositionContext -> {
complete(keywordContributor, positionContext)
}
@@ -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)
}
}
@@ -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)
@@ -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<FirTypeConstraintNameInWhereClausePositionContext>(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<LookupElement> {
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 = " : ")
}
}
@@ -34,7 +34,7 @@ internal object SuperCallInsertionHandler : InsertHandler<LookupElement> {
val lookupObject = item.`object` as SuperCallLookupObject
replaceWithClassIdAndShorten(lookupObject, context)
context.addDotAndInvokeCompletion()
context.addSymbolAndInvokeCompletion(symbol = ".")
}
private fun replaceWithClassIdAndShorten(
@@ -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)
}
@@ -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<LookupElement> {
val name = lookupElement.shortName.render()
context.document.replaceString(context.startOffset, context.tailOffset, name)
context.commitDocument()
context.addDotAndInvokeCompletion()
context.addSymbolAndInvokeCompletion(symbol = ".")
}
}