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.Name;
import org.jetbrains.kotlin.resolve.AnnotationChecker;
import org.jetbrains.kotlin.resolve.DescriptorUtils;
import org.jetbrains.kotlin.resolve.checkers.ExpectedActualDeclarationChecker;
import org.jetbrains.kotlin.resolve.constants.*;
import org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilsKt;
@@ -166,10 +167,17 @@ public abstract class AnnotationCodegen {
if (isInvisibleFromTheOutside(descriptor)) 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)) {
generateNullabilityAnnotation(descriptor.getReturnType(), annotationDescriptorsAlreadyPresent);
}
}
if (unwrapped instanceof ClassDescriptor) {
ClassDescriptor classDescriptor = (ClassDescriptor) unwrapped;
if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
@@ -232,7 +232,7 @@ public class FunctionCodegen {
v.getSerializationBindings().put(METHOD_FOR_FUNCTION, CodegenUtilKt.unwrapFrontendVersion(functionDescriptor), asmMethod);
}
generateMethodAnnotations(functionDescriptor, asmMethod, mv);
generateMethodAnnotations(functionDescriptor, asmMethod, mv, memberCodegen, typeMapper);
generateParameterAnnotations(functionDescriptor, mv, jvmSignature);
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(
@NotNull FunctionDescriptor functionDescriptor,
Method asmMethod,
@@ -266,15 +266,20 @@ public class PropertyCodegen {
@Nullable FunctionDescriptor expectedAnnotationConstructor
) {
JvmMethodGenericSignature signature = typeMapper.mapAnnotationParameterSignature(descriptor);
String name = parameter.getName();
if (name == null) return;
Method asmMethod = signature.getAsmMethod();
MethodVisitor mv = v.newMethod(
JvmDeclarationOriginKt.OtherOrigin(parameter, descriptor), ACC_PUBLIC | ACC_ABSTRACT, name,
signature.getAsmMethod().getDescriptor(),
JvmDeclarationOriginKt.OtherOrigin(parameter, descriptor),
ACC_PUBLIC | ACC_ABSTRACT,
asmMethod.getName(),
asmMethod.getDescriptor(),
signature.getGenericsSignature(),
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);
if (defaultValue != null) {
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);
}
@TestMetadata("annotatedAnnotationParameter.kt")
public void testAnnotatedAnnotationParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedAnnotationParameter.kt");
}
@TestMetadata("annotatedEnumEntry.kt")
public void testAnnotatedEnumEntry() throws Exception {
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);
}
@TestMetadata("annotatedAnnotationParameter.kt")
public void testAnnotatedAnnotationParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedAnnotationParameter.kt");
}
@TestMetadata("annotatedEnumEntry.kt")
public void testAnnotatedEnumEntry() throws Exception {
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);
}
@TestMetadata("annotatedAnnotationParameter.kt")
public void testAnnotatedAnnotationParameter() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedAnnotationParameter.kt");
}
@TestMetadata("annotatedEnumEntry.kt")
public void testAnnotatedEnumEntry() throws Exception {
runTest("compiler/testData/codegen/box/annotations/annotatedEnumEntry.kt");