Move KotlinClsStubBuilder from intellij repository

This commit is just move, without any modifications
This commit is contained in:
Ilya Kirillov
2021-12-16 11:56:38 +03:00
parent 78db89b46b
commit b9b0bb309d
3 changed files with 200 additions and 1 deletions
@@ -0,0 +1,21 @@
plugins {
kotlin("jvm")
id("jps-compatible")
}
dependencies {
api(project(":compiler:psi"))
api(project(":core:deserialization.common"))
api(project(":core:deserialization.common.jvm"))
api(project(":core:deserialization"))
implementation(project(":compiler:psi:cls-psi-stub-builder"))
implementation(project(":core:compiler.common.jvm"))
api(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
@@ -0,0 +1,177 @@
/*
* 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 com.intellij.openapi.vfs.VirtualFile
import com.intellij.psi.compiled.ClsStubBuilder
import com.intellij.psi.impl.compiled.ClassFileStubBuilder
import com.intellij.psi.stubs.PsiFileStub
import com.intellij.util.indexing.FileContent
import org.jetbrains.kotlin.SpecialJvmAnnotations
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.load.kotlin.*
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtFile
import org.jetbrains.kotlin.psi.stubs.KotlinStubVersions
import org.jetbrains.kotlin.psi.stubs.builder.*
import org.jetbrains.kotlin.resolve.constants.ClassLiteralValue
import org.jetbrains.kotlin.resolve.constants.ConstantValue
import org.jetbrains.kotlin.resolve.constants.KClassValue
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.storage.LockBasedStorageManager
open class KotlinClsStubBuilder : ClsStubBuilder() {
override fun getStubVersion() = ClassFileStubBuilder.STUB_VERSION + KotlinStubVersions.CLASSFILE_STUB_VERSION
override fun buildFileStub(content: FileContent): PsiFileStub<*>? {
val virtualFile = content.file
if (isKotlinInternalCompiledFile(virtualFile, content.content)) {
return null
}
if (isVersioned(virtualFile)) {
// Kotlin can't build stubs for versioned class files, because list of versioned inner classes
// might be incomplete
return null
}
return doBuildFileStub(virtualFile, content.content)
}
private fun doBuildFileStub(file: VirtualFile, fileContent: ByteArray): PsiFileStub<KtFile>? {
val kotlinClass: KotlinJvmBinaryClass = IDEKotlinBinaryClassCache.getInstance().getKotlinBinaryClass(file, fileContent)
?: error("Can't find binary class for Kotlin file: $file")
val header = kotlinClass.classHeader
val classId = kotlinClass.classId
val packageFqName = header.packageName?.let { FqName(it) } ?: classId.packageFqName
if (!header.metadataVersion.isCompatible()) {
return createIncompatibleAbiVersionFileStub()
}
val components = createStubBuilderComponents(file, packageFqName, fileContent)
if (header.kind == KotlinClassHeader.Kind.MULTIFILE_CLASS) {
val partFiles = findMultifileClassParts(file, classId, header.multifilePartNames)
return createMultifileClassStub(header, partFiles, classId.asSingleFqName(), components)
}
val annotationData = header.data
if (annotationData == null) {
LOG.error("Corrupted kotlin header for file ${file.name}")
return null
}
val strings = header.strings
if (strings == null) {
LOG.error("String table not found in file ${file.name}")
return null
}
return when (header.kind) {
KotlinClassHeader.Kind.CLASS -> {
if (classId.isLocal) return null
val (nameResolver, classProto) = JvmProtoBufUtil.readClassDataFrom(annotationData, strings)
if (Flags.VISIBILITY.get(classProto.flags) == ProtoBuf.Visibility.LOCAL) {
// Older Kotlin compiler versions didn't put 'INNERCLASS' attributes in some cases (e.g. for cross-inline lambdas),
// so 'ClassFileViewProvider.isInnerClass()' pre-check won't find them (EA-105730).
// Example: `Timer().schedule(1000) { foo () }`.
return null
}
val context = components.createContext(nameResolver, packageFqName, TypeTable(classProto.typeTable))
createTopLevelClassStub(classId, classProto, KotlinJvmBinarySourceElement(kotlinClass), context, header.isScript)
}
KotlinClassHeader.Kind.FILE_FACADE -> {
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(annotationData, strings)
val context = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
val fqName = header.packageName?.let { ClassId(FqName(it), classId.relativeClassName, classId.isLocal).asSingleFqName() }
?: classId.asSingleFqName()
createFileFacadeStub(packageProto, fqName, context)
}
else -> throw IllegalStateException("Should have processed " + file.path + " with header $header")
}
}
private fun createStubBuilderComponents(file: VirtualFile, packageFqName: FqName, fileContent: ByteArray): ClsStubBuilderComponents {
val classFinder = DirectoryBasedClassFinder(file.parent!!, packageFqName)
val classDataFinder = DirectoryBasedDataFinder(classFinder, LOG)
val annotationLoader = AnnotationLoaderForClassFileStubBuilder(classFinder, file, fileContent)
return ClsStubBuilderComponents(classDataFinder, annotationLoader, file)
}
companion object {
val LOG = Logger.getInstance(KotlinClsStubBuilder::class.java)
// Archive separator + META-INF + versions
private val VERSIONED_PATH_MARKER = "!/META-INF/versions/"
fun isVersioned(virtualFile: VirtualFile): Boolean {
return virtualFile.path.contains(VERSIONED_PATH_MARKER)
}
}
}
class AnnotationLoaderForClassFileStubBuilder(
kotlinClassFinder: KotlinClassFinder,
private val cachedFile: VirtualFile,
private val cachedFileContent: ByteArray
) : AbstractBinaryClassAnnotationAndConstantLoader<ClassId, Unit>(LockBasedStorageManager.NO_LOCKS, kotlinClassFinder) {
override fun getCachedFileContent(kotlinClass: KotlinJvmBinaryClass): ByteArray? {
if ((kotlinClass as? VirtualFileKotlinClass)?.file == cachedFile) {
return cachedFileContent
}
return null
}
override fun loadTypeAnnotation(proto: ProtoBuf.Annotation, nameResolver: NameResolver): ClassId = nameResolver.getClassId(proto.id)
override fun loadConstant(desc: String, initializer: Any) = null
override fun transformToUnsignedConstant(constant: Unit) = null
override fun loadAnnotation(
annotationClassId: ClassId, source: SourceElement, result: MutableList<ClassId>
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? {
if (annotationClassId != SpecialJvmAnnotations.JAVA_LANG_ANNOTATION_REPEATABLE) {
result += annotationClassId
return null
}
return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor {
private val arguments = mutableMapOf<Name, ConstantValue<*>>()
override fun visitClassLiteral(name: Name?, value: ClassLiteralValue) {
if (name != null)
arguments[name] = KClassValue(value)
}
override fun visitEnd() {
if (!isRepeatableWithImplicitContainer(annotationClassId, arguments)) {
result.add(annotationClassId)
}
}
override fun visit(name: Name?, value: Any?) = Unit
override fun visitEnum(name: Name?, enumClassId: ClassId, enumEntryName: Name) = Unit
override fun visitArray(name: Name?): KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor? = null
override fun visitAnnotation(name: Name?, classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? = null
}
}
override fun loadAnnotationMethodDefaultValue(
annotationClass: KotlinJvmBinaryClass,
methodSignature: MemberSignature,
visitResult: (Unit) -> Unit
): KotlinJvmBinaryClass.AnnotationArgumentVisitor? = null
}
+2 -1
View File
@@ -293,7 +293,8 @@ include ":benchmarks",
":wasm:wasm.ir"
include ":compiler:psi",
":compiler:psi:cls-psi-stub-builder"
":compiler:psi:cls-psi-stub-builder",
":compiler:psi:cls-psi-file-stub-builder"
include ":kotlinx-atomicfu-compiler-plugin",