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 31d63e7130c..44b32ecd843 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 @@ -11,27 +11,21 @@ import com.intellij.patterns.PsiJavaPatterns import com.intellij.util.ProcessingContext import org.jetbrains.kotlin.idea.caches.project.getModuleInfo import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker -import org.jetbrains.kotlin.idea.completion.checkers.ExtensionApplicabilityChecker +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.FirExpressionNameReferencePositionContext import org.jetbrains.kotlin.idea.completion.context.FirPositionCompletionContextDetector +import org.jetbrains.kotlin.idea.completion.context.FirTypeNameReferencePositionContext import org.jetbrains.kotlin.idea.completion.context.FirUnknownPositionContext import org.jetbrains.kotlin.idea.completion.contributors.FirCallableCompletionContributor import org.jetbrains.kotlin.idea.completion.contributors.FirClassifierCompletionContributor -import org.jetbrains.kotlin.idea.completion.contributors.FirContextCompletionContributorBase import org.jetbrains.kotlin.idea.completion.contributors.FirKeywordCompletionContributor +import org.jetbrains.kotlin.idea.completion.contributors.complete import org.jetbrains.kotlin.idea.completion.weighers.Weighers import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper import org.jetbrains.kotlin.idea.fir.low.level.api.util.originalKtFile import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession -import org.jetbrains.kotlin.idea.frontend.api.components.KtScopeContext -import org.jetbrains.kotlin.idea.frontend.api.scopes.KtCompositeScope -import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope -import org.jetbrains.kotlin.idea.frontend.api.symbols.* -import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType -import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.lexer.KtTokens -import org.jetbrains.kotlin.psi.* class KotlinFirCompletionContributor : CompletionContributor() { init { @@ -51,39 +45,35 @@ private object KotlinFirCompletionProvider : CompletionProvider { - val visibilityChecker = CompletionVisibilityChecker { - parameters.invocationCount > 1 || isVisible( - it, - basicContext.originalKtFile.getFileSymbol(), - positionContext.explicitReceiver, - positionContext.position - ) - } + complete(basicContext, positionContext, indexHelper) + } + } - with(FirCallableCompletionContributor(basicContext, indexHelper)) { - complete(positionContext, visibilityChecker) - } + private fun KtAnalysisSession.complete( + basicContext: FirBasicCompletionContext, + positionContext: FirRawPositionCompletionContext, + indexHelper: IndexHelper, + ) { + val keywordContributor = FirKeywordCompletionContributor(basicContext) + val callableContributor = FirCallableCompletionContributor(basicContext, indexHelper) + val classifierContributor = FirClassifierCompletionContributor(basicContext, indexHelper) - if (positionContext.explicitReceiver == null) { - with(FirClassifierCompletionContributor(basicContext, indexHelper)) { - collectTypesCompletion( - basicContext.originalKtFile.getScopeContextForPosition(positionContext.nameExpression).scopes, - visibilityChecker - ) - } - } - - } - is FirUnknownPositionContext -> { - } + when (positionContext) { + is FirExpressionNameReferencePositionContext -> { + complete(keywordContributor, positionContext) + complete(callableContributor, positionContext) + complete(classifierContributor, positionContext) + } + is FirTypeNameReferencePositionContext -> { + complete(keywordContributor, positionContext) + complete(classifierContributor, positionContext) + } + is FirUnknownPositionContext -> { + complete(keywordContributor, positionContext) } } } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/checkers/CompletionVisibilityChecker.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/checkers/CompletionVisibilityChecker.kt index d792e5f9d9a..9cfe2376c0d 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/checkers/CompletionVisibilityChecker.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/checkers/CompletionVisibilityChecker.kt @@ -5,6 +5,8 @@ package org.jetbrains.kotlin.idea.completion.checkers +import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext +import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassifierSymbol @@ -20,4 +22,18 @@ internal fun interface CompletionVisibilityChecker { fun KtAnalysisSession.isVisible(symbol: KtClassifierSymbol): Boolean { return symbol !is KtSymbolWithVisibility || isVisible(symbol as KtSymbolWithVisibility) } + + companion object { + fun create( + basicContext: FirBasicCompletionContext, + positionContext: FirNameReferenceRawPositionContext + ): CompletionVisibilityChecker = CompletionVisibilityChecker { + basicContext.parameters.invocationCount > 1 || isVisible( + it, + basicContext.originalKtFile.getFileSymbol(), + positionContext.explicitReceiver, + positionContext.position + ) + } + } } \ No newline at end of file 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 887061971b3..7c5a6590372 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 @@ -14,37 +14,57 @@ import org.jetbrains.kotlin.idea.references.mainReference import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtLabelReferenceExpression import org.jetbrains.kotlin.psi.KtSimpleNameExpression +import org.jetbrains.kotlin.psi.KtUserType import org.jetbrains.kotlin.psi.psiUtil.getReceiverExpression -internal sealed class FirPositionCompletionContext { +internal sealed class FirRawPositionCompletionContext { abstract val position: PsiElement } -internal class FirNameReferencePositionContext( +internal sealed class FirNameReferencePositionContext : FirRawPositionCompletionContext() { + abstract val reference: KtSimpleNameReference + abstract val nameExpression: KtSimpleNameExpression + abstract val explicitReceiver: KtExpression? +} + +internal class FirTypeNameReferencePositionContext( override val position: PsiElement, - val reference: KtSimpleNameReference, - val nameExpression: KtSimpleNameExpression, - val explicitReceiver: KtExpression? -) : FirPositionCompletionContext() + override val reference: KtSimpleNameReference, + override val nameExpression: KtSimpleNameExpression, + override val explicitReceiver: KtExpression? +) : FirNameReferencePositionContext() + +internal class FirExpressionNameReferencePositionContext( + override val position: PsiElement, + override val reference: KtSimpleNameReference, + override val nameExpression: KtSimpleNameExpression, + override val explicitReceiver: KtExpression? +) : FirNameReferencePositionContext() + internal class FirUnknownPositionContext( override val position: PsiElement -) : FirPositionCompletionContext() +) : FirRawPositionCompletionContext() internal object FirPositionCompletionContextDetector { - fun detect(basicContext: FirBasicCompletionContext): FirPositionCompletionContext { + fun detect(basicContext: FirBasicCompletionContext): FirRawPositionCompletionContext { val position = basicContext.parameters.position val reference = (position.parent as? KtSimpleNameExpression)?.mainReference ?: return FirUnknownPositionContext(position) val nameExpression = reference.expression.takeIf { it !is KtLabelReferenceExpression } ?: return FirUnknownPositionContext(position) val explicitReceiver = nameExpression.getReceiverExpression() - return FirNameReferencePositionContext(position, reference, nameExpression, explicitReceiver) + + return if (nameExpression.parent is KtUserType) { + FirTypeNameReferencePositionContext(position, reference, nameExpression, explicitReceiver) + } else { + FirExpressionNameReferencePositionContext(position, reference, nameExpression, explicitReceiver) + } } inline fun analyseInContext( basicContext: FirBasicCompletionContext, - positionContext: FirPositionCompletionContext, + positionContext: FirRawPositionCompletionContext, action: KtAnalysisSession.() -> Unit ) { return when (positionContext) { diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCallableCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCallableCompletionContributor.kt index fe96e82cee0..904584e76c7 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCallableCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCallableCompletionContributor.kt @@ -19,41 +19,42 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassOrObjectSymbol import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.psi.KtExpression -import org.jetbrains.kotlin.psi.KtUserType internal class FirCallableCompletionContributor( basicContext: FirBasicCompletionContext, indexHelper: IndexHelper -) : FirContextCompletionContributorBase(basicContext, indexHelper) { +) : FirContextCompletionContributorBase(basicContext, indexHelper) { private val typeNamesProvider = TypeNamesProvider(indexHelper) private val shouldCompleteTopLevelCallablesFromIndex: Boolean get() = prefixMatcher.prefix.isNotEmpty() - fun KtAnalysisSession.complete(positionContext: FirNameReferencePositionContext, visibilityChecker: CompletionVisibilityChecker) = - with(positionContext) { - val expectedType = nameExpression.getExpectedType() - val scopesContext = originalKtFile.getScopeContextForPosition(nameExpression) + override fun KtAnalysisSession.complete(positionContext: FirNameReferencePositionContext): Unit = with(positionContext) { + val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext) + val expectedType = nameExpression.getExpectedType() + val scopesContext = originalKtFile.getScopeContextForPosition(nameExpression) - val extensionChecker = ExtensionApplicabilityChecker { - it.checkExtensionIsSuitable(originalKtFile, nameExpression, explicitReceiver) - } - - when { - explicitReceiver != null -> { - collectDotCompletion( - scopesContext.scopes, - explicitReceiver, - expectedType, - extensionChecker, - visibilityChecker, - ) - } - - else -> completeWithoutReceiver(scopesContext, expectedType, extensionChecker, visibilityChecker) - } + val extensionChecker = ExtensionApplicabilityChecker { + it.checkExtensionIsSuitable(originalKtFile, nameExpression, explicitReceiver) } + val receiver = explicitReceiver + + when { + receiver != null -> { + collectDotCompletion( + scopesContext.scopes, + receiver, + expectedType, + extensionChecker, + visibilityChecker, + ) + } + + else -> completeWithoutReceiver(scopesContext, expectedType, extensionChecker, visibilityChecker) + } + } + private fun KtAnalysisSession.completeWithoutReceiver( implicitScopesContext: KtScopeContext, diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirClassifierCompletionContributor.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirClassifierCompletionContributor.kt index 4bc3c151917..48a7cfaebbd 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirClassifierCompletionContributor.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirClassifierCompletionContributor.kt @@ -7,6 +7,7 @@ package org.jetbrains.kotlin.idea.completion.contributors import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext +import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScope @@ -17,12 +18,11 @@ import org.jetbrains.kotlin.psi.KtEnumEntry internal class FirClassifierCompletionContributor( basicContext: FirBasicCompletionContext, indexHelper: IndexHelper -) : FirContextCompletionContributorBase(basicContext, indexHelper) { +) : FirContextCompletionContributorBase(basicContext, indexHelper) { - fun KtAnalysisSession.collectTypesCompletion( - implicitScopes: KtScope, - visibilityChecker: CompletionVisibilityChecker, - ) { + override fun KtAnalysisSession.complete(positionContext: FirNameReferenceRawPositionContext) { + val implicitScopes = originalKtFile.getScopeContextForPosition(positionContext.nameExpression).scopes + val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext) val classesFromScopes = implicitScopes .getClassifierSymbols(scopeNameFilter) .filter { with(visibilityChecker) { isVisible(it) } } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt index 4ae9e89c314..54d3f6db9f5 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirCompletionContributorBase.kt @@ -12,8 +12,8 @@ import com.intellij.codeInsight.lookup.LookupElement import com.intellij.openapi.project.Project import org.jetbrains.kotlin.idea.completion.KotlinFirLookupElementFactory import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext +import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext import org.jetbrains.kotlin.idea.completion.weighers.Weighers -import org.jetbrains.kotlin.idea.completion.weighers.Weighers.applyWeighsToLookupElement import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSymbol import org.jetbrains.kotlin.idea.frontend.api.symbols.markers.KtNamedSymbol @@ -21,7 +21,7 @@ import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.platform.TargetPlatform import org.jetbrains.kotlin.psi.KtFile -internal abstract class FirCompletionContributorBase(protected val basicContext: FirBasicCompletionContext) { +internal abstract class FirCompletionContributorBase(protected val basicContext: FirBasicCompletionContext) { protected val prefixMatcher: PrefixMatcher get() = basicContext.prefixMatcher protected val parameters: CompletionParameters get() = basicContext.parameters protected val result: CompletionResultSet get() = basicContext.result @@ -31,6 +31,8 @@ internal abstract class FirCompletionContributorBase(protected val basicContext: protected val targetPlatform: TargetPlatform get() = basicContext.targetPlatform protected val lookupElementFactory: KotlinFirLookupElementFactory get() = basicContext.lookupElementFactory + abstract fun KtAnalysisSession.complete(positionContext: C) + protected fun KtAnalysisSession.addSymbolToCompletion(expectedType: KtType?, symbol: KtSymbol) { if (symbol !is KtNamedSymbol) return with(lookupElementFactory) { @@ -47,4 +49,13 @@ internal abstract class FirCompletionContributorBase(protected val basicContext: ): LookupElement = lookupElement.apply { with(Weighers) { applyWeighsToLookupElement(lookupElement, symbol, expectedType) } } +} + +internal fun KtAnalysisSession.complete( + contextContributor: FirCompletionContributorBase, + positionContext: C, +) { + with(contextContributor) { + complete(positionContext) + } } \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirContextCompletionContributorBase.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirContextCompletionContributorBase.kt index cd5ffa9a219..aef88c815e0 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirContextCompletionContributorBase.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/contributors/FirContextCompletionContributorBase.kt @@ -6,13 +6,16 @@ package org.jetbrains.kotlin.idea.completion.contributors import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext +import org.jetbrains.kotlin.idea.completion.context.FirNameReferenceRawPositionContext +import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper +import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter -internal abstract class FirContextCompletionContributorBase( +internal abstract class FirContextCompletionContributorBase( basicContext: FirBasicCompletionContext, protected val indexHelper: IndexHelper -) : FirCompletionContributorBase(basicContext) { +) : FirCompletionContributorBase(basicContext) { protected val scopeNameFilter: KtScopeNameFilter = { name -> !name.isSpecial && prefixMatcher.prefixMatches(name.identifier) } 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 66c013f6358..5521d9787b3 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 @@ -8,15 +8,13 @@ package org.jetbrains.kotlin.idea.completion.contributors import com.intellij.codeInsight.lookup.LookupElement import com.intellij.openapi.module.Module import com.intellij.psi.PsiElement -import org.jetbrains.kotlin.config.LanguageVersionSettingsImpl import org.jetbrains.kotlin.idea.completion.* import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.context.FirNameReferencePositionContext -import org.jetbrains.kotlin.idea.completion.context.FirPositionCompletionContext +import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext 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 -import org.jetbrains.kotlin.idea.completion.contributors.keywords.ReturnKeywordHandler.createLookups import org.jetbrains.kotlin.idea.completion.contributors.keywords.ThisKeywordHandler import org.jetbrains.kotlin.idea.completion.keywords.CompletionKeywordHandlerProvider import org.jetbrains.kotlin.idea.completion.keywords.CompletionKeywordHandlers @@ -27,7 +25,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(basicContext) { +internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionContext) : + FirCompletionContributorBase(basicContext) { private val keywordCompletion = KeywordCompletion(object : KeywordCompletion.LanguageVersionSettingProvider { override fun getLanguageVersionSetting(element: PsiElement) = element.languageVersionSettings override fun getLanguageVersionSetting(module: Module) = module.languageVersionSettings @@ -35,9 +34,7 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC private val resolveDependentCompletionKeywordHandlers = ResolveDependentCompletionKeywordHandlerProvider(basicContext) - fun KtAnalysisSession.completeKeywords( - positionContext: FirPositionCompletionContext - ) { + override fun KtAnalysisSession.complete(positionContext: FirRawPositionCompletionContext) { val expression = when (positionContext) { is FirNameReferencePositionContext -> { val reference = positionContext.reference @@ -51,6 +48,7 @@ internal class FirKeywordCompletionContributor(basicContext: FirBasicCompletionC completeWithResolve(expression ?: positionContext.position, expression) } + fun KtAnalysisSession.completeWithResolve(position: PsiElement, expression: KtExpression?) { complete(position) { lookupElement, keyword -> val lookups = DefaultCompletionKeywordHandlerProvider.getHandlerForKeyword(keyword)