diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java index b8ac58e8cc4..2f230c791fb 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java @@ -17,25 +17,26 @@ package org.jetbrains.jet.codegen; import com.intellij.psi.PsiElement; +import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.AnnotationVisitor; import org.jetbrains.asm4.ClassVisitor; import org.jetbrains.asm4.FieldVisitor; import org.jetbrains.asm4.MethodVisitor; -import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods; import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.Annotated; +import org.jetbrains.jet.lang.descriptors.annotations.AnnotationArgumentVisitor; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; -import org.jetbrains.jet.lang.psi.*; +import org.jetbrains.jet.lang.psi.JetAnnotationEntry; +import org.jetbrains.jet.lang.psi.JetClass; +import org.jetbrains.jet.lang.psi.JetModifierList; +import org.jetbrains.jet.lang.psi.JetModifierListOwner; import org.jetbrains.jet.lang.resolve.BindingContext; -import org.jetbrains.jet.lang.resolve.calls.model.DefaultValueArgument; import org.jetbrains.jet.lang.resolve.calls.model.ResolvedCall; -import org.jetbrains.jet.lang.resolve.calls.model.ResolvedValueArgument; -import org.jetbrains.jet.lang.resolve.calls.model.VarargValueArgument; -import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant; -import org.jetbrains.jet.lang.resolve.name.Name; -import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.resolve.constants.*; +import org.jetbrains.jet.lang.resolve.constants.StringValue; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.lang.annotation.RetentionPolicy; import java.util.List; @@ -84,124 +85,136 @@ public abstract class AnnotationCodegen { AnnotationDescriptor annotationDescriptor = bindingContext.get(BindingContext.ANNOTATION, annotationEntry); if (annotationDescriptor == null) continue; // Skipping annotations if they are not resolved. Needed for JetLightClass generation - JetType type = annotationDescriptor.getType(); - genAnnotation(resolvedCall, type); + genAnnotation(annotationDescriptor); } } - private void genAnnotation( - ResolvedCall resolvedCall, - JetType type - ) { - ClassifierDescriptor classifierDescriptor = type.getConstructor().getDeclarationDescriptor(); + private void genAnnotation(AnnotationDescriptor annotationDescriptor) { + ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor(); RetentionPolicy rp = getRetentionPolicy(classifierDescriptor, typeMapper); if (rp == RetentionPolicy.SOURCE) { return; } - String internalName = typeMapper.mapType(type).getDescriptor(); + String internalName = typeMapper.mapType(annotationDescriptor.getType()).getDescriptor(); AnnotationVisitor annotationVisitor = visitAnnotation(internalName, rp == RetentionPolicy.RUNTIME); - getAnnotation(resolvedCall, annotationVisitor); - + genAnnotationArguments(annotationDescriptor, annotationVisitor); annotationVisitor.visitEnd(); } - private void getAnnotation(ResolvedCall resolvedCall, AnnotationVisitor annotationVisitor) { - for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) { - ResolvedValueArgument valueArgument = entry.getValue(); - if (valueArgument instanceof DefaultValueArgument) { - continue; - } - - Name keyName = entry.getKey().getName(); - genAnnotationValueArgument(annotationVisitor, valueArgument, keyName.asString()); + private void genAnnotationArguments(AnnotationDescriptor annotationDescriptor, AnnotationVisitor annotationVisitor) { + for (Map.Entry> entry : annotationDescriptor.getAllValueArguments().entrySet()) { + ValueParameterDescriptor descriptor = entry.getKey(); + String name = descriptor.getName().asString(); + genAnnotationArgument(name, entry.getValue(), annotationVisitor); } } - private void genAnnotationValueArgument(AnnotationVisitor annotationVisitor, ResolvedValueArgument valueArgument, String keyName) { - List valueArguments = valueArgument.getArguments(); - if (valueArgument instanceof VarargValueArgument) { - AnnotationVisitor visitor = annotationVisitor.visitArray(keyName); - for (ValueArgument argument : valueArguments) { - genAnnotationExpressionValue(visitor, null, argument.getArgumentExpression()); + private void genAnnotationArgument( + @Nullable final String name, + @NotNull CompileTimeConstant value, + @NotNull final AnnotationVisitor annotationVisitor + ) { + AnnotationArgumentVisitor argumentVisitor = new AnnotationArgumentVisitor() { + @Override + public Void visitLongValue(@NotNull LongValue value, Void data) { + return visitSimpleValue(value); } - visitor.visitEnd(); - } - else { - assert valueArguments.size() == 1 : "Number of arguments on " + keyName + " = " + valueArguments.size(); // todo - JetExpression expression = valueArguments.get(0).getArgumentExpression(); - genAnnotationExpressionValue(annotationVisitor, keyName, expression); - } - } - private void genAnnotationExpressionValue(AnnotationVisitor annotationVisitor, @Nullable String keyName, JetExpression expression) { - CompileTimeConstant compileTimeConstant = - bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expression); + @Override + public Void visitIntValue(IntValue value, Void data) { + return visitSimpleValue(value); + } - if (compileTimeConstant != null) { - Object value = compileTimeConstant.getValue(); - annotationVisitor.visit(keyName, value); - return; - } + @Override + public Void visitShortValue(ShortValue value, Void data) { + return visitSimpleValue(value); + } - if (expression instanceof JetDotQualifiedExpression) { - JetDotQualifiedExpression qualifiedExpression = (JetDotQualifiedExpression) expression; - ResolvedCall call = - bindingContext.get(BindingContext.RESOLVED_CALL, qualifiedExpression.getSelectorExpression()); - if (call != null) { - if (call.getResultingDescriptor() instanceof PropertyDescriptor) { - PropertyDescriptor descriptor = (PropertyDescriptor) call.getResultingDescriptor(); - annotationVisitor.visitEnum(keyName, typeMapper.mapType(descriptor).getDescriptor(), descriptor.getName().asString()); - return; + @Override + public Void visitByteValue(ByteValue value, Void data) { + return visitSimpleValue(value); + } + + @Override + public Void visitDoubleValue(DoubleValue value, Void data) { + return visitSimpleValue(value); + } + + @Override + public Void visitFloatValue(FloatValue value, Void data) { + return visitSimpleValue(value); + } + + @Override + public Void visitBooleanValue(BooleanValue value, Void data) { + return visitSimpleValue(value); + } + + @Override + public Void visitCharValue(CharValue value, Void data) { + return visitSimpleValue(value); + } + + @Override + public Void visitStringValue(StringValue value, Void data) { + return visitSimpleValue(value); + } + + @Override + public Void visitEnumValue(EnumValue value, Void data) { + String propertyName = value.getValue().getName().asString(); + annotationVisitor.visitEnum(name, typeMapper.mapType(value.getType(KotlinBuiltIns.getInstance())).getDescriptor(), propertyName); + return null; + } + + @Override + public Void visitArrayValue(ArrayValue value, Void data) { + AnnotationVisitor visitor = annotationVisitor.visitArray(name); + for (CompileTimeConstant argument : value.getValue()) { + genAnnotationArgument(null, argument, visitor); } + visitor.visitEnd(); + return null; } - } - else { - if (expression instanceof JetCallExpression) { - JetCallExpression callExpression = (JetCallExpression) expression; - ResolvedCall call = - bindingContext.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression()); - if (call != null) { - List annotations = call.getResultingDescriptor().getOriginal().getAnnotations(); - String value = null; - if (annotations != null) { - for (AnnotationDescriptor annotation : annotations) { - //noinspection ConstantConditions - if ("Intrinsic".equals(annotation.getType().getConstructor().getDeclarationDescriptor().getName().asString())) { - value = (String) annotation.getAllValueArguments().values().iterator().next().getValue(); - break; - } - } - } - if (IntrinsicMethods.KOTLIN_JAVA_CLASS_FUNCTION.equals(value)) { - //noinspection ConstantConditions - annotationVisitor.visit(keyName, typeMapper - .mapType(call.getResultingDescriptor().getReturnType().getArguments().get(0).getType())); - return; - } - else if (IntrinsicMethods.KOTLIN_ARRAYS_ARRAY.equals(value)) { - AnnotationVisitor visitor = annotationVisitor.visitArray(keyName); - VarargValueArgument next = (VarargValueArgument) call.getValueArguments().values().iterator().next(); - for (ValueArgument argument : next.getArguments()) { - genAnnotationExpressionValue(visitor, null, argument.getArgumentExpression()); - } - visitor.visitEnd(); - return; - } - else if (call.getResultingDescriptor() instanceof ConstructorDescriptor) { - ConstructorDescriptor descriptor = (ConstructorDescriptor) call.getResultingDescriptor(); - AnnotationVisitor visitor = annotationVisitor.visitAnnotation(keyName, typeMapper - .mapType(descriptor.getContainingDeclaration()).getDescriptor()); - getAnnotation(call, visitor); - visitor.visitEnd(); - return; - } - } - } - } - throw new IllegalStateException("Don't know how to compile annotation value"); + @Override + public Void visitAnnotationValue(AnnotationValue value, Void data) { + String internalAnnName = typeMapper.mapType(value.getValue().getType()).getDescriptor(); + AnnotationVisitor visitor = annotationVisitor.visitAnnotation(name, internalAnnName); + genAnnotationArguments(value.getValue(), visitor); + visitor.visitEnd(); + return null; + } + + @Override + public Void visitJavaClassValue(JavaClassValue value, Void data) { + annotationVisitor.visit(name, typeMapper.mapType(value.getValue())); + return null; + } + + private Void visitSimpleValue(CompileTimeConstant value) { + annotationVisitor.visit(name, value.getValue()); + return null; + } + + @Override + public Void visitErrorValue(ErrorValue value, Void data) { + return visitUnsupportedValue(value); + } + + @Override + public Void visitNullValue(NullValue value, Void data) { + return visitUnsupportedValue(value); + } + + private Void visitUnsupportedValue(CompileTimeConstant value) { + throw new IllegalStateException("Don't know how to compile annotation value " + value); + } + }; + + value.accept(argumentVisitor, null); } private static RetentionPolicy getRetentionPolicy(ClassifierDescriptor descriptor, JetTypeMapper typeMapper) { diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/varargInAnnotationParameter.kt b/compiler/testData/codegen/boxWithStdlib/annotations/varargInAnnotationParameter.kt new file mode 100644 index 00000000000..d845f7ee4d4 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/varargInAnnotationParameter.kt @@ -0,0 +1,21 @@ +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann(val s: String, vararg val p: Int) + +Ann("str", 1, 2, 3) class MyClass + +fun box(): String { + val ann = javaClass().getAnnotation(javaClass()) + if (ann == null) return "fail: cannot find Ann on MyClass" + if (ann.s != "str") return "fail: annotation parameter s should be \"str\"" + if (ann.p[0] != 1) return "fail: annotation parameter p[0] should be 1" + if (ann.p[1] != 2) return "fail: annotation parameter p[1] should be 2" + if (ann.p[2] != 3) return "fail: annotation parameter p[2] should be 3" + return "OK" +} + +fun main(args: Array) { + println(box()) +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 17e6c9b373d..24e69e94441 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -31,12 +31,25 @@ import org.jetbrains.jet.codegen.generated.AbstractBlackBoxCodegenTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/boxWithStdlib") -@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class}) +@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class}) public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBoxWithStdlib() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/boxWithStdlib"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/annotations") + public static class Annotations extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInAnnotations() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/boxWithStdlib/annotations"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("varargInAnnotationParameter.kt") + public void testVarargInAnnotationParameter() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/varargInAnnotationParameter.kt"); + } + + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/casts") public static class Casts extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInCasts() throws Exception { @@ -882,6 +895,7 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode public static Test suite() { TestSuite suite = new TestSuite("BlackBoxWithStdlibCodegenTestGenerated"); suite.addTestSuite(BlackBoxWithStdlibCodegenTestGenerated.class); + suite.addTestSuite(Annotations.class); suite.addTestSuite(Casts.class); suite.addTest(DataClasses.innerSuite()); suite.addTestSuite(FullJdk.class);