FIR IDE: implement basic classifier name contributor

This commit is contained in:
Ilya Kirillov
2021-05-27 00:52:11 +02:00
committed by TeamCityServer
parent 58d5907041
commit 1e1ce3067f
6 changed files with 70 additions and 8 deletions
@@ -7,7 +7,7 @@ package org.jetbrains.kotlin.psi
import org.jetbrains.kotlin.name.ClassId
interface KtClassLikeDeclaration : KtDeclaration {
interface KtClassLikeDeclaration : KtNamedDeclaration {
/**
* Return [ClassId], if the class is not local (E.e, if a class can be accessed by that [ClassId] from another context)
*
@@ -4,6 +4,4 @@ fun Strange(){}
fun Annotations<S<caret>
// INVOCATION_COUNT: 0
// EXIST: String
// EXIST: Set
// ABSENT: Strange
@@ -70,6 +70,7 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
val packageCompletionContributor = FirPackageCompletionContributor(basicContext)
val importDirectivePackageMembersCompletionContributor = FirImportDirectivePackageMembersCompletionContributor(basicContext)
val typeParameterConstraintNameInWhereClauseContributor = FirTypeParameterConstraintNameInWhereClauseCompletionContributor(basicContext)
val classifierNameContributor = FirSameAsFileClassifierNameCompletionContributor(basicContext)
when (positionContext) {
is FirExpressionNameReferencePositionContext -> {
@@ -112,6 +113,10 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
complete(keywordContributor, positionContext)
}
is FirClassifierNamePositionContext -> {
complete(classifierNameContributor, positionContext)
}
is FirIncorrectPositionContext -> {
// do nothing, completion is not suposed to be called here
}
@@ -20,9 +20,15 @@ internal sealed class FirRawPositionCompletionContext {
abstract val position: PsiElement
}
internal class FirClassifierNamePositionContext(
override val position: PsiElement,
val classLikeDeclaration: KtClassLikeDeclaration,
) : FirRawPositionCompletionContext()
internal class FirIncorrectPositionContext(
override val position: PsiElement
): FirRawPositionCompletionContext()
) : FirRawPositionCompletionContext()
internal class FirTypeConstraintNameInWhereClausePositionContext(
override val position: PsiElement,
@@ -89,10 +95,26 @@ internal class FirUnknownPositionContext(
internal object FirPositionCompletionContextDetector {
fun detect(basicContext: FirBasicCompletionContext): FirRawPositionCompletionContext {
val position = basicContext.parameters.position
return detectForPositionWithReference(position)
?: detectForPositionWithoutReference(position)
?: FirUnknownPositionContext(position)
}
private fun detectForPositionWithoutReference(position: PsiElement): FirRawPositionCompletionContext? {
val parent = position.parent
return when {
parent is KtClassLikeDeclaration && parent.nameIdentifier == position -> {
FirClassifierNamePositionContext(position, parent)
}
else -> null
}
}
private fun detectForPositionWithReference(position: PsiElement): FirRawPositionCompletionContext? {
val reference = (position.parent as? KtSimpleNameExpression)?.mainReference
?: return FirUnknownPositionContext(position)
?: return null
val nameExpression = reference.expression.takeIf { it !is KtLabelReferenceExpression }
?: return FirUnknownPositionContext(position)
?: return null
val explicitReceiver = nameExpression.getReceiverExpression()
val parent = nameExpression.parent
@@ -190,7 +212,8 @@ internal object FirPositionCompletionContextDetector {
is FirImportDirectivePositionContext,
is FirPackageDirectivePositionContext,
is FirTypeConstraintNameInWhereClausePositionContext,
is FirIncorrectPositionContext -> {
is FirIncorrectPositionContext,
is FirClassifierNamePositionContext -> {
analyse(basicContext.originalKtFile, action)
}
}
@@ -46,7 +46,7 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC
else -> reference.expression
}
}
is FirTypeConstraintNameInWhereClausePositionContext, is FirIncorrectPositionContext -> {
is FirTypeConstraintNameInWhereClausePositionContext, is FirIncorrectPositionContext, is FirClassifierNamePositionContext -> {
error("keyword completion should not be called for ${positionContext::class.simpleName}")
}
is FirUnknownPositionContext -> null
@@ -0,0 +1,36 @@
/*
* 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.lookup.LookupElementBuilder
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
import org.jetbrains.kotlin.idea.completion.context.FirClassifierNamePositionContext
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.renderer.render
internal class FirSameAsFileClassifierNameCompletionContributor(
basicContext: FirBasicCompletionContext
) : FirCompletionContributorBase<FirClassifierNamePositionContext>(basicContext) {
override fun KtAnalysisSession.complete(positionContext: FirClassifierNamePositionContext) {
if (positionContext.classLikeDeclaration is KtClassOrObject) {
completeTopLevelClassName(positionContext.classLikeDeclaration)
}
}
private fun completeTopLevelClassName(classOrObject: KtClassOrObject) {
if (!classOrObject.isTopLevel()) return
val name = originalKtFile.virtualFile.nameWithoutExtension
if (!isValidUpperCapitalizedClassName(name)) return
if (originalKtFile.declarations.any { it is KtClassOrObject && it.name == name }) return
result.addElement(LookupElementBuilder.create(name))
}
private fun isValidUpperCapitalizedClassName(name: String) =
Name.isValidIdentifier(name) && Name.identifier(name).render() == name && name[0].isUpperCase()
}