diff --git a/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt b/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt index 3b0583d7280..d95894faf07 100644 --- a/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt +++ b/idea/idea-completion/testData/basic/common/callableReference/SyntheticExtensions.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON import java.io.File val v = File:: diff --git a/idea/idea-completion/testData/basic/multifile/CallableReferenceNotImportedExtension2/CallableReferenceNotImportedExtension2.kt b/idea/idea-completion/testData/basic/multifile/CallableReferenceNotImportedExtension2/CallableReferenceNotImportedExtension2.kt index 1c82bd561b0..67264a87c1e 100644 --- a/idea/idea-completion/testData/basic/multifile/CallableReferenceNotImportedExtension2/CallableReferenceNotImportedExtension2.kt +++ b/idea/idea-completion/testData/basic/multifile/CallableReferenceNotImportedExtension2/CallableReferenceNotImportedExtension2.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON val v = "a":: // EXIST: extFun diff --git a/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt b/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt index 3380161e199..01d7c47de3e 100644 --- a/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt +++ b/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON package ppp class X(p: Int) diff --git a/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt.after b/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt.after index 6ca0de4b4ea..3b681d43185 100644 --- a/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt.after +++ b/idea/idea-completion/testData/handlers/basic/callableReference/ClassConstructor.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON package ppp class X(p: Int) diff --git a/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt b/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt index 92f30106c05..42584df5e52 100644 --- a/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt +++ b/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON fun globalFun(p: Int) {} class C { diff --git a/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt.after b/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt.after index 39cd106b427..f55a70b8932 100644 --- a/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt.after +++ b/idea/idea-completion/testData/handlers/basic/callableReference/EmptyQualifier.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON fun globalFun(p: Int) {} class C { diff --git a/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt b/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt index 1169d4959e7..1b6771f1096 100644 --- a/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt +++ b/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON class C { fun foo() { val v = D:: diff --git a/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt.after b/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt.after index 5188b836d5e..38cf218cf44 100644 --- a/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt.after +++ b/idea/idea-completion/testData/handlers/basic/callableReference/NonEmptyQualifier.kt.after @@ -1,3 +1,4 @@ +// FIR_COMPARISON class C { fun foo() { val v = D::memberFun 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 628106f8187..5d1dd121585 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 @@ -79,7 +79,9 @@ private object KotlinFirCompletionProvider : CompletionProvider { + complete(callableReferenceContributor, positionContext) + complete(classifierReferenceContributor, positionContext) + } + is FirIncorrectPositionContext -> { // do nothing, completion is not suposed to be called here } 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 dd6a1f463b4..b42e8fae279 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 @@ -96,6 +96,13 @@ internal class FirWithSubjectEntryPositionContext( val whenCondition: KtWhenCondition, ) : FirNameReferencePositionContext() +internal class FirCallableReferencePositionContext( + override val position: PsiElement, + override val reference: KtSimpleNameReference, + override val nameExpression: KtSimpleNameExpression, + override val explicitReceiver: KtExpression? +) : FirNameReferencePositionContext() + internal class FirUnknownPositionContext( override val position: PsiElement ) : FirRawPositionCompletionContext() @@ -130,6 +137,11 @@ internal object FirPositionCompletionContextDetector { parent is KtUserType -> { detectForTypeContext(parent, position, reference, nameExpression, explicitReceiver) } + parent is KtCallableReferenceExpression -> { + FirCallableReferencePositionContext( + position, reference, nameExpression, parent.receiverExpression + ) + } parent is KtWhenCondition && parent.isConditionOnWhenWithSubject() -> { FirWithSubjectEntryPositionContext( position, 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 9c3e6752d0a..707ae0cd061 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 @@ -9,22 +9,27 @@ import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker import org.jetbrains.kotlin.idea.completion.checkers.ExtensionApplicabilityChecker import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.context.FirNameReferencePositionContext +import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy +import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy import org.jetbrains.kotlin.idea.fir.HLIndexHelper 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.symbols.markers.KtSymbolWithVisibility import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType import org.jetbrains.kotlin.idea.frontend.api.types.KtNonErrorClassType import org.jetbrains.kotlin.idea.frontend.api.types.KtType import org.jetbrains.kotlin.psi.KtExpression -internal class FirCallableCompletionContributor( +internal open class FirCallableCompletionContributor( basicContext: FirBasicCompletionContext, ) : FirContextCompletionContributorBase(basicContext) { private val typeNamesProvider = TypeNamesProvider(indexHelper) + protected open val insertionStrategy: CallableInsertionStrategy = CallableInsertionStrategy.AS_CALL + private val shouldCompleteTopLevelCallablesFromIndex: Boolean get() = prefixMatcher.prefix.isNotEmpty() @@ -67,22 +72,22 @@ internal class FirCallableCompletionContributor( val availableNonExtensions = collectNonExtensions(implicitScopes, visibilityChecker) val extensionsWhichCanBeCalled = collectSuitableExtensions(implicitScopes, extensionChecker, visibilityChecker) - availableNonExtensions.forEach { addSymbolToCompletion(expectedType, it) } - extensionsWhichCanBeCalled.forEach { addSymbolToCompletion(expectedType, it) } + availableNonExtensions.forEach { addCallableSymbolToCompletion(expectedType, it, insertionStrategy = insertionStrategy) } + extensionsWhichCanBeCalled.forEach { addCallableSymbolToCompletion(expectedType, it, insertionStrategy = insertionStrategy) } if (shouldCompleteTopLevelCallablesFromIndex) { val topLevelCallables = indexHelper.getTopLevelCallables(scopeNameFilter) topLevelCallables.asSequence() .map { it.getSymbol() as KtCallableSymbol } .filter { with(visibilityChecker) { isVisible(it) } } - .forEach { addSymbolToCompletion(expectedType, it) } + .forEach { addCallableSymbolToCompletion(expectedType, it, insertionStrategy = insertionStrategy) } } collectTopLevelExtensionsFromIndices(implicitReceiversTypes, extensionChecker, visibilityChecker) - .forEach { addSymbolToCompletion(expectedType, it) } + .forEach { addCallableSymbolToCompletion(expectedType, it, insertionStrategy = insertionStrategy) } } - private fun KtAnalysisSession.collectDotCompletion( + protected open fun KtAnalysisSession.collectDotCompletion( implicitScopes: KtCompositeScope, explicitReceiver: KtExpression, expectedType: KtType?, @@ -111,11 +116,11 @@ internal class FirCallableCompletionContributor( .filterNot { it.isExtension } .filter { with(visibilityChecker) { isVisible(it) } } .forEach { callable -> - addSymbolToCompletion(expectedType, callable) + addCallableSymbolToCompletion(expectedType, callable, insertionStrategy = insertionStrategy) } } - private fun KtAnalysisSession.collectDotCompletionForCallableReceiver( + protected fun KtAnalysisSession.collectDotCompletionForCallableReceiver( implicitScopes: KtCompositeScope, explicitReceiver: KtExpression, expectedType: KtType?, @@ -128,11 +133,11 @@ internal class FirCallableCompletionContributor( val nonExtensionMembers = collectNonExtensions(possibleReceiverScope, visibilityChecker) val extensionNonMembers = collectSuitableExtensions(implicitScopes, extensionChecker, visibilityChecker) - nonExtensionMembers.forEach { addSymbolToCompletion(expectedType, it) } - extensionNonMembers.forEach { addSymbolToCompletion(expectedType, it) } + nonExtensionMembers.forEach { addCallableSymbolToCompletion(expectedType, it, insertionStrategy = insertionStrategy) } + extensionNonMembers.forEach { addCallableSymbolToCompletion(expectedType, it, insertionStrategy = insertionStrategy) } collectTopLevelExtensionsFromIndices(listOf(typeOfPossibleReceiver), extensionChecker, visibilityChecker) - .forEach { addSymbolToCompletion(expectedType, it) } + .forEach { addCallableSymbolToCompletion(expectedType, it, insertionStrategy = insertionStrategy) } } private fun KtAnalysisSession.collectTopLevelExtensionsFromIndices( @@ -168,6 +173,36 @@ internal class FirCallableCompletionContributor( implicitReceiversTypes.flatMapTo(hashSetOf()) { with(typeNamesProvider) { findAllNames(it) } } } +internal class FirCallableReferenceCompletionContributor( + basicContext: FirBasicCompletionContext +) : FirCallableCompletionContributor(basicContext) { + override val insertionStrategy: CallableInsertionStrategy = CallableInsertionStrategy.AS_IDENTIFIER + + override fun KtAnalysisSession.collectDotCompletion( + implicitScopes: KtCompositeScope, + explicitReceiver: KtExpression, + expectedType: KtType?, + extensionChecker: ExtensionApplicabilityChecker, + visibilityChecker: CompletionVisibilityChecker + ) { + when (val resolved = explicitReceiver.reference()?.resolveToSymbol()) { + is KtPackageSymbol -> return + is KtNamedClassOrObjectSymbol -> { + resolved.getMemberScope() + .getCallableSymbols(scopeNameFilter) + .filter { with(visibilityChecker) { isVisible(it) } } + .forEach { symbol -> + addCallableSymbolToCompletion(expectedType = null, symbol, insertionStrategy = insertionStrategy) + } + + } + else -> { + collectDotCompletionForCallableReceiver(implicitScopes, explicitReceiver, expectedType, extensionChecker, visibilityChecker) + } + } + } +} + private class TypeNamesProvider(private val indexHelper: HLIndexHelper) { fun KtAnalysisSession.findAllNames(type: KtType): Set { if (type !is KtNonErrorClassType) return emptySet() 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 1bb3958a1f6..bacccc045f0 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 @@ -14,6 +14,8 @@ import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.idea.frontend.api.types.KtClassType import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.idea.completion.contributors.helpers.FirClassifierProvider.getAvailableClassifiersCurrentScope +import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy +import org.jetbrains.kotlin.idea.completion.lookups.detectImportStrategy import org.jetbrains.kotlin.idea.frontend.api.types.KtNonErrorClassType internal open class FirClassifierCompletionContributor( @@ -22,6 +24,9 @@ internal open class FirClassifierCompletionContributor( protected open fun KtAnalysisSession.filterClassifiers(classifierSymbol: KtClassifierSymbol): Boolean = true + protected open fun KtAnalysisSession.getImportingStrategy(classifierSymbol: KtClassifierSymbol): ImportStrategy = + detectImportStrategy(classifierSymbol) + override fun KtAnalysisSession.complete(positionContext: FirNameReferencePositionContext) { val visibilityChecker = CompletionVisibilityChecker.create(basicContext, positionContext) @@ -45,7 +50,7 @@ internal open class FirClassifierCompletionContributor( .getClassifierSymbols(scopeNameFilter) .filter { filterClassifiers(it) } .filter { with(visibilityChecker) { isVisible(it) } } - .forEach { addClassifierSymbolToCompletion(it, insertFqName = false) } + .forEach { addClassifierSymbolToCompletion(it, ImportStrategy.DoNothing) } } private fun KtAnalysisSession.completeWithoutReceiver( @@ -60,7 +65,9 @@ internal open class FirClassifierCompletionContributor( visibilityChecker ) .filter { filterClassifiers(it) } - .forEach { addClassifierSymbolToCompletion(it, insertFqName = true) } + .forEach { classifierSymbol -> + addClassifierSymbolToCompletion(classifierSymbol, getImportingStrategy(classifierSymbol)) + } } } @@ -87,4 +94,12 @@ internal class FirAnnotationCompletionContributor( expendedClass?.let { filterClassifiers(it) } == true } } -} \ No newline at end of file +} + +internal class FirClassifierReferenceCompletionContributor( + basicContext: FirBasicCompletionContext +) : FirClassifierCompletionContributor(basicContext) { + + override fun KtAnalysisSession.getImportingStrategy(classifierSymbol: KtClassifierSymbol): ImportStrategy = + ImportStrategy.DoNothing +} 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 0b66912b4c0..eeb64d771d7 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 @@ -6,15 +6,15 @@ package org.jetbrains.kotlin.idea.completion.contributors import com.intellij.codeInsight.completion.CompletionParameters -import com.intellij.codeInsight.completion.CompletionResultSet import com.intellij.codeInsight.completion.PrefixMatcher import com.intellij.codeInsight.lookup.LookupElement import com.intellij.openapi.project.Project import org.jetbrains.kotlin.idea.completion.LookupElementSink import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext import org.jetbrains.kotlin.idea.completion.context.FirRawPositionCompletionContext -import org.jetbrains.kotlin.idea.completion.lookups.CallableImportStrategy +import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy +import org.jetbrains.kotlin.idea.completion.lookups.detectImportStrategy import org.jetbrains.kotlin.idea.completion.lookups.factories.KotlinFirLookupElementFactory import org.jetbrains.kotlin.idea.completion.weighers.Weighers import org.jetbrains.kotlin.idea.fir.HLIndexHelper @@ -50,16 +50,18 @@ internal abstract class FirCompletionContributorBase createLookupElementForClassLikeSymbol(symbol, insertFqName) + is KtClassLikeSymbol -> createLookupElementForClassLikeSymbol(symbol, importingStrategy) is KtTypeParameterSymbol -> createLookupElement(symbol) } } ?: return @@ -67,14 +69,16 @@ internal abstract class FirCompletionContributorBase detectImportStrategyForCallableSymbol(symbol) + is KtClassLikeSymbol -> detectImportStrategyForClassLikeSymbol(symbol) + else -> ImportStrategy.DoNothing +} + +internal fun KtAnalysisSession.detectImportStrategyForCallableSymbol(symbol: KtCallableSymbol): ImportStrategy { + if (symbol !is KtPossibleMemberSymbol || symbol.dispatchType != null) return ImportStrategy.DoNothing + + val propertyId = symbol.callableIdIfNonLocal?.asSingleFqName() ?: return ImportStrategy.DoNothing + + return if (symbol.isExtension) { + ImportStrategy.AddImport(propertyId) + } else { + ImportStrategy.InsertFqNameAndShorten(propertyId) + } +} + +internal fun KtAnalysisSession.detectImportStrategyForClassLikeSymbol(symbol: KtClassLikeSymbol): ImportStrategy { + val classId = symbol.classIdIfNonLocal ?: return ImportStrategy.DoNothing + return ImportStrategy.InsertFqNameAndShorten(classId.asSingleFqName()) +} + +internal fun addCallableImportIfRequired(targetFile: KtFile, nameToImport: FqName) { + if (!alreadyHasImport(targetFile, nameToImport)) { + addImportToFile(targetFile.project, targetFile, nameToImport) + } +} + +private fun alreadyHasImport(file: KtFile, nameToImport: FqName): Boolean { + if (file.importDirectives.any { it.importPath?.fqName == nameToImport }) return true + + withAllowedResolve { + analyse(file) { + val scopes = file.getScopeContextForFile().scopes + if (!scopes.mayContainName(nameToImport.shortName())) return false + + val anyCallableSymbolMatches = scopes + .getCallableSymbols { it == nameToImport.shortName() } + .any { callable -> + val callableFqName = callable.callableIdIfNonLocal?.asSingleFqName() + callable is KtKotlinPropertySymbol && callableFqName == nameToImport || + callable is KtFunctionSymbol && callableFqName == nameToImport + } + if (anyCallableSymbolMatches) return true + + return scopes.getClassifierSymbols { it == nameToImport.shortName() }.any { classifier -> + val classId = (classifier as? KtClassLikeSymbol)?.classIdIfNonLocal + classId?.asSingleFqName() == nameToImport + } + } + } +} \ No newline at end of file diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/ClassLookupElementFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/ClassLookupElementFactory.kt index 077a5472200..30ef2652b72 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/ClassLookupElementFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/ClassLookupElementFactory.kt @@ -10,6 +10,8 @@ import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.openapi.util.TextRange +import org.jetbrains.kotlin.idea.completion.lookups.* +import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy import org.jetbrains.kotlin.idea.completion.lookups.KotlinLookupObject import org.jetbrains.kotlin.idea.completion.lookups.shortenReferencesForFirCompletion import org.jetbrains.kotlin.idea.completion.lookups.withSymbolInfo @@ -21,10 +23,13 @@ import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtFile import org.jetbrains.kotlin.renderer.render -class ClassLookupElementFactory { - fun KtAnalysisSession.createLookup(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElementBuilder { +internal class ClassLookupElementFactory { + fun KtAnalysisSession.createLookup( + symbol: KtClassLikeSymbol, + importingStrategy: ImportStrategy = detectImportStrategy(symbol) + ): LookupElementBuilder { val name = symbol.nameOrAnonymous - return LookupElementBuilder.create(ClassifierLookupObject(name, symbol.classIdIfNonLocal, insertFqName), name.asString()) + return LookupElementBuilder.create(ClassifierLookupObject(name, importingStrategy), name.asString()) .withInsertHandler(ClassifierInsertionHandler) .let { withSymbolInfo(symbol, it) } } @@ -33,9 +38,8 @@ class ClassLookupElementFactory { private data class ClassifierLookupObject( override val shortName: Name, - val classId: ClassId?, - val insertFqName: Boolean -) : KotlinLookupObject {} + val importingStrategy: ImportStrategy +) : KotlinLookupObject /** * The simplest implementation of the insertion handler for a classifiers. @@ -45,8 +49,8 @@ private object ClassifierInsertionHandler : InsertHandler { val targetFile = context.file as? KtFile ?: return val lookupObject = item.`object` as ClassifierLookupObject - if (lookupObject.classId != null && lookupObject.insertFqName) { - val fqName = lookupObject.classId.asSingleFqName() + if (lookupObject.importingStrategy is ImportStrategy.InsertFqNameAndShorten) { + val fqName = lookupObject.importingStrategy.fqName context.document.replaceString(context.startOffset, context.tailOffset, fqName.render()) context.commitDocument() diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/FunctionLookupElementFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/FunctionLookupElementFactory.kt index ff32507bc7a..98d40730d59 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/FunctionLookupElementFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/FunctionLookupElementFactory.kt @@ -10,18 +10,15 @@ import com.intellij.codeInsight.completion.InsertionContext import com.intellij.codeInsight.lookup.Lookup import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder -import com.intellij.openapi.diagnostic.ControlFlowException -import com.intellij.openapi.diagnostic.logger import com.intellij.openapi.util.TextRange import com.intellij.psi.PsiElement import org.jetbrains.kotlin.idea.completion.lookups.* -import org.jetbrains.kotlin.idea.completion.lookups.CallableImportStrategy +import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy import org.jetbrains.kotlin.idea.completion.lookups.CompletionShortNamesRenderer import org.jetbrains.kotlin.idea.completion.lookups.QuotedNamesAwareInsertionHandler import org.jetbrains.kotlin.idea.completion.lookups.addCallableImportIfRequired import org.jetbrains.kotlin.idea.completion.lookups.shortenReferencesForFirCompletion -import org.jetbrains.kotlin.idea.core.asFqNameWithRootPrefixIfNeeded import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.symbols.* import org.jetbrains.kotlin.lexer.KtTokens @@ -34,11 +31,12 @@ import org.jetbrains.kotlin.idea.completion.lookups.TailTextProvider.getTailText import org.jetbrains.kotlin.idea.completion.lookups.TailTextProvider.insertLambdaBraces import org.jetbrains.kotlin.idea.completion.lookups.CompletionShortNamesRenderer.renderFunctionParameters import org.jetbrains.kotlin.idea.completion.lookups.CompletionShortNamesRenderer.TYPE_RENDERING_OPTIONS +import org.jetbrains.kotlin.idea.core.withRootPrefixIfNeeded internal class FunctionLookupElementFactory { fun KtAnalysisSession.createLookup( symbol: KtFunctionSymbol, - importStrategy: CallableImportStrategy, + importStrategy: ImportStrategy, insertionStrategy: CallableInsertionStrategy ): LookupElementBuilder { val lookupObject = FunctionLookupObject( @@ -68,7 +66,7 @@ internal class FunctionLookupElementFactory { */ private data class FunctionLookupObject( override val shortName: Name, - val importStrategy: CallableImportStrategy, + val importStrategy: ImportStrategy, val inputValueArguments: Boolean, val insertEmptyLambda: Boolean, // for distinction between different overloads @@ -167,11 +165,11 @@ private object FunctionInsertionHandler : QuotedNamesAwareInsertionHandler() { val element = context.file.findElementAt(startOffset) ?: return val importStrategy = lookupObject.importStrategy - if (importStrategy is CallableImportStrategy.InsertFqNameAndShorten) { + if (importStrategy is ImportStrategy.InsertFqNameAndShorten) { context.document.replaceString( context.startOffset, context.tailOffset, - importStrategy.callableId.asFqNameWithRootPrefixIfNeeded().render() + importStrategy.fqName.withRootPrefixIfNeeded().render() ) context.commitDocument() @@ -183,7 +181,7 @@ private object FunctionInsertionHandler : QuotedNamesAwareInsertionHandler() { addArguments(context, element, lookupObject) context.commitDocument() - if (importStrategy is CallableImportStrategy.AddImport) { + if (importStrategy is ImportStrategy.AddImport) { addCallableImportIfRequired(targetFile, importStrategy.nameToImport) } } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/KotlinFirLookupElementFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/KotlinFirLookupElementFactory.kt index 05e913f2caf..367fba9d94b 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/KotlinFirLookupElementFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/KotlinFirLookupElementFactory.kt @@ -7,7 +7,7 @@ package org.jetbrains.kotlin.idea.completion.lookups.factories import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder -import org.jetbrains.kotlin.idea.completion.lookups.CallableImportStrategy +import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy import org.jetbrains.kotlin.idea.completion.lookups.detectImportStrategy import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession @@ -37,7 +37,7 @@ internal class KotlinFirLookupElementFactory { fun KtAnalysisSession.createCallableLookupElement( symbol: KtCallableSymbol, - importingStrategy: CallableImportStrategy, + importingStrategy: ImportStrategy, insertionStrategy: CallableInsertionStrategy, ): LookupElementBuilder { return when (symbol) { @@ -50,9 +50,12 @@ internal class KotlinFirLookupElementFactory { fun createPackagePartLookupElement(packagePartFqName: FqName): LookupElement = packagePartLookupElementFactory.createPackagePartLookupElement(packagePartFqName) - fun KtAnalysisSession.createLookupElementForClassLikeSymbol(symbol: KtClassLikeSymbol, insertFqName: Boolean = true): LookupElement? { + fun KtAnalysisSession.createLookupElementForClassLikeSymbol( + symbol: KtClassLikeSymbol, + importingStrategy: ImportStrategy = detectImportStrategy(symbol) + ): LookupElement? { if (symbol !is KtNamedSymbol) return null - return with(classLookupElementFactory) { createLookup(symbol, insertFqName) } + return with(classLookupElementFactory) { createLookup(symbol, importingStrategy) } } } diff --git a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/VariableLookupElementFactory.kt b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/VariableLookupElementFactory.kt index 370c8af9dc5..95668605aa4 100644 --- a/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/VariableLookupElementFactory.kt +++ b/idea/idea-fir/src/org/jetbrains/kotlin/idea/completion/lookups/factories/VariableLookupElementFactory.kt @@ -11,12 +11,12 @@ import com.intellij.codeInsight.lookup.LookupElement import com.intellij.codeInsight.lookup.LookupElementBuilder import com.intellij.openapi.util.TextRange import org.jetbrains.kotlin.idea.completion.lookups.* -import org.jetbrains.kotlin.idea.completion.lookups.CallableImportStrategy +import org.jetbrains.kotlin.idea.completion.lookups.ImportStrategy import org.jetbrains.kotlin.idea.completion.lookups.TailTextProvider.getTailText import org.jetbrains.kotlin.idea.completion.lookups.addCallableImportIfRequired import org.jetbrains.kotlin.idea.completion.lookups.detectImportStrategy import org.jetbrains.kotlin.idea.completion.lookups.shortenReferencesForFirCompletion -import org.jetbrains.kotlin.idea.core.asFqNameWithRootPrefixIfNeeded +import org.jetbrains.kotlin.idea.core.withRootPrefixIfNeeded import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession import org.jetbrains.kotlin.idea.frontend.api.components.KtTypeRendererOptions import org.jetbrains.kotlin.idea.frontend.api.symbols.KtSyntheticJavaPropertySymbol @@ -28,7 +28,7 @@ import org.jetbrains.kotlin.renderer.render internal class VariableLookupElementFactory { fun KtAnalysisSession.createLookup( symbol: KtVariableLikeSymbol, - importStrategy: CallableImportStrategy = detectImportStrategy(symbol) + importStrategy: ImportStrategy = detectImportStrategy(symbol) ): LookupElementBuilder { val lookupObject = VariableLookupObject( symbol.name, @@ -63,7 +63,7 @@ internal class VariableLookupElementFactory { */ private data class VariableLookupObject( override val shortName: Name, - val importStrategy: CallableImportStrategy, + val importStrategy: ImportStrategy, override val renderedReceiverType: String?, ) : KotlinCallableLookupObject() @@ -74,22 +74,22 @@ private object VariableInsertionHandler : InsertHandler { val lookupObject = item.`object` as VariableLookupObject when (val importStrategy = lookupObject.importStrategy) { - is CallableImportStrategy.AddImport -> { + is ImportStrategy.AddImport -> { addCallableImportIfRequired(targetFile, importStrategy.nameToImport) } - is CallableImportStrategy.InsertFqNameAndShorten -> { + is ImportStrategy.InsertFqNameAndShorten -> { context.document.replaceString( context.startOffset, context.tailOffset, - importStrategy.callableId.asFqNameWithRootPrefixIfNeeded().render() + importStrategy.fqName.withRootPrefixIfNeeded().render() ) context.commitDocument() shortenReferencesForFirCompletion(targetFile, TextRange(context.startOffset, context.tailOffset)) } - is CallableImportStrategy.DoNothing -> { + is ImportStrategy.DoNothing -> { } } } diff --git a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/scopes/KtScope.kt b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/scopes/KtScope.kt index 265b6a0f751..ef86df14990 100644 --- a/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/scopes/KtScope.kt +++ b/idea/idea-frontend-api/src/org/jetbrains/kotlin/idea/frontend/api/scopes/KtScope.kt @@ -47,6 +47,17 @@ interface KtScope : ValidityTokenOwner { } } + /** + * Return a sequence of all [KtSymbol] which current scope contain if declaration name matches [nameFilter] + * Constructors are not included here as they have no name + */ + fun getAllNamedSymbols(nameFilter: KtScopeNameFilter = { true }): Sequence = withValidityAssertion { + sequence { + yieldAll(getCallableSymbols(nameFilter)) + yieldAll(getClassifierSymbols(nameFilter)) + } + } + /** * Return a sequence of [KtCallableSymbol] which current scope contain if declaration name matches [nameFilter] */