diff --git a/compiler/psi/cls-psi-file-stub-builder/build.gradle.kts b/compiler/psi/cls-psi-file-stub-builder/build.gradle.kts index 216b1fe6d00..293624131c4 100644 --- a/compiler/psi/cls-psi-file-stub-builder/build.gradle.kts +++ b/compiler/psi/cls-psi-file-stub-builder/build.gradle.kts @@ -9,10 +9,10 @@ dependencies { api(project(":core:deserialization.common.jvm")) api(project(":core:deserialization")) implementation(project(":compiler:psi:cls-psi-stub-builder")) + implementation(project(":core:deserialization.common.jvm.impl")) implementation(project(":core:compiler.common.jvm")) api(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) } - } sourceSets { diff --git a/compiler/psi/cls-psi-file-stub-builder/src/org/jetbrains/kotlin/psi/stubs/file/builder/DirectoryBasedClassFinder.kt b/compiler/psi/cls-psi-file-stub-builder/src/org/jetbrains/kotlin/psi/stubs/file/builder/DirectoryBasedClassFinder.kt new file mode 100644 index 00000000000..dd3f3bfacec --- /dev/null +++ b/compiler/psi/cls-psi-file-stub-builder/src/org/jetbrains/kotlin/psi/stubs/file/builder/DirectoryBasedClassFinder.kt @@ -0,0 +1,55 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi.stubs.file.builder + +import com.intellij.openapi.vfs.VirtualFile +import org.jetbrains.kotlin.load.java.structure.JavaClass +import org.jetbrains.kotlin.load.java.structure.classId +import org.jetbrains.kotlin.load.kotlin.KotlinClassFinder +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.name.FqName +import java.io.InputStream + +class DirectoryBasedClassFinder( + val packageDirectory: VirtualFile, + val directoryPackageFqName: FqName +) : KotlinClassFinder { + override fun findKotlinClassOrContent(javaClass: JavaClass): KotlinClassFinder.Result? = findKotlinClassOrContent(javaClass.classId!!) + + 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.getInstance().getKotlinBinaryClass(virtualFile)?.let(::KotlinClass) + } + return null + } + + // TODO + override fun findMetadata(classId: ClassId): InputStream? = null + + // TODO + override fun hasMetadataPackage(fqName: FqName): Boolean = false + + // TODO: load built-ins from packageDirectory? + override fun findBuiltInsData(packageFqName: FqName): InputStream? = null +} + +/** + * Checks if this file is a compiled Kotlin class file ABI-compatible with the current plugin + */ +private fun isKotlinWithCompatibleAbiVersion(file: VirtualFile): Boolean { + val ideKotlinBinaryClassCache = IDEKotlinBinaryClassCache.getInstance() + if (!ideKotlinBinaryClassCache.isKotlinJvmCompiledFile(file)) return false + + val kotlinClass = ideKotlinBinaryClassCache.getKotlinBinaryClassHeaderData(file) + return kotlinClass != null && kotlinClass.metadataVersion.isCompatible() +} + + diff --git a/compiler/psi/cls-psi-file-stub-builder/src/org/jetbrains/kotlin/psi/stubs/file/builder/DirectoryBasedDataFinder.kt b/compiler/psi/cls-psi-file-stub-builder/src/org/jetbrains/kotlin/psi/stubs/file/builder/DirectoryBasedDataFinder.kt new file mode 100644 index 00000000000..c63f4103b73 --- /dev/null +++ b/compiler/psi/cls-psi-file-stub-builder/src/org/jetbrains/kotlin/psi/stubs/file/builder/DirectoryBasedDataFinder.kt @@ -0,0 +1,37 @@ +/* + * Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors. + * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file. + */ + +package org.jetbrains.kotlin.psi.stubs.file.builder + +import com.intellij.openapi.diagnostic.Logger +import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinarySourceElement +import org.jetbrains.kotlin.load.kotlin.findKotlinClass +import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil +import org.jetbrains.kotlin.name.ClassId +import org.jetbrains.kotlin.serialization.deserialization.ClassData +import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder + +class DirectoryBasedDataFinder( + val classFinder: DirectoryBasedClassFinder, + val log: Logger +) : ClassDataFinder { + override fun findClassData(classId: ClassId): ClassData? { + val binaryClass = classFinder.findKotlinClass(classId) ?: return null + val classHeader = binaryClass.classHeader + val data = classHeader.data + if (data == null) { + log.error("Annotation data missing for ${binaryClass.classId}") + return null + } + val strings = classHeader.strings + if (strings == null) { + log.error("String table not found in class ${binaryClass.classId}") + return null + } + + val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(data, strings) + return ClassData(nameResolver, classProto, classHeader.metadataVersion, KotlinJvmBinarySourceElement(binaryClass)) + } +} \ No newline at end of file