diff --git a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/KtFileElementType.java b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/KtFileElementType.java index 0962b22ef1b..0bbc9afc7dc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/KtFileElementType.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/psi/stubs/elements/KtFileElementType.java @@ -34,7 +34,7 @@ import org.jetbrains.kotlin.psi.stubs.KotlinFileStub; import java.io.IOException; public class KtFileElementType extends IStubFileElementType { - public static final int STUB_VERSION = 64; + public static final int STUB_VERSION = 65; private static final String NAME = "kotlin.FILE"; diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/common/AnnotationLoaderForStubBuilderImpl.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/common/AnnotationLoaderForStubBuilderImpl.kt index 65cba34a914..5945296070a 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/common/AnnotationLoaderForStubBuilderImpl.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/common/AnnotationLoaderForStubBuilderImpl.kt @@ -52,10 +52,8 @@ public class AnnotationLoaderForStubBuilderImpl( } } - override fun loadEnumEntryAnnotations(container: ProtoContainer, proto: ProtoBuf.EnumEntry): List { - // TODO - return listOf() - } + override fun loadEnumEntryAnnotations(container: ProtoContainer, proto: ProtoBuf.EnumEntry): List = + proto.getExtension(protocol.enumEntryAnnotation).orEmpty().map { container.nameResolver.getClassId(it.id) } override fun loadValueParameterAnnotations( container: ProtoContainer, @@ -64,9 +62,7 @@ public class AnnotationLoaderForStubBuilderImpl( parameterIndex: Int, proto: ProtoBuf.ValueParameter ): List = - proto.getExtension(protocol.parameterAnnotation).orEmpty().map { - container.nameResolver.getClassId(it.id) - } + proto.getExtension(protocol.parameterAnnotation).orEmpty().map { container.nameResolver.getClassId(it.id) } override fun loadExtensionReceiverParameterAnnotations( container: ProtoContainer, 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 7de29d48fc0..a177af8f00b 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 @@ -172,9 +172,22 @@ private class ClassClsStubBuilder( } private fun createEnumEntryStubs(classBody: KotlinPlaceHolderStubImpl) { - classProto.getEnumEntryNameList().forEach { id -> - val name = c.nameResolver.getName(id) - KotlinClassStubImpl( + if (classKind != ProtoBuf.Class.Kind.ENUM_CLASS) return + + val container = ProtoContainer(classProto, null, c.nameResolver, c.typeTable) + val enumEntries: List>> = + if (classProto.enumEntryList.isNotEmpty()) + classProto.enumEntryList.map { enumEntryProto -> + enumEntryProto.name to c.components.annotationLoader.loadEnumEntryAnnotations(container, enumEntryProto) + } + else classProto.enumEntryNameList.map { enumEntryName -> + enumEntryName to listOf() + } + + enumEntries.forEach { entry -> + val name = c.nameResolver.getName(entry.first) + val annotations = entry.second + val enumEntryStub = KotlinClassStubImpl( KtStubElementTypes.ENUM_ENTRY, classBody, qualifiedName = c.containerFqName.child(name).ref(), @@ -185,6 +198,9 @@ private class ClassClsStubBuilder( isLocal = false, isTopLevel = false ) + if (annotations.isNotEmpty()) { + createAnnotationStubs(annotations, createEmptyModifierListStub(enumEntryStub)) + } } } 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 93e614d8809..de99894e434 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 @@ -19,7 +19,6 @@ 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.SmartList import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.lexer.KtModifierKeywordToken import org.jetbrains.kotlin.lexer.KtTokens @@ -175,21 +174,13 @@ class TypeClsStubBuilder(private val c: ClsStubBuilderContext) { container, callableProto, callableProto.annotatedCallableKind, index, valueParameterProto ) if (parameterAnnotations.isNotEmpty()) { - createAnnotationStubs(parameterAnnotations, modifierList ?: createEmptyModifierList(parameterStub)) + createAnnotationStubs(parameterAnnotations, modifierList ?: createEmptyModifierListStub(parameterStub)) } createTypeReferenceStub(parameterStub, typeProto) } } - private fun createEmptyModifierList(parameterStub: KotlinParameterStubImpl): KotlinModifierListStubImpl { - return KotlinModifierListStubImpl( - parameterStub, - ModifierMaskUtils.computeMask { false }, - KtStubElementTypes.MODIFIER_LIST - ) - } - fun createTypeParameterListStub( parent: StubElement, typeParameterProtoList: List 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 1e8dc8d6bbf..f3458fef9dd 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 @@ -262,6 +262,14 @@ fun createModifierListStub( ) } +fun createEmptyModifierListStub(parent: KotlinStubBaseImpl<*>): KotlinModifierListStubImpl { + return KotlinModifierListStubImpl( + parent, + ModifierMaskUtils.computeMask { false }, + KtStubElementTypes.MODIFIER_LIST + ) +} + fun createAnnotationStubs(annotationIds: List, parent: KotlinStubBaseImpl<*>) { return createTargetedAnnotationStubs(annotationIds.map { ClassIdWithTarget(it, null) }, parent) } diff --git a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt index 8944a30ba40..123b63dc3ec 100644 --- a/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt +++ b/idea/idea-analysis/src/org/jetbrains/kotlin/idea/decompiler/textBuilder/DecompiledTextFactory.kt @@ -77,13 +77,19 @@ public fun buildDecompiledText( if (descriptor is MissingDependencyErrorClass) { throw IllegalStateException("${descriptor.javaClass.getSimpleName()} cannot be rendered. FqName: ${descriptor.fullFqName}") } - val startOffset = builder.length() - val header = if (isEnumEntry(descriptor)) - descriptor.name.asString() + if (lastEnumEntry!!) ";" else "," - else - descriptorRenderer.render(descriptor).replace("= ...", DECOMPILED_COMMENT_FOR_PARAMETER) - builder.append(header) - var endOffset = builder.length() + val startOffset = builder.length + if (isEnumEntry(descriptor)) { + for (annotation in descriptor.annotations) { + builder.append(descriptorRenderer.renderAnnotation(annotation)) + builder.append(" ") + } + builder.append(descriptor.name.asString()) + builder.append(if (lastEnumEntry!!) ";" else ",") + } + else { + builder.append(descriptorRenderer.render(descriptor).replace("= ...", DECOMPILED_COMMENT_FOR_PARAMETER)) + } + var endOffset = builder.length if (descriptor is CallableDescriptor) { //NOTE: assuming that only return types can be flexible diff --git a/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry.expected.kt b/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry.expected.kt new file mode 100644 index 00000000000..bbe96ec1bfc --- /dev/null +++ b/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry.expected.kt @@ -0,0 +1,12 @@ +// IntelliJ API Decompiler stub source generated from a class file +// Implementation of methods is not available + +package test + +public final enum class AnnotatedEnumEntry private constructor() : kotlin.Enum { + Entry1, + + @dependency.A @dependency.B Entry2, + + @dependency.A Entry3; +} diff --git a/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/AnnotatedEnumEntry.kt b/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/AnnotatedEnumEntry.kt new file mode 100644 index 00000000000..2b35c489179 --- /dev/null +++ b/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/AnnotatedEnumEntry.kt @@ -0,0 +1,9 @@ +package test + +import dependency.* + +enum class AnnotatedEnumEntry { + Entry1, + @A("2") @B(2) Entry2, + @A("3") Entry3 +} diff --git a/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/Dependency.kt b/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/Dependency.kt new file mode 100644 index 00000000000..46a64bff8de --- /dev/null +++ b/idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/Dependency.kt @@ -0,0 +1,7 @@ +package dependency + +@Target(AnnotationTarget.FIELD) +annotation class A(val s: String) + +@Target(AnnotationTarget.FIELD) +annotation class B(val i: Int) diff --git a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt index fb56700ce11..cae3f43fee6 100644 --- a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt +++ b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.kt @@ -22,6 +22,8 @@ class Nested @a private @b(E.E1) @b(E.E2) constructor() + enum class En { Entry1, @a @b(E.E2) Entry2, @a @c Entry3 } + fun types(param: @a @b(E.E1) LongRange): @a @b(E.E2) Unit {} } @@ -36,4 +38,9 @@ annotation class a @Repeatable annotation class b(val e: E) -enum class E { E1, E2 } \ No newline at end of file +@Target(AnnotationTarget.PROPERTY, AnnotationTarget.VALUE_PARAMETER, AnnotationTarget.FUNCTION, + AnnotationTarget.CONSTRUCTOR, AnnotationTarget.PROPERTY_GETTER, AnnotationTarget.PROPERTY_SETTER, + AnnotationTarget.TYPE, AnnotationTarget.CLASS) +annotation class c + +enum class E { E1, E2 } diff --git a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt index dc61763b9f7..8c99fd45505 100644 --- a/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt +++ b/idea/testData/decompiler/stubBuilder/Annotations/Annotations.txt @@ -172,6 +172,46 @@ PsiJetFileStubImpl[package=] USER_TYPE:[isAbsoluteInRootPackage=false] REFERENCE_EXPRESSION:[referencedName=kotlin] REFERENCE_EXPRESSION:[referencedName=Unit] + CLASS:[fqName=Annotations.En, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=En, superNames=[Enum]] + MODIFIER_LIST:[enum public final] + PRIMARY_CONSTRUCTOR: + MODIFIER_LIST:[private] + VALUE_PARAMETER_LIST: + SUPER_TYPE_LIST: + SUPER_TYPE_ENTRY: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=kotlin] + REFERENCE_EXPRESSION:[referencedName=Enum] + TYPE_ARGUMENT_LIST: + TYPE_PROJECTION:[projectionKind=NONE] + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=Annotations] + REFERENCE_EXPRESSION:[referencedName=En] + CLASS_BODY: + ENUM_ENTRY:[fqName=Annotations.En.Entry1, isEnumEntry=true, isInterface=false, isLocal=false, isTopLevel=false, name=Entry1, superNames=[]] + ENUM_ENTRY:[fqName=Annotations.En.Entry2, isEnumEntry=true, isInterface=false, isLocal=false, isTopLevel=false, name=Entry2, superNames=[]] + MODIFIER_LIST:[] + ANNOTATION_ENTRY:[hasValueArguments=false, shortName=a] + CONSTRUCTOR_CALLEE: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=a] + ENUM_ENTRY:[fqName=Annotations.En.Entry3, isEnumEntry=true, isInterface=false, isLocal=false, isTopLevel=false, name=Entry3, superNames=[]] + MODIFIER_LIST:[] + ANNOTATION_ENTRY:[hasValueArguments=false, shortName=a] + CONSTRUCTOR_CALLEE: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=a] + ANNOTATION_ENTRY:[hasValueArguments=false, shortName=c] + CONSTRUCTOR_CALLEE: + TYPE_REFERENCE: + USER_TYPE:[isAbsoluteInRootPackage=false] + REFERENCE_EXPRESSION:[referencedName=c] CLASS:[fqName=Annotations.Nested, isEnumEntry=false, isInterface=false, isLocal=false, isTopLevel=false, name=Nested, superNames=[]] MODIFIER_LIST:[public final] PRIMARY_CONSTRUCTOR: diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java index 4eed32c5c9f..f4819e52134 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextFromJsMetadataTestGenerated.java @@ -65,6 +65,12 @@ public class CommonDecompiledTextFromJsMetadataTestGenerated extends AbstractCom KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/decompiler/decompiledText"), Pattern.compile("^([^\\.]+)$"), true); } + @TestMetadata("AnnotatedEnumEntry") + public void testAnnotatedEnumEntry() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/"); + doTest(fileName); + } + @TestMetadata("Annotations") public void testAnnotations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/Annotations/"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java index 15f7bb10192..060057beb2c 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/textBuilder/CommonDecompiledTextTestGenerated.java @@ -35,6 +35,12 @@ public class CommonDecompiledTextTestGenerated extends AbstractCommonDecompiledT KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("idea/testData/decompiler/decompiledText"), Pattern.compile("^([^\\.]+)$"), true); } + @TestMetadata("AnnotatedEnumEntry") + public void testAnnotatedEnumEntry() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/AnnotatedEnumEntry/"); + doTest(fileName); + } + @TestMetadata("Annotations") public void testAnnotations() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("idea/testData/decompiler/decompiledText/Annotations/");