FIR IDE: introduce basic weighting for completion based by groups

This commit is contained in:
Ilya Kirillov
2021-06-10 13:25:29 +02:00
committed by teamcityserver
parent a5edbd531b
commit 20f2e4f313
18 changed files with 168 additions and 80 deletions
@@ -5,4 +5,3 @@ fun String.foo() {
// EXIST: xxx_topLevelFun
// EXIST: xxx_topLevelVal
// ABSENT: xxx_extFun
@@ -76,83 +76,70 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
basicContext: FirBasicCompletionContext,
positionContext: FirRawPositionCompletionContext,
) {
val keywordContributor = FirKeywordCompletionContributor(basicContext)
val classReferenceContributor = FirClassReferenceCompletionContributor(basicContext)
val callableContributor = FirCallableCompletionContributor(basicContext)
val infixCallableContributor = FirInfixCallableCompletionContributor(basicContext)
val callableReferenceContributor = FirCallableReferenceCompletionContributor(basicContext)
val classifierContributor = FirClassifierCompletionContributor(basicContext)
val classifierReferenceContributor = FirClassifierReferenceCompletionContributor(basicContext)
val annotationsContributor = FirAnnotationCompletionContributor(basicContext)
val packageCompletionContributor = FirPackageCompletionContributor(basicContext)
val importDirectivePackageMembersCompletionContributor = FirImportDirectivePackageMembersCompletionContributor(basicContext)
val typeParameterConstraintNameInWhereClauseContributor =
FirTypeParameterConstraintNameInWhereClauseCompletionContributor(basicContext)
val classifierNameContributor = FirSameAsFileClassifierNameCompletionContributor(basicContext)
val whenWithSubjecConditionContributor = FirWhenWithSubjectConditionContributor(basicContext)
val factory = FirCompletionContributorFactory(basicContext)
when (positionContext) {
is FirExpressionNameReferencePositionContext -> {
complete(keywordContributor, positionContext)
complete(packageCompletionContributor, positionContext)
complete(callableContributor, positionContext)
complete(classifierContributor, positionContext)
complete(factory.keywordContributor(1), positionContext)
complete(factory.callableContributor(1), positionContext)
complete(factory.classifierContributor(1), positionContext)
complete(factory.packageCompletionContributor(2), positionContext)
}
is FirTypeNameReferencePositionContext -> {
complete(keywordContributor, positionContext)
complete(packageCompletionContributor, positionContext)
complete(classifierContributor, positionContext)
complete(factory.classifierContributor(0), positionContext)
complete(factory.keywordContributor(1), positionContext)
complete(factory.packageCompletionContributor(2), positionContext)
}
is FirAnnotationTypeNameReferencePositionContext -> {
complete(keywordContributor, positionContext)
complete(packageCompletionContributor, positionContext)
complete(annotationsContributor, positionContext)
complete(factory.annotationsContributor(0), positionContext)
complete(factory.keywordContributor(1), positionContext)
complete(factory.packageCompletionContributor(2), positionContext)
}
is FirSuperTypeCallNameReferencePositionContext -> {
complete(FirSuperEntryContributor(basicContext), positionContext)
complete(factory.superEntryContributor(0), positionContext)
}
is FirImportDirectivePositionContext -> {
complete(packageCompletionContributor, positionContext)
complete(importDirectivePackageMembersCompletionContributor, positionContext)
complete(factory.packageCompletionContributor(0), positionContext)
complete(factory.importDirectivePackageMembersContributor(0), positionContext)
}
is FirPackageDirectivePositionContext -> {
complete(packageCompletionContributor, positionContext)
complete(factory.packageCompletionContributor(0), positionContext)
}
is FirTypeConstraintNameInWhereClausePositionContext -> {
complete(typeParameterConstraintNameInWhereClauseContributor, positionContext)
complete(factory.typeParameterConstraintNameInWhereClauseContributor(0), positionContext)
}
is FirUnknownPositionContext -> {
complete(keywordContributor, positionContext)
complete(factory.keywordContributor(0), positionContext)
}
is FirClassifierNamePositionContext -> {
complete(classifierNameContributor, positionContext)
complete(factory.classifierNameContributor(0), positionContext)
}
is FirWithSubjectEntryPositionContext -> {
complete(whenWithSubjecConditionContributor, positionContext)
complete(factory.whenWithSubjectConditionContributor(0), positionContext)
}
is FirCallableReferencePositionContext -> {
complete(classReferenceContributor, positionContext)
complete(callableReferenceContributor, positionContext)
complete(classifierReferenceContributor, positionContext)
complete(factory.classReferenceContributor(0), positionContext)
complete(factory.callableReferenceContributor(1), positionContext)
complete(factory.classifierReferenceContributor(1), positionContext)
}
is FirInfixCallPositionContext -> {
complete(keywordContributor, positionContext)
complete(infixCallableContributor, positionContext)
complete(factory.keywordContributor(0), positionContext)
complete(factory.infixCallableContributor(0), positionContext)
}
is FirIncorrectPositionContext -> {
// do nothing, completion is not suposed to be called here
// do nothing, completion is not supposed to be called here
}
}
}
@@ -13,6 +13,7 @@ import com.intellij.codeInsight.lookup.LookupElementDecorator
import com.intellij.openapi.editor.Document
import com.intellij.psi.util.elementType
import org.jetbrains.kotlin.idea.completion.stringTemplates.InsertStringTemplateBracesLookupElementDecorator
import org.jetbrains.kotlin.idea.completion.weighers.CompletionContributorGroupWeigher.groupPriority
import org.jetbrains.kotlin.idea.core.canDropBraces
import org.jetbrains.kotlin.idea.core.dropBraces
import org.jetbrains.kotlin.lexer.KtTokens
@@ -24,13 +25,21 @@ import org.jetbrains.kotlin.psi.KtStringTemplateEntryWithExpression
internal class LookupElementSink(
private val resultSet: CompletionResultSet,
private val parameters: KotlinFirCompletionParameters,
private val groupPriority: Int = 0,
) {
fun withPriority(priority: Int): LookupElementSink =
LookupElementSink(resultSet, parameters, priority)
fun addElement(element: LookupElement) {
element.groupPriority = groupPriority
resultSet.addElement(applyWrappersToLookupElement(element))
}
fun addAllElements(elements: Iterable<LookupElement>) {
elements.forEach {
it.groupPriority = groupPriority
}
resultSet.addAllElements(elements.map(::applyWrappersToLookupElement))
}
@@ -40,6 +49,7 @@ internal class LookupElementSink(
}
}
private object WrappersProvider {
fun getWrapperForLookupElement(parameters: KotlinFirCompletionParameters): List<LookupElementWrapper> {
return when (parameters.type) {
@@ -28,7 +28,8 @@ import org.jetbrains.kotlin.idea.completion.lookups.detectImportStrategy
internal open class FirCallableCompletionContributor(
basicContext: FirBasicCompletionContext,
) : FirContextCompletionContributorBase<FirNameReferencePositionContext>(basicContext) {
priority: Int,
) : FirCompletionContributorBase<FirNameReferencePositionContext>(basicContext, priority) {
private val typeNamesProvider = TypeNamesProvider(indexHelper)
protected open fun KtAnalysisSession.getInsertionStrategy(symbol: KtCallableSymbol): CallableInsertionStrategy = when (symbol) {
@@ -216,8 +217,9 @@ internal open class FirCallableCompletionContributor(
}
internal class FirCallableReferenceCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirCallableCompletionContributor(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirCallableCompletionContributor(basicContext, priority) {
override fun KtAnalysisSession.getInsertionStrategy(symbol: KtCallableSymbol): CallableInsertionStrategy =
CallableInsertionStrategy.AsIdentifier
@@ -257,8 +259,9 @@ internal class FirCallableReferenceCompletionContributor(
}
internal class FirInfixCallableCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirCallableCompletionContributor(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirCallableCompletionContributor(basicContext, priority) {
override fun KtAnalysisSession.getInsertionStrategy(symbol: KtCallableSymbol): CallableInsertionStrategy =
insertionStrategy
@@ -12,8 +12,9 @@ import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.platform.jvm.isJvm
internal class FirClassReferenceCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirCompletionContributorBase<FirCallableReferencePositionContext>(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirCompletionContributorBase<FirCallableReferencePositionContext>(basicContext, priority) {
override fun KtAnalysisSession.complete(positionContext: FirCallableReferencePositionContext) {
if (positionContext.explicitReceiver == null) return
sink.addElement(createKeywordElement("class"))
@@ -20,7 +20,8 @@ import org.jetbrains.kotlin.idea.frontend.api.types.KtNonErrorClassType
internal open class FirClassifierCompletionContributor(
basicContext: FirBasicCompletionContext,
) : FirContextCompletionContributorBase<FirNameReferencePositionContext>(basicContext) {
priority: Int,
) : FirCompletionContributorBase<FirNameReferencePositionContext>(basicContext, priority) {
protected open fun KtAnalysisSession.filterClassifiers(classifierSymbol: KtClassifierSymbol): Boolean = true
@@ -72,8 +73,9 @@ internal open class FirClassifierCompletionContributor(
}
internal class FirAnnotationCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirClassifierCompletionContributor(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirClassifierCompletionContributor(basicContext, priority) {
override fun KtAnalysisSession.filterClassifiers(classifierSymbol: KtClassifierSymbol): Boolean = when (classifierSymbol) {
is KtAnonymousObjectSymbol -> false
@@ -97,8 +99,9 @@ internal class FirAnnotationCompletionContributor(
}
internal class FirClassifierReferenceCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirClassifierCompletionContributor(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirClassifierCompletionContributor(basicContext, priority) {
override fun KtAnalysisSession.getImportingStrategy(classifierSymbol: KtClassifierSymbol): ImportStrategy =
ImportStrategy.DoNothing
@@ -30,10 +30,25 @@ import org.jetbrains.kotlin.psi.KtDotQualifiedExpression
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtFile
internal abstract class FirCompletionContributorBase<C : FirRawPositionCompletionContext>(protected val basicContext: FirBasicCompletionContext) {
internal class FirCompletionContributorOptions(
val priority: Int = 0
) {
companion object {
val DEFAULT = FirCompletionContributorOptions()
}
}
internal abstract class FirCompletionContributorBase<C : FirRawPositionCompletionContext>(
protected val basicContext: FirBasicCompletionContext,
options: FirCompletionContributorOptions,
) {
constructor(basicContext: FirBasicCompletionContext, priority: Int) :
this(basicContext, FirCompletionContributorOptions(priority))
protected val prefixMatcher: PrefixMatcher get() = basicContext.prefixMatcher
protected val parameters: CompletionParameters get() = basicContext.parameters
protected val sink: LookupElementSink get() = basicContext.sink
protected val sink: LookupElementSink = basicContext.sink.withPriority(options.priority)
protected val originalKtFile: KtFile get() = basicContext.originalKtFile
protected val fakeKtFile: KtFile get() = basicContext.fakeKtFile
protected val project: Project get() = basicContext.project
@@ -42,6 +57,7 @@ internal abstract class FirCompletionContributorBase<C : FirRawPositionCompletio
protected val lookupElementFactory: KotlinFirLookupElementFactory get() = basicContext.lookupElementFactory
protected val visibleScope = basicContext.visibleScope
protected val scopeNameFilter: KtScopeNameFilter =
{ name -> !name.isSpecial && prefixMatcher.prefixMatches(name.identifier) }
@@ -0,0 +1,52 @@
/*
* 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 org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
internal class FirCompletionContributorFactory(private val basicContext: FirBasicCompletionContext) {
fun keywordContributor(priority: Int = 0) =
FirKeywordCompletionContributor(basicContext, priority)
fun classReferenceContributor(priority: Int = 0) =
FirClassReferenceCompletionContributor(basicContext, priority)
fun callableContributor(priority: Int = 0) =
FirCallableCompletionContributor(basicContext, priority)
fun infixCallableContributor(priority: Int = 0) =
FirInfixCallableCompletionContributor(basicContext, priority)
fun callableReferenceContributor(priority: Int = 0) =
FirCallableReferenceCompletionContributor(basicContext, priority)
fun classifierContributor(priority: Int = 0) =
FirClassifierCompletionContributor(basicContext, priority)
fun classifierReferenceContributor(priority: Int = 0) =
FirClassifierReferenceCompletionContributor(basicContext, priority)
fun annotationsContributor(priority: Int = 0) =
FirAnnotationCompletionContributor(basicContext, priority)
fun packageCompletionContributor(priority: Int = 0) =
FirPackageCompletionContributor(basicContext, priority)
fun importDirectivePackageMembersContributor(priority: Int = 0) =
FirImportDirectivePackageMembersCompletionContributor(basicContext, priority)
fun typeParameterConstraintNameInWhereClauseContributor(priority: Int = 0) =
FirTypeParameterConstraintNameInWhereClauseCompletionContributor(basicContext, priority)
fun classifierNameContributor(priority: Int = 0) =
FirSameAsFileClassifierNameCompletionContributor(basicContext, priority)
fun whenWithSubjectConditionContributor(priority: Int = 0) =
FirWhenWithSubjectConditionContributor(basicContext, priority)
fun superEntryContributor(priority: Int) =
FirSuperEntryContributor(basicContext, priority)
}
@@ -1,16 +0,0 @@
/*
* 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 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.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter
internal abstract class FirContextCompletionContributorBase<C : FirNameReferencePositionContext>(
basicContext: FirBasicCompletionContext
) : FirCompletionContributorBase<C>(basicContext)
@@ -15,8 +15,9 @@ import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
internal class FirImportDirectivePackageMembersCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirCompletionContributorBase<FirImportDirectivePositionContext>(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirCompletionContributorBase<FirImportDirectivePositionContext>(basicContext, priority) {
override fun KtAnalysisSession.complete(positionContext: FirImportDirectivePositionContext) {
val reference = positionContext.explicitReceiver?.reference() ?: return
val scope = getStaticScope(reference) ?: return
@@ -28,8 +28,8 @@ import org.jetbrains.kotlin.idea.project.languageVersionSettings
import org.jetbrains.kotlin.platform.jvm.isJvm
import org.jetbrains.kotlin.psi.*
internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionContext) :
FirCompletionContributorBase<FirRawPositionCompletionContext>(basicContext) {
internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionContext, priority: Int) :
FirCompletionContributorBase<FirRawPositionCompletionContext>(basicContext, priority) {
private val keywordCompletion = KeywordCompletion(object : KeywordCompletion.LanguageVersionSettingProvider {
override fun getLanguageVersionSetting(element: PsiElement) = element.languageVersionSettings
override fun getLanguageVersionSetting(module: Module) = module.languageVersionSettings
@@ -15,7 +15,8 @@ import org.jetbrains.kotlin.idea.project.languageVersionSettings
internal class FirPackageCompletionContributor(
basicContext: FirBasicCompletionContext,
) : FirCompletionContributorBase<FirRawPositionCompletionContext>(basicContext) {
priority: Int,
) : FirCompletionContributorBase<FirRawPositionCompletionContext>(basicContext, priority) {
override fun KtAnalysisSession.complete(positionContext: FirRawPositionCompletionContext) {
val rootSymbol = if (positionContext !is FirNameReferencePositionContext || positionContext.explicitReceiver == null) {
@@ -14,8 +14,9 @@ import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.renderer.render
internal class FirSameAsFileClassifierNameCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirCompletionContributorBase<FirClassifierNamePositionContext>(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirCompletionContributorBase<FirClassifierNamePositionContext>(basicContext, priority) {
override fun KtAnalysisSession.complete(positionContext: FirClassifierNamePositionContext) {
if (positionContext.classLikeDeclaration is KtClassOrObject) {
@@ -18,7 +18,8 @@ import org.jetbrains.kotlin.name.Name
internal class FirSuperEntryContributor(
basicContext: FirBasicCompletionContext,
) : FirContextCompletionContributorBase<FirSuperTypeCallNameReferencePositionContext>(basicContext) {
priority: Int,
) : FirCompletionContributorBase<FirSuperTypeCallNameReferencePositionContext>(basicContext, priority) {
override fun KtAnalysisSession.complete(positionContext: FirSuperTypeCallNameReferencePositionContext) {
getSuperClassesAvailableForSuperCall(positionContext.nameExpression).forEach { superType ->
val tailText = superType.classIdIfNonLocal?.asString()?.let { "($it)" }
@@ -20,8 +20,9 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.renderer.render
internal class FirTypeParameterConstraintNameInWhereClauseCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirCompletionContributorBase<FirTypeConstraintNameInWhereClausePositionContext>(basicContext) {
basicContext: FirBasicCompletionContext,
priority: Int
) : FirCompletionContributorBase<FirTypeConstraintNameInWhereClausePositionContext>(basicContext, priority) {
override fun KtAnalysisSession.complete(positionContext: FirTypeConstraintNameInWhereClausePositionContext) {
val ownerSymbol = positionContext.typeParametersOwner.getSymbol() as? KtSymbolWithTypeParameters ?: return
@@ -40,7 +40,8 @@ import org.jetbrains.kotlin.renderer.render
internal class FirWhenWithSubjectConditionContributor(
basicContext: FirBasicCompletionContext,
) : FirContextCompletionContributorBase<FirWithSubjectEntryPositionContext>(basicContext) {
priority: Int,
) : FirCompletionContributorBase<FirWithSubjectEntryPositionContext>(basicContext, priority) {
override fun KtAnalysisSession.complete(positionContext: FirWithSubjectEntryPositionContext) {
val whenCondition = positionContext.whenCondition
val whenExpression = whenCondition.parentOfType<KtWhenExpression>() ?: return
@@ -0,0 +1,26 @@
/*
* Copyright 2010-2020 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.weighers
import com.intellij.codeInsight.lookup.LookupElement
import com.intellij.codeInsight.lookup.LookupElementWeigher
import com.intellij.openapi.util.Key
import org.jetbrains.kotlin.psi.UserDataProperty
internal object CompletionContributorGroupWeigher {
object Weigher : LookupElementWeigher(WEIGHER_ID) {
override fun weigh(element: LookupElement): Comparable<*>? =
element.groupPriority
}
var LookupElement.groupPriority by UserDataProperty(Key<Int>("GROUP_PRIORITY"))
const val WEIGHER_ID = "kotlin.group.id"
}
@@ -19,6 +19,7 @@ internal object Weighers {
fun addWeighersToCompletionSorter(sorter: CompletionSorter): CompletionSorter =
sorter
.weighBefore(PlatformWeighersIds.STATS, ExpectedTypeWeigher.Weigher)
.weighBefore(ExpectedTypeWeigher.WEIGHER_ID, CompletionContributorGroupWeigher.Weigher)
private object PlatformWeighersIds {
const val PREFIX = "prefix"