[FIR] KT-57207 Avoid FirJavaFacade.knownClassNamesInPackage in the IDE

- `FirJavaFacade.knownClassNamesInPackage` cannot be computed in the IDE
  using the current strategy because there are multiple finders and
  there is no `CliFinder`. However, the cache was still used, which
  caused it to be filled with `null` values and additionally caused
  worse performance in `JavaSymbolProvider` due to hash map accesses via
  `hasTopLevelClassOf`.
- Rewriting the strategy is non-trivial as additional indices are needed
  on the IDE side. See KTIJ-24642.
This commit is contained in:
Marco Pennekamp
2023-03-08 18:11:58 +01:00
committed by Space Team
parent 624164e183
commit 288606868e
6 changed files with 24 additions and 5 deletions
@@ -42,7 +42,6 @@ import org.jetbrains.kotlin.load.java.structure.*
import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl import org.jetbrains.kotlin.load.java.structure.impl.JavaElementImpl
import org.jetbrains.kotlin.name.* import org.jetbrains.kotlin.name.*
import org.jetbrains.kotlin.types.Variance.INVARIANT import org.jetbrains.kotlin.types.Variance.INVARIANT
import org.jetbrains.kotlin.util.OperatorNameConventions
class FirJavaFacadeForSource( class FirJavaFacadeForSource(
session: FirSession, session: FirSession,
@@ -66,7 +65,7 @@ abstract class FirJavaFacade(
} }
private val packageCache = session.firCachesFactory.createCache { fqName: FqName -> private val packageCache = session.firCachesFactory.createCache { fqName: FqName ->
val knownClassNames: Set<String>? = knownClassNamesInPackage.getValue(fqName) val knownClassNames: Set<String>? = knownClassNamesInPackage(fqName)
classFinder.findPackage( classFinder.findPackage(
fqName, fqName,
mayHaveAnnotations = if (knownClassNames != null) PACKAGE_INFO_CLASS_NAME in knownClassNames else true mayHaveAnnotations = if (knownClassNames != null) PACKAGE_INFO_CLASS_NAME in knownClassNames else true
@@ -86,11 +85,15 @@ abstract class FirJavaFacade(
packageCache.getValue(fqName)?.fqName packageCache.getValue(fqName)?.fqName
fun hasTopLevelClassOf(classId: ClassId): Boolean { fun hasTopLevelClassOf(classId: ClassId): Boolean {
val knownNames = knownClassNamesInPackage.getValue(classId.packageFqName) ?: return true val knownNames = knownClassNamesInPackage(classId.packageFqName) ?: return true
return classId.relativeClassName.topLevelName() in knownNames return classId.relativeClassName.topLevelName() in knownNames
} }
fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? = knownClassNamesInPackage.getValue(packageFqName) fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? {
// Avoid filling the cache with `null`s and accessing the cache if `knownClassNamesInPackage` cannot be calculated anyway.
if (!classFinder.canComputeKnownClassNamesInPackage()) return null
return knownClassNamesInPackage.getValue(packageFqName)
}
abstract fun getModuleDataForClass(javaClass: JavaClass): FirModuleData abstract fun getModuleDataForClass(javaClass: JavaClass): FirModuleData
@@ -52,4 +52,7 @@ class JavaClassFinderImpl : AbstractJavaClassFinder() {
return javaFacade.knownClassNamesInPackage(packageFqName, javaSearchScope) return javaFacade.knownClassNamesInPackage(packageFqName, javaSearchScope)
} }
override fun canComputeKnownClassNamesInPackage(): Boolean {
return javaFacade.canComputeKnownClassNamesInPackage()
}
} }
@@ -45,4 +45,5 @@ class JavacBasedClassFinder : AbstractJavaClassFinder() {
override fun findPackage(fqName: FqName, mayHaveAnnotations: Boolean) = javac.findPackage(fqName, javaSearchScope) override fun findPackage(fqName: FqName, mayHaveAnnotations: Boolean) = javac.findPackage(fqName, javaSearchScope)
override fun knownClassNamesInPackage(packageFqName: FqName) = javac.knownClassNamesInPackage(packageFqName) override fun knownClassNamesInPackage(packageFqName: FqName) = javac.knownClassNamesInPackage(packageFqName)
override fun canComputeKnownClassNamesInPackage(): Boolean = true
} }
@@ -220,13 +220,18 @@ public class KotlinJavaPsiFacade implements Disposable {
KotlinPsiElementFinderWrapper[] finders = finders(); KotlinPsiElementFinderWrapper[] finders = finders();
if (finders.length == 1 && finders[0] instanceof CliFinder) { if (canComputeKnownClassNamesInPackage()) {
return ((CliFinder) finders[0]).knownClassNamesInPackage(packageFqName); return ((CliFinder) finders[0]).knownClassNamesInPackage(packageFqName);
} }
return null; return null;
} }
public Boolean canComputeKnownClassNamesInPackage() {
KotlinPsiElementFinderWrapper[] finders = finders();
return finders.length == 1 && finders[0] instanceof CliFinder;
}
@NotNull @NotNull
private PsiClass[] findClassesInDumbMode(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) { private PsiClass[] findClassesInDumbMode(@NotNull String qualifiedName, @NotNull GlobalSearchScope scope) {
String packageName = StringUtil.getPackageName(qualifiedName); String packageName = StringUtil.getPackageName(qualifiedName);
@@ -24,4 +24,10 @@ interface JavaClassFinder {
fun findPackage(fqName: FqName, mayHaveAnnotations: Boolean = true): JavaPackage? fun findPackage(fqName: FqName, mayHaveAnnotations: Boolean = true): JavaPackage?
fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? fun knownClassNamesInPackage(packageFqName: FqName): Set<String>?
/**
* Whether [knownClassNamesInPackage] can be computed. When [canComputeKnownClassNamesInPackage] is `false`, [knownClassNamesInPackage]
* will always return `null`.
*/
fun canComputeKnownClassNamesInPackage(): Boolean
} }
@@ -42,6 +42,7 @@ class ReflectJavaClassFinder(private val classLoader: ClassLoader) : JavaClassFi
} }
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? = null override fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? = null
override fun canComputeKnownClassNamesInPackage(): Boolean = false
} }
fun ClassLoader.tryLoadClass(fqName: String) = fun ClassLoader.tryLoadClass(fqName: String) =