From f9785c1050c7e9703f3cb3279bfa14e58d9c4597 Mon Sep 17 00:00:00 2001 From: Marco Pennekamp Date: Mon, 20 Mar 2023 20:14:21 +0100 Subject: [PATCH] [LL FIR] KT-57455 Avoid creating optional annotation class providers - An `OptionalAnnotationClassesProvider` only needs to be created if the package part provider may even have optional annotation classes. - In the IDE case, the package part provider never provides optional annotation classes, so especially in the IDE, we can avoid a lot of useless symbol providers with this. --- .../structure/LLFirLibraryProviderFactory.kt | 28 +++++++++---------- .../services/PackagePartProviderTestImpl.kt | 1 + .../OptionalAnnotationClassesProvider.kt | 24 ++++++++++++++++ .../IncrementalPackagePartProvider.kt | 3 ++ .../load/kotlin/JvmPackagePartProviderBase.kt | 5 ++++ .../kotlin/load/kotlin/PackagePartProvider.kt | 7 +++++ 6 files changed, 53 insertions(+), 15 deletions(-) diff --git a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibraryProviderFactory.kt b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibraryProviderFactory.kt index e2860d30d1a..c1a78f5c89a 100644 --- a/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibraryProviderFactory.kt +++ b/analysis/low-level-api-fir/src/org/jetbrains/kotlin/analysis/low/level/api/fir/project/structure/LLFirLibraryProviderFactory.kt @@ -35,7 +35,7 @@ internal object LLFirLibraryProviderFactory { val packagePartProvider = project.createPackagePartProvider(scope) return LLFirModuleWithDependenciesSymbolProvider( session, - providers = listOf( + providers = listOfNotNull( JvmClassFileBasedSymbolProvider( session, moduleDataProvider, @@ -44,7 +44,7 @@ internal object LLFirLibraryProviderFactory { VirtualFileFinderFactory.getInstance(project).create(scope), LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider) ), - OptionalAnnotationClassesProvider(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider), + OptionalAnnotationClassesProvider.createIfNeeded(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider), ), LLFirDependenciesSymbolProvider(session, listOf(builtinSymbolProvider)), ) @@ -60,18 +60,16 @@ internal object LLFirLibraryProviderFactory { ): List { val moduleDataProvider = SingleModuleDataProvider(moduleData) val packagePartProvider = project.createPackagePartProvider(scope) - return buildList { - add( - JvmClassFileBasedSymbolProvider( - session, - moduleDataProvider, - kotlinScopeProvider, - packagePartProvider, - VirtualFileFinderFactory.getInstance(project).create(scope), - LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider) - ) - ) - add(OptionalAnnotationClassesProvider(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider)) - } + return listOfNotNull( + JvmClassFileBasedSymbolProvider( + session, + moduleDataProvider, + kotlinScopeProvider, + packagePartProvider, + VirtualFileFinderFactory.getInstance(project).create(scope), + LLFirJavaFacadeForBinaries(session, builtinTypes, project.createJavaClassFinder(scope), moduleDataProvider) + ), + OptionalAnnotationClassesProvider.createIfNeeded(session, moduleDataProvider, kotlinScopeProvider, packagePartProvider), + ) } } \ No newline at end of file diff --git a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/PackagePartProviderTestImpl.kt b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/PackagePartProviderTestImpl.kt index 99acff0b225..107bf9c7027 100644 --- a/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/PackagePartProviderTestImpl.kt +++ b/analysis/low-level-api-fir/tests/org/jetbrains/kotlin/analysis/low/level/api/fir/services/PackagePartProviderTestImpl.kt @@ -37,6 +37,7 @@ internal class PackagePartProviderTestImpl( return providers.flatMapTo(mutableSetOf()) { it.getAllOptionalAnnotationClasses() }.toList() } + override fun mayHaveOptionalAnnotationClasses(): Boolean = providers.any { it.mayHaveOptionalAnnotationClasses() } } } } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/OptionalAnnotationClassesProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/OptionalAnnotationClassesProvider.kt index 2b59592d9f4..7d413124e6a 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/OptionalAnnotationClassesProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/OptionalAnnotationClassesProvider.kt @@ -84,4 +84,28 @@ class OptionalAnnotationClassesProvider( override fun getPackage(fqName: FqName): FqName? = if (optionalAnnotationClassesAndPackages.second.contains(fqName.asString())) fqName else null + + companion object { + /** + * Creates a new [OptionalAnnotationClassesProvider] if [packagePartProvider] has any optional annotation classes. Otherwise, the + * symbol provider does not need to be created because it would provide no symbols. + */ + fun createIfNeeded( + session: FirSession, + moduleDataProvider: ModuleDataProvider, + kotlinScopeProvider: FirKotlinScopeProvider, + packagePartProvider: PackagePartProvider, + defaultDeserializationOrigin: FirDeclarationOrigin = FirDeclarationOrigin.Library, + ): OptionalAnnotationClassesProvider? { + if (!packagePartProvider.mayHaveOptionalAnnotationClasses()) return null + + return OptionalAnnotationClassesProvider( + session, + moduleDataProvider, + kotlinScopeProvider, + packagePartProvider, + defaultDeserializationOrigin, + ) + } + } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt index 4d55c4f92ec..85c9cbe7a86 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/incremental/IncrementalPackagePartProvider.kt @@ -68,4 +68,7 @@ class IncrementalPackagePartProvider( override fun getAllOptionalAnnotationClasses(): List = moduleMappings.flatMap(JvmPackagePartProviderBase.Companion::getAllOptionalAnnotationClasses) + parent.getAllOptionalAnnotationClasses() + + override fun mayHaveOptionalAnnotationClasses(): Boolean = + moduleMappings.any { it.moduleData.optionalAnnotations.isNotEmpty() } || parent.mayHaveOptionalAnnotationClasses() } diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt index cb45c9408ef..9c52a845293 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/JvmPackagePartProviderBase.kt @@ -66,6 +66,11 @@ abstract class JvmPackagePartProviderBase : PackageAndMetadataPartP getAllOptionalAnnotationClasses(module.mapping) } + override fun mayHaveOptionalAnnotationClasses(): Boolean { + // `loadedModules` is mutable, so even a package part provider without optional annotation classes may have some in the future. + return true + } + companion object { fun getAllOptionalAnnotationClasses(module: ModuleMapping): List { val data = module.moduleData diff --git a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt index 8d4eabe5eb5..41b72e07420 100644 --- a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt +++ b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/PackagePartProvider.kt @@ -28,6 +28,11 @@ interface PackagePartProvider { fun getAllOptionalAnnotationClasses(): List + /** + * Returns `true` if [getAllOptionalAnnotationClasses] may return a non-empty list. + */ + fun mayHaveOptionalAnnotationClasses(): Boolean + object Empty : PackagePartProvider { override fun findPackageParts(packageFqName: String): List = emptyList() @@ -35,6 +40,8 @@ interface PackagePartProvider { override fun getAllOptionalAnnotationClasses(): List = emptyList() + override fun mayHaveOptionalAnnotationClasses(): Boolean = false + override fun computePackageSetWithNonClassDeclarations(): Set = emptySet() } }