[Analysis API] forbid Analysis inside KtResolveExtensionProvider

As it's called during FIR sessions initialization

^KT-57930
This commit is contained in:
Ilya Kirillov
2023-04-18 14:14:10 +02:00
committed by Space Team
parent 0d0b1b7945
commit 806fff0887
@@ -8,8 +8,10 @@ package org.jetbrains.kotlin.analysis.low.level.api.fir.resolve.extensions
import com.intellij.openapi.util.Key import com.intellij.openapi.util.Key
import com.intellij.openapi.util.ModificationTracker import com.intellij.openapi.util.ModificationTracker
import com.intellij.openapi.vfs.VirtualFile import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.analysis.api.KtAnalysisAllowanceManager
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtension import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtension
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionFile
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionProvider
import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionReferencePsiTargetsProvider import org.jetbrains.kotlin.analysis.api.resolve.extensions.KtResolveExtensionReferencePsiTargetsProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.FileBasedKotlinDeclarationProvider import org.jetbrains.kotlin.analysis.low.level.api.fir.project.structure.FileBasedKotlinDeclarationProvider
import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession import org.jetbrains.kotlin.analysis.low.level.api.fir.sessions.LLFirSession
@@ -70,27 +72,27 @@ private class LLFirResolveExtensionToolNameCache(
private val packageFilter: LLFirResolveExtensionToolPackageFilter, private val packageFilter: LLFirResolveExtensionToolPackageFilter,
private val fileProvider: LLFirResolveExtensionsFileProvider, private val fileProvider: LLFirResolveExtensionsFileProvider,
) : LLFirSymbolProviderNameCache() { ) : LLFirSymbolProviderNameCache() {
override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String>? { override fun getTopLevelClassifierNamesInPackage(packageFqName: FqName): Set<String>? = forbidAnalysis {
if (!packageFilter.packageExists(packageFqName)) return emptySet() if (!packageFilter.packageExists(packageFqName)) return emptySet()
return fileProvider.getFilesByPackage(packageFqName) return fileProvider.getFilesByPackage(packageFqName)
.flatMap { it.getTopLevelClassifierNames() } .flatMap { it.getTopLevelClassifierNames() }
.mapTo(mutableSetOf()) { it.asString() } .mapTo(mutableSetOf()) { it.asString() }
} }
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> { override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> = forbidAnalysis {
if (!packageFilter.packageExists(packageFqName)) return emptySet() if (!packageFilter.packageExists(packageFqName)) return emptySet()
return fileProvider.getFilesByPackage(packageFqName) return fileProvider.getFilesByPackage(packageFqName)
.flatMapTo(mutableSetOf()) { it.getTopLevelCallableNames() } .flatMapTo(mutableSetOf()) { it.getTopLevelCallableNames() }
} }
override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean { override fun mayHaveTopLevelClassifier(classId: ClassId, mayHaveFunctionClass: Boolean): Boolean = forbidAnalysis {
if (!packageFilter.packageExists(classId.packageFqName)) return false if (!packageFilter.packageExists(classId.packageFqName)) return false
return fileProvider.getFilesByPackage(classId.packageFqName) return fileProvider.getFilesByPackage(classId.packageFqName)
.any { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) } .any { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
} }
override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean { override fun mayHaveTopLevelCallable(packageFqName: FqName, name: Name): Boolean = forbidAnalysis {
if (!packageFilter.packageExists(packageFqName)) return false if (!packageFilter.packageExists(packageFqName)) return false
return fileProvider.getFilesByPackage(packageFqName) return fileProvider.getFilesByPackage(packageFqName)
@@ -102,7 +104,9 @@ private class LLFirResolveExtensionToolPackageFilter(
private val extensions: List<KtResolveExtension> private val extensions: List<KtResolveExtension>
) { ) {
val allPackages: Set<FqName> by lazy { val allPackages: Set<FqName> by lazy {
extensions.flatMapTo(mutableSetOf()) { it.getContainedPackages() } forbidAnalysis {
extensions.flatMapTo(mutableSetOf()) { it.getContainedPackages() }
}
} }
fun packageExists(packageFqName: FqName): Boolean { fun packageExists(packageFqName: FqName): Boolean {
@@ -118,52 +122,52 @@ private class LLFirResolveExtensionToolDeclarationProvider(
private val extensionFileToDeclarationProvider: ConcurrentHashMap<KtResolveExtensionFile, FileBasedKotlinDeclarationProvider> = private val extensionFileToDeclarationProvider: ConcurrentHashMap<KtResolveExtensionFile, FileBasedKotlinDeclarationProvider> =
ConcurrentHashMap() ConcurrentHashMap()
override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? { override fun getClassLikeDeclarationByClassId(classId: ClassId): KtClassLikeDeclaration? = forbidAnalysis {
return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) } return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
.firstNotNullOfOrNull { it.getClassLikeDeclarationByClassId(classId) } .firstNotNullOfOrNull { it.getClassLikeDeclarationByClassId(classId) }
} }
override fun getAllClassesByClassId(classId: ClassId): Collection<KtClassOrObject> { override fun getAllClassesByClassId(classId: ClassId): Collection<KtClassOrObject> = forbidAnalysis {
return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) } return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
.flatMapTo(mutableListOf()) { it.getAllClassesByClassId(classId) } .flatMapTo(mutableListOf()) { it.getAllClassesByClassId(classId) }
} }
override fun getAllTypeAliasesByClassId(classId: ClassId): Collection<KtTypeAlias> { override fun getAllTypeAliasesByClassId(classId: ClassId): Collection<KtTypeAlias> = forbidAnalysis {
return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) } return getDeclarationProvidersByPackage(classId.packageFqName) { it.mayHaveTopLevelClassifier(classId.getTopLevelShortClassName()) }
.flatMapTo(mutableListOf()) { it.getAllTypeAliasesByClassId(classId) } .flatMapTo(mutableListOf()) { it.getAllTypeAliasesByClassId(classId) }
} }
override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName): Set<Name> { override fun getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName: FqName): Set<Name> = forbidAnalysis {
return getDeclarationProvidersByPackage(packageFqName) { true } return getDeclarationProvidersByPackage(packageFqName) { true }
.flatMapTo(mutableSetOf()) { it.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) } .flatMapTo(mutableSetOf()) { it.getTopLevelKotlinClassLikeDeclarationNamesInPackage(packageFqName) }
} }
override fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty> { override fun getTopLevelProperties(callableId: CallableId): Collection<KtProperty> = forbidAnalysis {
return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) } return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) }
.flatMapTo(mutableListOf()) { it.getTopLevelProperties(callableId) } .flatMapTo(mutableListOf()) { it.getTopLevelProperties(callableId) }
} }
override fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction> { override fun getTopLevelFunctions(callableId: CallableId): Collection<KtNamedFunction> = forbidAnalysis {
return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) } return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) }
.flatMapTo(mutableListOf()) { it.getTopLevelFunctions(callableId) } .flatMapTo(mutableListOf()) { it.getTopLevelFunctions(callableId) }
} }
override fun getTopLevelCallableFiles(callableId: CallableId): Collection<KtFile> { override fun getTopLevelCallableFiles(callableId: CallableId): Collection<KtFile> = forbidAnalysis {
return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) } return getDeclarationProvidersByPackage(callableId.packageName) { it.mayHaveTopLevelCallable(callableId.callableName) }
.mapTo(mutableListOf()) { it.kotlinFile } .mapTo(mutableListOf()) { it.kotlinFile }
} }
override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> { override fun getTopLevelCallableNamesInPackage(packageFqName: FqName): Set<Name> = forbidAnalysis {
return extensionProvider.getFilesByPackage(packageFqName).flatMapTo(mutableSetOf()) { it.getTopLevelClassifierNames() } return extensionProvider.getFilesByPackage(packageFqName).flatMapTo(mutableSetOf()) { it.getTopLevelClassifierNames() }
} }
override fun findFilesForFacadeByPackage(packageFqName: FqName): Collection<KtFile> { override fun findFilesForFacadeByPackage(packageFqName: FqName): Collection<KtFile> = forbidAnalysis {
return getDeclarationProvidersByPackage(packageFqName) { file -> return getDeclarationProvidersByPackage(packageFqName) { file ->
file.getTopLevelCallableNames().isNotEmpty() file.getTopLevelCallableNames().isNotEmpty()
}.mapTo(mutableListOf()) { it.kotlinFile } }.mapTo(mutableListOf()) { it.kotlinFile }
} }
override fun findFilesForFacade(facadeFqName: FqName): Collection<KtFile> { override fun findFilesForFacade(facadeFqName: FqName): Collection<KtFile> = forbidAnalysis {
if (facadeFqName.isRoot) return emptyList() if (facadeFqName.isRoot) return emptyList()
val packageFqName = facadeFqName.parent() val packageFqName = facadeFqName.parent()
return getDeclarationProvidersByPackage(packageFqName) { file -> return getDeclarationProvidersByPackage(packageFqName) { file ->
@@ -172,7 +176,7 @@ private class LLFirResolveExtensionToolDeclarationProvider(
.mapTo(mutableListOf()) { it.kotlinFile } .mapTo(mutableListOf()) { it.kotlinFile }
} }
override fun findInternalFilesForFacade(facadeFqName: FqName): Collection<KtFile> { override fun findInternalFilesForFacade(facadeFqName: FqName): Collection<KtFile> = forbidAnalysis {
// no decompiled files here (see the `org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider.findInternalFilesForFacade` KDoc) // no decompiled files here (see the `org.jetbrains.kotlin.analysis.providers.KotlinDeclarationProvider.findInternalFilesForFacade` KDoc)
return emptyList() return emptyList()
} }
@@ -180,13 +184,13 @@ private class LLFirResolveExtensionToolDeclarationProvider(
private inline fun getDeclarationProvidersByPackage( private inline fun getDeclarationProvidersByPackage(
packageFqName: FqName, packageFqName: FqName,
crossinline filter: (KtResolveExtensionFile) -> Boolean crossinline filter: (KtResolveExtensionFile) -> Boolean
): Sequence<FileBasedKotlinDeclarationProvider> { ): Sequence<FileBasedKotlinDeclarationProvider> = forbidAnalysis {
return extensionProvider.getFilesByPackage(packageFqName) return extensionProvider.getFilesByPackage(packageFqName)
.filter { filter(it) } .filter { filter(it) }
.map { createDeclarationProviderByFile(it) } .map { createDeclarationProviderByFile(it) }
} }
private fun createDeclarationProviderByFile(file: KtResolveExtensionFile): FileBasedKotlinDeclarationProvider { private fun createDeclarationProviderByFile(file: KtResolveExtensionFile): FileBasedKotlinDeclarationProvider = forbidAnalysis {
return extensionFileToDeclarationProvider.getOrPut(file) { return extensionFileToDeclarationProvider.getOrPut(file) {
val factory = KtPsiFactory( val factory = KtPsiFactory(
ktModule.project, ktModule.project,
@@ -219,7 +223,7 @@ private class LLFirResolveExtensionToolDeclarationProvider(
private class LLFirResolveExtensionsFileProvider( private class LLFirResolveExtensionsFileProvider(
val extensions: List<KtResolveExtension>, val extensions: List<KtResolveExtension>,
) { ) {
fun getFilesByPackage(packageFqName: FqName): Sequence<KtResolveExtensionFile> { fun getFilesByPackage(packageFqName: FqName): Sequence<KtResolveExtensionFile> = forbidAnalysis {
return extensions return extensions
.asSequence() .asSequence()
.filter { packageFqName in it.getContainedPackages() } .filter { packageFqName in it.getContainedPackages() }
@@ -287,3 +291,7 @@ private fun KtResolveExtensionFile.mayHaveTopLevelCallable(name: Name): Boolean
@KtModuleStructureInternals @KtModuleStructureInternals
public var VirtualFile.psiTargetsProvider: KtResolveExtensionReferencePsiTargetsProvider? by UserDataProperty(Key.create("KT_RESOLVE_EXTENSION_PSI_TARGETS_PROVIDER")) public var VirtualFile.psiTargetsProvider: KtResolveExtensionReferencePsiTargetsProvider? by UserDataProperty(Key.create("KT_RESOLVE_EXTENSION_PSI_TARGETS_PROVIDER"))
private inline fun <R> forbidAnalysis(action: () -> R): R {
return KtAnalysisAllowanceManager.forbidAnalysisInside(KtResolveExtensionProvider::class.java.simpleName, action)
}