FIR IDE: use FirCaches in JavaSymbolProvider

This commit is contained in:
Ilya Kirillov
2021-01-17 04:32:22 +01:00
parent 1fef5859e3
commit 7284acc9f9
3 changed files with 44 additions and 50 deletions
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.caches.*
import org.jetbrains.kotlin.fir.declarations.* import org.jetbrains.kotlin.fir.declarations.*
import org.jetbrains.kotlin.fir.declarations.builder.* import org.jetbrains.kotlin.fir.declarations.builder.*
import org.jetbrains.kotlin.fir.declarations.impl.FirResolvedDeclarationStatusImpl 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.defaultType
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProvider
import org.jetbrains.kotlin.fir.resolve.providers.FirSymbolProviderInternals 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.resolve.scopes.wrapScopeWithJvmMapped
import org.jetbrains.kotlin.fir.symbols.CallableId import org.jetbrains.kotlin.fir.symbols.CallableId
import org.jetbrains.kotlin.fir.symbols.impl.* import org.jetbrains.kotlin.fir.symbols.impl.*
@@ -53,8 +53,17 @@ class JavaSymbolProvider(
internal val VALUE_METHOD_NAME = Name.identifier("value") internal val VALUE_METHOD_NAME = Name.identifier("value")
} }
private val classCache = SymbolProviderCache<ClassId, FirRegularClassSymbol>() private val classCache =
private val packageCache = SymbolProviderCache<FqName, FqName>() 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<FqName, Set<String>?>(::getKnownClassNames)
private val scopeProvider = JavaScopeProvider(::wrapScopeWithJvmMapped, this) private val scopeProvider = JavaScopeProvider(::wrapScopeWithJvmMapped, this)
@@ -138,24 +147,23 @@ class JavaSymbolProvider(
fun getFirJavaClass(classId: ClassId, content: KotlinClassFinder.Result.ClassFileContent? = null): FirRegularClassSymbol? { fun getFirJavaClass(classId: ClassId, content: KotlinClassFinder.Result.ClassFileContent? = null): FirRegularClassSymbol? {
if (!hasTopLevelClassOf(classId)) return null if (!hasTopLevelClassOf(classId)) return null
return classCache.lookupCacheOrCalculateWithPostCompute( return classCache.getValue(classId, content)
classId, }
{
val foundClass = findClass(classId, content) private fun findAndConvertJavaClass(classId: ClassId, content: KotlinClassFinder.Result.ClassFileContent?): Pair<FirRegularClassSymbol?, JavaClass?> {
if (foundClass == null || val foundClass = findClass(classId, content)
foundClass.hasDifferentRelativeClassName(classId) || return if (foundClass == null ||
foundClass.hasMetadataAnnotation() foundClass.hasDifferentRelativeClassName(classId) ||
) { foundClass.hasMetadataAnnotation()
null to null ) {
} else { null to null
FirRegularClassSymbol(classId) to foundClass } else {
} val symbol = FirRegularClassSymbol(classId)
}, symbol to foundClass
) { firSymbol, foundClass ->
convertJavaClassToFir(firSymbol, foundClass)
} }
} }
/** /**
* We do not check the package because we can look for the class in the same package by class name without package specified. * 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`. * In this case, found [JavaClass] may have different `packageFqName`, but not `relativeClassName`.
@@ -171,14 +179,15 @@ class JavaSymbolProvider(
var valueParameterForValue: FirJavaValueParameter? = null var valueParameterForValue: FirJavaValueParameter? = null
} }
private fun convertJavaClassToFir(classSymbol: FirRegularClassSymbol, javaClass: JavaClass?): FirJavaClass? { private fun convertJavaClassToFir(classSymbol: FirRegularClassSymbol, javaClass: JavaClass): FirJavaClass {
if (javaClass == null) return null
val classId = classSymbol.classId val classId = classSymbol.classId
val javaTypeParameterStack = JavaTypeParameterStack() val javaTypeParameterStack = JavaTypeParameterStack()
val outerClassId = classId.outerClassId val outerClassId = classId.outerClassId
val parentClassSymbol = if (outerClassId != null) { val parentClassSymbol = if (outerClassId != null) {
getClassLikeSymbolByFqName(outerClassId) getClassLikeSymbolByFqName(outerClassId)
} else null } else null
if (parentClassSymbol != null) { if (parentClassSymbol != null) {
val parentStack = parentClassTypeParameterStackCache[parentClassSymbol] val parentStack = parentClassTypeParameterStackCache[parentClassSymbol]
?: (parentClassSymbol.fir as? FirJavaClass)?.javaTypeParameterStack ?: (parentClassSymbol.fir as? FirJavaClass)?.javaTypeParameterStack
@@ -527,25 +536,26 @@ class JavaSymbolProvider(
) )
override fun getPackage(fqName: FqName): FqName? { override fun getPackage(fqName: FqName): FqName? {
return packageCache.lookupCacheOrCalculate(fqName) { return packageCache.getValue(fqName)
try { }
val facade = KotlinJavaPsiFacade.getInstance(project)
val javaPackage = facade.findPackage(fqName.asString(), searchScope) ?: return@lookupCacheOrCalculate null private fun findPackage(fqName: FqName): FqName? {
FqName(javaPackage.qualifiedName) return try {
} catch (e: ProcessCanceledException) { val facade = KotlinJavaPsiFacade.getInstance(project)
return@lookupCacheOrCalculate null val javaPackage = facade.findPackage(fqName.asString(), searchScope) ?: return null
} FqName(javaPackage.qualifiedName)
} catch (e: ProcessCanceledException) {
return null
} }
} }
private val knownClassNamesInPackage = mutableMapOf<FqName, Set<String>?>()
private fun hasTopLevelClassOf(classId: ClassId): Boolean { private fun hasTopLevelClassOf(classId: ClassId): Boolean {
val knownNames = knownClassNamesInPackage.getOrPut(classId.packageFqName) { val knownNames = knownClassNamesInPackage.getValue(classId.packageFqName) ?: return true
facade.knownClassNamesInPackage(classId.packageFqName, searchScope)
} ?: return true
return classId.relativeClassName.topLevelName() in knownNames return classId.relativeClassName.topLevelName() in knownNames
} }
private fun getKnownClassNames(packageFqName: FqName): MutableSet<String>? =
facade.knownClassNamesInPackage(packageFqName, searchScope)
} }
fun FqName.topLevelName() = fun FqName.topLevelName() =
@@ -29,23 +29,6 @@ inline class SymbolProviderCache<K, V : Any> @PrivateForInline constructor(@Priv
} }
} }
@OptIn(PrivateForInline::class)
inline fun <T> lookupCacheOrCalculateWithPostCompute(
key: K, crossinline l: (K) -> Pair<V?, T>, 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) @OptIn(PrivateForInline::class)
operator fun contains(key: K): Boolean = key in cache operator fun contains(key: K): Boolean = key in cache
+1
View File
@@ -1,3 +1,4 @@
// FIR_COMPARISON
import java.util.Collections import java.util.Collections
fun <T> checkSubtype(t: T) = t fun <T> checkSubtype(t: T) = t