From cac0cf6a50efda989a6f4f458b3beca79b696035 Mon Sep 17 00:00:00 2001 From: pyos Date: Thu, 9 Sep 2021 13:48:42 +0200 Subject: [PATCH] FIR: join KotlinDeserializedJvmSymbolsProvider and JavaSymbolProvider This allows reusing class finder results. --- .../java/AbstractFirTypeEnhancementTest.kt | 6 +- .../kotlin/fir/session/FirSessionFactory.kt | 36 +++--- .../AbstractFirDeserializedSymbolsProvider.kt | 5 + .../kotlin/fir/java/JavaScopeProvider.kt | 6 +- .../kotlin/fir/java/JavaSymbolProvider.kt | 121 ++++++++---------- .../KotlinDeserializedJvmSymbolsProvider.kt | 11 +- .../api/sessions/FirIdeSessionFactory.kt | 12 +- 7 files changed, 97 insertions(+), 100 deletions(-) diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt b/compiler/fir/analysis-tests/legacy-fir-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt index 34b322bba4a..9cff415985f 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests/org/jetbrains/kotlin/fir/java/AbstractFirTypeEnhancementTest.kt @@ -23,7 +23,6 @@ import org.jetbrains.kotlin.codegen.forTestCompile.ForTestCompileRuntime import org.jetbrains.kotlin.fir.FirRenderer import org.jetbrains.kotlin.fir.createSessionForTests import org.jetbrains.kotlin.fir.java.declarations.FirJavaClass -import org.jetbrains.kotlin.fir.resolve.providers.impl.FirCompositeSymbolProvider import org.jetbrains.kotlin.fir.resolve.symbolProvider import org.jetbrains.kotlin.fir.symbols.SymbolInternals import org.jetbrains.kotlin.name.ClassId @@ -142,13 +141,10 @@ abstract class AbstractFirTypeEnhancementTest : KtUsefulTestCase() { val javaFirDump = StringBuilder().also { builder -> val renderer = FirRenderer(builder) - val symbolProvider = session.symbolProvider as FirCompositeSymbolProvider - val javaProvider = symbolProvider.providers.filterIsInstance().first() - val processedJavaClasses = mutableSetOf() fun processClassWithChildren(psiClass: PsiClass, parentFqName: FqName) { val classId = psiClass.classId(parentFqName) - val javaClass = javaProvider.getClassLikeSymbolByClassId(classId)?.fir + val javaClass = session.symbolProvider.getClassLikeSymbolByClassId(classId)?.fir ?: throw AssertionError(classId.asString()) if (javaClass !is FirJavaClass || javaClass in processedJavaClasses) { return diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt index 827e1f47a54..3450415ad53 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/session/FirSessionFactory.kt @@ -24,6 +24,7 @@ import org.jetbrains.kotlin.fir.extensions.extensionService import org.jetbrains.kotlin.fir.extensions.registerExtensions import org.jetbrains.kotlin.fir.java.FirCliSession import org.jetbrains.kotlin.fir.java.FirProjectSessionProvider +import org.jetbrains.kotlin.fir.java.JavaSymbolProviderWrapper import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider @@ -146,19 +147,14 @@ object FirSessionFactory { register(FirProvider::class, firProvider) val symbolProviderForBinariesFromIncrementalCompilation = providerAndScopeForIncrementalCompilation?.let { - FirCompositeSymbolProvider( + KotlinDeserializedJvmSymbolsProvider( this@session, - listOfNotNull( - KotlinDeserializedJvmSymbolsProvider( - this@session, - SingleModuleDataProvider(moduleData), - kotlinScopeProvider, - it.packagePartProvider, - projectEnvironment.getKotlinClassFinder(it.scope), - projectEnvironment.getJavaClassFinder(it.scope) - ), - projectEnvironment.getJavaSymbolProvider(this, moduleData, it.scope) - ) + SingleModuleDataProvider(moduleData), + kotlinScopeProvider, + it.packagePartProvider, + projectEnvironment.getKotlinClassFinder(it.scope), + projectEnvironment.getJavaClassFinder(it.scope), + projectEnvironment.getJavaSymbolProvider(this, moduleData, it.scope) ) } @@ -170,7 +166,7 @@ object FirSessionFactory { listOfNotNull( firProvider.symbolProvider, symbolProviderForBinariesFromIncrementalCompilation, - projectEnvironment.getJavaSymbolProvider(this, moduleData, scope), + JavaSymbolProviderWrapper(this, projectEnvironment.getJavaSymbolProvider(this, moduleData, scope)), dependenciesSymbolProvider, ) ) @@ -213,12 +209,13 @@ object FirSessionFactory { val kotlinScopeProvider = FirKotlinScopeProvider(::wrapScopeWithJvmMapped) val deserializedProviderForIncrementalCompilation = KotlinDeserializedJvmSymbolsProvider( - session = this, - moduleDataProvider = moduleDataProvider, - kotlinScopeProvider = kotlinScopeProvider, - packagePartProvider = packagePartProvider, - kotlinClassFinder = projectEnvironment.getKotlinClassFinder(scope), - javaClassFinder = projectEnvironment.getJavaClassFinder(scope) + this, + moduleDataProvider, + kotlinScopeProvider, + packagePartProvider, + projectEnvironment.getKotlinClassFinder(scope), + projectEnvironment.getJavaClassFinder(scope), + projectEnvironment.getJavaSymbolProvider(this, moduleDataProvider.allModuleData.last(), scope) ) val builtinsModuleData = createModuleDataForBuiltins( @@ -233,7 +230,6 @@ object FirSessionFactory { deserializedProviderForIncrementalCompilation, FirBuiltinSymbolProvider(this, builtinsModuleData, kotlinScopeProvider), FirCloneableSymbolProvider(this, builtinsModuleData, kotlinScopeProvider), - projectEnvironment.getJavaSymbolProvider(this, moduleDataProvider.allModuleData.last(), scope), FirDependenciesSymbolProviderImpl(this) ) ) diff --git a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolsProvider.kt b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolsProvider.kt index 93d7c8d4fff..bdf8325cd77 100644 --- a/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolsProvider.kt +++ b/compiler/fir/fir-deserialization/src/org/jetbrains/kotlin/fir/deserialization/AbstractFirDeserializedSymbolsProvider.kt @@ -91,6 +91,10 @@ abstract class AbstractFirDeserializedSymbolsProvider( // ------------------------ Deserialization methods ------------------------ sealed class ClassMetadataFindResult { + data class NoMetadata( + val classPostProcessor: DeserializedClassPostProcessor + ) : ClassMetadataFindResult() + data class Metadata( val nameResolver: NameResolver, val classProto: ProtoBuf.Class, @@ -125,6 +129,7 @@ abstract class AbstractFirDeserializedSymbolsProvider( parentContext: FirDeserializationContext? = null ): Pair { return when (val result = extractClassMetadata(classId, parentContext)) { + is ClassMetadataFindResult.NoMetadata -> FirRegularClassSymbol(classId) to result.classPostProcessor is ClassMetadataFindResult.Metadata -> { val (nameResolver, classProto, annotationDeserializer, containingLibrary, sourceElement, postProcessor) = result val moduleData = moduleDataProvider.getModuleData(containingLibrary) ?: return null to null diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt index 57467a3b0b8..afe7c80bd79 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaScopeProvider.kt @@ -25,9 +25,7 @@ import org.jetbrains.kotlin.fir.types.constructClassLikeType import org.jetbrains.kotlin.name.StandardClassIds import org.jetbrains.kotlin.utils.DFS -class JavaScopeProvider( - val symbolProvider: JavaSymbolProvider -) : FirScopeProvider() { +object JavaScopeProvider : FirScopeProvider() { override fun getUseSiteMemberScope( klass: FirClass, useSiteSession: FirSession, @@ -74,7 +72,7 @@ class JavaScopeProvider( return if (regularClass is FirJavaClass) useSiteSession.declaredMemberScopeWithLazyNestedScope( regularClass, existingNames = regularClass.existingNestedClassifierNames, - symbolProvider = symbolProvider + symbolProvider = useSiteSession.symbolProvider ) else useSiteSession.declaredMemberScope(regularClass) } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt index 49aa4f7feb5..977e0e6865b 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/JavaSymbolProvider.kt @@ -51,59 +51,67 @@ import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade import org.jetbrains.kotlin.types.Variance.INVARIANT import org.jetbrains.kotlin.util.OperatorNameConventions -@ThreadSafeMutableState -class JavaSymbolProvider( - session: FirSession, - val baseModuleData: FirModuleData, - val project: Project, - private val searchScope: GlobalSearchScope, -) : FirSymbolProvider(session) { - companion object { - val VALUE_METHOD_NAME = Name.identifier("value") - } - +class JavaSymbolProviderWrapper(session: FirSession, private val javaSymbolProvider: JavaSymbolProvider) : FirSymbolProvider(session) { private val classCache = - session.firCachesFactory.createCacheWithPostCompute( - createValue = { classId, _ -> - val foundClass = findClass(classId) - if (foundClass == null) { - null to null - } else { - FirRegularClassSymbol(classId) to foundClass - } + session.firCachesFactory.createCacheWithPostCompute( + createValue = { classId: ClassId, parentClassSymbol: FirRegularClassSymbol? -> + javaSymbolProvider.findClass(classId)?.let { FirRegularClassSymbol(classId) to (it to parentClassSymbol) } + ?: null to (null to null) }, - postCompute = { _, classSymbol, javaClass -> + postCompute = { _, classSymbol, (javaClass, parentClassSymbol) -> if (classSymbol != null && javaClass != null) { - convertJavaClassToFir(classSymbol, javaClass) + javaSymbolProvider.convertJavaClassToFir(classSymbol, parentClassSymbol, javaClass) } } ) + override fun getPackage(fqName: FqName): FqName? = + javaSymbolProvider.getPackage(fqName) + + override fun getClassLikeSymbolByClassId(classId: ClassId): FirRegularClassSymbol? { + return try { + if (!javaSymbolProvider.hasTopLevelClassOf(classId)) return null + getFirJavaClass(classId) + } catch (e: ProcessCanceledException) { + null + } + } + + private fun getFirJavaClass(classId: ClassId): FirRegularClassSymbol? = + classCache.getValue(classId, classId.outerClassId?.let { getFirJavaClass(it) }) + + @OptIn(FirSymbolProviderInternals::class) + override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) {} + + @OptIn(FirSymbolProviderInternals::class) + override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {} + + @OptIn(FirSymbolProviderInternals::class) + override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) {} +} + +@ThreadSafeMutableState +class JavaSymbolProvider( + private val session: FirSession, + val baseModuleData: FirModuleData, + val project: Project, + private val searchScope: GlobalSearchScope, +) { + companion object { + val VALUE_METHOD_NAME = Name.identifier("value") + } + private val packageCache = session.firCachesFactory.createCache(::findPackage) private val knownClassNamesInPackage = session.firCachesFactory.createCache?>(::getKnownClassNames) - private val scopeProvider = JavaScopeProvider(this) - private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project) private val parentClassTypeParameterStackCache = mutableMapOf() private val parentClassEffectiveVisibilityCache = mutableMapOf() - private fun findClass(classId: ClassId): JavaClass? = - facade.findClass(JavaClassFinder.Request(classId), searchScope) + fun findClass(classId: ClassId, knownContent: ByteArray? = null): JavaClass? = + facade.findClass(JavaClassFinder.Request(classId, knownContent), searchScope) ?.takeIf { !it.hasDifferentClassId(classId) && !it.hasMetadataAnnotation() } - @FirSymbolProviderInternals - override fun getTopLevelCallableSymbolsTo(destination: MutableList>, packageFqName: FqName, name: Name) { - } - - @FirSymbolProviderInternals - override fun getTopLevelFunctionSymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { - } - - @FirSymbolProviderInternals - override fun getTopLevelPropertySymbolsTo(destination: MutableList, packageFqName: FqName, name: Name) { - } - private fun JavaTypeParameter.toFirTypeParameter(javaTypeParameterStack: JavaTypeParameterStack): FirTypeParameter { return buildTypeParameter { moduleData = this@JavaSymbolProvider.baseModuleData @@ -131,19 +139,8 @@ class JavaSymbolProvider( private fun List.convertTypeParameters(stack: JavaTypeParameterStack): List = map { it.toFirTypeParameter(stack) } - override fun getClassLikeSymbolByClassId(classId: ClassId): FirRegularClassSymbol? { - return try { - if (!hasTopLevelClassOf(classId)) return null - getFirJavaClass(classId) - } catch (e: ProcessCanceledException) { - null - } - } - - private fun getFirJavaClass(classId: ClassId): FirRegularClassSymbol? { - // Enforce loading of outer class first - classId.outerClassId?.let { getFirJavaClass(it) } - return classCache.getValue(classId, null) + fun getPackage(fqName: FqName): FqName? { + return packageCache.getValue(fqName)?.fqName } private fun JavaClass.hasDifferentClassId(lookupClassId: ClassId): Boolean = @@ -162,14 +159,13 @@ class JavaSymbolProvider( } } - private fun convertJavaClassToFir(classSymbol: FirRegularClassSymbol, javaClass: JavaClass): FirJavaClass { + fun convertJavaClassToFir( + classSymbol: FirRegularClassSymbol, + parentClassSymbol: FirRegularClassSymbol?, + javaClass: JavaClass, + ): FirJavaClass { val classId = classSymbol.classId val javaTypeParameterStack = JavaTypeParameterStack() - val outerClassId = classId.outerClassId - val parentClassSymbol = if (outerClassId != null) { - getClassLikeSymbolByClassId(outerClassId) - } else null - if (parentClassSymbol != null) { val parentStack = parentClassTypeParameterStackCache[parentClassSymbol] @@ -179,7 +175,7 @@ class JavaSymbolProvider( } } parentClassTypeParameterStackCache[classSymbol] = javaTypeParameterStack - val firJavaClass = createFirJavaClass(javaClass, classSymbol, outerClassId, parentClassSymbol, classId, javaTypeParameterStack) + val firJavaClass = createFirJavaClass(javaClass, classSymbol, parentClassSymbol, classId, javaTypeParameterStack) parentClassTypeParameterStackCache.remove(classSymbol) parentClassEffectiveVisibilityCache.remove(classSymbol) @@ -197,7 +193,6 @@ class JavaSymbolProvider( private fun createFirJavaClass( javaClass: JavaClass, classSymbol: FirRegularClassSymbol, - outerClassId: ClassId?, parentClassSymbol: FirRegularClassSymbol?, classId: ClassId, javaTypeParameterStack: JavaTypeParameterStack, @@ -213,12 +208,12 @@ class JavaSymbolProvider( this@buildJavaClass.visibility = visibility classKind = javaClass.classKind modality = if (classKind == ClassKind.ANNOTATION_CLASS || classKind == ClassKind.ENUM_CLASS) Modality.FINAL else javaClass.modality - this.isTopLevel = outerClassId == null + this.isTopLevel = classId.outerClassId == null isStatic = javaClass.isStatic javaPackage = packageCache.getValue(classSymbol.classId.packageFqName) this.javaTypeParameterStack = javaTypeParameterStack existingNestedClassifierNames += javaClass.innerClassNames - scopeProvider = this@JavaSymbolProvider.scopeProvider + scopeProvider = JavaScopeProvider val selfEffectiveVisibility = visibility.toEffectiveVisibility(parentClassSymbol?.toLookupTag(), forClass = true) val parentEffectiveVisibility = parentClassSymbol?.let { @@ -555,10 +550,6 @@ class JavaSymbolProvider( isNullable = false, ) - override fun getPackage(fqName: FqName): FqName? { - return packageCache.getValue(fqName)?.fqName - } - private fun findPackage(fqName: FqName): JavaPackage? { return try { val facade = KotlinJavaPsiFacade.getInstance(project) @@ -569,7 +560,7 @@ class JavaSymbolProvider( } } - private fun hasTopLevelClassOf(classId: ClassId): Boolean { + fun hasTopLevelClassOf(classId: ClassId): Boolean { val knownNames = knownClassNamesInPackage.getValue(classId.packageFqName) ?: return true return classId.relativeClassName.topLevelName() in knownNames } diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt index 8e51adcc2c5..104f4c8b3c6 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/KotlinDeserializedJvmSymbolsProvider.kt @@ -43,6 +43,7 @@ open class KotlinDeserializedJvmSymbolsProvider( private val packagePartProvider: PackagePartProvider, private val kotlinClassFinder: KotlinClassFinder, javaClassFinder: JavaClassFinder, + private val javaSymbolProvider: JavaSymbolProvider ) : AbstractFirDeserializedSymbolsProvider(session, moduleDataProvider, kotlinScopeProvider) { private val knownNameInPackageCache = KnownNameInPackageCache(session, javaClassFinder) private val annotationsLoader = AnnotationsLoader(session, kotlinClassFinder) @@ -101,7 +102,12 @@ open class KotlinDeserializedJvmSymbolsProvider( } val kotlinClass = when (result) { is KotlinClassFinder.Result.KotlinClass -> result - is KotlinClassFinder.Result.ClassFileContent -> return null + is KotlinClassFinder.Result.ClassFileContent -> { + val javaClass = javaSymbolProvider.findClass(classId, result.content) ?: return null + return ClassMetadataFindResult.NoMetadata { symbol -> + javaSymbolProvider.convertJavaClassToFir(symbol, classId.outerClassId?.let(::getClass), javaClass) + } + } null -> return ClassMetadataFindResult.ShouldDeserializeViaParent } if (kotlinClass.kotlinJvmBinaryClass.classHeader.kind != KotlinClassHeader.Kind.CLASS) return null @@ -121,6 +127,9 @@ open class KotlinDeserializedJvmSymbolsProvider( ) } + override fun getPackage(fqName: FqName): FqName? = + javaSymbolProvider.getPackage(fqName) + private fun loadAnnotationsFromClassFile( kotlinClass: KotlinClassFinder.Result.KotlinClass, symbol: FirRegularClassSymbol diff --git a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt index b457d952d28..15c51304466 100644 --- a/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt +++ b/idea/idea-frontend-fir/idea-fir-low-level-api/src/org/jetbrains/kotlin/idea/fir/low/level/api/sessions/FirIdeSessionFactory.kt @@ -19,6 +19,7 @@ import org.jetbrains.kotlin.fir.declarations.SealedClassInheritorsProvider import org.jetbrains.kotlin.fir.deserialization.FirDeserializationContext import org.jetbrains.kotlin.fir.deserialization.ModuleDataProvider import org.jetbrains.kotlin.fir.java.JavaSymbolProvider +import org.jetbrains.kotlin.fir.java.JavaSymbolProviderWrapper import org.jetbrains.kotlin.fir.java.deserialization.KotlinDeserializedJvmSymbolsProvider import org.jetbrains.kotlin.fir.resolve.providers.FirDependenciesSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirProvider @@ -150,7 +151,7 @@ internal object FirIdeSessionFactory { this, providers = listOf( provider.symbolProvider, - JavaSymbolProvider(this@session, moduleData, project, searchScope), + JavaSymbolProviderWrapper(this@session, JavaSymbolProvider(this@session, moduleData, project, searchScope)), ), dependencyProvider ) @@ -214,10 +215,10 @@ internal object FirIdeSessionFactory { kotlinScopeProvider, packagePartProvider, kotlinClassFinder, - javaClassFinder + javaClassFinder, + JavaSymbolProvider(this@session, mainModuleData, project, searchScope) ) ) - add(JavaSymbolProvider(this@session, mainModuleData, project, searchScope)) addAll((builtinsAndCloneableSession.symbolProvider as FirCompositeSymbolProvider).providers) } ) @@ -239,10 +240,11 @@ internal object FirIdeSessionFactory { kotlinScopeProvider: FirKotlinScopeProvider, packagePartProvider: PackagePartProvider, kotlinClassFinder: KotlinClassFinder, - javaClassFinder: JavaClassFinder + javaClassFinder: JavaClassFinder, + javaSymbolProvider: JavaSymbolProvider ) : KotlinDeserializedJvmSymbolsProvider( session, moduleDataProvider, kotlinScopeProvider, packagePartProvider, kotlinClassFinder, - javaClassFinder + javaClassFinder, javaSymbolProvider ) { override fun getClass( classId: ClassId,