Support new protobuf messages in cls stub builder

This commit is contained in:
Alexander Udalov
2015-10-05 10:50:59 +03:00
parent a44f74ea20
commit e02854db6d
4 changed files with 157 additions and 80 deletions
@@ -16,61 +16,111 @@
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
import com.google.protobuf.MessageLite
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.idea.decompiler.stubBuilder.FlagsToModifiers.*
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.KotlinClassStubImpl
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.dataClassUtils.isComponentLike
import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.ProtoBuf.CallableKind
import org.jetbrains.kotlin.serialization.ProtoBuf.MemberKind
import org.jetbrains.kotlin.serialization.ProtoBuf.Modality
import org.jetbrains.kotlin.serialization.deserialization.NameResolver
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
fun createCallableStub(
fun createCallableStubs(
parentStub: StubElement<out PsiElement>,
callableProto: ProtoBuf.Callable,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer
protoContainer: ProtoContainer,
functionProtos: List<ProtoBuf.Function>,
propertyProtos: List<ProtoBuf.Property>
) {
if (!shouldSkip(callableProto, outerContext.nameResolver)) {
CallableClsStubBuilder(parentStub, callableProto, outerContext, protoContainer).build()
for (propertyProto in propertyProtos) {
if (!shouldSkip(propertyProto.flags, outerContext.nameResolver.getName(propertyProto.name))) {
CallableClsStubBuilder(parentStub, propertyProto, outerContext, protoContainer).build()
}
}
for (functionProto in functionProtos) {
if (!shouldSkip(functionProto.flags, outerContext.nameResolver.getName(functionProto.name))) {
CallableClsStubBuilder(parentStub, functionProto, outerContext, protoContainer).build()
}
}
}
private fun shouldSkip(callableProto: ProtoBuf.Callable, nameResolver: NameResolver): Boolean {
val memberKind = Flags.MEMBER_KIND[callableProto.getFlags()]
return when (memberKind) {
fun createConstructorStub(
parentStub: StubElement<out PsiElement>,
constructorProto: ProtoBuf.Constructor,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer
) {
ConstructorClsStubBuilder(parentStub, constructorProto, outerContext, protoContainer).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 -> !isComponentLike(nameResolver.getName(callableProto.getName()))
MemberKind.SYNTHESIZED -> !isComponentLike(name)
else -> false
}
}
private class CallableClsStubBuilder(
private class CallableClsStubBuilder private constructor(
private val parent: StubElement<out PsiElement>,
private val callableProto: ProtoBuf.Callable,
private val callableProto: MessageLite,
outerContext: ClsStubBuilderContext,
private val protoContainer: ProtoContainer
private val protoContainer: ProtoContainer,
private val callableKind: CallableClsStubBuilder.CallableKind,
private val nameIndex: Int,
private val typeParameterList: List<ProtoBuf.TypeParameter>,
private val valueParameterList: List<ProtoBuf.ValueParameter>,
private val receiverType: ProtoBuf.Type?,
private val returnType: ProtoBuf.Type?,
private val flags: Int
) {
private val c = outerContext.child(callableProto.getTypeParameterList())
private val c = outerContext.child(typeParameterList)
private val typeStubBuilder = TypeClsStubBuilder(c)
private val isTopLevel: Boolean get() = protoContainer.packageFqName != null
private val callableKind = Flags.CALLABLE_KIND[callableProto.getFlags()]
private val isConstructor = callableKind == CallableKind.CONSTRUCTOR
private val isPrimaryConstructor = isConstructor && parent is KotlinClassStubImpl
private val callableStub = doCreateCallableStub()
enum class CallableKind {
FUN, VAL, VAR
}
constructor(
parent: StubElement<out PsiElement>,
functionProto: ProtoBuf.Function,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer
) : this(
parent, functionProto, outerContext, protoContainer, CallableKind.FUN,
functionProto.name, functionProto.typeParameterList, functionProto.valueParameterList,
if (functionProto.hasReceiverType()) functionProto.receiverType else null,
if (functionProto.hasReturnType()) functionProto.returnType else null,
functionProto.flags
)
constructor(
parent: StubElement<out PsiElement>,
propertyProto: ProtoBuf.Property,
outerContext: ClsStubBuilderContext,
protoContainer: ProtoContainer
) : this(
parent, propertyProto, outerContext, protoContainer,
if (Flags.IS_VAR.get(propertyProto.flags)) CallableKind.VAR else CallableKind.VAL,
propertyProto.name, propertyProto.typeParameterList, emptyList(),
if (propertyProto.hasReceiverType()) propertyProto.receiverType else null,
if (propertyProto.hasReturnType()) propertyProto.returnType else null,
propertyProto.flags
)
fun build() {
createModifierListStub()
val typeParameterList = if (isConstructor) emptyList() else callableProto.getTypeParameterList()
val typeConstraintListData = typeStubBuilder.createTypeParameterListStub(callableStub, typeParameterList)
createReceiverTypeReferenceStub()
createValueParameterList()
@@ -79,23 +129,25 @@ private class CallableClsStubBuilder(
}
private fun createValueParameterList() {
typeStubBuilder.createValueParameterListStub(callableStub, callableProto, protoContainer)
if (callableKind == CallableKind.FUN) {
typeStubBuilder.createValueParameterListStub(callableStub, callableProto, valueParameterList, protoContainer)
}
}
private fun createReceiverTypeReferenceStub() {
if (callableProto.hasReceiverType()) {
typeStubBuilder.createTypeReferenceStub(callableStub, callableProto.getReceiverType())
if (receiverType != null) {
typeStubBuilder.createTypeReferenceStub(callableStub, receiverType)
}
}
private fun createReturnTypeStub() {
if (!isConstructor)
typeStubBuilder.createTypeReferenceStub(callableStub, callableProto.getReturnType())
if (returnType != null) {
typeStubBuilder.createTypeReferenceStub(callableStub, returnType)
}
}
private fun createModifierListStub() {
val isModalityIrrelevant = isTopLevel || isConstructor
val modalityModifiers = if (isModalityIrrelevant) listOf() else listOf(MODALITY)
val modalityModifiers = if (isTopLevel) listOf() else listOf(MODALITY)
val constModifiers = if (callableKind == CallableKind.VAL) listOf(CONST) else listOf()
val additionalModifiers = when (callableKind) {
@@ -105,9 +157,7 @@ private class CallableClsStubBuilder(
}
val relevantModifiers = listOf(VISIBILITY) + constModifiers + modalityModifiers + additionalModifiers
val modifierListStubImpl = createModifierListStubForDeclaration(
callableStub, callableProto.getFlags(), relevantModifiers
)
val modifierListStubImpl = createModifierListStubForDeclaration(callableStub, flags, relevantModifiers)
val kind = callableProto.annotatedCallableKind
val annotationIds = c.components.annotationLoader.loadCallableAnnotations(protoContainer, callableProto, kind)
@@ -115,7 +165,7 @@ private class CallableClsStubBuilder(
}
private fun doCreateCallableStub(): StubElement<out PsiElement> {
val callableName = c.nameResolver.getName(callableProto.getName())
val callableName = c.nameResolver.getName(nameIndex)
return when (callableKind) {
CallableKind.FUN -> {
@@ -124,10 +174,10 @@ private class CallableClsStubBuilder(
callableName.ref(),
isTopLevel,
c.containerFqName.child(callableName),
isExtension = callableProto.hasReceiverType(),
isExtension = receiverType != null,
hasBlockBody = true,
hasBody = Flags.MODALITY[callableProto.getFlags()] != Modality.ABSTRACT,
hasTypeParameterListBeforeFunctionName = callableProto.getTypeParameterList().isNotEmpty()
hasBody = Flags.MODALITY.get(flags) != Modality.ABSTRACT,
hasTypeParameterListBeforeFunctionName = typeParameterList.isNotEmpty()
)
}
CallableKind.VAL, CallableKind.VAR -> {
@@ -139,18 +189,48 @@ private class CallableClsStubBuilder(
hasDelegate = false,
hasDelegateExpression = false,
hasInitializer = false,
isExtension = callableProto.hasReceiverType(),
isExtension = receiverType != null,
hasReturnTypeRef = true,
fqName = c.containerFqName.child(callableName)
)
}
CallableKind.CONSTRUCTOR -> {
if (isPrimaryConstructor)
KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.PRIMARY_CONSTRUCTOR)
else
KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.SECONDARY_CONSTRUCTOR)
}
else -> throw IllegalStateException("Unknown callable kind $callableKind")
}
}
}
private class ConstructorClsStubBuilder(
private val parent: StubElement<out PsiElement>,
private val constructorProto: ProtoBuf.Constructor,
outerContext: ClsStubBuilderContext,
private val protoContainer: ProtoContainer
) {
private val c = outerContext.child(emptyList())
private val typeStubBuilder = TypeClsStubBuilder(c)
private val callableStub = doCreateCallableStub()
fun build() {
createModifierListStub()
createValueParameterList()
}
private fun createValueParameterList() {
typeStubBuilder.createValueParameterListStub(callableStub, constructorProto, constructorProto.valueParameterList, protoContainer)
}
private fun createModifierListStub() {
val modifierListStubImpl = createModifierListStubForDeclaration(callableStub, constructorProto.flags, listOf(VISIBILITY))
val annotationIds = c.components.annotationLoader.loadCallableAnnotations(
protoContainer, constructorProto, AnnotatedCallableKind.FUNCTION
)
createTargetedAnnotationStubs(annotationIds, modifierListStubImpl)
}
private fun doCreateCallableStub(): StubElement<out PsiElement> {
return if (Flags.IS_SECONDARY.get(constructorProto.flags))
KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.SECONDARY_CONSTRUCTOR)
else
KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.PRIMARY_CONSTRUCTOR)
}
}
@@ -129,12 +129,11 @@ private class ClassClsStubBuilder(
}
private fun createConstructorStub() {
if (!isClass() || !classProto.hasPrimaryConstructor()) return
val primaryConstructorProto = classProto.getPrimaryConstructor()
if (!isClass()) return
assert(classProto.getPrimaryConstructor().hasData()) { "Primary constructor in class is always non-default, so data should not be empty" }
val primaryConstructorProto = classProto.constructorList.find { !Flags.IS_SECONDARY.get(it.flags) } ?: return
createCallableStub(classOrObjectStub, primaryConstructorProto.getData(), c, ProtoContainer(classProto, null, c.nameResolver))
createConstructorStub(classOrObjectStub, primaryConstructorProto, c, ProtoContainer(classProto, null, c.nameResolver))
}
private fun createDelegationSpecifierList() {
@@ -188,10 +187,14 @@ private class ClassClsStubBuilder(
private fun createCallableMemberStubs(classBody: KotlinPlaceHolderStubImpl<JetClassBody>) {
val container = ProtoContainer(classProto, null, c.nameResolver)
val allMembers = classProto.getSecondaryConstructorList() + classProto.getMemberList()
for (callableProto in allMembers) {
createCallableStub(classBody, callableProto, c, container)
for (secondaryConstructorProto in classProto.constructorList) {
if (Flags.IS_SECONDARY.get(secondaryConstructorProto.flags)) {
createConstructorStub(classBody, secondaryConstructorProto, c, container)
}
}
createCallableStubs(classBody, c, container, classProto.functionList, classProto.propertyList)
}
private fun isClass(): Boolean {
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
import com.google.protobuf.MessageLite
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
@@ -29,9 +30,7 @@ import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.stubs.KotlinUserTypeStub
import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.*
import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.ProtoBuf.CallableKind
import org.jetbrains.kotlin.serialization.ProtoBuf.Type
import org.jetbrains.kotlin.serialization.ProtoBuf.Type.Argument.Projection
import org.jetbrains.kotlin.serialization.ProtoBuf.TypeParameter.Variance
@@ -138,13 +137,14 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) {
createTypeReferenceStub(functionType, returnType)
}
fun createValueParameterListStub(parent: StubElement<out PsiElement>, callableProto: ProtoBuf.Callable, container: ProtoContainer) {
val callableKind = Flags.CALLABLE_KIND[callableProto.flags]
if (callableKind == CallableKind.VAL || callableKind == CallableKind.VAR) {
return
}
fun createValueParameterListStub(
parent: StubElement<out PsiElement>,
callableProto: MessageLite,
parameters: List<ProtoBuf.ValueParameter>,
container: ProtoContainer
) {
val parameterListStub = KotlinPlaceHolderStubImpl<JetParameterList>(parent, JetStubElementTypes.VALUE_PARAMETER_LIST)
for ((index, valueParameterProto) in callableProto.valueParameterList.withIndex()) {
for ((index, valueParameterProto) in parameters.withIndex()) {
val name = c.nameResolver.getName(valueParameterProto.name)
val parameterStub = KotlinParameterStubImpl(
parameterListStub,
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.idea.decompiler.stubBuilder
import com.google.protobuf.MessageLite
import com.intellij.psi.PsiElement
import com.intellij.psi.stubs.StubElement
import com.intellij.util.io.StringRef
@@ -33,7 +34,6 @@ import org.jetbrains.kotlin.psi.stubs.elements.JetStubElementTypes
import org.jetbrains.kotlin.psi.stubs.impl.*
import org.jetbrains.kotlin.serialization.Flags
import org.jetbrains.kotlin.serialization.ProtoBuf
import org.jetbrains.kotlin.serialization.ProtoBuf.CallableKind
import org.jetbrains.kotlin.serialization.deserialization.AnnotatedCallableKind
import org.jetbrains.kotlin.serialization.deserialization.ProtoContainer
import org.jetbrains.kotlin.serialization.jvm.JvmProtoBufUtil
@@ -51,10 +51,8 @@ fun createPackageFacadeStub(
): KotlinFileStubImpl {
val fileStub = KotlinFileStubForIde.forFile(packageFqName, packageFqName.isRoot)
setupFileStub(fileStub, packageFqName)
val container = ProtoContainer(null, packageFqName, c.nameResolver)
for (callableProto in packageProto.getMemberList()) {
createCallableStub(fileStub, callableProto, c, container)
}
createCallableStubs(fileStub, c, ProtoContainer(null, packageFqName, c.nameResolver),
packageProto.functionList, packageProto.propertyList)
return fileStub
}
@@ -66,10 +64,8 @@ fun createFileFacadeStub(
val packageFqName = facadeFqName.parent()
val fileStub = KotlinFileStubForIde.forFileFacadeStub(facadeFqName, packageFqName.isRoot)
setupFileStub(fileStub, packageFqName)
val container = ProtoContainer(null, facadeFqName.parent(), c.nameResolver)
for (callableProto in packageProto.getMemberList()) {
createCallableStub(fileStub, callableProto, c, container)
}
createCallableStubs(fileStub, c, ProtoContainer(null, packageFqName, c.nameResolver),
packageProto.functionList, packageProto.propertyList)
return fileStub
}
@@ -85,11 +81,10 @@ fun createMultifileClassStub(
setupFileStub(fileStub, packageFqName)
for (partFile in partFiles) {
val partHeader = partFile.classHeader
val partData = JvmProtoBufUtil.readPackageDataFrom(partHeader.annotationData!!, partHeader.strings!!)
val partContext = components.createContext(partData.nameResolver, packageFqName)
for (partMember in partData.packageProto.memberList) {
createCallableStub(fileStub, partMember, partContext, ProtoContainer(null, packageFqName, partContext.nameResolver))
}
val (nameResolver, packageProto) = JvmProtoBufUtil.readPackageDataFrom(partHeader.annotationData!!, partHeader.strings!!)
val partContext = components.createContext(nameResolver, packageFqName)
createCallableStubs(fileStub, partContext, ProtoContainer(null, packageFqName, partContext.nameResolver),
packageProto.functionList, packageProto.propertyList)
}
return fileStub
}
@@ -187,25 +182,25 @@ enum class FlagsToModifiers {
CONST {
override fun getModifiers(flags: Int): JetModifierKeywordToken? {
return if (Flags.OLD_IS_CONST.get(flags)) JetTokens.CONST_KEYWORD else null
return if (Flags.IS_CONST.get(flags)) JetTokens.CONST_KEYWORD else null
}
},
LATEINIT {
override fun getModifiers(flags: Int): JetModifierKeywordToken? {
return if (Flags.OLD_LATE_INIT.get(flags)) JetTokens.LATE_INIT_KEYWORD else null
return if (Flags.LATE_INIT.get(flags)) JetTokens.LATE_INIT_KEYWORD else null
}
},
OPERATOR {
override fun getModifiers(flags: Int): JetModifierKeywordToken? {
return if (Flags.OLD_IS_OPERATOR.get(flags)) JetTokens.OPERATOR_KEYWORD else null
return if (Flags.IS_OPERATOR.get(flags)) JetTokens.OPERATOR_KEYWORD else null
}
},
INFIX {
override fun getModifiers(flags: Int): JetModifierKeywordToken? {
return if (Flags.OLD_IS_INFIX.get(flags)) JetTokens.INFIX_KEYWORD else null
return if (Flags.IS_INFIX.get(flags)) JetTokens.INFIX_KEYWORD else null
}
};
@@ -264,13 +259,12 @@ fun createTargetedAnnotationStubs(
}
}
val ProtoBuf.Callable.annotatedCallableKind: AnnotatedCallableKind
val MessageLite.annotatedCallableKind: AnnotatedCallableKind
get() {
val callableKind = Flags.CALLABLE_KIND[getFlags()]
return when (callableKind) {
CallableKind.VAL, CallableKind.VAR -> AnnotatedCallableKind.PROPERTY
CallableKind.FUN, CallableKind.CONSTRUCTOR -> AnnotatedCallableKind.FUNCTION
else -> throw IllegalStateException("Unsupported callable kind: ${callableKind}")
return when (this) {
is ProtoBuf.Property -> AnnotatedCallableKind.PROPERTY
is ProtoBuf.Function, is ProtoBuf.Constructor -> AnnotatedCallableKind.FUNCTION
else -> throw IllegalStateException("Unsupported message: $this")
}
}