Do not use CoreJavaFileManager in KotlinCliJavaFileManagerImpl
The inheritance is still needed because of the code in intellij-core, specifically in JavaCoreProjectEnvironment.addSourcesToClasspath and CoreJavaDirectoryService.getPackage, which assumes that the JavaFileManager instance in the project is a CoreJavaFileManager
This commit is contained in:
+37
-29
@@ -20,10 +20,7 @@ import com.intellij.core.CoreJavaFileManager
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.util.text.StringUtil
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import com.intellij.psi.PsiClass
|
||||
import com.intellij.psi.PsiClassOwner
|
||||
import com.intellij.psi.PsiManager
|
||||
import com.intellij.psi.PsiPackage
|
||||
import com.intellij.psi.*
|
||||
import com.intellij.psi.impl.file.PsiPackageImpl
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
|
||||
@@ -35,6 +32,9 @@ import org.jetbrains.kotlin.util.PerformanceCounter
|
||||
import java.util.*
|
||||
import kotlin.properties.Delegates
|
||||
|
||||
// TODO: do not inherit from CoreJavaFileManager to avoid accidental usage of its methods which do not use caches/indices
|
||||
// Currently, the only relevant usage of this class as CoreJavaFileManager is at CoreJavaDirectoryService.getPackage,
|
||||
// which is indirectly invoked from PsiPackage.getSubPackages
|
||||
class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJavaFileManager(myPsiManager), KotlinCliJavaFileManager {
|
||||
private val perfCounter = PerformanceCounter.create("Find Java class")
|
||||
private var index: JvmDependenciesIndex by Delegates.notNull()
|
||||
@@ -44,13 +44,11 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
this.index = packagesCache
|
||||
}
|
||||
|
||||
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): PsiClass? {
|
||||
return perfCounter.time {
|
||||
val classNameWithInnerClasses = classId.relativeClassName.asString()
|
||||
index.findClass(classId) { dir, type ->
|
||||
findClassGivenPackage(allScope, dir, classNameWithInnerClasses, type)
|
||||
}?.takeIf { it.containingFile.virtualFile in searchScope }
|
||||
}
|
||||
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): PsiClass? = perfCounter.time {
|
||||
val relativeClassName = classId.relativeClassName.asString()
|
||||
index.findClass(classId) { dir, type ->
|
||||
findClassGivenPackage(allScope, dir, relativeClassName, type)
|
||||
}?.takeIf { it.containingFile.virtualFile in searchScope }
|
||||
}
|
||||
|
||||
// this method is called from IDEA to resolve dependencies in Java code
|
||||
@@ -62,10 +60,18 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
// Below, we start by looking for the top level class "e" in the package "a.b.c.d" first, then for the class "d.e" in the package
|
||||
// "a.b.c", and so on, until we find something. Most classes are top level, so most of the times the search ends quickly
|
||||
|
||||
var classId = qName.toSafeTopLevelClassId() ?: return super.findClass(qName, scope)
|
||||
forEachClassId(qName) { classId ->
|
||||
findClass(classId, scope)?.let { return it }
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private inline fun forEachClassId(fqName: String, block: (ClassId) -> Unit) {
|
||||
var classId = fqName.toSafeTopLevelClassId() ?: return
|
||||
|
||||
while (true) {
|
||||
findClass(classId, scope)?.let { return it }
|
||||
block(classId)
|
||||
|
||||
val packageFqName = classId.packageFqName
|
||||
if (packageFqName.isRoot) break
|
||||
@@ -76,31 +82,26 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
false
|
||||
)
|
||||
}
|
||||
|
||||
return super.findClass(qName, scope)
|
||||
}
|
||||
|
||||
override fun findClasses(qName: String, scope: GlobalSearchScope): Array<PsiClass> {
|
||||
return perfCounter.time {
|
||||
val classIdAsTopLevelClass = qName.toSafeTopLevelClassId() ?: return@time super.findClasses(qName, scope)
|
||||
|
||||
val result = ArrayList<PsiClass>()
|
||||
val classNameWithInnerClasses = classIdAsTopLevelClass.relativeClassName.asString()
|
||||
index.traverseDirectoriesInPackage(classIdAsTopLevelClass.packageFqName) { dir, rootType ->
|
||||
val psiClass = findClassGivenPackage(scope, dir, classNameWithInnerClasses, rootType)
|
||||
override fun findClasses(qName: String, scope: GlobalSearchScope): Array<PsiClass> = perfCounter.time {
|
||||
val result = ArrayList<PsiClass>(1)
|
||||
forEachClassId(qName) { classId ->
|
||||
val relativeClassName = classId.relativeClassName.asString()
|
||||
index.traverseDirectoriesInPackage(classId.packageFqName) { dir, rootType ->
|
||||
val psiClass = findClassGivenPackage(scope, dir, relativeClassName, rootType)
|
||||
if (psiClass != null) {
|
||||
result.add(psiClass)
|
||||
}
|
||||
// traverse all
|
||||
true
|
||||
}
|
||||
if (result.isEmpty()) {
|
||||
super.findClasses(qName, scope)
|
||||
}
|
||||
else {
|
||||
result.toTypedArray()
|
||||
if (result.isNotEmpty()) {
|
||||
return@time result.toTypedArray()
|
||||
}
|
||||
}
|
||||
|
||||
PsiClass.EMPTY_ARRAY
|
||||
}
|
||||
|
||||
override fun findPackage(packageName: String): PsiPackage? {
|
||||
@@ -157,6 +158,13 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
return result
|
||||
}
|
||||
|
||||
override fun findModules(moduleName: String, scope: GlobalSearchScope): Collection<PsiJavaModule> {
|
||||
// TODO
|
||||
return emptySet()
|
||||
}
|
||||
|
||||
override fun getNonTrivialPackagePrefixes(): Collection<String> = emptyList()
|
||||
|
||||
companion object {
|
||||
private val LOG = Logger.getInstance(KotlinCliJavaFileManagerImpl::class.java)
|
||||
|
||||
@@ -202,4 +210,4 @@ catch (e: AssertionError) {
|
||||
}
|
||||
|
||||
private fun String.toSafeFqName(): FqName? = safely { FqName(this) }
|
||||
private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) }
|
||||
private fun String.toSafeTopLevelClassId(): ClassId? = safely { ClassId.topLevel(FqName(this)) }
|
||||
|
||||
Reference in New Issue
Block a user