Remove KotlinFirCompletionProvider
- We should strive to use only high-level API for completion from now on
This commit is contained in:
committed by
Ilya Kirillov
parent
dee58e1d86
commit
d2fbd8e338
+4
-123
@@ -11,21 +11,6 @@ import com.intellij.openapi.project.Project
|
|||||||
import com.intellij.patterns.PlatformPatterns
|
import com.intellij.patterns.PlatformPatterns
|
||||||
import com.intellij.psi.search.GlobalSearchScope
|
import com.intellij.psi.search.GlobalSearchScope
|
||||||
import com.intellij.util.ProcessingContext
|
import com.intellij.util.ProcessingContext
|
||||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
|
||||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.ScopeSession
|
|
||||||
import org.jetbrains.kotlin.fir.resolve.scope
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.FirScope
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractSimpleImportingScope
|
|
||||||
import org.jetbrains.kotlin.fir.scopes.impl.FirAbstractStarImportingScope
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirCallableSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.symbols.impl.FirConstructorSymbol
|
|
||||||
import org.jetbrains.kotlin.fir.typeContext
|
|
||||||
import org.jetbrains.kotlin.fir.types.ConeKotlinType
|
|
||||||
import org.jetbrains.kotlin.fir.types.coneTypeUnsafe
|
|
||||||
import org.jetbrains.kotlin.idea.fir.getFirOfClosestParent
|
|
||||||
import org.jetbrains.kotlin.idea.fir.getOrBuildFirSafe
|
|
||||||
import org.jetbrains.kotlin.idea.fir.low.level.api.LowLevelFirApiFacade
|
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.getAnalysisSessionFor
|
import org.jetbrains.kotlin.idea.frontend.api.getAnalysisSessionFor
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtCallableSymbol
|
||||||
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedSymbol
|
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtNamedSymbol
|
||||||
@@ -37,87 +22,19 @@ import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelFunctionByPackageIndex
|
|||||||
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyByPackageIndex
|
import org.jetbrains.kotlin.idea.stubindex.KotlinTopLevelPropertyByPackageIndex
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.KtCallableDeclaration
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getNonStrictParentOfType
|
import org.jetbrains.kotlin.psi.KtFile
|
||||||
|
import org.jetbrains.kotlin.psi.KtLabelReferenceExpression
|
||||||
|
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
import org.jetbrains.kotlin.psi.psiUtil.getQualifiedExpressionForSelector
|
||||||
import org.jetbrains.kotlin.types.AbstractTypeChecker
|
|
||||||
import org.jetbrains.kotlin.types.model.TypeCheckerProviderContext
|
|
||||||
|
|
||||||
class KotlinFirCompletionContributor : CompletionContributor() {
|
class KotlinFirCompletionContributor : CompletionContributor() {
|
||||||
init {
|
init {
|
||||||
// extend(CompletionType.BASIC, PlatformPatterns.psiElement(), KotlinFirCompletionProvider)
|
|
||||||
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), KotlinHighLevelApiContributor)
|
extend(CompletionType.BASIC, PlatformPatterns.psiElement(), KotlinHighLevelApiContributor)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private object KotlinFirCompletionProvider : CompletionProvider<CompletionParameters>() {
|
|
||||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
|
||||||
val originalFile = parameters.originalFile as? KtFile ?: return
|
|
||||||
|
|
||||||
val originalFileFir = originalFile.getOrBuildFirSafe<FirFile>(LowLevelFirApiFacade.getResolveStateFor(originalFile)) ?: return
|
|
||||||
|
|
||||||
val reference = (parameters.position.parent as? KtSimpleNameExpression)?.mainReference ?: return
|
|
||||||
val nameExpression = reference.expression.takeIf { it !is KtLabelReferenceExpression } ?: return
|
|
||||||
|
|
||||||
val parentFunction = nameExpression.getNonStrictParentOfType<KtNamedFunction>() ?: return
|
|
||||||
|
|
||||||
val completionContext = LowLevelFirApiFacade.buildCompletionContextForFunction(
|
|
||||||
originalFileFir,
|
|
||||||
parentFunction,
|
|
||||||
LowLevelFirApiFacade.getResolveStateFor(originalFile)
|
|
||||||
)
|
|
||||||
|
|
||||||
val element = nameExpression.getFirOfClosestParent() as? FirQualifiedAccessExpression ?: return
|
|
||||||
val towerDataContext = completionContext.getTowerDataContext(nameExpression)
|
|
||||||
|
|
||||||
val symbols: Sequence<FirCallableSymbol<*>> = sequence {
|
|
||||||
val packageIndexHelper = PackageIndexHelper(parameters.position.project)
|
|
||||||
|
|
||||||
val explicitReceiver = element.explicitReceiver
|
|
||||||
val explicitReceiverType = explicitReceiver?.typeRef?.coneTypeUnsafe<ConeKotlinType>()
|
|
||||||
val explicitReceiverScope = explicitReceiverType?.scope(completionContext.session, ScopeSession())
|
|
||||||
|
|
||||||
val implicitReceivers = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.implicitReceiver }
|
|
||||||
val implicitReceiversTypes = implicitReceivers.map { it.type }
|
|
||||||
|
|
||||||
val localScopes = towerDataContext.localScopes
|
|
||||||
val nonLocalScopes = towerDataContext.nonLocalTowerDataElements.mapNotNull { it.scope }
|
|
||||||
val implicitReceiversScopes = implicitReceivers.mapNotNull { it.implicitScope }
|
|
||||||
|
|
||||||
val allNonExplicitScopes = localScopes.asSequence() + nonLocalScopes + implicitReceiversScopes
|
|
||||||
|
|
||||||
val typeContext = completionContext.session.typeContext
|
|
||||||
|
|
||||||
if (explicitReceiverScope != null) {
|
|
||||||
val nonExtensionMembers = explicitReceiverScope.collectCallableSymbols(packageIndexHelper).filter { !it.isExtension }
|
|
||||||
yieldAll(nonExtensionMembers)
|
|
||||||
|
|
||||||
val allApplicableExtensions = allNonExplicitScopes
|
|
||||||
.flatMap { it.collectCallableSymbols(packageIndexHelper) }
|
|
||||||
.filter { it.isExtension && it.isExtensionThatCanBeCalledOnTypes(listOf(explicitReceiverType), typeContext) }
|
|
||||||
|
|
||||||
yieldAll(allApplicableExtensions)
|
|
||||||
} else {
|
|
||||||
val allAvailableSymbols = allNonExplicitScopes
|
|
||||||
.flatMap { it.collectCallableSymbols(packageIndexHelper) }
|
|
||||||
.filter { !it.isExtension || it.isExtensionThatCanBeCalledOnTypes(implicitReceiversTypes, typeContext) }
|
|
||||||
|
|
||||||
yieldAll(allAvailableSymbols)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (symbol in symbols) {
|
|
||||||
if (symbol is FirConstructorSymbol) continue
|
|
||||||
val symbolName = symbol.callableId.callableName
|
|
||||||
|
|
||||||
result.addElement(LookupElementBuilder.create(symbolName.toString()))
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
private object KotlinHighLevelApiContributor : CompletionProvider<CompletionParameters>() {
|
private object KotlinHighLevelApiContributor : CompletionProvider<CompletionParameters>() {
|
||||||
|
|
||||||
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
override fun addCompletions(parameters: CompletionParameters, context: ProcessingContext, result: CompletionResultSet) {
|
||||||
val originalFile = parameters.originalFile as? KtFile ?: return
|
val originalFile = parameters.originalFile as? KtFile ?: return
|
||||||
|
|
||||||
@@ -172,34 +89,6 @@ private fun KtCallableSymbol.canBeCalledWith(implicitReceivers: List<KtType>): B
|
|||||||
return implicitReceivers.any { it.isSubTypeOf(requiredReceiverType) }
|
return implicitReceivers.any { it.isSubTypeOf(requiredReceiverType) }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val FirCallableSymbol<*>.isExtension get() = fir.receiverTypeRef != null
|
|
||||||
|
|
||||||
|
|
||||||
private fun FirScope.getScopeNames(indexHelper: PackageIndexHelper): Set<Name> = when (this) {
|
|
||||||
is FirAbstractStarImportingScope -> {
|
|
||||||
this.starImports.flatMapTo(mutableSetOf()) { indexHelper.getPackageTopLevelNames(it.packageFqName) }
|
|
||||||
}
|
|
||||||
|
|
||||||
is FirAbstractSimpleImportingScope -> simpleImports.keys
|
|
||||||
|
|
||||||
else -> getCallableNames()
|
|
||||||
}
|
|
||||||
|
|
||||||
private fun FirScope.collectCallableSymbols(packageIndexHelper: PackageIndexHelper): MutableList<FirCallableSymbol<*>> {
|
|
||||||
val allCallableSymbols = mutableListOf<FirCallableSymbol<*>>()
|
|
||||||
fun symbolsCollector(symbol: FirCallableSymbol<*>) {
|
|
||||||
allCallableSymbols.add(symbol)
|
|
||||||
}
|
|
||||||
|
|
||||||
val scopeNames = getScopeNames(packageIndexHelper)
|
|
||||||
for (name in scopeNames) {
|
|
||||||
processFunctionsByName(name, ::symbolsCollector)
|
|
||||||
processPropertiesByName(name, ::symbolsCollector)
|
|
||||||
}
|
|
||||||
|
|
||||||
return allCallableSymbols
|
|
||||||
}
|
|
||||||
|
|
||||||
class PackageIndexHelper(private val project: Project) {
|
class PackageIndexHelper(private val project: Project) {
|
||||||
//todo use more concrete scope
|
//todo use more concrete scope
|
||||||
private val searchScope = GlobalSearchScope.allScope(project)
|
private val searchScope = GlobalSearchScope.allScope(project)
|
||||||
@@ -217,11 +106,3 @@ class PackageIndexHelper(private val project: Project) {
|
|||||||
addAll(propertyByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
addAll(propertyByPackageIndex.get(packageFqName.asString(), project, searchScope))
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun FirCallableSymbol<*>.isExtensionThatCanBeCalledOnTypes(
|
|
||||||
receivers: List<ConeKotlinType>,
|
|
||||||
session: TypeCheckerProviderContext
|
|
||||||
): Boolean {
|
|
||||||
val expectedReceiverType = fir.receiverTypeRef?.coneTypeUnsafe<ConeKotlinType>() ?: return false
|
|
||||||
return receivers.any { AbstractTypeChecker.isSubtypeOf(session, it, expectedReceiverType) }
|
|
||||||
}
|
|
||||||
|
|||||||
Reference in New Issue
Block a user