From 6c989bfd4b0137bc75440be7b709341535478f9f Mon Sep 17 00:00:00 2001 From: Ting-Yuan Huang Date: Thu, 25 Mar 2021 22:34:47 -0700 Subject: [PATCH] Support array of annotation in KotlinJvmBinaryClass KotlinJvmBinaryClass.AnnotationArrayArgumentVisitor didn't cover the case when the element type is an Annotation. Therefore, when the compiler read an array of annotations from JVM binary classes built from Kotlin sources, it got an empty array regardless of what was written in the bytecode. For example, Foo.value below is read as an empty array when SomeClass resides in another Kotlin module. @Foo( value = [Bar(1), Bar(2)] ) class SomeClass --- .../fir/FirLoadCompiledKotlinGenerated.java | 5 +++++ .../annotations/AnnotationInArray.txt | 20 +++++++++++++++++++ .../java/deserialization/AnnotationsLoader.kt | 11 ++++++++++ .../load/kotlin/FileBasedKotlinClass.java | 6 ++++++ .../annotations/AnnotationInArray.kt | 16 +++++++++++++++ .../annotations/AnnotationInArray.txt | 17 ++++++++++++++++ .../jvm/compiler/LoadJavaTestGenerated.java | 5 +++++ .../LoadKotlinWithTypeTableTestGenerated.java | 5 +++++ .../compiler/ir/IrLoadJavaTestGenerated.java | 5 +++++ .../LoadJavaUsingJavacTestGenerated.java | 5 +++++ ...aryClassAnnotationAndConstantLoaderImpl.kt | 11 ++++++++++ ...eadKotlinClassHeaderAnnotationVisitor.java | 6 ++++++ .../runtime/components/ReflectKotlinClass.kt | 4 ++++ ...mRuntimeDescriptorLoaderTestGenerated.java | 5 +++++ .../load/kotlin/KotlinJvmBinaryClass.kt | 2 ++ .../LoadJavaClsStubTestGenerated.java | 5 +++++ .../stubs/ResolveByStubTestGenerated.java | 5 +++++ 17 files changed, 133 insertions(+) create mode 100644 compiler/fir/analysis-tests/testData/loadCompiledKotlin/annotations/AnnotationInArray.txt create mode 100644 compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt create mode 100644 compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.txt diff --git a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java index be732663889..cb2be00ecdf 100644 --- a/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java +++ b/compiler/fir/analysis-tests/legacy-fir-tests/tests-gen/org/jetbrains/kotlin/fir/FirLoadCompiledKotlinGenerated.java @@ -56,6 +56,11 @@ public class FirLoadCompiledKotlinGenerated extends AbstractFirLoadCompiledKotli runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt"); diff --git a/compiler/fir/analysis-tests/testData/loadCompiledKotlin/annotations/AnnotationInArray.txt b/compiler/fir/analysis-tests/testData/loadCompiledKotlin/annotations/AnnotationInArray.txt new file mode 100644 index 00000000000..c7a16f98697 --- /dev/null +++ b/compiler/fir/analysis-tests/testData/loadCompiledKotlin/annotations/AnnotationInArray.txt @@ -0,0 +1,20 @@ +public final annotation class Anno : R|kotlin/Annotation| { + public final val value: R|kotlin/Array| + public get(): R|kotlin/Array| + + public constructor(value: R|kotlin/Array|): R|test/Anno| + +} + +@R|test/Anno|(value = (@R|test/Bnno|(value = String(x)) , @R|test/Bnno|(value = String(y)) )) public final class AnnotationInArray : R|kotlin/Any| { + public constructor(): R|test/AnnotationInArray| + +} + +public final annotation class Bnno : R|kotlin/Annotation| { + public final val value: R|kotlin/String| + public get(): R|kotlin/String| + + public constructor(value: R|kotlin/String|): R|test/Bnno| + +} diff --git a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt index cfae7fe2866..f2dc7882f8c 100644 --- a/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt +++ b/compiler/fir/java/src/org/jetbrains/kotlin/fir/java/deserialization/AnnotationsLoader.kt @@ -108,6 +108,17 @@ internal class AnnotationsLoader(private val session: FirSession) { ) } + override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + val list = mutableListOf() + val visitor = loadAnnotation(classId, list) + return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor { + override fun visitEnd() { + visitor.visitEnd() + elements.add(list.single()) + } + } + } + override fun visitEnd() { argumentMap[name] = buildArrayOfCall { argumentList = buildArgumentList { diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java index a2ba8d5bf4b..0700386b2ba 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/load/kotlin/FileBasedKotlinClass.java @@ -200,6 +200,12 @@ public abstract class FileBasedKotlinClass implements KotlinJvmBinaryClass { arv.visitEnum(resolveNameByDesc(desc, innerClasses), Name.identifier(value)); } + @Override + public org.jetbrains.org.objectweb.asm.AnnotationVisitor visitAnnotation(String name, @NotNull String desc) { + AnnotationArgumentVisitor aav = arv.visitAnnotation(resolveNameByDesc(desc, innerClasses)); + return aav == null ? null : convertAnnotationVisitor(aav, innerClasses); + } + @Override public void visitEnd() { arv.visitEnd(); diff --git a/compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt b/compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt new file mode 100644 index 00000000000..5b6ca79c529 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt @@ -0,0 +1,16 @@ +// ALLOW_AST_ACCESS + +package test + +annotation class Anno( + val value: Array +) + +annotation class Bnno( + val value: String +) + +@Anno( + value = [Bnno("x"), Bnno("y")] +) +public class AnnotationInArray diff --git a/compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.txt b/compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.txt new file mode 100644 index 00000000000..d26e86e0b24 --- /dev/null +++ b/compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.txt @@ -0,0 +1,17 @@ +package test + +public final annotation class Anno : kotlin.Annotation { + /*primary*/ public constructor Anno(/*0*/ value: kotlin.Array) + public final val value: kotlin.Array + public final fun (): kotlin.Array +} + +@test.Anno(value = {test.Bnno(value = "x"), test.Bnno(value = "y")}) public final class AnnotationInArray { + /*primary*/ public constructor AnnotationInArray() +} + +public final annotation class Bnno : kotlin.Annotation { + /*primary*/ public constructor Bnno(/*0*/ value: kotlin.String) + public final val value: kotlin.String + public final fun (): kotlin.String +} diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java index 0f907fd9823..1d909b24fa5 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadJavaTestGenerated.java @@ -1734,6 +1734,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest { runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java index b002ad1056a..19c32986e01 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/LoadKotlinWithTypeTableTestGenerated.java @@ -56,6 +56,11 @@ public class LoadKotlinWithTypeTableTestGenerated extends AbstractLoadKotlinWith runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java index 7629b8b0658..c7dd0eb931f 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/ir/IrLoadJavaTestGenerated.java @@ -1735,6 +1735,11 @@ public class IrLoadJavaTestGenerated extends AbstractIrLoadJavaTest { runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt"); diff --git a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java index 8c65f26c389..ca1e5b6ec37 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/jvm/compiler/javac/LoadJavaUsingJavacTestGenerated.java @@ -1734,6 +1734,11 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt"); diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt index a160db964bb..b5fdb62a9bc 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/BinaryClassAnnotationAndConstantLoaderImpl.kt @@ -111,6 +111,17 @@ class BinaryClassAnnotationAndConstantLoaderImpl( elements.add(KClassValue(value)) } + override fun visitAnnotation(classId: ClassId): KotlinJvmBinaryClass.AnnotationArgumentVisitor? { + val list = ArrayList() + val visitor = loadAnnotation(classId, SourceElement.NO_SOURCE, list)!! + return object : KotlinJvmBinaryClass.AnnotationArgumentVisitor by visitor { + override fun visitEnd() { + visitor.visitEnd() + elements.add(AnnotationValue(list.single())) + } + } + } + override fun visitEnd() { val parameter = DescriptorResolverUtils.getAnnotationParameterByName(name, annotationClass) if (parameter != null) { diff --git a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java index 0e0c8f1165a..7bf938ecfdf 100644 --- a/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java +++ b/core/descriptors.jvm/src/org/jetbrains/kotlin/load/kotlin/header/ReadKotlinClassHeaderAnnotationVisitor.java @@ -293,6 +293,12 @@ public class ReadKotlinClassHeaderAnnotationVisitor implements AnnotationVisitor public void visitClassLiteral(@NotNull ClassLiteralValue classLiteralValue) { } + @Nullable + @Override + public AnnotationArgumentVisitor visitAnnotation(@NotNull ClassId classId) { + return null; + } + @Override public void visitEnd() { //noinspection SSBasedInspection diff --git a/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/ReflectKotlinClass.kt b/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/ReflectKotlinClass.kt index 7d5c82162f6..f6a44df0424 100644 --- a/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/ReflectKotlinClass.kt +++ b/core/descriptors.runtime/src/org/jetbrains/kotlin/descriptors/runtime/components/ReflectKotlinClass.kt @@ -243,6 +243,10 @@ private object ReflectClassStructure { componentType == Class::class.java -> for (element in value as Array<*>) { v.visitClassLiteral((element as Class<*>).classLiteralValue()) } + Annotation::class.java.isAssignableFrom(componentType) -> for (element in value as Array<*>) { + val vv = v.visitAnnotation(componentType.classId) ?: continue + processAnnotationArguments(vv, element as Annotation, componentType) + } else -> for (element in value as Array<*>) { v.visit(element) } diff --git a/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java b/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java index 7b564c3d6e2..d53ff04d4bf 100644 --- a/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java +++ b/core/descriptors.runtime/tests/org/jetbrains/kotlin/jvm/runtime/JvmRuntimeDescriptorLoaderTestGenerated.java @@ -58,6 +58,11 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt"); diff --git a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt index b3df740fe96..229b4fc632f 100644 --- a/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt +++ b/core/deserialization.common.jvm/src/org/jetbrains/kotlin/load/kotlin/KotlinJvmBinaryClass.kt @@ -64,6 +64,8 @@ interface KotlinJvmBinaryClass { fun visitClassLiteral(value: ClassLiteralValue) + fun visitAnnotation(classId: ClassId): AnnotationArgumentVisitor? + fun visitEnd() } } diff --git a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/LoadJavaClsStubTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/LoadJavaClsStubTestGenerated.java index 449eb06a4d3..141fa4401b4 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/LoadJavaClsStubTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/decompiler/stubBuilder/LoadJavaClsStubTestGenerated.java @@ -56,6 +56,11 @@ public class LoadJavaClsStubTestGenerated extends AbstractLoadJavaClsStubTest { runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt"); diff --git a/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java index 0c8b0104a3c..74d23958827 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/stubs/ResolveByStubTestGenerated.java @@ -56,6 +56,11 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest { runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInAnnotationArguments.kt"); } + @TestMetadata("AnnotationInArray.kt") + public void testAnnotationInArray() throws Exception { + runTest("compiler/testData/loadJava/compiledKotlin/annotations/AnnotationInArray.kt"); + } + @TestMetadata("ClassLiteralArguments.kt") public void testClassLiteralArguments() throws Exception { runTest("compiler/testData/loadJava/compiledKotlin/annotations/ClassLiteralArguments.kt");