FIR IDE: implement basic classifier name contributor
This commit is contained in:
committed by
TeamCityServer
parent
58d5907041
commit
1e1ce3067f
@@ -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)
|
||||
*
|
||||
|
||||
-2
@@ -4,6 +4,4 @@ fun Strange(){}
|
||||
fun Annotations<S<caret>
|
||||
|
||||
// INVOCATION_COUNT: 0
|
||||
// EXIST: String
|
||||
// EXIST: Set
|
||||
// ABSENT: Strange
|
||||
|
||||
+5
@@ -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
|
||||
}
|
||||
|
||||
+27
-4
@@ -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)
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -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
|
||||
|
||||
+36
@@ -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()
|
||||
}
|
||||
Reference in New Issue
Block a user