Avoid multiple subsequent reading of the same class-file in front-end
^KT-23466 Fixed
This commit is contained in:
+16
-5
@@ -28,6 +28,7 @@ import gnu.trove.THashSet
|
||||
import org.jetbrains.kotlin.cli.jvm.index.JavaRoot
|
||||
import org.jetbrains.kotlin.cli.jvm.index.JvmDependenciesIndex
|
||||
import org.jetbrains.kotlin.cli.jvm.index.SingleJavaFileRootsIndex
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.classFiles.BinaryClassSignatureParser
|
||||
@@ -81,7 +82,10 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
private val binaryCache: MutableMap<ClassId, JavaClass?> = THashMap()
|
||||
private val signatureParsingComponent = BinaryClassSignatureParser()
|
||||
|
||||
override fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? {
|
||||
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass? = findClass(JavaClassFinder.Request(classId), searchScope)
|
||||
|
||||
override fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass? {
|
||||
val (classId, classFileContentFromRequest, outerClassFromRequest) = request
|
||||
val virtualFile = findVirtualFileForTopLevelClass(classId, searchScope) ?: return null
|
||||
|
||||
if (useFastClassFilesReading && virtualFile.extension == "class") {
|
||||
@@ -92,13 +96,20 @@ class KotlinCliJavaFileManagerImpl(private val myPsiManager: PsiManager) : CoreJ
|
||||
// This is a true assumption by now since there are two search scopes in compiler: one for sources and another one for binary
|
||||
// When it become wrong because we introduce the modules into CLI, it's worth to consider
|
||||
// having different KotlinCliJavaFileManagerImpl's for different modules
|
||||
val classContent = virtualFile.contentsToByteArray()
|
||||
if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null
|
||||
|
||||
classId.outerClassId?.let { outerClassId ->
|
||||
val outerClass = findClass(outerClassId, searchScope)
|
||||
return@getOrPut outerClass?.findInnerClass(classId.shortClassName)
|
||||
val outerClass = outerClassFromRequest ?: findClass(outerClassId, searchScope)
|
||||
|
||||
return if (outerClass is BinaryJavaClass)
|
||||
outerClass.findInnerClass(classId.shortClassName, classFileContentFromRequest)
|
||||
else
|
||||
outerClass?.findInnerClass(classId.shortClassName)
|
||||
}
|
||||
|
||||
// Here, we assume the class is top-level
|
||||
val classContent = classFileContentFromRequest ?: virtualFile.contentsToByteArray()
|
||||
if (virtualFile.nameWithoutExtension.contains("$") && isNotTopLevelClass(classContent)) return@getOrPut null
|
||||
|
||||
val resolver = ClassifierResolutionContext { findClass(it, allScope) }
|
||||
|
||||
BinaryJavaClass(
|
||||
|
||||
@@ -10,6 +10,7 @@ import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.fir.java.symbols.JavaClassSymbol
|
||||
import org.jetbrains.kotlin.fir.resolve.FirSymbolProvider
|
||||
import org.jetbrains.kotlin.fir.symbols.ConeSymbol
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||
@@ -38,7 +39,7 @@ class JavaSymbolProvider(val project: Project) : FirSymbolProvider {
|
||||
override fun getSymbolByFqName(classId: ClassId): ConeSymbol? {
|
||||
return classCache.lookupCacheOrCalculate(classId) {
|
||||
val facade = KotlinJavaPsiFacade.getInstance(project)
|
||||
val foundClass = facade.findClass(classId, allScope)
|
||||
val foundClass = facade.findClass(JavaClassFinder.Request(classId), allScope)
|
||||
foundClass?.let { javaClass -> JavaClassSymbol(javaClass) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,7 +18,6 @@ package org.jetbrains.kotlin.load.java
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaPackageImpl
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.jvm.KotlinJavaPsiFacade
|
||||
@@ -33,10 +32,10 @@ class JavaClassFinderImpl : AbstractJavaClassFinder() {
|
||||
super.initialize(trace, codeAnalyzer)
|
||||
}
|
||||
|
||||
override fun findClass(classId: ClassId): JavaClass? = javaFacade.findClass(classId, javaSearchScope)
|
||||
override fun findClass(request: JavaClassFinder.Request): JavaClass? = javaFacade.findClass(request, javaSearchScope)
|
||||
|
||||
override fun findPackage(fqName: FqName) = javaFacade.findPackage(fqName.asString(), javaSearchScope)?.let { JavaPackageImpl(it, javaSearchScope) }
|
||||
|
||||
override fun knownClassNamesInPackage(packageFqName: FqName): Set<String>? = javaFacade.knownClassNamesInPackage(packageFqName)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
+7
-2
@@ -201,11 +201,16 @@ class BinaryJavaClass(
|
||||
override fun visitAnnotation(desc: String, visible: Boolean) =
|
||||
BinaryJavaAnnotation.addAnnotation(annotations, desc, context, signatureParser)
|
||||
|
||||
override fun findInnerClass(name: Name): JavaClass? {
|
||||
override fun findInnerClass(name: Name): JavaClass? = findInnerClass(name, classFileContent = null)
|
||||
|
||||
fun findInnerClass(name: Name, classFileContent: ByteArray?): JavaClass? {
|
||||
val access = ownInnerClassNameToAccess[name] ?: return null
|
||||
|
||||
return virtualFile.parent.findChild("${virtualFile.nameWithoutExtension}$$name.class")?.let {
|
||||
BinaryJavaClass(it, fqName.child(name), context.copyForMember(), signatureParser, access, this)
|
||||
BinaryJavaClass(
|
||||
it, fqName.child(name), context.copyForMember(), signatureParser, access, this,
|
||||
classFileContent
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+11
-6
@@ -28,14 +28,17 @@ class KotlinBinaryClassCache : Disposable {
|
||||
private class RequestCache {
|
||||
internal var virtualFile: VirtualFile? = null
|
||||
internal var modificationStamp: Long = 0
|
||||
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
|
||||
internal var result: KotlinClassFinder.Result? = null
|
||||
|
||||
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
|
||||
fun cache(
|
||||
file: VirtualFile,
|
||||
result: KotlinClassFinder.Result?
|
||||
): KotlinClassFinder.Result? {
|
||||
virtualFile = file
|
||||
virtualFileKotlinClass = aClass
|
||||
this.result = result
|
||||
modificationStamp = file.modificationStamp
|
||||
|
||||
return aClass
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,7 +56,9 @@ class KotlinBinaryClassCache : Disposable {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||
fun getKotlinBinaryClassOrClassFileContent(
|
||||
file: VirtualFile, fileContent: ByteArray? = null
|
||||
): KotlinClassFinder.Result? {
|
||||
if (file.fileType !== JavaClassFileType.INSTANCE) return null
|
||||
|
||||
if (file.name == PsiJavaModule.MODULE_INFO_CLS_FILE) return null
|
||||
@@ -62,7 +67,7 @@ class KotlinBinaryClassCache : Disposable {
|
||||
val requestCache = service.cache.get()
|
||||
|
||||
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
|
||||
return requestCache.virtualFileKotlinClass
|
||||
return requestCache.result
|
||||
}
|
||||
|
||||
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
|
||||
|
||||
+11
-6
@@ -27,14 +27,17 @@ class KotlinBinaryClassCache : Disposable {
|
||||
private class RequestCache {
|
||||
internal var virtualFile: VirtualFile? = null
|
||||
internal var modificationStamp: Long = 0
|
||||
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
|
||||
internal var result: KotlinClassFinder.Result? = null
|
||||
|
||||
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
|
||||
fun cache(
|
||||
file: VirtualFile,
|
||||
result: KotlinClassFinder.Result?
|
||||
): KotlinClassFinder.Result? {
|
||||
virtualFile = file
|
||||
virtualFileKotlinClass = aClass
|
||||
this.result = result
|
||||
modificationStamp = file.modificationStamp
|
||||
|
||||
return aClass
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +55,16 @@ class KotlinBinaryClassCache : Disposable {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||
fun getKotlinBinaryClassOrClassFileContent(
|
||||
file: VirtualFile, fileContent: ByteArray? = null
|
||||
): KotlinClassFinder.Result? {
|
||||
if (file.fileType !== JavaClassFileType.INSTANCE) return null
|
||||
|
||||
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
|
||||
val requestCache = service.cache.get()
|
||||
|
||||
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
|
||||
return requestCache.virtualFileKotlinClass
|
||||
return requestCache.result
|
||||
}
|
||||
|
||||
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
|
||||
|
||||
+11
-6
@@ -27,14 +27,17 @@ class KotlinBinaryClassCache : Disposable {
|
||||
private class RequestCache {
|
||||
internal var virtualFile: VirtualFile? = null
|
||||
internal var modificationStamp: Long = 0
|
||||
internal var virtualFileKotlinClass: VirtualFileKotlinClass? = null
|
||||
internal var result: KotlinClassFinder.Result? = null
|
||||
|
||||
fun cache(file: VirtualFile, aClass: VirtualFileKotlinClass?): VirtualFileKotlinClass? {
|
||||
fun cache(
|
||||
file: VirtualFile,
|
||||
result: KotlinClassFinder.Result?
|
||||
): KotlinClassFinder.Result? {
|
||||
virtualFile = file
|
||||
virtualFileKotlinClass = aClass
|
||||
this.result = result
|
||||
modificationStamp = file.modificationStamp
|
||||
|
||||
return aClass
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
@@ -52,14 +55,16 @@ class KotlinBinaryClassCache : Disposable {
|
||||
}
|
||||
|
||||
companion object {
|
||||
fun getKotlinBinaryClass(file: VirtualFile, fileContent: ByteArray? = null): KotlinJvmBinaryClass? {
|
||||
fun getKotlinBinaryClassOrClassFileContent(
|
||||
file: VirtualFile, fileContent: ByteArray? = null
|
||||
): KotlinClassFinder.Result? {
|
||||
if (file.fileType !== JavaClassFileType.INSTANCE) return null
|
||||
|
||||
val service = ServiceManager.getService(KotlinBinaryClassCache::class.java)
|
||||
val requestCache = service.cache.get()
|
||||
|
||||
if (file.modificationStamp == requestCache.modificationStamp && file == requestCache.virtualFile) {
|
||||
return requestCache.virtualFileKotlinClass
|
||||
return requestCache.result
|
||||
}
|
||||
|
||||
val aClass = ApplicationManager.getApplication().runReadAction(Computable {
|
||||
|
||||
@@ -27,12 +27,12 @@ import org.jetbrains.kotlin.utils.sure
|
||||
abstract class VirtualFileFinder : KotlinClassFinder {
|
||||
abstract fun findVirtualFileWithHeader(classId: ClassId): VirtualFile?
|
||||
|
||||
override fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? {
|
||||
override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? {
|
||||
val file = findVirtualFileWithHeader(classId) ?: return null
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClass(file)
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file)
|
||||
}
|
||||
|
||||
override fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? {
|
||||
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? {
|
||||
var file = (javaClass as? VirtualFileBoundJavaClass)?.virtualFile ?: return null
|
||||
|
||||
if (javaClass.outerClass != null) {
|
||||
@@ -41,7 +41,7 @@ abstract class VirtualFileFinder : KotlinClassFinder {
|
||||
file = file.parent!!.findChild(classFileName(javaClass) + ".class").sure { "Virtual file not found for $javaClass" }
|
||||
}
|
||||
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClass(file)
|
||||
return KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file)
|
||||
}
|
||||
|
||||
private fun classFileName(jClass: JavaClass): String {
|
||||
|
||||
+6
-3
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.load.kotlin
|
||||
import com.intellij.ide.highlighter.JavaClassFileType
|
||||
import com.intellij.openapi.diagnostic.Logger
|
||||
import com.intellij.openapi.vfs.VirtualFile
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.util.PerformanceCounter
|
||||
@@ -56,17 +57,19 @@ class VirtualFileKotlinClass private constructor(
|
||||
private val perfCounter = PerformanceCounter.create("Binary class from Kotlin file")
|
||||
|
||||
@Deprecated("Use KotlinBinaryClassCache")
|
||||
fun create(file: VirtualFile, fileContent: ByteArray?): VirtualFileKotlinClass? {
|
||||
fun create(file: VirtualFile, fileContent: ByteArray?): KotlinClassFinder.Result? {
|
||||
return perfCounter.time {
|
||||
assert(file.fileType == JavaClassFileType.INSTANCE) { "Trying to read binary data from a non-class file $file" }
|
||||
|
||||
try {
|
||||
val byteContent = fileContent ?: file.contentsToByteArray(false)
|
||||
if (!byteContent.isEmpty()) {
|
||||
return@time FileBasedKotlinClass.create(byteContent) {
|
||||
name, classVersion, header, innerClasses ->
|
||||
val kotlinJvmBinaryClass = FileBasedKotlinClass.create(byteContent) { name, classVersion, header, innerClasses ->
|
||||
VirtualFileKotlinClass(file, name, classVersion, header, innerClasses)
|
||||
}
|
||||
|
||||
return@time kotlinJvmBinaryClass?.let(::KotlinClass)
|
||||
?: KotlinClassFinder.Result.ClassFileContent(byteContent)
|
||||
}
|
||||
}
|
||||
catch (e: FileNotFoundException) {
|
||||
|
||||
+2
-2
@@ -18,11 +18,11 @@ package org.jetbrains.kotlin.resolve.jvm
|
||||
|
||||
import com.intellij.psi.impl.file.impl.JavaFileManager
|
||||
import com.intellij.psi.search.GlobalSearchScope
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
interface KotlinCliJavaFileManager : JavaFileManager {
|
||||
fun findClass(classId: ClassId, searchScope: GlobalSearchScope): JavaClass?
|
||||
fun findClass(request: JavaClassFinder.Request, searchScope: GlobalSearchScope): JavaClass?
|
||||
fun knownClassNamesInPackage(packageFqName: FqName): Set<String>?
|
||||
}
|
||||
|
||||
+6
-4
@@ -43,6 +43,7 @@ import org.jetbrains.annotations.NotNull;
|
||||
import org.jetbrains.annotations.Nullable;
|
||||
import org.jetbrains.kotlin.asJava.KtLightClassMarker;
|
||||
import org.jetbrains.kotlin.idea.KotlinLanguage;
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder;
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinderImpl;
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass;
|
||||
import org.jetbrains.kotlin.load.java.structure.impl.JavaClassImpl;
|
||||
@@ -104,9 +105,10 @@ public class KotlinJavaPsiFacade {
|
||||
return emptyModifierList;
|
||||
}
|
||||
|
||||
public JavaClass findClass(@NotNull ClassId classId, @NotNull GlobalSearchScope scope) {
|
||||
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
|
||||
ProgressIndicatorAndCompilationCanceledStatus.checkCanceled(); // We hope this method is being called often enough to cancel daemon processes smoothly
|
||||
|
||||
ClassId classId = request.getClassId();
|
||||
String qualifiedName = classId.asSingleFqName().asString();
|
||||
|
||||
if (shouldUseSlowResolve()) {
|
||||
@@ -119,7 +121,7 @@ public class KotlinJavaPsiFacade {
|
||||
|
||||
for (KotlinPsiElementFinderWrapper finder : finders()) {
|
||||
if (finder instanceof CliFinder) {
|
||||
JavaClass aClass = ((CliFinder) finder).findClass(classId, scope);
|
||||
JavaClass aClass = ((CliFinder) finder).findClass(request, scope);
|
||||
if (aClass != null) return aClass;
|
||||
}
|
||||
else {
|
||||
@@ -383,8 +385,8 @@ public class KotlinJavaPsiFacade {
|
||||
return javaFileManager.findClass(qualifiedName, scope);
|
||||
}
|
||||
|
||||
public JavaClass findClass(@NotNull ClassId classId, @NotNull GlobalSearchScope scope) {
|
||||
return javaFileManager.findClass(classId, scope);
|
||||
public JavaClass findClass(@NotNull JavaClassFinder.Request request, @NotNull GlobalSearchScope scope) {
|
||||
return javaFileManager.findClass(request, scope);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
|
||||
+5
-3
@@ -18,7 +18,7 @@ package org.jetbrains.kotlin.javac.components
|
||||
|
||||
import org.jetbrains.kotlin.javac.JavacWrapper
|
||||
import org.jetbrains.kotlin.load.java.AbstractJavaClassFinder
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.BindingTrace
|
||||
import org.jetbrains.kotlin.resolve.lazy.KotlinCodeAnalyzer
|
||||
@@ -32,10 +32,12 @@ class JavacBasedClassFinder : AbstractJavaClassFinder() {
|
||||
super.initialize(trace, codeAnalyzer)
|
||||
}
|
||||
|
||||
override fun findClass(classId: ClassId) = javac.findClass(classId, javaSearchScope)
|
||||
override fun findClass(request: JavaClassFinder.Request) =
|
||||
// TODO: reuse previouslyFoundClassFileContent if it's possible in javac
|
||||
javac.findClass(request.classId, javaSearchScope)
|
||||
|
||||
override fun findPackage(fqName: FqName) = javac.findPackage(fqName, javaSearchScope)
|
||||
|
||||
override fun knownClassNamesInPackage(packageFqName: FqName) = javac.knownClassNamesInPackage(packageFqName)
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -22,7 +22,15 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
interface JavaClassFinder {
|
||||
fun findClass(classId: ClassId): JavaClass?
|
||||
data class Request(
|
||||
val classId: ClassId,
|
||||
@Suppress("ArrayInDataClass")
|
||||
val previouslyFoundClassFileContent: ByteArray? = null,
|
||||
val outerClass: JavaClass? = null
|
||||
)
|
||||
|
||||
fun findClass(request: Request): JavaClass?
|
||||
fun findClass(classId: ClassId): JavaClass? = findClass(Request(classId))
|
||||
|
||||
fun findPackage(fqName: FqName): JavaPackage?
|
||||
|
||||
|
||||
+6
-1
@@ -706,7 +706,12 @@ class LazyJavaClassMemberScope(
|
||||
)
|
||||
} else null
|
||||
} else {
|
||||
c.components.finder.findClass(ownerDescriptor.classId!!.createNestedClassId(name))?.let {
|
||||
c.components.finder.findClass(
|
||||
JavaClassFinder.Request(
|
||||
ownerDescriptor.classId!!.createNestedClassId(name),
|
||||
outerClass = jClass
|
||||
)
|
||||
)?.let {
|
||||
LazyJavaClassDescriptor(c, ownerDescriptor, it)
|
||||
.also(c.components.javaClassesTracker::reportClass)
|
||||
}
|
||||
|
||||
+16
-4
@@ -22,10 +22,12 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.LookupLocation
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.load.java.JavaClassFinder
|
||||
import org.jetbrains.kotlin.load.java.lazy.LazyJavaResolverContext
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaPackage
|
||||
import org.jetbrains.kotlin.load.java.structure.LightClassOriginKind
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
@@ -33,6 +35,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.resolve.scopes.DescriptorKindFilter
|
||||
import org.jetbrains.kotlin.storage.NullableLazyValue
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
import org.jetbrains.kotlin.utils.alwaysTrue
|
||||
import java.util.*
|
||||
|
||||
@@ -51,12 +54,14 @@ class LazyJavaPackageScope(
|
||||
c.storageManager.createMemoizedFunctionWithNullableValues<FindClassRequest, ClassDescriptor> classByRequest@{ request ->
|
||||
val requestClassId = ClassId(ownerDescriptor.fqName, request.name)
|
||||
|
||||
val kotlinBinaryClass =
|
||||
val kotlinClassOrClassFileContent =
|
||||
// These branches should be semantically equal, but the first one could be faster
|
||||
if (request.javaClass != null)
|
||||
c.components.kotlinClassFinder.findKotlinClass(request.javaClass)
|
||||
c.components.kotlinClassFinder.findKotlinClassOrContent(request.javaClass)
|
||||
else
|
||||
c.components.kotlinClassFinder.findKotlinClass(requestClassId)
|
||||
c.components.kotlinClassFinder.findKotlinClassOrContent(requestClassId)
|
||||
|
||||
val kotlinBinaryClass = kotlinClassOrClassFileContent?.toKotlinJvmBinaryClass()
|
||||
|
||||
val classId = kotlinBinaryClass?.classId
|
||||
// Nested/local classes can be found when running in CLI in case when request.name looks like 'Outer$Inner'
|
||||
@@ -69,7 +74,14 @@ class LazyJavaPackageScope(
|
||||
is KotlinClassLookupResult.Found -> kotlinResult.descriptor
|
||||
is KotlinClassLookupResult.SyntheticClass -> null
|
||||
is KotlinClassLookupResult.NotFound -> {
|
||||
val javaClass = request.javaClass ?: c.components.finder.findClass(requestClassId)
|
||||
val javaClass =
|
||||
request.javaClass ?: c.components.finder.findClass(
|
||||
JavaClassFinder.Request(
|
||||
requestClassId,
|
||||
kotlinClassOrClassFileContent?.safeAs<KotlinClassFinder.Result.ClassFileContent>()
|
||||
?.content
|
||||
)
|
||||
)
|
||||
|
||||
if (javaClass?.lightClassOriginKind == LightClassOriginKind.BINARY) {
|
||||
throw IllegalStateException(
|
||||
|
||||
@@ -21,7 +21,23 @@ import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.serialization.deserialization.KotlinMetadataFinder
|
||||
|
||||
interface KotlinClassFinder : KotlinMetadataFinder {
|
||||
fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass?
|
||||
fun findKotlinClassOrContent(classId: ClassId): Result?
|
||||
|
||||
fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass?
|
||||
fun findKotlinClassOrContent(javaClass: JavaClass): Result?
|
||||
|
||||
fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? =
|
||||
findKotlinClassOrContent(classId)?.toKotlinJvmBinaryClass()
|
||||
|
||||
fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? =
|
||||
findKotlinClassOrContent(javaClass)?.toKotlinJvmBinaryClass()
|
||||
|
||||
sealed class Result {
|
||||
fun toKotlinJvmBinaryClass(): KotlinJvmBinaryClass? = (this as? KotlinClass)?.kotlinJvmBinaryClass
|
||||
|
||||
data class KotlinClass(val kotlinJvmBinaryClass: KotlinJvmBinaryClass) : Result()
|
||||
data class ClassFileContent(
|
||||
@Suppress("ArrayInDataClass")
|
||||
val content: ByteArray
|
||||
) : Result()
|
||||
}
|
||||
}
|
||||
|
||||
+2
-1
@@ -25,7 +25,8 @@ import kotlin.reflect.jvm.internal.structure.ReflectJavaClass
|
||||
import kotlin.reflect.jvm.internal.structure.ReflectJavaPackage
|
||||
|
||||
class ReflectJavaClassFinder(private val classLoader: ClassLoader) : JavaClassFinder {
|
||||
override fun findClass(classId: ClassId): JavaClass? {
|
||||
override fun findClass(request: JavaClassFinder.Request): JavaClass? {
|
||||
val classId = request.classId
|
||||
val packageFqName = classId.packageFqName
|
||||
val relativeClassName = classId.relativeClassName.asString().replace('.', '$')
|
||||
val name =
|
||||
|
||||
+5
-5
@@ -18,19 +18,19 @@ package kotlin.reflect.jvm.internal.components
|
||||
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import java.io.InputStream
|
||||
|
||||
class ReflectKotlinClassFinder(private val classLoader: ClassLoader) : KotlinClassFinder {
|
||||
private fun findKotlinClass(fqName: String): KotlinJvmBinaryClass? {
|
||||
return classLoader.tryLoadClass(fqName)?.let { ReflectKotlinClass.create(it) }
|
||||
private fun findKotlinClass(fqName: String): KotlinClassFinder.Result? {
|
||||
return classLoader.tryLoadClass(fqName)?.let { ReflectKotlinClass.create(it) }?.let(::KotlinClass)
|
||||
}
|
||||
|
||||
override fun findKotlinClass(classId: ClassId) = findKotlinClass(classId.toRuntimeFqName())
|
||||
override fun findKotlinClassOrContent(classId: ClassId) = findKotlinClass(classId.toRuntimeFqName())
|
||||
|
||||
override fun findKotlinClass(javaClass: JavaClass): KotlinJvmBinaryClass? {
|
||||
override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? {
|
||||
// TODO: go through javaClass's class loader
|
||||
return findKotlinClass(javaClass.fqName?.asString() ?: return null)
|
||||
}
|
||||
|
||||
+1
-1
@@ -60,7 +60,7 @@ object IDEKotlinBinaryClassCache {
|
||||
return null
|
||||
}
|
||||
|
||||
val kotlinBinaryClass = KotlinBinaryClassCache.getKotlinBinaryClass(file, fileContent)
|
||||
val kotlinBinaryClass = KotlinBinaryClassCache.getKotlinBinaryClassOrClassFileContent(file, fileContent)?.toKotlinJvmBinaryClass()
|
||||
|
||||
val isKotlinBinaryClass = kotlinBinaryClass != null
|
||||
if (file is VirtualFileWithId) {
|
||||
|
||||
+8
-4
@@ -31,12 +31,16 @@ import org.jetbrains.kotlin.incremental.components.LookupTracker
|
||||
import org.jetbrains.kotlin.load.java.structure.JavaClass
|
||||
import org.jetbrains.kotlin.load.java.structure.classId
|
||||
import org.jetbrains.kotlin.load.kotlin.*
|
||||
import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder.Result.KotlinClass
|
||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.TargetPlatform
|
||||
import org.jetbrains.kotlin.resolve.jvm.platform.JvmPlatform
|
||||
import org.jetbrains.kotlin.serialization.deserialization.*
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassData
|
||||
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationComponents
|
||||
import org.jetbrains.kotlin.serialization.deserialization.DeserializationConfiguration
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.DeserializedPackageMemberScope
|
||||
import java.io.InputStream
|
||||
|
||||
@@ -109,16 +113,16 @@ class DirectoryBasedClassFinder(
|
||||
val packageDirectory: VirtualFile,
|
||||
val directoryPackageFqName: FqName
|
||||
) : KotlinClassFinder {
|
||||
override fun findKotlinClass(javaClass: JavaClass) = findKotlinClass(javaClass.classId!!)
|
||||
override fun findKotlinClassOrContent(javaClass: JavaClass) = findKotlinClassOrContent(javaClass.classId!!)
|
||||
|
||||
override fun findKotlinClass(classId: ClassId): KotlinJvmBinaryClass? {
|
||||
override fun findKotlinClassOrContent(classId: ClassId): KotlinClassFinder.Result? {
|
||||
if (classId.packageFqName != directoryPackageFqName) {
|
||||
return null
|
||||
}
|
||||
val targetName = classId.relativeClassName.pathSegments().joinToString("$", postfix = ".class")
|
||||
val virtualFile = packageDirectory.findChild(targetName)
|
||||
if (virtualFile != null && isKotlinWithCompatibleAbiVersion(virtualFile)) {
|
||||
return IDEKotlinBinaryClassCache.getKotlinBinaryClass(virtualFile)
|
||||
return IDEKotlinBinaryClassCache.getKotlinBinaryClass(virtualFile)?.let(::KotlinClass)
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user