Generate get-targeted annotations on annotation constructor parameters

This change would also make NotNull annotations to be generated on
non-primitive annotation methods, but we skip this deliberately because
annotation methods never return null on JVM anyway

 #KT-25287 Fixed
This commit is contained in:
Alexander Udalov
2018-07-05 14:21:49 +02:00
committed by Ilya Gorbunov
parent 9df949c039
commit dc1f4c7d5b
7 changed files with 51 additions and 13 deletions
@@ -29,6 +29,7 @@ import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.name.Name;
import org.jetbrains.kotlin.resolve.AnnotationChecker; import org.jetbrains.kotlin.resolve.AnnotationChecker;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker; import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker;
import org.jetbrains.kotlin.resolve.constants.*; import org.jetbrains.kotlin.resolve.constants.*;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt; import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
@@ -166,10 +167,17 @@ public abstract class AnnotationCodegen {
if (isInvisibleFromTheOutside(descriptor)) return; if (isInvisibleFromTheOutside(descriptor)) return;
if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return; if (descriptor instanceof ValueParameterDescriptor && isInvisibleFromTheOutside(descriptor.getContainingDeclaration())) return;
// No need to annotate annotation methods since they're always non-null
if (descriptor instanceof PropertyGetterDescriptor &&
DescriptorUtils.isAnnotationClass(descriptor.getContainingDeclaration())) {
return;
}
if (returnType != null && !AsmUtil.isPrimitive(returnType)) { if (returnType != null && !AsmUtil.isPrimitive(returnType)) {
generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent); generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
} }
} }
if (unwrapped instanceof ClassDescriptor) { if (unwrapped instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) unwrapped; ClassDescriptor classDescriptor = (ClassDescriptor) unwrapped;
if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) { if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
@@ -232,7 +232,7 @@ public class FunctionCodegen {
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, CodegenUtilKt.unwrapFrontendVersion(functionDescriptor), asmMethod); v.getSerializationBindings().put(METHOD_FOR_FUNCTION, CodegenUtilKt.unwrapFrontendVersion(functionDescriptor), asmMethod);
} }
generateMethodAnnotations(functionDescriptor, asmMethod, mv); generateMethodAnnotations(functionDescriptor, asmMethod, mv, memberCodegen, typeMapper);
generateParameterAnnotations(functionDescriptor, mv, jvmSignature); generateParameterAnnotations(functionDescriptor, mv, jvmSignature);
GenerateJava8ParameterNamesKt.generateParameterNames(functionDescriptor, mv, jvmSignature, state, (flags & ACC_SYNTHETIC) != 0); GenerateJava8ParameterNamesKt.generateParameterNames(functionDescriptor, mv, jvmSignature, state, (flags & ACC_SYNTHETIC) != 0);
@@ -474,14 +474,6 @@ public class FunctionCodegen {
); );
} }
private void generateMethodAnnotations(
@NotNull FunctionDescriptor functionDescriptor,
Method asmMethod,
MethodVisitor mv
) {
generateMethodAnnotations(functionDescriptor, asmMethod, mv, memberCodegen, typeMapper);
}
public static void generateMethodAnnotations( public static void generateMethodAnnotations(
@NotNull FunctionDescriptor functionDescriptor, @NotNull FunctionDescriptor functionDescriptor,
Method asmMethod, Method asmMethod,
@@ -266,15 +266,20 @@ public class PropertyCodegen {
@Nullable FunctionDescriptor expectedAnnotationConstructor @Nullable FunctionDescriptor expectedAnnotationConstructor
) { ) {
JvmMethodGenericSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor); JvmMethodGenericSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor);
String name = parameter.getName(); Method asmMethod = signature.getAsmMethod();
if (name == null) return;
MethodVisitor mv = v.newMethod( MethodVisitor mv = v.newMethod(
JvmDeclarationOriginKt.OtherOrigin(parameter, descriptor), ACC_PUBLIC | ACC_ABSTRACT, name, JvmDeclarationOriginKt.OtherOrigin(parameter, descriptor),
signature.getAsmMethod().getDescriptor(), ACC_PUBLIC | ACC_ABSTRACT,
asmMethod.getName(),
asmMethod.getDescriptor(),
signature.getGenericsSignature(), signature.getGenericsSignature(),
null null
); );
PropertyGetterDescriptor getter = descriptor.getGetter();
assert getter != null : "Annotation property should have a getter: " + descriptor;
FunctionCodegen.generateMethodAnnotations(getter, asmMethod, mv, memberCodegen, typeMapper);
KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor); KtExpression defaultValue = loadAnnotationArgumentDefaultValue(parameter, descriptor, expectedAnnotationConstructor);
if (defaultValue != null) { if (defaultValue != null) {
ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant( ConstantValue<?> constant = ExpressionCodegen.getCompileTimeConstant(
@@ -0,0 +1,18 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
import kotlin.test.assertEquals
annotation class Name(val value: String)
annotation class Anno(
@get:Name("O") val o: String,
@get:Name("K") val k: String
)
fun box(): String {
val ms = Anno::class.java.declaredMethods
return (ms.single { it.name == "o" }.annotations.single() as Name).value +
(ms.single { it.name == "k" }.annotations.single() as Name).value
}
@@ -41,6 +41,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("annotatedAnnotationParameter.kt")
public void testAnnotatedAnnotationParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedAnnotationParameter.kt");
}
@TestMetadata("annotatedEnumEntry.kt") @TestMetadata("annotatedEnumEntry.kt")
public void testAnnotatedEnumEntry() throws Exception { public void testAnnotatedEnumEntry() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedEnumEntry.kt"); runTest("compiler/testData/codegen/box/annotations/annotatedEnumEntry.kt");
@@ -46,6 +46,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
} }
@TestMetadata("annotatedAnnotationParameter.kt")
public void testAnnotatedAnnotationParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedAnnotationParameter.kt");
}
@TestMetadata("annotatedEnumEntry.kt") @TestMetadata("annotatedEnumEntry.kt")
public void testAnnotatedEnumEntry() throws Exception { public void testAnnotatedEnumEntry() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedEnumEntry.kt"); runTest("compiler/testData/codegen/box/annotations/annotatedEnumEntry.kt");
@@ -41,6 +41,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true); KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/annotations"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM_IR, true);
} }
@TestMetadata("annotatedAnnotationParameter.kt")
public void testAnnotatedAnnotationParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedAnnotationParameter.kt");
}
@TestMetadata("annotatedEnumEntry.kt") @TestMetadata("annotatedEnumEntry.kt")
public void testAnnotatedEnumEntry() throws Exception { public void testAnnotatedEnumEntry() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedEnumEntry.kt"); runTest("compiler/testData/codegen/box/annotations/annotatedEnumEntry.kt");