diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirClassifierCompletionContributor.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirClassifierCompletionContributor.kt index c925d85f440d..c87c2dd9a5e8 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirClassifierCompletionContributor.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirClassifierCompletionContributor.kt @@ -9,7 +9,7 @@ import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker import org.jetbrains.kotlin.idea.completion.contributors.helpers.CompletionSymbolOrigin import org.jetbrains.kotlin.idea.completion.contributors.helpers.FirClassifierProvider.getAvailableClassifiersCurrentScope import org.jetbrains.kotlin.idea.completion.contributors.helpers.FirClassifierProvider.getAvailableClassifiersFromIndex -import org.jetbrains.kotlin.idea.completion.contributors.helpers.getStaticScopes +import org.jetbrains.kotlin.idea.completion.contributors.helpers.staticScope import org.jetbrains.kotlin.idea.completion.impl.k2.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy import org.jetbrains.kotlin.idea.completion.reference @@ -54,8 +54,13 @@ internal open class FirClassifierCompletionContributor( visibilityChecker: CompletionVisibilityChecker, context: WeighingContext ) { - val reference = receiver.reference() ?: return - getStaticScopes(reference).forEach { scopeWithKind -> + val symbols = receiver.reference() + ?.resolveToSymbols() + ?: return + + symbols.asSequence() + .mapNotNull { it.staticScope } + .forEach { scopeWithKind -> scopeWithKind.scope .classifiers(scopeNameFilter) .filter { filterClassifiers(it) } diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirImportDirectivePackageMembersCompletionContributor.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirImportDirectivePackageMembersCompletionContributor.kt index 5015716c860e..4cbd0d500a9e 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirImportDirectivePackageMembersCompletionContributor.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirImportDirectivePackageMembersCompletionContributor.kt @@ -6,12 +6,12 @@ import org.jetbrains.kotlin.analysis.api.KaSession import org.jetbrains.kotlin.idea.completion.FirCompletionSessionParameters import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker import org.jetbrains.kotlin.idea.completion.contributors.helpers.CompletionSymbolOrigin -import org.jetbrains.kotlin.idea.completion.contributors.helpers.getStaticScopes +import org.jetbrains.kotlin.idea.completion.contributors.helpers.resolveToSymbols +import org.jetbrains.kotlin.idea.completion.contributors.helpers.staticScope import org.jetbrains.kotlin.idea.completion.impl.k2.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionOptions import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy -import org.jetbrains.kotlin.idea.completion.reference import org.jetbrains.kotlin.idea.completion.weighers.WeighingContext import org.jetbrains.kotlin.idea.util.positionContext.KotlinImportDirectivePositionContext @@ -27,25 +27,32 @@ internal class FirImportDirectivePackageMembersCompletionContributor( weighingContext: WeighingContext, sessionParameters: FirCompletionSessionParameters, ) { - val reference = positionContext.explicitReceiver?.reference() ?: return - getStaticScopes(reference).forEach { scopeWithKind -> - val symbolOrigin = CompletionSymbolOrigin.Scope(scopeWithKind.kind) - val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext) + positionContext.resolveToSymbols() + .mapNotNull { it.staticScope } + .forEach { scopeWithKind -> + val symbolOrigin = CompletionSymbolOrigin.Scope(scopeWithKind.kind) + val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext) - scopeWithKind.scope.classifiers(scopeNameFilter) - .filter { visibilityChecker.isVisible(it) } - .forEach { addClassifierSymbolToCompletion(it, weighingContext, symbolOrigin, ImportStrategy.DoNothing) } + val classifiers = scopeWithKind.scope + .classifiers(scopeNameFilter) + .toList() + classifiers + .filter { visibilityChecker.isVisible(it) } + .forEach { addClassifierSymbolToCompletion(it, weighingContext, symbolOrigin, ImportStrategy.DoNothing) } - scopeWithKind.scope.callables(scopeNameFilter) - .filter { visibilityChecker.isVisible(it) } - .forEach { - addCallableSymbolToCompletion( - weighingContext, - it.asSignature(), - CallableInsertionOptions(ImportStrategy.DoNothing, CallableInsertionStrategy.AsIdentifier), - symbolOrigin, - ) - } - } + val callables = scopeWithKind.scope + .callables(scopeNameFilter) + .toList() + callables + .filter { visibilityChecker.isVisible(it) } + .forEach { + addCallableSymbolToCompletion( + weighingContext, + it.asSignature(), + CallableInsertionOptions(ImportStrategy.DoNothing, CallableInsertionStrategy.AsIdentifier), + symbolOrigin, + ) + } + } } } \ No newline at end of file diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirPackageCompletionContributor.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirPackageCompletionContributor.kt index 7454811f121f..b6be1ea63f1b 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirPackageCompletionContributor.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/FirPackageCompletionContributor.kt @@ -9,12 +9,11 @@ import org.jetbrains.kotlin.base.analysis.isExcludedFromAutoImport import org.jetbrains.kotlin.idea.completion.FirCompletionSessionParameters import org.jetbrains.kotlin.idea.completion.contributors.helpers.CompletionSymbolOrigin import org.jetbrains.kotlin.idea.completion.contributors.helpers.KtSymbolWithOrigin +import org.jetbrains.kotlin.idea.completion.contributors.helpers.resolveToSymbols import org.jetbrains.kotlin.idea.completion.impl.k2.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.lookups.factories.KotlinFirLookupElementFactory -import org.jetbrains.kotlin.idea.completion.reference import org.jetbrains.kotlin.idea.completion.weighers.Weighers import org.jetbrains.kotlin.idea.completion.weighers.WeighingContext -import org.jetbrains.kotlin.idea.util.positionContext.KotlinNameReferencePositionContext import org.jetbrains.kotlin.idea.util.positionContext.KotlinRawPositionContext internal class FirPackageCompletionContributor( @@ -29,11 +28,11 @@ internal class FirPackageCompletionContributor( weighingContext: WeighingContext, sessionParameters: FirCompletionSessionParameters, ) { - val rootSymbol = if (positionContext !is KotlinNameReferencePositionContext || positionContext.explicitReceiver == null) { - rootPackageSymbol - } else { - positionContext.explicitReceiver?.reference()?.resolveToSymbols()?.filterIsInstance()?.singleOrNull() - } ?: return + + val rootSymbol = positionContext.resolveToSymbols() + .filterIsInstance() + .singleOrNull() + ?: return val symbolOrigin = CompletionSymbolOrigin.Scope(KaScopeKinds.PackageMemberScope(CompletionSymbolOrigin.SCOPE_OUTSIDE_TOWER_INDEX)) diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/symbolUtils.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/symbolUtils.kt index 045dcc1e89db..2b6141b2ff20 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/symbolUtils.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/symbolUtils.kt @@ -1,46 +1,39 @@ // Copyright 2000-2022 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file. - package org.jetbrains.kotlin.idea.completion.contributors.helpers import org.jetbrains.kotlin.analysis.api.KaSession import org.jetbrains.kotlin.analysis.api.components.KaScopeKind import org.jetbrains.kotlin.analysis.api.components.KaScopeKinds import org.jetbrains.kotlin.analysis.api.components.KaScopeWithKindImpl -import org.jetbrains.kotlin.analysis.api.components.KaScopeWithKind import org.jetbrains.kotlin.analysis.api.lifetime.KaLifetimeOwner import org.jetbrains.kotlin.analysis.api.lifetime.KaLifetimeToken import org.jetbrains.kotlin.analysis.api.lifetime.withValidityAssertion import org.jetbrains.kotlin.analysis.api.signatures.KaCallableSignature -import org.jetbrains.kotlin.analysis.api.symbols.* +import org.jetbrains.kotlin.analysis.api.symbols.KaClassifierSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KaNamedClassSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KaPackageSymbol +import org.jetbrains.kotlin.analysis.api.symbols.KaSymbol import org.jetbrains.kotlin.analysis.api.symbols.markers.KaDeclarationContainerSymbol -import org.jetbrains.kotlin.idea.references.KtReference /** - * Resolves [reference] to symbol and returns static scope for the obtained symbol. * Note that if the symbol is [org.jetbrains.kotlin.analysis.api.symbols.KaTypeAliasSymbol], `null` is returned. * See KT-34281 for more details. */ context(KaSession) -internal fun getStaticScopes(reference: KtReference): List { - val scopeIndex = CompletionSymbolOrigin.SCOPE_OUTSIDE_TOWER_INDEX +internal val KaSymbol.staticScope + get() = when (this) { + is KaDeclarationContainerSymbol -> KaScopeWithKindImpl( + backingScope = if (this is KaNamedClassSymbol && classKind.isObject) memberScope else staticMemberScope, + backingKind = KaScopeKinds.StaticMemberScope(CompletionSymbolOrigin.SCOPE_OUTSIDE_TOWER_INDEX), + ) - return reference.resolveToSymbols().mapNotNull { symbol -> - when (symbol) { - is KaDeclarationContainerSymbol -> { - val scope = if (symbol is KaNamedClassSymbol && symbol.classKind.isObject) { - symbol.memberScope - } else { - symbol.staticMemberScope - } + is KaPackageSymbol -> KaScopeWithKindImpl( + backingScope = packageScope, + backingKind = KaScopeKinds.PackageMemberScope(CompletionSymbolOrigin.SCOPE_OUTSIDE_TOWER_INDEX), + ) - KaScopeWithKindImpl(scope, KaScopeKinds.StaticMemberScope(scopeIndex)) - } - - is KaPackageSymbol -> KaScopeWithKindImpl(symbol.packageScope, KaScopeKinds.PackageMemberScope(scopeIndex)) - else -> null - } + else -> null } -} internal data class KaClassifierSymbolWithContainingScopeKind( private val _symbol: KaClassifierSymbol, diff --git a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/utils.kt b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/utils.kt index 45fa161bcc68..6c7eb37db6fe 100644 --- a/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/utils.kt +++ b/plugins/kotlin/completion/impl-k2/src/org/jetbrains/kotlin/idea/completion/impl/k2/contributors/helpers/utils.kt @@ -5,9 +5,9 @@ package org.jetbrains.kotlin.idea.completion.contributors.helpers import com.intellij.util.applyIf import org.jetbrains.kotlin.analysis.api.KaExperimentalApi import org.jetbrains.kotlin.analysis.api.KaSession +import org.jetbrains.kotlin.analysis.api.components.KaScopeContext import org.jetbrains.kotlin.analysis.api.components.KaScopeKind import org.jetbrains.kotlin.analysis.api.components.KaScopeKinds -import org.jetbrains.kotlin.analysis.api.components.KaScopeContext import org.jetbrains.kotlin.analysis.api.scopes.KaScope import org.jetbrains.kotlin.analysis.api.signatures.KaCallableSignature import org.jetbrains.kotlin.analysis.api.symbols.* @@ -15,6 +15,9 @@ import org.jetbrains.kotlin.analysis.api.types.KaType import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.idea.completion.FirCompletionSessionParameters import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker +import org.jetbrains.kotlin.idea.completion.reference +import org.jetbrains.kotlin.idea.util.positionContext.KotlinNameReferencePositionContext +import org.jetbrains.kotlin.idea.util.positionContext.KotlinRawPositionContext import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.load.java.JvmAbi import org.jetbrains.kotlin.name.Name @@ -34,6 +37,23 @@ internal sealed class CompletionSymbolOrigin { } } +context(KaSession) +internal fun KotlinRawPositionContext.resolveToSymbols(): Sequence = + when (this) { + is KotlinNameReferencePositionContext -> resolveToSymbols() + else -> sequenceOf(rootPackageSymbol) + } + +context(KaSession) +internal fun KotlinNameReferencePositionContext.resolveToSymbols(): Sequence = + when (val explicitReceiver = explicitReceiver) { + null -> sequenceOf(rootPackageSymbol) + else -> explicitReceiver.reference() + ?.resolveToSymbols() + ?.asSequence() + ?: emptySequence() + } + internal fun createStarTypeArgumentsList(typeArgumentsCount: Int): String = if (typeArgumentsCount > 0) { List(typeArgumentsCount) { "*" }.joinToString(prefix = "<", postfix = ">") diff --git a/plugins/kotlin/completion/testData/basic/multifile/ClassInRootPackage/ClassInRootPackage.dependency.kt b/plugins/kotlin/completion/testData/basic/multifile/ClassInRootPackage/ClassInRootPackage.dependency.kt new file mode 100644 index 000000000000..074a751a7c73 --- /dev/null +++ b/plugins/kotlin/completion/testData/basic/multifile/ClassInRootPackage/ClassInRootPackage.dependency.kt @@ -0,0 +1 @@ +object RootPackageClass \ No newline at end of file diff --git a/plugins/kotlin/completion/testData/basic/multifile/ClassInRootPackage/ClassInRootPackage.kt b/plugins/kotlin/completion/testData/basic/multifile/ClassInRootPackage/ClassInRootPackage.kt new file mode 100644 index 000000000000..75dab904efe8 --- /dev/null +++ b/plugins/kotlin/completion/testData/basic/multifile/ClassInRootPackage/ClassInRootPackage.kt @@ -0,0 +1,8 @@ +// FIR_COMPARISON +// FIR_IDENTICAL +package foo + +import R + +// EXIST: RootPackageClass +// NOTHING_ELSE \ No newline at end of file diff --git a/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java b/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java index 687d440047e7..5ee79c1769ea 100644 --- a/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java +++ b/plugins/kotlin/completion/tests-k1/test/org/jetbrains/kotlin/idea/completion/test/MultiFileJvmBasicCompletionTestGenerated.java @@ -55,6 +55,11 @@ public class MultiFileJvmBasicCompletionTestGenerated extends AbstractMultiFileJ runTest("../testData/basic/multifile/ClassInExcludedPackage/"); } + @TestMetadata("ClassInRootPackage") + public void testClassInRootPackage() throws Exception { + runTest("../testData/basic/multifile/ClassInRootPackage/"); + } + @TestMetadata("CompleteFunctionWithNoSpecifiedType") public void testCompleteFunctionWithNoSpecifiedType() throws Exception { runTest("../testData/basic/multifile/CompleteFunctionWithNoSpecifiedType/"); diff --git a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java index 369f9e6968c6..e800b8657595 100644 --- a/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java +++ b/plugins/kotlin/fir/tests/test/org/jetbrains/kotlin/idea/fir/completion/HighLevelMultiFileJvmBasicCompletionTestGenerated.java @@ -55,6 +55,11 @@ public class HighLevelMultiFileJvmBasicCompletionTestGenerated extends AbstractH runTest("../../completion/testData/basic/multifile/ClassInExcludedPackage/"); } + @TestMetadata("ClassInRootPackage") + public void testClassInRootPackage() throws Exception { + runTest("../../completion/testData/basic/multifile/ClassInRootPackage/"); + } + @TestMetadata("CompleteFunctionWithNoSpecifiedType") public void testCompleteFunctionWithNoSpecifiedType() throws Exception { runTest("../../completion/testData/basic/multifile/CompleteFunctionWithNoSpecifiedType/");