Load annotations on constructors and parameters of Kotlin reflected classes
This commit is contained in:
@@ -0,0 +1,6 @@
|
|||||||
|
//ALLOW_AST_ACCESS
|
||||||
|
package test
|
||||||
|
|
||||||
|
annotation class Anno(val value: String)
|
||||||
|
|
||||||
|
class Constructor [Anno(value = "string")]()
|
||||||
@@ -0,0 +1,11 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
internal final annotation class Anno : kotlin.Annotation {
|
||||||
|
/*primary*/ public constructor Anno(/*0*/ value: kotlin.String)
|
||||||
|
internal final val value: kotlin.String
|
||||||
|
internal final fun <get-value>(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
internal final class Constructor {
|
||||||
|
/*primary*/ test.Anno(value = "string": kotlin.String) public constructor Constructor()
|
||||||
|
}
|
||||||
+10
@@ -0,0 +1,10 @@
|
|||||||
|
//ALLOW_AST_ACCESS
|
||||||
|
package test
|
||||||
|
|
||||||
|
annotation class A(val s: String)
|
||||||
|
|
||||||
|
class Outer {
|
||||||
|
class Nested([A("nested")] val x: String)
|
||||||
|
|
||||||
|
inner class Inner([A("inner")] val y: String)
|
||||||
|
}
|
||||||
+23
@@ -0,0 +1,23 @@
|
|||||||
|
package test
|
||||||
|
|
||||||
|
internal final annotation class A : kotlin.Annotation {
|
||||||
|
/*primary*/ public constructor A(/*0*/ s: kotlin.String)
|
||||||
|
internal final val s: kotlin.String
|
||||||
|
internal final fun <get-s>(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
internal final class Outer {
|
||||||
|
/*primary*/ public constructor Outer()
|
||||||
|
|
||||||
|
internal final inner class Inner {
|
||||||
|
/*primary*/ public constructor Inner(/*0*/ test.A(s = "inner": kotlin.String) y: kotlin.String)
|
||||||
|
test.A(s = "inner": kotlin.String) internal final val y: kotlin.String
|
||||||
|
internal final fun <get-y>(): kotlin.String
|
||||||
|
}
|
||||||
|
|
||||||
|
internal final class Nested {
|
||||||
|
/*primary*/ public constructor Nested(/*0*/ test.A(s = "nested": kotlin.String) x: kotlin.String)
|
||||||
|
test.A(s = "nested": kotlin.String) internal final val x: kotlin.String
|
||||||
|
internal final fun <get-x>(): kotlin.String
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -1939,6 +1939,12 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
|||||||
doTestCompiledKotlin(fileName);
|
doTestCompiledKotlin(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Constructor.kt")
|
||||||
|
public void testConstructor() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Constructor.kt");
|
||||||
|
doTestCompiledKotlin(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("DelegatedProperty.kt")
|
@TestMetadata("DelegatedProperty.kt")
|
||||||
public void testDelegatedProperty() throws Exception {
|
public void testDelegatedProperty() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/DelegatedProperty.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/DelegatedProperty.kt");
|
||||||
@@ -2176,6 +2182,12 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
|
|||||||
doTestCompiledKotlin(fileName);
|
doTestCompiledKotlin(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InnerClassConstructor.kt")
|
||||||
|
public void testInnerClassConstructor() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/InnerClassConstructor.kt");
|
||||||
|
doTestCompiledKotlin(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ManyAnnotations.kt")
|
@TestMetadata("ManyAnnotations.kt")
|
||||||
public void testManyAnnotations() throws Exception {
|
public void testManyAnnotations() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/ManyAnnotations.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/ManyAnnotations.kt");
|
||||||
|
|||||||
+12
@@ -113,6 +113,12 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Constructor.kt")
|
||||||
|
public void testConstructor() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Constructor.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("DelegatedProperty.kt")
|
@TestMetadata("DelegatedProperty.kt")
|
||||||
public void testDelegatedProperty() throws Exception {
|
public void testDelegatedProperty() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/DelegatedProperty.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/DelegatedProperty.kt");
|
||||||
@@ -350,6 +356,12 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InnerClassConstructor.kt")
|
||||||
|
public void testInnerClassConstructor() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/InnerClassConstructor.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ManyAnnotations.kt")
|
@TestMetadata("ManyAnnotations.kt")
|
||||||
public void testManyAnnotations() throws Exception {
|
public void testManyAnnotations() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/ManyAnnotations.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/ManyAnnotations.kt");
|
||||||
|
|||||||
+25
-11
@@ -17,6 +17,7 @@
|
|||||||
package org.jetbrains.kotlin.load.kotlin.reflect
|
package org.jetbrains.kotlin.load.kotlin.reflect
|
||||||
|
|
||||||
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
import org.jetbrains.kotlin.load.java.structure.reflect.classId
|
||||||
|
import org.jetbrains.kotlin.load.java.structure.reflect.isEnumClassOrSpecializedEnumEntryClass
|
||||||
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
import org.jetbrains.kotlin.load.kotlin.KotlinJvmBinaryClass
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
import org.jetbrains.kotlin.load.kotlin.header.KotlinClassHeader
|
||||||
import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor
|
import org.jetbrains.kotlin.load.kotlin.header.ReadKotlinClassHeaderAnnotationVisitor
|
||||||
@@ -105,20 +106,33 @@ private object ReflectClassStructure {
|
|||||||
|
|
||||||
private fun loadConstructorAnnotations(klass: Class<*>, memberVisitor: KotlinJvmBinaryClass.MemberVisitor) {
|
private fun loadConstructorAnnotations(klass: Class<*>, memberVisitor: KotlinJvmBinaryClass.MemberVisitor) {
|
||||||
for (constructor in klass.getDeclaredConstructors()) {
|
for (constructor in klass.getDeclaredConstructors()) {
|
||||||
// TODO: load annotations on constructors
|
|
||||||
val visitor = memberVisitor.visitMethod(Name.special("<init>"), SignatureSerializer.constructorDesc(constructor)) ?: continue
|
val visitor = memberVisitor.visitMethod(Name.special("<init>"), SignatureSerializer.constructorDesc(constructor)) ?: continue
|
||||||
|
|
||||||
// Constructors of enums have 2 additional synthetic parameters
|
for (annotation in constructor.getDeclaredAnnotations()) {
|
||||||
// TODO: the similar logic should probably be present for annotations on parameters of inner class constructors
|
processAnnotation(visitor, annotation)
|
||||||
val shift = if (klass.isEnum()) 2 else 0
|
}
|
||||||
for ((parameterIndex, annotations) in constructor.getParameterAnnotations().withIndex()) {
|
|
||||||
for (annotation in annotations) {
|
val parameterAnnotations = constructor.getParameterAnnotations()
|
||||||
val annotationType = annotation.annotationType()
|
if (parameterAnnotations.isNotEmpty()) {
|
||||||
visitor.visitParameterAnnotation(parameterIndex + shift, annotationType.classId)?.let {
|
// Constructors of some classes have additional synthetic parameters:
|
||||||
processAnnotationArguments(it, annotation, annotationType)
|
// - inner classes have one parameter, instance of the outer class
|
||||||
|
// - enum classes have two parameters, String name and int ordinal
|
||||||
|
// - local/anonymous classes may have many parameters for captured values
|
||||||
|
// At the moment this seems like a working heuristic for computing number of synthetic parameters for Kotlin classes,
|
||||||
|
// although this is wrong and likely to change, see KT-6886
|
||||||
|
val shift = constructor.getParameterTypes().size() - parameterAnnotations.size()
|
||||||
|
|
||||||
|
for ((parameterIndex, annotations) in parameterAnnotations.withIndex()) {
|
||||||
|
for (annotation in annotations) {
|
||||||
|
val annotationType = annotation.annotationType()
|
||||||
|
visitor.visitParameterAnnotation(parameterIndex + shift, annotationType.classId)?.let {
|
||||||
|
processAnnotationArguments(it, annotation, annotationType)
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
visitor.visitEnd()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -158,8 +172,8 @@ private object ReflectClassStructure {
|
|||||||
clazz in TYPES_ELIGIBLE_FOR_SIMPLE_VISIT -> {
|
clazz in TYPES_ELIGIBLE_FOR_SIMPLE_VISIT -> {
|
||||||
visitor.visit(name, value)
|
visitor.visit(name, value)
|
||||||
}
|
}
|
||||||
javaClass<Enum<*>>().isAssignableFrom(clazz) -> {
|
clazz.isEnumClassOrSpecializedEnumEntryClass() -> {
|
||||||
// isEnum returns false for specialized enum constants (enum entries which are subclasses)
|
// isEnum returns false for specialized enum constants (enum entries which are anonymous enum subclasses)
|
||||||
val classId = (if (clazz.isEnum()) clazz else clazz.getEnclosingClass()).classId
|
val classId = (if (clazz.isEnum()) clazz else clazz.getEnclosingClass()).classId
|
||||||
visitor.visitEnum(name, classId, Name.identifier((value as Enum<*>).name()))
|
visitor.visitEnum(name, classId, Name.identifier((value as Enum<*>).name()))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -107,6 +107,12 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("Constructor.kt")
|
||||||
|
public void testConstructor() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/Constructor.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("DelegatedProperty.kt")
|
@TestMetadata("DelegatedProperty.kt")
|
||||||
public void testDelegatedProperty() throws Exception {
|
public void testDelegatedProperty() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/DelegatedProperty.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/classMembers/DelegatedProperty.kt");
|
||||||
@@ -344,6 +350,12 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("InnerClassConstructor.kt")
|
||||||
|
public void testInnerClassConstructor() throws Exception {
|
||||||
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/InnerClassConstructor.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ManyAnnotations.kt")
|
@TestMetadata("ManyAnnotations.kt")
|
||||||
public void testManyAnnotations() throws Exception {
|
public void testManyAnnotations() throws Exception {
|
||||||
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/ManyAnnotations.kt");
|
String fileName = JetTestUtils.navigationMetadata("compiler/testData/loadJava/compiledKotlin/annotations/parameters/ManyAnnotations.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user