From e02854db6db1ab51890d69df80792fcde15b82bb Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 5 Oct 2015 10:50:59 +0300 Subject: [PATCH] Support new protobuf messages in cls stub builder --- .../stubBuilder/CallableClsStubBuilder.kt | 162 +++++++++++++----- .../stubBuilder/ClassClsStubBuilder.kt | 17 +- .../stubBuilder/TypeClsStubBuilder.kt | 16 +- .../decompiler/stubBuilder/clsStubBuilding.kt | 42 ++--- 4 files changed, 157 insertions(+), 80 deletions(-) diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/CallableClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/CallableClsStubBuilder.kt index 004efa98160..6f977e9cb95 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/CallableClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/CallableClsStubBuilder.kt @@ -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, - callableProto: ProtoBuf.Callable, outerContext: ClsStubBuilderContext, - protoContainer: ProtoContainer + protoContainer: ProtoContainer, + functionProtos: List, + propertyProtos: List ) { - 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, + 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, - 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, + private val valueParameterList: List, + 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, + 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, + 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 { - 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, + 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 { + return if (Flags.IS_SECONDARY.get(constructorProto.flags)) + KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.SECONDARY_CONSTRUCTOR) + else + KotlinPlaceHolderStubImpl(parent, JetStubElementTypes.PRIMARY_CONSTRUCTOR) + } +} diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt index 3904036a216..6ddb7c866c4 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/ClassClsStubBuilder.kt @@ -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) { 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 { diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt index 6450a4c30c1..0b3c8926ee8 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/TypeClsStubBuilder.kt @@ -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, callableProto: ProtoBuf.Callable, container: ProtoContainer) { - val callableKind = Flags.CALLABLE_KIND[callableProto.flags] - if (callableKind == CallableKind.VAL || callableKind == CallableKind.VAR) { - return - } + fun createValueParameterListStub( + parent: StubElement, + callableProto: MessageLite, + parameters: List, + container: ProtoContainer + ) { val parameterListStub = KotlinPlaceHolderStubImpl(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, diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt index 7f79e29650f..ac4065ee710 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/stubBuilder/clsStubBuilding.kt @@ -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") } }