FIR: join KotlinDeserializedJvmSymbolsProvider and JavaSymbolProvider

This allows reusing class finder results.
This commit is contained in:
pyos
2021-09-09 13:48:42 +02:00
committed by TeamCityServer
parent 0181c80ddb
commit cac0cf6a50
7 changed files with 97 additions and 100 deletions
@@ -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)
}
@@ -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<ClassId, FirRegularClassSymbol?, Nothing?, JavaClass?>(
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<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {}
@OptIn(FirSymbolProviderInternals::class)
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {}
@OptIn(FirSymbolProviderInternals::class)
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, 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<FqName, Set<String>?>(::getKnownClassNames)
private val scopeProvider = JavaScopeProvider(this)
private val facade: KotlinJavaPsiFacade get() = KotlinJavaPsiFacade.getInstance(project)
private val parentClassTypeParameterStackCache = mutableMapOf<FirRegularClassSymbol, JavaTypeParameterStack>()
private val parentClassEffectiveVisibilityCache = mutableMapOf<FirRegularClassSymbol, EffectiveVisibility>()
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<FirCallableSymbol<*>>, packageFqName: FqName, name: Name) {
}
@FirSymbolProviderInternals
override fun getTopLevelFunctionSymbolsTo(destination: MutableList<FirNamedFunctionSymbol>, packageFqName: FqName, name: Name) {
}
@FirSymbolProviderInternals
override fun getTopLevelPropertySymbolsTo(destination: MutableList<FirPropertySymbol>, 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<JavaTypeParameter>.convertTypeParameters(stack: JavaTypeParameterStack): List<FirTypeParameter> =
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
}
@@ -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