Refactor KotlinFirCompletionContributor

Replace extensions checking lambdas with `ExtensionApplicabilityChecker`
type
This commit is contained in:
Roman Golyshev
2021-03-29 17:06:26 +03:00
committed by Space
parent 86348ed981
commit 78b2324a51
@@ -82,6 +82,10 @@ private object KotlinFirCompletionProvider : CompletionProvider<CompletionParame
} }
} }
private fun interface ExtensionApplicabilityChecker {
fun isApplicable(symbol: KtCallableSymbol): Boolean
}
/** /**
* Currently, this class is responsible for collecting all possible completion variants. * Currently, this class is responsible for collecting all possible completion variants.
* *
@@ -138,8 +142,9 @@ private class KotlinCommonCompletionProvider(
val scopesContext = originalFile.getScopeContextForPosition(nameExpression) val scopesContext = originalFile.getScopeContextForPosition(nameExpression)
fun KtCallableSymbol.hasSuitableExtensionReceiver(): Boolean = val extensionChecker = ExtensionApplicabilityChecker {
checkExtensionIsSuitable(originalFile, nameExpression, explicitReceiver) it.checkExtensionIsSuitable(originalFile, nameExpression, explicitReceiver)
}
when { when {
nameExpression.parent is KtUserType -> collectTypesCompletion(result, scopesContext.scopes, expectedType) nameExpression.parent is KtUserType -> collectTypesCompletion(result, scopesContext.scopes, expectedType)
@@ -148,9 +153,9 @@ private class KotlinCommonCompletionProvider(
scopesContext.scopes, scopesContext.scopes,
explicitReceiver, explicitReceiver,
expectedType, expectedType,
KtCallableSymbol::hasSuitableExtensionReceiver extensionChecker
) )
else -> collectDefaultCompletion(result, scopesContext, expectedType, KtCallableSymbol::hasSuitableExtensionReceiver) else -> collectDefaultCompletion(result, scopesContext, expectedType, extensionChecker)
} }
} }
} }
@@ -172,18 +177,18 @@ private class KotlinCommonCompletionProvider(
implicitScopes: KtCompositeScope, implicitScopes: KtCompositeScope,
explicitReceiver: KtExpression, explicitReceiver: KtExpression,
expectedType: KtType?, expectedType: KtType?,
hasSuitableExtensionReceiver: KtCallableSymbol.() -> Boolean extensionChecker: ExtensionApplicabilityChecker,
) { ) {
val typeOfPossibleReceiver = explicitReceiver.getKtType() val typeOfPossibleReceiver = explicitReceiver.getKtType()
val possibleReceiverScope = typeOfPossibleReceiver.getTypeScope() ?: return val possibleReceiverScope = typeOfPossibleReceiver.getTypeScope() ?: return
val nonExtensionMembers = possibleReceiverScope.collectNonExtensions() val nonExtensionMembers = possibleReceiverScope.collectNonExtensions()
val extensionNonMembers = implicitScopes.collectSuitableExtensions(hasSuitableExtensionReceiver) val extensionNonMembers = implicitScopes.collectSuitableExtensions(extensionChecker)
nonExtensionMembers.forEach { addSymbolToCompletion(result, expectedType, it) } nonExtensionMembers.forEach { addSymbolToCompletion(result, expectedType, it) }
extensionNonMembers.forEach { addSymbolToCompletion(result, expectedType, it) } extensionNonMembers.forEach { addSymbolToCompletion(result, expectedType, it) }
collectTopLevelExtensionsFromIndices(listOf(typeOfPossibleReceiver), hasSuitableExtensionReceiver) collectTopLevelExtensionsFromIndices(listOf(typeOfPossibleReceiver), extensionChecker)
.forEach { addSymbolToCompletion(result, expectedType, it) } .forEach { addSymbolToCompletion(result, expectedType, it) }
} }
@@ -192,12 +197,12 @@ private class KotlinCommonCompletionProvider(
result: CompletionResultSet, result: CompletionResultSet,
implicitScopesContext: KtScopeContext, implicitScopesContext: KtScopeContext,
expectedType: KtType?, expectedType: KtType?,
hasSuitableExtensionReceiver: KtCallableSymbol.() -> Boolean, extensionChecker: ExtensionApplicabilityChecker,
) { ) {
val (implicitScopes, implicitReceiversTypes) = implicitScopesContext val (implicitScopes, implicitReceiversTypes) = implicitScopesContext
val availableNonExtensions = implicitScopes.collectNonExtensions() val availableNonExtensions = implicitScopes.collectNonExtensions()
val extensionsWhichCanBeCalled = implicitScopes.collectSuitableExtensions(hasSuitableExtensionReceiver) val extensionsWhichCanBeCalled = implicitScopes.collectSuitableExtensions(extensionChecker)
availableNonExtensions.forEach { addSymbolToCompletion(result, expectedType, it) } availableNonExtensions.forEach { addSymbolToCompletion(result, expectedType, it) }
extensionsWhichCanBeCalled.forEach { addSymbolToCompletion(result, expectedType, it) } extensionsWhichCanBeCalled.forEach { addSymbolToCompletion(result, expectedType, it) }
@@ -209,7 +214,7 @@ private class KotlinCommonCompletionProvider(
.forEach { addSymbolToCompletion(result, expectedType, it) } .forEach { addSymbolToCompletion(result, expectedType, it) }
} }
collectTopLevelExtensionsFromIndices(implicitReceiversTypes, hasSuitableExtensionReceiver) collectTopLevelExtensionsFromIndices(implicitReceiversTypes, extensionChecker)
.forEach { addSymbolToCompletion(result, expectedType, it) } .forEach { addSymbolToCompletion(result, expectedType, it) }
collectTypesCompletion(result, implicitScopes, expectedType) collectTypesCompletion(result, implicitScopes, expectedType)
@@ -217,23 +222,21 @@ private class KotlinCommonCompletionProvider(
private fun KtAnalysisSession.collectTopLevelExtensionsFromIndices( private fun KtAnalysisSession.collectTopLevelExtensionsFromIndices(
receiverTypes: List<KtType>, receiverTypes: List<KtType>,
hasSuitableExtensionReceiver: KtCallableSymbol.() -> Boolean extensionChecker: ExtensionApplicabilityChecker,
): Sequence<KtCallableSymbol> { ): Sequence<KtCallableSymbol> {
val implicitReceiverNames = findAllNamesOfTypes(receiverTypes) val implicitReceiverNames = findAllNamesOfTypes(receiverTypes)
val topLevelExtensions = indexHelper.getTopLevelExtensions(scopeNameFilter, implicitReceiverNames) val topLevelExtensions = indexHelper.getTopLevelExtensions(scopeNameFilter, implicitReceiverNames)
return topLevelExtensions.asSequence() return topLevelExtensions.asSequence()
.map { it.getSymbol() as KtCallableSymbol } .map { it.getSymbol() as KtCallableSymbol }
.filter(hasSuitableExtensionReceiver) .filter { extensionChecker.isApplicable(it) }
} }
private fun KtScope.collectNonExtensions(): Sequence<KtCallableSymbol> = private fun KtScope.collectNonExtensions(): Sequence<KtCallableSymbol> =
getCallableSymbols(scopeNameFilter).filterNot { it.isExtension } getCallableSymbols(scopeNameFilter).filterNot { it.isExtension }
private fun KtScope.collectSuitableExtensions( private fun KtScope.collectSuitableExtensions(extensionChecker: ExtensionApplicabilityChecker): Sequence<KtCallableSymbol> =
hasSuitableExtensionReceiver: KtCallableSymbol.() -> Boolean getCallableSymbols(scopeNameFilter).filter { it.isExtension && extensionChecker.isApplicable(it) }
): Sequence<KtCallableSymbol> =
getCallableSymbols(scopeNameFilter).filter { it.isExtension && it.hasSuitableExtensionReceiver() }
private fun KtAnalysisSession.findAllNamesOfTypes(implicitReceiversTypes: List<KtType>) = private fun KtAnalysisSession.findAllNamesOfTypes(implicitReceiversTypes: List<KtType>) =
implicitReceiversTypes.flatMapTo(hashSetOf()) { with(typeNamesProvider) { findAllNames(it) } } implicitReceiversTypes.flatMapTo(hashSetOf()) { with(typeNamesProvider) { findAllNames(it) } }