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:
Alexander Udalov
2017-03-26 13:37:20 +03:00
parent c67eb84369
commit 1c7ac2da5a
@@ -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)) }