FIR IDE: separate index helper in LL API and completion

This commit is contained in:
Ilya Kirillov
2021-06-14 16:27:25 +02:00
parent 7a5d61928b
commit 32919489f4
8 changed files with 129 additions and 91 deletions
@@ -14,7 +14,7 @@ import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.completion.KotlinFirCompletionParameters
import org.jetbrains.kotlin.idea.completion.LookupElementSink
import org.jetbrains.kotlin.idea.completion.lookups.factories.KotlinFirLookupElementFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
import org.jetbrains.kotlin.idea.fir.HLIndexHelper
import org.jetbrains.kotlin.idea.project.TargetPlatformDetector
import org.jetbrains.kotlin.idea.stubindex.KotlinSourceFilterScope
import org.jetbrains.kotlin.platform.TargetPlatform
@@ -28,7 +28,7 @@ internal class FirBasicCompletionContext(
val fakeKtFile: KtFile,
val project: Project,
val targetPlatform: TargetPlatform,
val indexHelper: IndexHelper,
val indexHelper: HLIndexHelper,
val lookupElementFactory: KotlinFirLookupElementFactory = KotlinFirLookupElementFactory(),
) {
val visibleScope = KotlinSourceFilterScope.projectSourceAndClassFiles(originalKtFile.resolveScope, project)
@@ -55,7 +55,7 @@ internal class FirBasicCompletionContext(
)
}
private fun createIndexHelper(parameters: CompletionParameters) = IndexHelper(
private fun createIndexHelper(parameters: CompletionParameters) = HLIndexHelper(
parameters.position.project,
parameters.position.getModuleInfo().contentScope()
)
@@ -9,7 +9,7 @@ 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.fir.low.level.api.IndexHelper
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
@@ -168,7 +168,7 @@ internal class FirCallableCompletionContributor(
implicitReceiversTypes.flatMapTo(hashSetOf()) { with(typeNamesProvider) { findAllNames(it) } }
}
private class TypeNamesProvider(private val indexHelper: IndexHelper) {
private class TypeNamesProvider(private val indexHelper: HLIndexHelper) {
fun KtAnalysisSession.findAllNames(type: KtType): Set<String> {
if (type !is KtNonErrorClassType) return emptySet()
@@ -17,7 +17,7 @@ import org.jetbrains.kotlin.idea.completion.lookups.CallableImportStrategy
import org.jetbrains.kotlin.idea.completion.lookups.CallableInsertionStrategy
import org.jetbrains.kotlin.idea.completion.lookups.factories.KotlinFirLookupElementFactory
import org.jetbrains.kotlin.idea.completion.weighers.Weighers
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
import org.jetbrains.kotlin.idea.fir.HLIndexHelper
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.idea.frontend.api.symbols.*
@@ -37,7 +37,7 @@ internal abstract class FirCompletionContributorBase<C : FirRawPositionCompletio
protected val fakeKtFile: KtFile get() = basicContext.fakeKtFile
protected val project: Project get() = basicContext.project
protected val targetPlatform: TargetPlatform get() = basicContext.targetPlatform
protected val indexHelper: IndexHelper get() = basicContext.indexHelper
protected val indexHelper: HLIndexHelper get() = basicContext.indexHelper
protected val lookupElementFactory: KotlinFirLookupElementFactory get() = basicContext.lookupElementFactory
protected val visibleScope = basicContext.visibleScope
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.idea.completion.contributors
import org.jetbrains.kotlin.idea.completion.context.FirBasicCompletionContext
import org.jetbrains.kotlin.idea.completion.context.FirNameReferencePositionContext
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
@@ -6,7 +6,7 @@
package org.jetbrains.kotlin.idea.completion.contributors.helpers
import org.jetbrains.kotlin.idea.completion.checkers.CompletionVisibilityChecker
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
import org.jetbrains.kotlin.idea.fir.HLIndexHelper
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.scopes.KtScopeNameFilter
import org.jetbrains.kotlin.idea.frontend.api.symbols.KtClassifierSymbol
@@ -19,7 +19,7 @@ internal object FirClassifierProvider {
originalKtFile: KtFile,
position: KtElement,
scopeNameFilter: KtScopeNameFilter,
indexHelper: IndexHelper,
indexHelper: HLIndexHelper,
visibilityChecker: CompletionVisibilityChecker
): Sequence<KtClassifierSymbol> = sequence {
yieldAll(
@@ -0,0 +1,113 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.idea.fir
import com.intellij.openapi.progress.ProgressManager
import com.intellij.openapi.project.Project
import com.intellij.psi.PsiElement
import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.stubs.StringStubIndexExtension
import com.intellij.psi.stubs.StubIndex
import com.intellij.psi.stubs.StubIndexKey
import org.jetbrains.kotlin.idea.stubindex.*
import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
/*
* Move to another module
*/
class HLIndexHelper(val project: Project, private val scope: GlobalSearchScope) {
fun getClassNamesInPackage(packageFqName: FqName): Set<Name> =
KotlinTopLevelClassByPackageIndex.getInstance()
.get(packageFqName.asStringForIndexes(), project, scope)
.mapNotNullTo(hashSetOf()) { it.nameAsName }
fun getKotlinClasses(
nameFilter: (Name) -> Boolean,
psiFilter: (element: KtClassOrObject) -> Boolean = { true }
): Collection<KtClassOrObject> {
val index = KotlinFullClassNameIndex.getInstance()
return index.getAllKeys(project).asSequence()
.onEach { ProgressManager.checkCanceled() }
.filter { fqName -> nameFilter(getShortName(fqName)) }
.flatMap { fqName -> index[fqName, project, scope] }
.filter(psiFilter)
.toList()
}
fun getTopLevelCallables(nameFilter: (Name) -> Boolean): Collection<KtCallableDeclaration> {
fun sequenceOfElements(index: StringStubIndexExtension<out KtCallableDeclaration>): Sequence<KtCallableDeclaration> =
index.getAllKeys(project).asSequence()
.onEach { ProgressManager.checkCanceled() }
.filter { fqName -> nameFilter(getShortName(fqName)) }
.flatMap { fqName -> index[fqName, project, scope] }
.filter { it.receiverTypeReference == null }
val functions = sequenceOfElements(KotlinTopLevelFunctionFqnNameIndex.getInstance())
val properties = sequenceOfElements(KotlinTopLevelPropertyFqnNameIndex.getInstance())
return (functions + properties).toList()
}
fun getKotlinCallablesByName(name: Name): Collection<KtCallableDeclaration> {
val functions: Sequence<KtCallableDeclaration> =
KotlinFunctionShortNameIndex.getInstance().get(name.asString(), project, scope).asSequence()
val properties: Sequence<KtNamedDeclaration> =
KotlinPropertyShortNameIndex.getInstance().get(name.asString(), project, scope).asSequence()
return (functions + properties)
.filterIsInstance<KtCallableDeclaration>()
.toList()
}
fun getKotlinClassesByName(name: Name): Collection<KtClassOrObject> {
return KotlinClassShortNameIndex.getInstance().get(name.asString(), project, scope)
}
fun getTopLevelExtensions(nameFilter: (Name) -> Boolean, receiverTypeNames: Set<String>): Collection<KtCallableDeclaration> {
val index = KotlinTopLevelExtensionsByReceiverTypeIndex.INSTANCE
return index.getAllKeys(project).asSequence()
.onEach { ProgressManager.checkCanceled() }
.filter { KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames }
.filter { nameFilter(Name.identifier(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it))) }
.flatMap { key -> index[key, project, scope] }
.toList()
}
fun getPossibleTypeAliasExpansionNames(originalTypeName: String): Set<String> {
val index = KotlinTypeAliasByExpansionShortNameIndex.INSTANCE
val out = mutableSetOf<String>()
fun searchRecursively(typeName: String) {
ProgressManager.checkCanceled()
index[typeName, project, scope].asSequence()
.mapNotNull { it.name }
.filter { out.add(it) }
.forEach(::searchRecursively)
}
searchRecursively(originalTypeName)
return out
}
companion object {
private fun CallableId.asStringForIndexes(): String =
(if (packageName.isRoot) callableName.asString() else toString()).replace('/', '.')
private fun FqName.asStringForIndexes(): String =
asString().replace('/', '.')
private fun ClassId.asStringForIndexes(): String =
asSingleFqName().asStringForIndexes()
private fun getShortName(fqName: String) = Name.identifier(fqName.substringAfterLast('.'))
}
}
@@ -19,8 +19,8 @@ import com.intellij.psi.search.GlobalSearchScope
import com.intellij.psi.util.PsiModificationTracker
import org.jetbrains.kotlin.idea.KotlinBundle
import org.jetbrains.kotlin.idea.caches.project.getModuleInfo
import org.jetbrains.kotlin.idea.fir.HLIndexHelper
import org.jetbrains.kotlin.idea.fir.api.fixes.diagnosticFixFactory
import org.jetbrains.kotlin.idea.fir.low.level.api.IndexHelper
import org.jetbrains.kotlin.idea.fir.low.level.api.util.createScopeForModuleLibraries
import org.jetbrains.kotlin.idea.frontend.api.KtAnalysisSession
import org.jetbrains.kotlin.idea.frontend.api.fir.diagnostics.KtFirDiagnostic
@@ -137,7 +137,7 @@ internal class ImportQuickFix(
val FACTORY = diagnosticFixFactory(KtFirDiagnostic.UnresolvedReference::class) { diagnostic ->
val element = diagnostic.psi
val indexHelper = IndexHelper(element.project, createSearchScope(element))
val indexHelper = HLIndexHelper(element.project, createSearchScope(element))
val quickFix = when (element) {
is KtTypeReference -> createImportTypeFix(indexHelper, element)
@@ -157,7 +157,7 @@ internal class ImportQuickFix(
}
private fun KtAnalysisSession.createImportNameFix(
indexHelper: IndexHelper,
indexHelper: HLIndexHelper,
element: KtNameReferenceExpression
): ImportQuickFix? {
if (isSelectorInQualified(element)) return null
@@ -177,7 +177,7 @@ internal class ImportQuickFix(
return ImportQuickFix(element, importCandidates)
}
private fun KtAnalysisSession.createImportTypeFix(indexHelper: IndexHelper, element: KtTypeReference): ImportQuickFix? {
private fun KtAnalysisSession.createImportTypeFix(indexHelper: HLIndexHelper, element: KtTypeReference): ImportQuickFix? {
val firFile = element.containingKtFile.getFileSymbol()
val unresolvedName = element.typeName ?: return null
@@ -191,7 +191,7 @@ internal class ImportQuickFix(
}
private fun KtAnalysisSession.collectCallableCandidates(
indexHelper: IndexHelper,
indexHelper: HLIndexHelper,
unresolvedName: Name,
isVisible: (KtCallableSymbol) -> Boolean
): List<FqName> {
@@ -206,7 +206,7 @@ internal class ImportQuickFix(
}
private fun KtAnalysisSession.collectTypesCandidates(
indexHelper: IndexHelper,
indexHelper: HLIndexHelper,
unresolvedName: Name,
isVisible: (KtNamedClassOrObjectSymbol) -> Boolean
): List<FqName> {
@@ -22,7 +22,7 @@ import org.jetbrains.kotlin.psi.*
/*
* Move to another module
*/
public class IndexHelper(val project: Project, private val scope: GlobalSearchScope) {
internal class IndexHelper(val project: Project, private val scope: GlobalSearchScope) {
private val stubIndex: StubIndex = StubIndex.getInstance()
private inline fun <INDEX_KEY : Any, reified PSI : PsiElement> firstMatchingOrNull(
@@ -64,86 +64,12 @@ public class IndexHelper(val project: Project, private val scope: GlobalSearchSc
fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction> =
KotlinTopLevelFunctionFqnNameIndex.getInstance()[callableId.asStringForIndexes(), project, scope]
fun getTopLevelPropertiesInPackage(packageFqName: FqName): Collection<KtProperty> =
KotlinTopLevelPropertyByPackageIndex.getInstance().get(packageFqName.asStringForIndexes(), project, scope)
fun getTopLevelFunctionsInPackage(packageFqName: FqName): Collection<KtFunction> =
KotlinTopLevelFunctionByPackageIndex.getInstance().get(packageFqName.asStringForIndexes(), project, scope)
fun getClassNamesInPackage(packageFqName: FqName): Set<Name> =
KotlinTopLevelClassByPackageIndex.getInstance()
.get(packageFqName.asStringForIndexes(), project, scope)
.mapNotNullTo(hashSetOf()) { it.nameAsName }
fun getKotlinClasses(
nameFilter: (Name) -> Boolean,
psiFilter: (element: KtClassOrObject) -> Boolean = { true }
): Collection<KtClassOrObject> {
val index = KotlinFullClassNameIndex.getInstance()
return index.getAllKeys(project).asSequence()
.onEach { ProgressManager.checkCanceled() }
.filter { fqName -> nameFilter(getShortName(fqName)) }
.flatMap { fqName -> index[fqName, project, scope] }
.filter(psiFilter)
.toList()
}
fun getTopLevelCallables(nameFilter: (Name) -> Boolean): Collection<KtCallableDeclaration> {
fun sequenceOfElements(index: StringStubIndexExtension<out KtCallableDeclaration>): Sequence<KtCallableDeclaration> =
index.getAllKeys(project).asSequence()
.onEach { ProgressManager.checkCanceled() }
.filter { fqName -> nameFilter(getShortName(fqName)) }
.flatMap { fqName -> index[fqName, project, scope] }
.filter { it.receiverTypeReference == null }
val functions = sequenceOfElements(KotlinTopLevelFunctionFqnNameIndex.getInstance())
val properties = sequenceOfElements(KotlinTopLevelPropertyFqnNameIndex.getInstance())
return (functions + properties).toList()
}
fun getKotlinCallablesByName(name: Name): Collection<KtCallableDeclaration> {
val functions: Sequence<KtCallableDeclaration> =
KotlinFunctionShortNameIndex.getInstance().get(name.asString(), project, scope).asSequence()
val properties: Sequence<KtNamedDeclaration> =
KotlinPropertyShortNameIndex.getInstance().get(name.asString(), project, scope).asSequence()
return (functions + properties)
.filterIsInstance<KtCallableDeclaration>()
.toList()
}
fun getKotlinClassesByName(name: Name): Collection<KtClassOrObject> {
return KotlinClassShortNameIndex.getInstance().get(name.asString(), project, scope)
}
fun getTopLevelExtensions(nameFilter: (Name) -> Boolean, receiverTypeNames: Set<String>): Collection<KtCallableDeclaration> {
val index = KotlinTopLevelExtensionsByReceiverTypeIndex.INSTANCE
return index.getAllKeys(project).asSequence()
.onEach { ProgressManager.checkCanceled() }
.filter { KotlinTopLevelExtensionsByReceiverTypeIndex.receiverTypeNameFromKey(it) in receiverTypeNames }
.filter { nameFilter(Name.identifier(KotlinTopLevelExtensionsByReceiverTypeIndex.callableNameFromKey(it))) }
.flatMap { key -> index[key, project, scope] }
.toList()
}
fun getPossibleTypeAliasExpansionNames(originalTypeName: String): Set<String> {
val index = KotlinTypeAliasByExpansionShortNameIndex.INSTANCE
val out = mutableSetOf<String>()
fun searchRecursively(typeName: String) {
ProgressManager.checkCanceled()
index[typeName, project, scope].asSequence()
.mapNotNull { it.name }
.filter { out.add(it) }
.forEach(::searchRecursively)
}
searchRecursively(originalTypeName)
return out
}
companion object {
private fun CallableId.asStringForIndexes(): String =