diff --git a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt index b594262dd58..84e89b3f89c 100644 --- a/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt +++ b/analysis/analysis-api-providers/src/org/jetbrains/kotlin/analysis/providers/impl/KotlinStaticDeclarationProvider.kt @@ -5,6 +5,7 @@ package org.jetbrains.kotlin.analysis.providers.impl +import com.intellij.psi.PsiElement import com.intellij.psi.search.GlobalSearchScope import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider import org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProviderFactory @@ -14,54 +15,120 @@ import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.* -import org.jetbrains.kotlin.psi.psiUtil.collectDescendantsOfType public class KotlinStaticDeclarationProvider( scope: GlobalSearchScope, ktFiles: Collection ) : KotlinDeclarationProvider() { - private val filesInScope = ktFiles.filter { scope.contains(it.virtualFile) } - private fun filesByPackage(packageFqName: FqName) = - filesInScope.asSequence() - .filter { it.packageFqName == packageFqName } + private val index = Index() + + private class Index { + val facadeFileMap: MutableMap> = mutableMapOf() + val classMap: MutableMap> = mutableMapOf() + val typeAliasMap: MutableMap> = mutableMapOf() + val topLevelFunctionMap: MutableMap> = mutableMapOf() + val topLevelPropertyMap: MutableMap> = mutableMapOf() + } + + private class KtDeclarationRecorder(private val index: Index) : KtVisitorVoid() { + + override fun visitElement(element: PsiElement) { + element.acceptChildren(this) + } + + override fun visitKtFile(file: KtFile) { + if (file.hasTopLevelCallables()) { + index.facadeFileMap.computeIfAbsent(file.packageFqName) { + mutableSetOf() + }.add(file) + } + super.visitKtFile(file) + } + + override fun visitClassOrObject(classOrObject: KtClassOrObject) { + classOrObject.getClassId()?.let { classId -> + index.classMap.computeIfAbsent(classId.packageFqName) { + mutableSetOf() + }.add(classOrObject) + } + super.visitClassOrObject(classOrObject) + } + + override fun visitTypeAlias(typeAlias: KtTypeAlias) { + typeAlias.getClassId()?.let { classId -> + index.typeAliasMap.computeIfAbsent(classId.packageFqName) { + mutableSetOf() + }.add(typeAlias) + } + super.visitTypeAlias(typeAlias) + } + + override fun visitNamedFunction(function: KtNamedFunction) { + if (function.isTopLevel) { + val packageFqName = (function.parent as KtFile).packageFqName + index.topLevelFunctionMap.computeIfAbsent(packageFqName) { + mutableSetOf() + }.add(function) + } + super.visitNamedFunction(function) + } + + override fun visitProperty(property: KtProperty) { + if (property.isTopLevel) { + val packageFqName = (property.parent as KtFile).packageFqName + index.topLevelPropertyMap.computeIfAbsent(packageFqName) { + mutableSetOf() + }.add(property) + } + super.visitProperty(property) + } + } + + init { + val recorder = KtDeclarationRecorder(index) + ktFiles + .filter { + scope.contains(it.virtualFile) + } + .forEach { + it.accept(recorder) + } + } override fun getClassesByClassId(classId: ClassId): Collection = - filesByPackage(classId.packageFqName).flatMap { file -> - file.collectDescendantsOfType { ktClass -> - ktClass.getClassId() == classId - } - }.toList() + index.classMap[classId.packageFqName] + ?.filter { it.getClassId() == classId } + ?: emptyList() override fun getTypeAliasesByClassId(classId: ClassId): Collection = - filesByPackage(classId.packageFqName).flatMap { file -> - file.collectDescendantsOfType { typeAlias -> - typeAlias.getClassId() == classId - } - }.toList() + index.typeAliasMap[classId.packageFqName] + ?.filter { it.getClassId() == classId } + ?: emptyList() + + override fun getClassNamesInPackage(packageFqName: FqName): Set = + index.classMap[packageFqName] + ?.mapNotNullTo(mutableSetOf()) { it.nameAsName } + ?: emptySet() override fun getTypeAliasNamesInPackage(packageFqName: FqName): Set = - filesByPackage(packageFqName) - .flatMap { it.declarations } - .filterIsInstance() - .mapNotNullTo(mutableSetOf()) { it.nameAsName } + index.typeAliasMap[packageFqName] + ?.mapNotNullTo(mutableSetOf()) { it.nameAsName } + ?: emptySet() override fun getPropertyNamesInPackage(packageFqName: FqName): Set = - filesByPackage(packageFqName) - .flatMap { it.declarations } - .filterIsInstance() - .mapNotNullTo(mutableSetOf()) { it.nameAsName } + index.topLevelPropertyMap[packageFqName] + ?.mapNotNullTo(mutableSetOf()) { it.nameAsName } + ?: emptySet() override fun getFunctionsNamesInPackage(packageFqName: FqName): Set = - filesByPackage(packageFqName) - .flatMap { it.declarations } - .filterIsInstance() - .mapNotNullTo(mutableSetOf()) { it.nameAsName } + index.topLevelFunctionMap[packageFqName] + ?.mapNotNullTo(mutableSetOf()) { it.nameAsName } + ?: emptySet() override fun getFacadeFilesInPackage(packageFqName: FqName): Collection = - filesByPackage(packageFqName) - .filter { file -> file.hasTopLevelCallables() } - .toSet() + index.facadeFileMap[packageFqName] + ?: emptyList() override fun findFilesForFacade(facadeFqName: FqName): Collection { if (facadeFqName.shortNameOrSpecial().isSpecial) return emptyList() @@ -70,29 +137,19 @@ public class KotlinStaticDeclarationProvider( } override fun getTopLevelProperties(callableId: CallableId): Collection = - filesByPackage(callableId.packageName) - .flatMap { it.declarations } - .filterIsInstance() - .filter { it.nameAsName == callableId.callableName } - .toList() + index.topLevelPropertyMap[callableId.packageName] + ?.filter { it.nameAsName == callableId.callableName } + ?: emptyList() override fun getTopLevelFunctions(callableId: CallableId): Collection = - filesByPackage(callableId.packageName) - .flatMap { it.declarations } - .filterIsInstance() - .filter { it.nameAsName == callableId.callableName } - .toList() + index.topLevelFunctionMap[callableId.packageName] + ?.filter { it.nameAsName == callableId.callableName } + ?: emptyList() - - override fun getClassNamesInPackage(packageFqName: FqName): Set = - filesByPackage(packageFqName) - .flatMap { it.declarations } - .filterIsInstance() - .mapNotNullTo(mutableSetOf()) { it.nameAsName } } public class KotlinStaticDeclarationProviderFactory(private val files: Collection) : KotlinDeclarationProviderFactory() { override fun createDeclarationProvider(searchScope: GlobalSearchScope): KotlinDeclarationProvider { return KotlinStaticDeclarationProvider(searchScope, files) } -} \ No newline at end of file +}