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 1f01261282b..856d4f108f3 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 @@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.fir.* +import org.jetbrains.kotlin.fir.caches.* import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl @@ -22,7 +23,6 @@ import org.jetbrains.kotlin.fir.resolve.constructType import org.jetbrains.kotlin.fir.resolve.defaultType import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals -import org.jetbrains.kotlin.fir.resolve.providers.SymbolProviderCache import org.jetbrains.kotlin.fir.resolve.scopes.wrapScopeWithJvmMapped import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.impl.* @@ -53,8 +53,17 @@ class JavaSymbolProvider( internal val VALUE_METHOD_NAME = Name.identifier("value") } - private val classCache = SymbolProviderCache() - private val packageCache = SymbolProviderCache() + private val classCache = + session.firCachesFactory.createCacheWithPostCompute( + createValue = ::findAndConvertJavaClass, + postCompute = { _, classSymbol, javaClass, -> + if (classSymbol != null && javaClass != null) { + convertJavaClassToFir(classSymbol, javaClass) + } + } + ) + private val packageCache = session.firCachesFactory.createCache(::findPackage) + private val knownClassNamesInPackage = session.firCachesFactory.createCache?>(::getKnownClassNames) private val scopeProvider = JavaScopeProvider(::wrapScopeWithJvmMapped, this) @@ -138,24 +147,23 @@ class JavaSymbolProvider( fun getFirJavaClass(classId: ClassId, content: KotlinClassFinder.Result.ClassFileContent? = null): FirRegularClassSymbol? { if (!hasTopLevelClassOf(classId)) return null - return classCache.lookupCacheOrCalculateWithPostCompute( - classId, - { - val foundClass = findClass(classId, content) - if (foundClass == null || - foundClass.hasDifferentRelativeClassName(classId) || - foundClass.hasMetadataAnnotation() - ) { - null to null - } else { - FirRegularClassSymbol(classId) to foundClass - } - }, - ) { firSymbol, foundClass -> - convertJavaClassToFir(firSymbol, foundClass) + return classCache.getValue(classId, content) + } + + private fun findAndConvertJavaClass(classId: ClassId, content: KotlinClassFinder.Result.ClassFileContent?): Pair { + val foundClass = findClass(classId, content) + return if (foundClass == null || + foundClass.hasDifferentRelativeClassName(classId) || + foundClass.hasMetadataAnnotation() + ) { + null to null + } else { + val symbol = FirRegularClassSymbol(classId) + symbol to foundClass } } + /** * We do not check the package because we can look for the class in the same package by class name without package specified. * In this case, found [JavaClass] may have different `packageFqName`, but not `relativeClassName`. @@ -171,14 +179,15 @@ class JavaSymbolProvider( var valueParameterForValue: FirJavaValueParameter? = null } - private fun convertJavaClassToFir(classSymbol: FirRegularClassSymbol, javaClass: JavaClass?): FirJavaClass? { - if (javaClass == null) return null + private fun convertJavaClassToFir(classSymbol: FirRegularClassSymbol, javaClass: JavaClass): FirJavaClass { val classId = classSymbol.classId val javaTypeParameterStack = JavaTypeParameterStack() val outerClassId = classId.outerClassId val parentClassSymbol = if (outerClassId != null) { getClassLikeSymbolByFqName(outerClassId) } else null + + if (parentClassSymbol != null) { val parentStack = parentClassTypeParameterStackCache[parentClassSymbol] ?: (parentClassSymbol.fir as? FirJavaClass)?.javaTypeParameterStack @@ -527,25 +536,26 @@ class JavaSymbolProvider( ) override fun getPackage(fqName: FqName): FqName? { - return packageCache.lookupCacheOrCalculate(fqName) { - try { - val facade = KotlinJavaPsiFacade.getInstance(project) - val javaPackage = facade.findPackage(fqName.asString(), searchScope) ?: return@lookupCacheOrCalculate null - FqName(javaPackage.qualifiedName) - } catch (e: ProcessCanceledException) { - return@lookupCacheOrCalculate null - } + return packageCache.getValue(fqName) + } + + private fun findPackage(fqName: FqName): FqName? { + return try { + val facade = KotlinJavaPsiFacade.getInstance(project) + val javaPackage = facade.findPackage(fqName.asString(), searchScope) ?: return null + FqName(javaPackage.qualifiedName) + } catch (e: ProcessCanceledException) { + return null } } - private val knownClassNamesInPackage = mutableMapOf?>() - private fun hasTopLevelClassOf(classId: ClassId): Boolean { - val knownNames = knownClassNamesInPackage.getOrPut(classId.packageFqName) { - facade.knownClassNamesInPackage(classId.packageFqName, searchScope) - } ?: return true + val knownNames = knownClassNamesInPackage.getValue(classId.packageFqName) ?: return true return classId.relativeClassName.topLevelName() in knownNames } + + private fun getKnownClassNames(packageFqName: FqName): MutableSet? = + facade.knownClassNamesInPackage(packageFqName, searchScope) } fun FqName.topLevelName() = diff --git a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/SymbolProviderCache.kt b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/SymbolProviderCache.kt index 0a489a928de..451c738d3fc 100644 --- a/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/SymbolProviderCache.kt +++ b/compiler/fir/resolve/src/org/jetbrains/kotlin/fir/resolve/providers/SymbolProviderCache.kt @@ -29,23 +29,6 @@ inline class SymbolProviderCache @PrivateForInline constructor(@Priv } } - @OptIn(PrivateForInline::class) - inline fun lookupCacheOrCalculateWithPostCompute( - key: K, crossinline l: (K) -> Pair, postCompute: (V, T) -> Unit - ): V? { - @Suppress("UNCHECKED_CAST") - return when (val value = cache[key]) { - null -> { - val calculated = l(key) - cache[key] = calculated.first ?: NullValue - calculated.first?.let { postCompute(it, calculated.second) } - calculated.first - } - NullValue -> null - else -> value as V - } - } - @OptIn(PrivateForInline::class) operator fun contains(key: K): Boolean = key in cache diff --git a/idea/testData/checker/regression/Jet53.kt b/idea/testData/checker/regression/Jet53.kt index e7a7f0c8db9..382978af233 100644 --- a/idea/testData/checker/regression/Jet53.kt +++ b/idea/testData/checker/regression/Jet53.kt @@ -1,3 +1,4 @@ +// FIR_COMPARISON import java.util.Collections fun checkSubtype(t: T) = t