Move stub builder stuff from intellij

This is mechanical moving without fixing compilation errors,
just packages are changes
This commit is contained in:
Ilya Kirillov
2021-12-10 16:36:06 +01:00
parent af09fb51ac
commit a9d7e5db72
9 changed files with 1362 additions and 1 deletions
@@ -0,0 +1,22 @@
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(":core:compiler.common.jvm"))
api(intellijCoreDep()) { includeJars("intellij-core", rootProject = rootProject) }
}
sourceSets {
"main" { projectDefault() }
"test" {}
}
@@ -0,0 +1,286 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.psi.stubs.builder
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.MemberKind
import org.jetbrains.kotlin.metadata.ProtoBuf.Modality
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.hasReceiver
import org.jetbrains.kotlin.metadata.deserialization.receiverType
import org.jetbrains.kotlin.metadata.deserialization.returnType
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.stubs.builder.flags.*
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.KotlinFunctionStubImpl
import org.jetbrains.kotlin.psi.stubs.impl.KotlinPlaceHolderStubImpl
import org.jetbrains.kotlin.psi.stubs.impl.KotlinPropertyStubImpl
import org.jetbrains.kotlin.resolve.DataClassResolver
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.getName
fun createPackageDeclarationsStubs(
parentStub: StubElement<out PsiElement>,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer.Package,
packageProto: ProtoBuf.Package
) {
createDeclarationsStubs(parentStub, outerContext, protoContainer, packageProto.functionList, packageProto.propertyList)
createTypeAliasesStubs(parentStub, outerContext, protoContainer, packageProto.typeAliasList)
}
fun createDeclarationsStubs(
parentStub: StubElement<out PsiElement>,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer,
functionProtos: List<ProtoBuf.Function>,
propertyProtos: List<ProtoBuf.Property>,
) {
for (propertyProto in propertyProtos) {
if (!shouldSkip(propertyProto.flags, outerContext.nameResolver.getName(propertyProto.name))) {
PropertyClsStubBuilder(parentStub, outerContext, protoContainer, propertyProto).build()
}
}
for (functionProto in functionProtos) {
if (!shouldSkip(functionProto.flags, outerContext.nameResolver.getName(functionProto.name))) {
FunctionClsStubBuilder(parentStub, outerContext, protoContainer, functionProto).build()
}
}
}
fun createTypeAliasesStubs(
parentStub: StubElement<out PsiElement>,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer,
typeAliasesProtos: List<ProtoBuf.TypeAlias>
) {
for (typeAliasProto in typeAliasesProtos) {
createTypeAliasStub(parentStub, typeAliasProto, protoContainer, outerContext)
}
}
fun createConstructorStub(
parentStub: StubElement<out PsiElement>,
constructorProto: ProtoBuf.Constructor,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer
) {
ConstructorClsStubBuilder(parentStub, outerContext, protoContainer, constructorProto).build()
}
private fun shouldSkip(flags: Int, name: Name): Boolean {
return when (Flags.MEMBER_KIND.get(flags)) {
MemberKind.FAKE_OVERRIDE, MemberKind.DELEGATION -> true
//TODO: fix decompiler to use sane criteria
MemberKind.SYNTHESIZED -> !DataClassResolver.isComponentLike(name)
else -> false
}
}
abstract class CallableClsStubBuilder(
parent: StubElement<out PsiElement>,
outerContext: ClsStubBuilderContext,
protected val protoContainer: ProtoContainer,
private val typeParameters: List<ProtoBuf.TypeParameter>
) {
protected val c = outerContext.child(typeParameters)
protected val typeStubBuilder = TypeClsStubBuilder(c)
protected val isTopLevel: Boolean get() = protoContainer is ProtoContainer.Package
protected val callableStub: StubElement<out PsiElement> by lazy(LazyThreadSafetyMode.NONE) { doCreateCallableStub(parent) }
fun build() {
createModifierListStub()
val typeConstraintListData = typeStubBuilder.createTypeParameterListStub(callableStub, typeParameters)
createReceiverTypeReferenceStub()
createValueParameterList()
createReturnTypeStub()
typeStubBuilder.createTypeConstraintListStub(callableStub, typeConstraintListData)
}
abstract val receiverType: ProtoBuf.Type?
abstract val receiverAnnotations: List<ClassIdWithTarget>
abstract val returnType: ProtoBuf.Type?
private fun createReceiverTypeReferenceStub() {
receiverType?.let {
typeStubBuilder.createTypeReferenceStub(callableStub, it, this::receiverAnnotations)
}
}
private fun createReturnTypeStub() {
returnType?.let {
typeStubBuilder.createTypeReferenceStub(callableStub, it)
}
}
abstract fun createModifierListStub()
abstract fun createValueParameterList()
abstract fun doCreateCallableStub(parent: StubElement<out PsiElement>): StubElement<out PsiElement>
}
private class FunctionClsStubBuilder(
parent: StubElement<out PsiElement>,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer,
private val functionProto: ProtoBuf.Function
) : CallableClsStubBuilder(parent, outerContext, protoContainer, functionProto.typeParameterList) {
override val receiverType: ProtoBuf.Type?
get() = functionProto.receiverType(c.typeTable)
override val receiverAnnotations: List<ClassIdWithTarget>
get() {
return c.components.annotationLoader
.loadExtensionReceiverParameterAnnotations(protoContainer, functionProto, AnnotatedCallableKind.FUNCTION)
.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.RECEIVER) }
}
override val returnType: ProtoBuf.Type
get() = functionProto.returnType(c.typeTable)
override fun createValueParameterList() {
typeStubBuilder.createValueParameterListStub(callableStub, functionProto, functionProto.valueParameterList, protoContainer)
}
override fun createModifierListStub() {
val modalityModifier = if (isTopLevel) listOf() else listOf(MODALITY)
val modifierListStubImpl = createModifierListStubForDeclaration(
callableStub, functionProto.flags,
listOf(VISIBILITY, OPERATOR, INFIX, EXTERNAL_FUN, INLINE, TAILREC, SUSPEND) + modalityModifier
)
// If function is marked as having no annotations, we don't create stubs for it
if (!Flags.HAS_ANNOTATIONS.get(functionProto.flags)) return
val annotationIds = c.components.annotationLoader.loadCallableAnnotations(
protoContainer, functionProto, AnnotatedCallableKind.FUNCTION
)
createAnnotationStubs(annotationIds, modifierListStubImpl)
}
override fun doCreateCallableStub(parent: StubElement<out PsiElement>): StubElement<out PsiElement> {
val callableName = c.nameResolver.getName(functionProto.name)
return KotlinFunctionStubImpl(
parent,
callableName.ref(),
isTopLevel,
c.containerFqName.child(callableName),
isExtension = functionProto.hasReceiver(),
hasBlockBody = true,
hasBody = Flags.MODALITY.get(functionProto.flags) != Modality.ABSTRACT,
hasTypeParameterListBeforeFunctionName = functionProto.typeParameterList.isNotEmpty(),
mayHaveContract = functionProto.hasContract()
)
}
}
private class PropertyClsStubBuilder(
parent: StubElement<out PsiElement>,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer,
private val propertyProto: ProtoBuf.Property
) : CallableClsStubBuilder(parent, outerContext, protoContainer, propertyProto.typeParameterList) {
private val isVar = Flags.IS_VAR.get(propertyProto.flags)
override val receiverType: ProtoBuf.Type?
get() = propertyProto.receiverType(c.typeTable)
override val receiverAnnotations: List<ClassIdWithTarget>
get() = c.components.annotationLoader
.loadExtensionReceiverParameterAnnotations(protoContainer, propertyProto, AnnotatedCallableKind.PROPERTY_GETTER)
.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.RECEIVER) }
override val returnType: ProtoBuf.Type
get() = propertyProto.returnType(c.typeTable)
override fun createValueParameterList() {
}
override fun createModifierListStub() {
val constModifier = if (isVar) listOf() else listOf(CONST)
val modalityModifier = if (isTopLevel) listOf() else listOf(MODALITY)
val modifierListStubImpl = createModifierListStubForDeclaration(
callableStub, propertyProto.flags,
listOf(VISIBILITY, LATEINIT, EXTERNAL_PROPERTY) + constModifier + modalityModifier
)
// If field is marked as having no annotations, we don't create stubs for it
if (!Flags.HAS_ANNOTATIONS.get(propertyProto.flags)) return
val propertyAnnotations =
c.components.annotationLoader.loadCallableAnnotations(protoContainer, propertyProto, AnnotatedCallableKind.PROPERTY)
val backingFieldAnnotations =
c.components.annotationLoader.loadPropertyBackingFieldAnnotations(protoContainer, propertyProto)
val delegateFieldAnnotations =
c.components.annotationLoader.loadPropertyDelegateFieldAnnotations(protoContainer, propertyProto)
val allAnnotations =
propertyAnnotations.map { ClassIdWithTarget(it, null) } +
backingFieldAnnotations.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.FIELD) } +
delegateFieldAnnotations.map { ClassIdWithTarget(it, AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD) }
createTargetedAnnotationStubs(allAnnotations, modifierListStubImpl)
}
override fun doCreateCallableStub(parent: StubElement<out PsiElement>): StubElement<out PsiElement> {
val callableName = c.nameResolver.getName(propertyProto.name)
return KotlinPropertyStubImpl(
parent,
callableName.ref(),
isVar,
isTopLevel,
hasDelegate = false,
hasDelegateExpression = false,
hasInitializer = false,
isExtension = propertyProto.hasReceiver(),
hasReturnTypeRef = true,
fqName = c.containerFqName.child(callableName)
)
}
}
private class ConstructorClsStubBuilder(
parent: StubElement<out PsiElement>,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer,
private val constructorProto: ProtoBuf.Constructor
) : CallableClsStubBuilder(parent, outerContext, protoContainer, emptyList()) {
override val receiverType: ProtoBuf.Type?
get() = null
override val receiverAnnotations: List<ClassIdWithTarget>
get() = emptyList()
override val returnType: ProtoBuf.Type?
get() = null
override fun createValueParameterList() {
typeStubBuilder.createValueParameterListStub(callableStub, constructorProto, constructorProto.valueParameterList, protoContainer)
}
override fun createModifierListStub() {
val modifierListStubImpl = createModifierListStubForDeclaration(callableStub, constructorProto.flags, listOf(VISIBILITY))
// If constructor is marked as having no annotations, we don't create stubs for it
if (!Flags.HAS_ANNOTATIONS.get(constructorProto.flags)) return
val annotationIds = c.components.annotationLoader.loadCallableAnnotations(
protoContainer, constructorProto, AnnotatedCallableKind.FUNCTION
)
createAnnotationStubs(annotationIds, modifierListStubImpl)
}
override fun doCreateCallableStub(parent: StubElement<out PsiElement>): StubElement<out PsiElement> {
return if (Flags.IS_SECONDARY.get(constructorProto.flags))
KotlinPlaceHolderStubImpl(parent, KtStubElementTypes.SECONDARY_CONSTRUCTOR)
else
KotlinPlaceHolderStubImpl(parent, KtStubElementTypes.PRIMARY_CONSTRUCTOR)
}
}
@@ -0,0 +1,283 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.psi.stubs.builder
import com.intellij.openapi.diagnostic.Logger
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.isNumberedFunctionClassFqName
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
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.deserialization.supertypes
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.KtClassBody
import org.jetbrains.kotlin.psi.KtSuperTypeEntry
import org.jetbrains.kotlin.psi.KtSuperTypeList
import org.jetbrains.kotlin.psi.stubs.builder.flags.*
import org.jetbrains.kotlin.psi.stubs.elements.KtClassElementType
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.KotlinClassStubImpl
import org.jetbrains.kotlin.psi.stubs.impl.KotlinModifierListStubImpl
import org.jetbrains.kotlin.psi.stubs.impl.KotlinObjectStubImpl
import org.jetbrains.kotlin.psi.stubs.impl.KotlinPlaceHolderStubImpl
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
fun createClassStub(
parent: StubElement<out PsiElement>,
classProto: ProtoBuf.Class,
nameResolver: NameResolver,
classId: ClassId,
source: SourceElement?,
context: ClsStubBuilderContext
) {
ClassClsStubBuilder(parent, classProto, nameResolver, classId, source, context).build()
}
private class ClassClsStubBuilder(
private val parentStub: StubElement<out PsiElement>,
private val classProto: ProtoBuf.Class,
nameResolver: NameResolver,
private val classId: ClassId,
source: SourceElement?,
outerContext: ClsStubBuilderContext
) {
private val thisAsProtoContainer = ProtoContainer.Class(
classProto, nameResolver, TypeTable(classProto.typeTable), source, outerContext.protoContainer
)
private val classKind = thisAsProtoContainer.kind
private val c = outerContext.child(
classProto.typeParameterList, classId.shortClassName, nameResolver, thisAsProtoContainer.typeTable, thisAsProtoContainer
)
private val typeStubBuilder = TypeClsStubBuilder(c)
private val supertypeIds = run {
val supertypeIds = classProto.supertypes(c.typeTable).map { c.nameResolver.getClassId(it.className) }
//empty supertype list if single supertype is Any
if (supertypeIds.singleOrNull()?.let { StandardNames.FqNames.any == it.asSingleFqName().toUnsafe() } == true) {
listOf()
} else {
supertypeIds
}
}
private val companionObjectName = if (classProto.hasCompanionObjectName())
c.nameResolver.getName(classProto.companionObjectName)
else
null
private val classOrObjectStub = createClassOrObjectStubAndModifierListStub()
fun build() {
val typeConstraintListData = typeStubBuilder.createTypeParameterListStub(classOrObjectStub, classProto.typeParameterList)
createConstructorStub()
createDelegationSpecifierList()
typeStubBuilder.createTypeConstraintListStub(classOrObjectStub, typeConstraintListData)
createClassBodyAndMemberStubs()
}
private fun createClassOrObjectStubAndModifierListStub(): StubElement<out PsiElement> {
val classOrObjectStub = doCreateClassOrObjectStub()
val modifierList = createModifierListForClass(classOrObjectStub)
if (Flags.HAS_ANNOTATIONS.get(classProto.flags)) {
createAnnotationStubs(c.components.annotationLoader.loadClassAnnotations(thisAsProtoContainer), modifierList)
}
return classOrObjectStub
}
private fun createModifierListForClass(parent: StubElement<out PsiElement>): KotlinModifierListStubImpl {
val relevantFlags = arrayListOf(VISIBILITY)
relevantFlags.add(EXTERNAL_CLASS)
if (isClass()) {
relevantFlags.add(INNER)
relevantFlags.add(DATA)
relevantFlags.add(MODALITY)
relevantFlags.add(VALUE_CLASS)
}
if (isInterface()) {
relevantFlags.add(FUN_INTERFACE)
}
val additionalModifiers = when (classKind) {
ProtoBuf.Class.Kind.ENUM_CLASS -> listOf(KtTokens.ENUM_KEYWORD)
ProtoBuf.Class.Kind.COMPANION_OBJECT -> listOf(KtTokens.COMPANION_KEYWORD)
ProtoBuf.Class.Kind.ANNOTATION_CLASS -> listOf(KtTokens.ANNOTATION_KEYWORD)
else -> listOf<KtModifierKeywordToken>()
}
return createModifierListStubForDeclaration(parent, classProto.flags, relevantFlags, additionalModifiers)
}
private fun doCreateClassOrObjectStub(): StubElement<out PsiElement> {
val isCompanionObject = classKind == ProtoBuf.Class.Kind.COMPANION_OBJECT
val fqName = classId.asSingleFqName()
val shortName = fqName.shortName().ref()
val superTypeRefs = supertypeIds.filterNot {
//TODO: filtering function types should go away
isNumberedFunctionClassFqName(it.asSingleFqName().toUnsafe())
}.map { it.shortClassName.ref() }.toTypedArray()
val classId = classId.takeUnless { it.isLocal }
return when (classKind) {
ProtoBuf.Class.Kind.OBJECT, ProtoBuf.Class.Kind.COMPANION_OBJECT -> {
KotlinObjectStubImpl(
parentStub, shortName, fqName,
classId = classId,
superTypeRefs,
isTopLevel = !this.classId.isNestedClass,
isDefault = isCompanionObject,
isLocal = false,
isObjectLiteral = false,
)
}
else -> {
KotlinClassStubImpl(
KtClassElementType.getStubType(classKind == ProtoBuf.Class.Kind.ENUM_ENTRY),
parentStub,
fqName.ref(),
classId = classId,
shortName,
superTypeRefs,
isInterface = classKind == ProtoBuf.Class.Kind.INTERFACE,
isEnumEntry = classKind == ProtoBuf.Class.Kind.ENUM_ENTRY,
isLocal = false,
isTopLevel = !this.classId.isNestedClass,
)
}
}
}
private fun createConstructorStub() {
if (!isClass()) return
val primaryConstructorProto = classProto.constructorList.find { !Flags.IS_SECONDARY.get(it.flags) } ?: return
createConstructorStub(classOrObjectStub, primaryConstructorProto, c, thisAsProtoContainer)
}
private fun createDelegationSpecifierList() {
// if single supertype is any then no delegation specifier list is needed
if (supertypeIds.isEmpty()) return
val delegationSpecifierListStub = KotlinPlaceHolderStubImpl<KtSuperTypeList>(classOrObjectStub, KtStubElementTypes.SUPER_TYPE_LIST)
classProto.supertypes(c.typeTable).forEach { type ->
val superClassStub = KotlinPlaceHolderStubImpl<KtSuperTypeEntry>(
delegationSpecifierListStub, KtStubElementTypes.SUPER_TYPE_ENTRY
)
typeStubBuilder.createTypeReferenceStub(superClassStub, type)
}
}
private fun createClassBodyAndMemberStubs() {
val classBody = KotlinPlaceHolderStubImpl<KtClassBody>(classOrObjectStub, KtStubElementTypes.CLASS_BODY)
createEnumEntryStubs(classBody)
createCompanionObjectStub(classBody)
createCallableMemberStubs(classBody)
createInnerAndNestedClasses(classBody)
createTypeAliasesStubs(classBody)
}
private fun createCompanionObjectStub(classBody: KotlinPlaceHolderStubImpl<KtClassBody>) {
if (companionObjectName == null) {
return
}
val companionObjectId = classId.createNestedClassId(companionObjectName)
createNestedClassStub(classBody, companionObjectId)
}
private fun createEnumEntryStubs(classBody: KotlinPlaceHolderStubImpl<KtClassBody>) {
if (classKind != ProtoBuf.Class.Kind.ENUM_CLASS) return
classProto.enumEntryList.forEach { entry ->
val name = c.nameResolver.getName(entry.name)
val annotations = c.components.annotationLoader.loadEnumEntryAnnotations(thisAsProtoContainer, entry)
val enumEntryStub = KotlinClassStubImpl(
KtStubElementTypes.ENUM_ENTRY,
classBody,
qualifiedName = c.containerFqName.child(name).ref(),
classId = null, // enum entry do not have class id
name = name.ref(),
superNames = arrayOf(),
isInterface = false,
isEnumEntry = true,
isLocal = false,
isTopLevel = false
)
if (annotations.isNotEmpty()) {
createAnnotationStubs(annotations, createEmptyModifierListStub(enumEntryStub))
}
}
}
private fun createCallableMemberStubs(classBody: KotlinPlaceHolderStubImpl<KtClassBody>) {
for (secondaryConstructorProto in classProto.constructorList) {
if (Flags.IS_SECONDARY.get(secondaryConstructorProto.flags)) {
createConstructorStub(classBody, secondaryConstructorProto, c, thisAsProtoContainer)
}
}
createDeclarationsStubs(classBody, c, thisAsProtoContainer, classProto.functionList, classProto.propertyList)
}
private fun isClass(): Boolean {
return classKind == ProtoBuf.Class.Kind.CLASS ||
classKind == ProtoBuf.Class.Kind.ENUM_CLASS ||
classKind == ProtoBuf.Class.Kind.ANNOTATION_CLASS
}
private fun isInterface(): Boolean {
return classKind == ProtoBuf.Class.Kind.INTERFACE
}
private fun createInnerAndNestedClasses(classBody: KotlinPlaceHolderStubImpl<KtClassBody>) {
classProto.nestedClassNameList.forEach { id ->
val nestedClassName = c.nameResolver.getName(id)
if (nestedClassName != companionObjectName) {
val nestedClassId = classId.createNestedClassId(nestedClassName)
createNestedClassStub(classBody, nestedClassId)
}
}
}
private fun createTypeAliasesStubs(classBody: KotlinPlaceHolderStubImpl<KtClassBody>) {
createTypeAliasesStubs(classBody, c, thisAsProtoContainer, classProto.typeAliasList)
}
private fun createNestedClassStub(classBody: StubElement<out PsiElement>, nestedClassId: ClassId) {
val (nameResolver, classProto, _, sourceElement) =
c.components.classDataFinder.findClassData(nestedClassId)
?: c.components.virtualFileForDebug.let { rootFile ->
val outerClassId = nestedClassId.outerClassId
val sortedChildren = rootFile.parent.children.sortedBy { it.name }
val msgPrefix = "Could not find data for nested class $nestedClassId of class $outerClassId\n"
val explanation = when {
outerClassId != null && sortedChildren.none { it.name.startsWith("${outerClassId.relativeClassName}\$a") } ->
// KT-29427: case with obfuscation
"Reason: obfuscation suspected (single-letter name)\n"
else ->
// General case
""
}
val msg = msgPrefix + explanation +
"Root file: ${rootFile.canonicalPath}\n" +
"Dir: ${rootFile.parent.canonicalPath}\n" +
"Children:\n" +
sortedChildren.joinToString(separator = "\n") {
"${it.name} (valid: ${it.isValid})"
}
LOG.info(msg)
return
}
createClassStub(classBody, classProto, nameResolver, nestedClassId, sourceElement, c)
}
companion object {
private val LOG = Logger.getInstance(ClassClsStubBuilder::class.java)
}
}
@@ -0,0 +1,76 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.psi.stubs.builder
import com.intellij.openapi.vfs.VirtualFile
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.NameResolver
import org.jetbrains.kotlin.metadata.deserialization.TypeTable
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.serialization.deserialization.AnnotationAndConstantLoader
import org.jetbrains.kotlin.serialization.deserialization.ClassDataFinder
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.getName
data class ClassIdWithTarget(val classId: ClassId, val target: AnnotationUseSiteTarget?)
class ClsStubBuilderComponents(
val classDataFinder: ClassDataFinder,
val annotationLoader: AnnotationAndConstantLoader<ClassId, Unit>,
val virtualFileForDebug: VirtualFile
) {
fun createContext(
nameResolver: NameResolver,
packageFqName: FqName,
typeTable: TypeTable
): ClsStubBuilderContext =
ClsStubBuilderContext(this, nameResolver, packageFqName, EmptyTypeParameters, typeTable, protoContainer = null)
}
interface TypeParameters {
operator fun get(id: Int): Name
fun child(nameResolver: NameResolver, innerTypeParameters: List<ProtoBuf.TypeParameter>) =
TypeParametersImpl(nameResolver, innerTypeParameters, parent = this)
}
object EmptyTypeParameters : TypeParameters {
override fun get(id: Int): Name = throw IllegalStateException("Unknown type parameter with id = $id")
}
class TypeParametersImpl(
nameResolver: NameResolver,
typeParameterProtos: Collection<ProtoBuf.TypeParameter>,
private val parent: TypeParameters
) : TypeParameters {
private val typeParametersById = typeParameterProtos.map { Pair(it.id, nameResolver.getName(it.name)) }.toMap()
override fun get(id: Int): Name = typeParametersById[id] ?: parent[id]
}
class ClsStubBuilderContext(
val components: ClsStubBuilderComponents,
val nameResolver: NameResolver,
val containerFqName: FqName,
val typeParameters: TypeParameters,
val typeTable: TypeTable,
val protoContainer: ProtoContainer.Class?
)
internal fun ClsStubBuilderContext.child(
typeParameterList: List<ProtoBuf.TypeParameter>,
name: Name? = null,
nameResolver: NameResolver = this.nameResolver,
typeTable: TypeTable = this.typeTable,
protoContainer: ProtoContainer.Class? = this.protoContainer
): ClsStubBuilderContext = ClsStubBuilderContext(
this.components,
nameResolver,
if (name != null) this.containerFqName.child(name) else this.containerFqName,
this.typeParameters.child(nameResolver, typeParameterList),
typeTable,
protoContainer
)
@@ -0,0 +1,344 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.psi.stubs.builder
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.builtins.isBuiltinFunctionClass
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.ProtoBuf.Type
import org.jetbrains.kotlin.metadata.ProtoBuf.Type.Argument.Projection
import org.jetbrains.kotlin.metadata.ProtoBuf.TypeParameter.Variance
import org.jetbrains.kotlin.metadata.deserialization.*
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.protobuf.MessageLite
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.*
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
import org.jetbrains.kotlin.serialization.js.DynamicTypeDeserializer
import org.jetbrains.kotlin.utils.doNothing
import java.util.*
// TODO: see DescriptorRendererOptions.excludedTypeAnnotationClasses for decompiler
private val ANNOTATIONS_NOT_LOADED_FOR_TYPES = setOf(StandardNames.FqNames.parameterName)
class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
fun createTypeReferenceStub(
parent: StubElement<out PsiElement>,
type: Type,
additionalAnnotations: () -> List<ClassIdWithTarget> = { emptyList() }
) {
val abbreviatedType = type.abbreviatedType(c.typeTable)
if (abbreviatedType != null) {
return createTypeReferenceStub(parent, abbreviatedType, additionalAnnotations)
}
val typeReference = KotlinPlaceHolderStubImpl<KtTypeReference>(parent, KtStubElementTypes.TYPE_REFERENCE)
val annotations = c.components.annotationLoader.loadTypeAnnotations(type, c.nameResolver).filterNot {
val isTopLevelClass = !it.isNestedClass
isTopLevelClass && it.asSingleFqName() in ANNOTATIONS_NOT_LOADED_FOR_TYPES
}
val allAnnotations = additionalAnnotations() + annotations.map { ClassIdWithTarget(it, null) }
when {
type.hasClassName() || type.hasTypeAliasName() ->
createClassReferenceTypeStub(typeReference, type, allAnnotations)
type.hasTypeParameter() ->
createTypeParameterStub(typeReference, type, c.typeParameters[type.typeParameter], allAnnotations)
type.hasTypeParameterName() ->
createTypeParameterStub(typeReference, type, c.nameResolver.getName(type.typeParameterName), allAnnotations)
else -> {
doNothing()
}
}
}
private fun nullableTypeParent(parent: KotlinStubBaseImpl<*>, type: Type): KotlinStubBaseImpl<*> = if (type.nullable)
KotlinPlaceHolderStubImpl<KtNullableType>(parent, KtStubElementTypes.NULLABLE_TYPE)
else
parent
private fun createTypeParameterStub(parent: KotlinStubBaseImpl<*>, type: Type, name: Name, annotations: List<ClassIdWithTarget>) {
createTypeAnnotationStubs(parent, type, annotations)
val nullableParentWrapper = nullableTypeParent(parent, type)
createStubForTypeName(ClassId.topLevel(FqName.topLevel(name)), nullableParentWrapper)
}
private fun createClassReferenceTypeStub(parent: KotlinStubBaseImpl<*>, type: Type, annotations: List<ClassIdWithTarget>) {
if (type.hasFlexibleTypeCapabilitiesId()) {
val id = c.nameResolver.getString(type.flexibleTypeCapabilitiesId)
if (id == DynamicTypeDeserializer.id) {
KotlinPlaceHolderStubImpl<KtDynamicType>(nullableTypeParent(parent, type), KtStubElementTypes.DYNAMIC_TYPE)
return
}
}
assert(type.hasClassName() || type.hasTypeAliasName()) {
"Class reference stub must have either class or type alias name"
}
val classId = c.nameResolver.getClassId(if (type.hasClassName()) type.className else type.typeAliasName)
val shouldBuildAsFunctionType = isBuiltinFunctionClass(classId) && type.argumentList.none { it.projection == Projection.STAR }
if (shouldBuildAsFunctionType) {
val (extensionAnnotations, notExtensionAnnotations) = annotations.partition {
it.classId.asSingleFqName() == StandardNames.FqNames.extensionFunctionType
}
val isExtension = extensionAnnotations.isNotEmpty()
val isSuspend = Flags.SUSPEND_TYPE.get(type.flags)
val nullableWrapper = if (isSuspend) {
val wrapper = nullableTypeParent(parent, type)
createTypeAnnotationStubs(wrapper, type, notExtensionAnnotations)
wrapper
} else {
createTypeAnnotationStubs(parent, type, notExtensionAnnotations)
nullableTypeParent(parent, type)
}
createFunctionTypeStub(nullableWrapper, type, isExtension, isSuspend)
return
}
createTypeAnnotationStubs(parent, type, annotations)
val outerTypeChain = generateSequence(type) { it.outerType(c.typeTable) }.toList()
createStubForTypeName(classId, nullableTypeParent(parent, type)) { userTypeStub, index ->
outerTypeChain.getOrNull(index)?.let { createTypeArgumentListStub(userTypeStub, it.argumentList) }
}
}
private fun createTypeAnnotationStubs(parent: KotlinStubBaseImpl<*>, type: Type, annotations: List<ClassIdWithTarget>) {
val typeModifiers = getTypeModifiersAsWritten(type)
if (annotations.isEmpty() && typeModifiers.isEmpty()) return
val typeModifiersMask = ModifierMaskUtils.computeMask { it in typeModifiers }
val modifiersList = KotlinModifierListStubImpl(parent, typeModifiersMask, KtStubElementTypes.MODIFIER_LIST)
createTargetedAnnotationStubs(annotations, modifiersList)
}
private fun getTypeModifiersAsWritten(type: Type): Set<KtModifierKeywordToken> {
if (!type.hasClassName() && !type.hasTypeAliasName()) return emptySet()
val result = hashSetOf<KtModifierKeywordToken>()
if (Flags.SUSPEND_TYPE.get(type.flags)) {
result.add(KtTokens.SUSPEND_KEYWORD)
}
return result
}
private fun createTypeArgumentListStub(typeStub: KotlinUserTypeStub, typeArgumentProtoList: List<Type.Argument>) {
if (typeArgumentProtoList.isEmpty()) {
return
}
val typeArgumentsListStub = KotlinPlaceHolderStubImpl<KtTypeArgumentList>(typeStub, KtStubElementTypes.TYPE_ARGUMENT_LIST)
typeArgumentProtoList.forEach { typeArgumentProto ->
val projectionKind = typeArgumentProto.projection.toProjectionKind()
val typeProjection = KotlinTypeProjectionStubImpl(typeArgumentsListStub, projectionKind.ordinal)
if (projectionKind != KtProjectionKind.STAR) {
val modifierKeywordToken = projectionKind.token as? KtModifierKeywordToken
createModifierListStub(typeProjection, listOfNotNull(modifierKeywordToken))
createTypeReferenceStub(typeProjection, typeArgumentProto.type(c.typeTable)!!)
}
}
}
private fun Projection.toProjectionKind() = when (this) {
Projection.IN -> KtProjectionKind.IN
Projection.OUT -> KtProjectionKind.OUT
Projection.INV -> KtProjectionKind.NONE
Projection.STAR -> KtProjectionKind.STAR
}
private fun createFunctionTypeStub(
parent: StubElement<out PsiElement>,
type: Type,
isExtensionFunctionType: Boolean,
isSuspend: Boolean
) {
val typeArgumentList = type.argumentList
val functionType = KotlinPlaceHolderStubImpl<KtFunctionType>(parent, KtStubElementTypes.FUNCTION_TYPE)
if (isExtensionFunctionType) {
val functionTypeReceiverStub =
KotlinPlaceHolderStubImpl<KtFunctionTypeReceiver>(functionType, KtStubElementTypes.FUNCTION_TYPE_RECEIVER)
val receiverTypeProto = typeArgumentList.first().type(c.typeTable)!!
createTypeReferenceStub(functionTypeReceiverStub, receiverTypeProto)
}
val parameterList = KotlinPlaceHolderStubImpl<KtParameterList>(functionType, KtStubElementTypes.VALUE_PARAMETER_LIST)
val typeArgumentsWithoutReceiverAndReturnType =
typeArgumentList.subList(if (isExtensionFunctionType) 1 else 0, typeArgumentList.size - 1)
var suspendParameterType: Type? = null
for ((index, argument) in typeArgumentsWithoutReceiverAndReturnType.withIndex()) {
if (isSuspend && index == typeArgumentsWithoutReceiverAndReturnType.size - 1) {
val parameterType = argument.type(c.typeTable)!!
if (parameterType.hasClassName() && parameterType.argumentCount == 1) {
val classId = c.nameResolver.getClassId(parameterType.className)
val fqName = classId.asSingleFqName()
assert(
fqName == FqName("kotlin.coroutines.Continuation") ||
fqName == FqName("kotlin.coroutines.experimental.Continuation")
) {
"Last parameter type of suspend function must be Continuation, but it is $fqName"
}
suspendParameterType = parameterType
continue
}
}
val parameter = KotlinParameterStubImpl(
parameterList, fqName = null, name = null, isMutable = false, hasValOrVar = false, hasDefaultValue = false
)
createTypeReferenceStub(parameter, argument.type(c.typeTable)!!)
}
if (suspendParameterType == null) {
val returnType = typeArgumentList.last().type(c.typeTable)!!
createTypeReferenceStub(functionType, returnType)
} else {
val continuationArgumentType = suspendParameterType.getArgument(0).type(c.typeTable)!!
createTypeReferenceStub(functionType, continuationArgumentType)
}
}
fun createValueParameterListStub(
parent: StubElement<out PsiElement>,
callableProto: MessageLite,
parameters: List<ProtoBuf.ValueParameter>,
container: ProtoContainer
) {
val parameterListStub = KotlinPlaceHolderStubImpl<KtParameterList>(parent, KtStubElementTypes.VALUE_PARAMETER_LIST)
for ((index, valueParameterProto) in parameters.withIndex()) {
val name = c.nameResolver.getName(valueParameterProto.name)
val parameterStub = KotlinParameterStubImpl(
parameterListStub,
name = name.ref(),
fqName = null,
hasDefaultValue = false,
hasValOrVar = false,
isMutable = false
)
val varargElementType = valueParameterProto.varargElementType(c.typeTable)
val typeProto = varargElementType ?: valueParameterProto.type(c.typeTable)
val modifiers = arrayListOf<KtModifierKeywordToken>()
if (varargElementType != null) {
modifiers.add(KtTokens.VARARG_KEYWORD)
}
if (Flags.IS_CROSSINLINE.get(valueParameterProto.flags)) {
modifiers.add(KtTokens.CROSSINLINE_KEYWORD)
}
if (Flags.IS_NOINLINE.get(valueParameterProto.flags)) {
modifiers.add(KtTokens.NOINLINE_KEYWORD)
}
val modifierList = createModifierListStub(parameterStub, modifiers)
if (Flags.HAS_ANNOTATIONS.get(valueParameterProto.flags)) {
val parameterAnnotations = c.components.annotationLoader.loadValueParameterAnnotations(
container, callableProto, callableProto.annotatedCallableKind, index, valueParameterProto
)
if (parameterAnnotations.isNotEmpty()) {
createAnnotationStubs(parameterAnnotations, modifierList ?: createEmptyModifierListStub(parameterStub))
}
}
createTypeReferenceStub(parameterStub, typeProto)
}
}
fun createTypeParameterListStub(
parent: StubElement<out PsiElement>,
typeParameterProtoList: List<ProtoBuf.TypeParameter>
): List<Pair<Name, Type>> {
if (typeParameterProtoList.isEmpty()) return listOf()
val typeParameterListStub = KotlinPlaceHolderStubImpl<KtTypeParameterList>(parent, KtStubElementTypes.TYPE_PARAMETER_LIST)
val protosForTypeConstraintList = arrayListOf<Pair<Name, Type>>()
for (proto in typeParameterProtoList) {
val name = c.nameResolver.getName(proto.name)
val typeParameterStub = KotlinTypeParameterStubImpl(
typeParameterListStub,
name = name.ref(),
isInVariance = proto.variance == Variance.IN,
isOutVariance = proto.variance == Variance.OUT
)
createTypeParameterModifierListStub(typeParameterStub, proto)
val upperBoundProtos = proto.upperBounds(c.typeTable)
if (upperBoundProtos.isNotEmpty()) {
val upperBound = upperBoundProtos.first()
if (!upperBound.isDefaultUpperBound()) {
createTypeReferenceStub(typeParameterStub, upperBound)
}
protosForTypeConstraintList.addAll(upperBoundProtos.drop(1).map { Pair(name, it) })
}
}
return protosForTypeConstraintList
}
fun createTypeConstraintListStub(
parent: StubElement<out PsiElement>,
protosForTypeConstraintList: List<Pair<Name, Type>>
) {
if (protosForTypeConstraintList.isEmpty()) {
return
}
val typeConstraintListStub = KotlinPlaceHolderStubImpl<KtTypeConstraintList>(parent, KtStubElementTypes.TYPE_CONSTRAINT_LIST)
for ((name, type) in protosForTypeConstraintList) {
val typeConstraintStub = KotlinPlaceHolderStubImpl<KtTypeConstraint>(typeConstraintListStub, KtStubElementTypes.TYPE_CONSTRAINT)
KotlinNameReferenceExpressionStubImpl(typeConstraintStub, name.ref())
createTypeReferenceStub(typeConstraintStub, type)
}
}
private fun createTypeParameterModifierListStub(
typeParameterStub: KotlinTypeParameterStubImpl,
typeParameterProto: ProtoBuf.TypeParameter
) {
val modifiers = ArrayList<KtModifierKeywordToken>()
when (typeParameterProto.variance) {
Variance.IN -> modifiers.add(KtTokens.IN_KEYWORD)
Variance.OUT -> modifiers.add(KtTokens.OUT_KEYWORD)
Variance.INV -> { /* do nothing */
}
null -> { /* do nothing */
}
}
if (typeParameterProto.reified) {
modifiers.add(KtTokens.REIFIED_KEYWORD)
}
val modifierList = createModifierListStub(typeParameterStub, modifiers)
val annotations = c.components.annotationLoader.loadTypeParameterAnnotations(typeParameterProto, c.nameResolver)
if (annotations.isNotEmpty()) {
createAnnotationStubs(
annotations,
modifierList ?: createEmptyModifierListStub(typeParameterStub)
)
}
}
private fun Type.isDefaultUpperBound(): Boolean {
return this.hasClassName() &&
c.nameResolver.getClassId(className).let { StandardNames.FqNames.any == it.asSingleFqName().toUnsafe() } &&
this.nullable
}
}
@@ -0,0 +1,232 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.psi.stubs.builder
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.util.io.StringRef
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.psi.stubs.builder.flags.FlagsToModifiers
import org.jetbrains.kotlin.idea.stubindex.KotlinFileStubForIde
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.load.kotlin.JvmPackagePartSource
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
import org.jetbrains.kotlin.metadata.ProtoBuf
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.protobuf.MessageLite
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub
import org.jetbrains.kotlin.psi.stubs.builder.*
import org.jetbrains.kotlin.psi.stubs.elements.KtStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.*
import org.jetbrains.kotlin.resolve.jvm.JvmClassName
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
fun createTopLevelClassStub(
classId: ClassId,
classProto: ProtoBuf.Class,
source: SourceElement?,
context: ClsStubBuilderContext,
isScript: Boolean
): KotlinFileStubImpl {
val fileStub = createFileStub(classId.packageFqName, isScript)
createClassStub(fileStub, classProto, context.nameResolver, classId, source, context)
return fileStub
}
fun createPackageFacadeStub(
packageProto: ProtoBuf.Package,
packageFqName: FqName,
c: ClsStubBuilderContext
): KotlinFileStubImpl {
val fileStub = KotlinFileStubForIde.forFile(packageFqName, isScript = false)
setupFileStub(fileStub, packageFqName)
createPackageDeclarationsStubs(
fileStub, c, ProtoContainer.Package(packageFqName, c.nameResolver, c.typeTable, source = null), packageProto
)
return fileStub
}
fun createFileFacadeStub(
packageProto: ProtoBuf.Package,
facadeFqName: FqName,
c: ClsStubBuilderContext
): KotlinFileStubImpl {
val packageFqName = facadeFqName.parent()
val fileStub = KotlinFileStubForIde.forFileFacadeStub(facadeFqName)
setupFileStub(fileStub, packageFqName)
val container = ProtoContainer.Package(
packageFqName, c.nameResolver, c.typeTable,
JvmPackagePartSource(JvmClassName.byClassId(ClassId.topLevel(facadeFqName)), null, packageProto, c.nameResolver)
)
createPackageDeclarationsStubs(fileStub, c, container, packageProto)
return fileStub
}
fun createMultifileClassStub(
header: KotlinClassHeader,
partFiles: List<KotlinJvmBinaryClass>,
facadeFqName: FqName,
components: ClsStubBuilderComponents
): KotlinFileStubImpl {
val packageFqName = header.packageName?.let { FqName(it) } ?: facadeFqName.parent()
val partNames = header.data?.asList()?.map { it.substringAfterLast('/') }
val fileStub = KotlinFileStubForIde.forMultifileClassStub(facadeFqName, partNames)
setupFileStub(fileStub, packageFqName)
for (partFile in partFiles) {
val partHeader = partFile.classHeader
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(partHeader.data!!, partHeader.strings!!)
val partContext = components.createContext(nameResolver, packageFqName, TypeTable(packageProto.typeTable))
val container = ProtoContainer.Package(
packageFqName, partContext.nameResolver, partContext.typeTable,
JvmPackagePartSource(partFile, packageProto, nameResolver)
)
createPackageDeclarationsStubs(fileStub, partContext, container, packageProto)
}
return fileStub
}
fun createIncompatibleAbiVersionFileStub() = createFileStub(FqName.ROOT, isScript = false)
fun createFileStub(packageFqName: FqName, isScript: Boolean): KotlinFileStubImpl {
val fileStub = KotlinFileStubForIde.forFile(packageFqName, isScript)
setupFileStub(fileStub, packageFqName)
return fileStub
}
private fun setupFileStub(fileStub: KotlinFileStubImpl, packageFqName: FqName) {
val packageDirectiveStub = KotlinPlaceHolderStubImpl<KtPackageDirective>(fileStub, KtStubElementTypes.PACKAGE_DIRECTIVE)
createStubForPackageName(packageDirectiveStub, packageFqName)
KotlinPlaceHolderStubImpl<KtImportList>(fileStub, KtStubElementTypes.IMPORT_LIST)
}
fun createStubForPackageName(packageDirectiveStub: KotlinPlaceHolderStubImpl<KtPackageDirective>, packageFqName: FqName) {
val segments = packageFqName.pathSegments()
val iterator = segments.listIterator(segments.size)
fun recCreateStubForPackageName(current: StubElement<out PsiElement>) {
when (iterator.previousIndex()) {
-1 -> return
0 -> {
KotlinNameReferenceExpressionStubImpl(current, iterator.previous().ref())
return
}
else -> {
val lastSegment = iterator.previous()
val receiver = KotlinPlaceHolderStubImpl<KtDotQualifiedExpression>(current, KtStubElementTypes.DOT_QUALIFIED_EXPRESSION)
recCreateStubForPackageName(receiver)
KotlinNameReferenceExpressionStubImpl(receiver, lastSegment.ref())
}
}
}
recCreateStubForPackageName(packageDirectiveStub)
}
fun createStubForTypeName(
typeClassId: ClassId,
parent: StubElement<out PsiElement>,
bindTypeArguments: (KotlinUserTypeStub, Int) -> Unit = { _, _ -> }
): KotlinUserTypeStub {
val substituteWithAny = typeClassId.isLocal
val fqName = if (substituteWithAny) StandardNames.FqNames.any
else typeClassId.asSingleFqName().toUnsafe()
val segments = fqName.pathSegments().asReversed()
assert(segments.isNotEmpty())
fun recCreateStubForType(current: StubElement<out PsiElement>, level: Int): KotlinUserTypeStub {
val lastSegment = segments[level]
val userTypeStub = KotlinUserTypeStubImpl(current)
if (level + 1 < segments.size) {
recCreateStubForType(userTypeStub, level + 1)
}
KotlinNameReferenceExpressionStubImpl(userTypeStub, lastSegment.ref())
if (!substituteWithAny) {
bindTypeArguments(userTypeStub, level)
}
return userTypeStub
}
return recCreateStubForType(parent, level = 0)
}
fun createModifierListStubForDeclaration(
parent: StubElement<out PsiElement>,
flags: Int,
flagsToTranslate: List<FlagsToModifiers> = listOf(),
additionalModifiers: List<KtModifierKeywordToken> = listOf()
): KotlinModifierListStubImpl {
assert(flagsToTranslate.isNotEmpty())
val modifiers = flagsToTranslate.mapNotNull { it.getModifiers(flags) } + additionalModifiers
return createModifierListStub(parent, modifiers)!!
}
fun createModifierListStub(
parent: StubElement<out PsiElement>,
modifiers: Collection<KtModifierKeywordToken>
): KotlinModifierListStubImpl? {
if (modifiers.isEmpty()) {
return null
}
return KotlinModifierListStubImpl(
parent,
ModifierMaskUtils.computeMask { it in modifiers },
KtStubElementTypes.MODIFIER_LIST
)
}
fun createEmptyModifierListStub(parent: KotlinStubBaseImpl<*>): KotlinModifierListStubImpl {
return KotlinModifierListStubImpl(
parent,
ModifierMaskUtils.computeMask { false },
KtStubElementTypes.MODIFIER_LIST
)
}
fun createAnnotationStubs(annotationIds: List<ClassId>, parent: KotlinStubBaseImpl<*>) {
return createTargetedAnnotationStubs(annotationIds.map { ClassIdWithTarget(it, null) }, parent)
}
fun createTargetedAnnotationStubs(
annotationIds: List<ClassIdWithTarget>,
parent: KotlinStubBaseImpl<*>
) {
if (annotationIds.isEmpty()) return
annotationIds.forEach { annotation ->
val (annotationClassId, target) = annotation
val annotationEntryStubImpl = KotlinAnnotationEntryStubImpl(
parent,
shortName = annotationClassId.shortClassName.ref(),
hasValueArguments = false
)
if (target != null) {
KotlinAnnotationUseSiteTargetStubImpl(annotationEntryStubImpl, StringRef.fromString(target.name)!!)
}
val constructorCallee =
KotlinPlaceHolderStubImpl<KtConstructorCalleeExpression>(annotationEntryStubImpl, KtStubElementTypes.CONSTRUCTOR_CALLEE)
val typeReference = KotlinPlaceHolderStubImpl<KtTypeReference>(constructorCallee, KtStubElementTypes.TYPE_REFERENCE)
createStubForTypeName(annotationClassId, typeReference)
}
}
val MessageLite.annotatedCallableKind: AnnotatedCallableKind
get() = when (this) {
is ProtoBuf.Property -> AnnotatedCallableKind.PROPERTY
is ProtoBuf.Function, is ProtoBuf.Constructor -> AnnotatedCallableKind.FUNCTION
else -> throw IllegalStateException("Unsupported message: $this")
}
fun Name.ref() = StringRef.fromString(this.asString())!!
fun FqName.ref() = StringRef.fromString(this.asString())!!
@@ -0,0 +1,65 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.psi.stubs.builder.flags
import org.jetbrains.kotlin.lexer.KtModifierKeywordToken
import org.jetbrains.kotlin.lexer.KtToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
abstract class FlagsToModifiers {
abstract fun getModifiers(flags: Int): KtModifierKeywordToken?
}
val MODALITY: FlagsToModifiers = object : FlagsToModifiers() {
override fun getModifiers(flags: Int): KtModifierKeywordToken {
val modality = Flags.MODALITY.get(flags)
return when (modality) {
ProtoBuf.Modality.ABSTRACT -> KtTokens.ABSTRACT_KEYWORD
ProtoBuf.Modality.FINAL -> KtTokens.FINAL_KEYWORD
ProtoBuf.Modality.OPEN -> KtTokens.OPEN_KEYWORD
ProtoBuf.Modality.SEALED -> KtTokens.SEALED_KEYWORD
null -> throw IllegalStateException("Unexpected modality: null")
}
}
}
val VISIBILITY: FlagsToModifiers = object : FlagsToModifiers() {
override fun getModifiers(flags: Int): KtModifierKeywordToken? {
val visibility = Flags.VISIBILITY.get(flags)
return when (visibility) {
ProtoBuf.Visibility.PRIVATE, ProtoBuf.Visibility.PRIVATE_TO_THIS -> KtTokens.PRIVATE_KEYWORD
ProtoBuf.Visibility.INTERNAL -> KtTokens.INTERNAL_KEYWORD
ProtoBuf.Visibility.PROTECTED -> KtTokens.PROTECTED_KEYWORD
ProtoBuf.Visibility.PUBLIC -> KtTokens.PUBLIC_KEYWORD
else -> throw IllegalStateException("Unexpected visibility: $visibility")
}
}
}
val INNER = createBooleanFlagToModifier(Flags.IS_INNER, KtTokens.INNER_KEYWORD)
val CONST = createBooleanFlagToModifier(Flags.IS_CONST, KtTokens.CONST_KEYWORD)
val LATEINIT = createBooleanFlagToModifier(Flags.IS_LATEINIT, KtTokens.LATEINIT_KEYWORD)
val OPERATOR = createBooleanFlagToModifier(Flags.IS_OPERATOR, KtTokens.OPERATOR_KEYWORD)
val INFIX = createBooleanFlagToModifier(Flags.IS_INFIX, KtTokens.INFIX_KEYWORD)
val DATA = createBooleanFlagToModifier(Flags.IS_DATA, KtTokens.DATA_KEYWORD)
val EXTERNAL_FUN = createBooleanFlagToModifier(Flags.IS_EXTERNAL_FUNCTION, KtTokens.EXTERNAL_KEYWORD)
val EXTERNAL_PROPERTY = createBooleanFlagToModifier(Flags.IS_EXTERNAL_PROPERTY, KtTokens.EXTERNAL_KEYWORD)
val EXTERNAL_CLASS = createBooleanFlagToModifier(Flags.IS_EXTERNAL_CLASS, KtTokens.EXTERNAL_KEYWORD)
val INLINE = createBooleanFlagToModifier(Flags.IS_INLINE, KtTokens.INLINE_KEYWORD)
val VALUE_CLASS = createBooleanFlagToModifier(Flags.IS_INLINE_CLASS, KtTokens.VALUE_KEYWORD)
val FUN_INTERFACE = createBooleanFlagToModifier(Flags.IS_FUN_INTERFACE, KtTokens.FUN_KEYWORD)
val TAILREC = createBooleanFlagToModifier(Flags.IS_TAILREC, KtTokens.TAILREC_KEYWORD)
val SUSPEND = createBooleanFlagToModifier(Flags.IS_SUSPEND, KtTokens.SUSPEND_KEYWORD)
private fun createBooleanFlagToModifier(
flagField: Flags.BooleanFlagField, ktModifierKeywordToken: KtModifierKeywordToken
): FlagsToModifiers = BooleanFlagToModifier(flagField, ktModifierKeywordToken)
private class BooleanFlagToModifier(
private val flagField: Flags.BooleanFlagField,
private val ktModifierKeywordToken: KtModifierKeywordToken
) : FlagsToModifiers() {
override fun getModifiers(flags: Int): KtModifierKeywordToken? = if (flagField.get(flags)) ktModifierKeywordToken else null
}
@@ -0,0 +1,50 @@
// Copyright 2000-2021 JetBrains s.r.o. and contributors. Use of this source code is governed by the Apache 2.0 license that can be found in the LICENSE file.
package org.jetbrains.kotlin.psi.stubs.builder
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.psi.stubs.builder.flags.VISIBILITY
import org.jetbrains.kotlin.metadata.ProtoBuf
import org.jetbrains.kotlin.metadata.deserialization.Flags
import org.jetbrains.kotlin.metadata.deserialization.underlyingType
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.psi.stubs.impl.KotlinTypeAliasStubImpl
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.deserialization.getClassId
import org.jetbrains.kotlin.serialization.deserialization.getName
fun createTypeAliasStub(
parent: StubElement<out PsiElement>,
typeAliasProto: ProtoBuf.TypeAlias,
protoContainer: ProtoContainer,
outerContext: ClsStubBuilderContext
) {
val c = outerContext.child(typeAliasProto.typeParameterList)
val shortName = c.nameResolver.getName(typeAliasProto.name)
val classId = when (protoContainer) {
is ProtoContainer.Class -> protoContainer.classId.createNestedClassId(shortName)
is ProtoContainer.Package -> ClassId.topLevel(protoContainer.fqName.child(shortName))
}
val typeAlias = KotlinTypeAliasStubImpl(
parent, classId.shortClassName.ref(), classId.asSingleFqName().ref(), classId,
isTopLevel = !classId.isNestedClass
)
val modifierList = createModifierListStubForDeclaration(typeAlias, typeAliasProto.flags, arrayListOf(VISIBILITY), listOf())
val typeStubBuilder = TypeClsStubBuilder(c)
val restConstraints = typeStubBuilder.createTypeParameterListStub(typeAlias, typeAliasProto.typeParameterList)
assert(restConstraints.isEmpty()) {
"'where' constraints are not allowed for type aliases"
}
if (Flags.HAS_ANNOTATIONS.get(typeAliasProto.flags)) {
createAnnotationStubs(typeAliasProto.annotationList.map { c.nameResolver.getClassId(it.id) }, modifierList)
}
val typeAliasUnderlyingType = typeAliasProto.underlyingType(c.typeTable)
typeStubBuilder.createTypeReferenceStub(typeAlias, typeAliasUnderlyingType)
}
+4 -1
View File
@@ -112,7 +112,6 @@ include ":benchmarks",
":compiler:resolution.common.jvm",
":compiler:resolution",
":compiler:serialization",
":compiler:psi",
":compiler:visualizer",
":compiler:visualizer:common",
":compiler:visualizer:render-fir",
@@ -292,6 +291,10 @@ include ":benchmarks",
":kotlin-serialization-unshaded",
":wasm:wasm.ir"
include ":compiler:psi",
":compiler:psi:cls-psi-stub-builder"
include ":kotlinx-atomicfu-compiler-plugin",
":kotlinx-atomicfu-runtime",
":atomicfu"