Write default values for annotation parameters

#KT-3197 Fixed
This commit is contained in:
Natalia.Ukhorskaya
2013-07-25 16:44:03 +04:00
parent 73000ec407
commit c11bd7104c
7 changed files with 78 additions and 4 deletions
@@ -89,6 +89,12 @@ public abstract class AnnotationCodegen {
}
}
public void generateAnnotationDefaultValue(CompileTimeConstant value) {
AnnotationVisitor visitor = visitAnnotation(null, false); // Parameters are unimportant
genAnnotationArgument(null, value, visitor);
visitor.visitEnd();
}
private void genAnnotation(AnnotationDescriptor annotationDescriptor) {
ClassifierDescriptor classifierDescriptor = annotationDescriptor.getType().getConstructor().getDeclarationDescriptor();
RetentionPolicy rp = getRetentionPolicy(classifierDescriptor, typeMapper);
@@ -270,4 +276,13 @@ public abstract class AnnotationCodegen {
}
};
}
public static AnnotationCodegen forAnnotationDefaultValue(final MethodVisitor mv, JetTypeMapper mapper) {
return new AnnotationCodegen(mapper) {
@Override
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return mv.visitAnnotationDefault();
}
};
}
}
@@ -28,6 +28,7 @@ import org.jetbrains.jet.lang.descriptors.impl.SimpleFunctionDescriptorImpl;
import org.jetbrains.jet.lang.psi.*;
import org.jetbrains.jet.lang.resolve.BindingContext;
import org.jetbrains.jet.lang.resolve.DescriptorUtils;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.name.Name;
import java.util.Collections;
@@ -135,7 +136,16 @@ public abstract class ClassBodyCodegen extends MemberCodegen {
}
else {
Type type = state.getTypeMapper().mapType(propertyDescriptor);
v.newMethod(p, ACC_PUBLIC | ACC_ABSTRACT, p.getName(), "()" + type.getDescriptor(), null, null);
MethodVisitor visitor =
v.newMethod(p, ACC_PUBLIC | ACC_ABSTRACT, p.getName(), "()" + type.getDescriptor(), null, null);
JetExpression defaultValue = p.getDefaultValue();
if (defaultValue != null) {
CompileTimeConstant<?> constant =
state.getBindingContext().get(BindingContext.COMPILE_TIME_VALUE, defaultValue);
assert constant != null : "Default value for annotation parameter should be compile time value: " + defaultValue.getText();
AnnotationCodegen annotationCodegen = AnnotationCodegen.forAnnotationDefaultValue(visitor, typeMapper);
annotationCodegen.generateAnnotationDefaultValue(constant);
}
}
}
}
@@ -223,7 +223,7 @@ public class AnnotationResolver {
}
@Nullable
private CompileTimeConstant<?> resolveAnnotationArgument(@NotNull JetExpression expression, @NotNull final JetType expectedType, final BindingTrace trace) {
public CompileTimeConstant<?> resolveAnnotationArgument(@NotNull JetExpression expression, @NotNull final JetType expectedType, final BindingTrace trace) {
JetVisitor<CompileTimeConstant<?>, Void> visitor = new JetVisitor<CompileTimeConstant<?>, Void>() {
@Override
public CompileTimeConstant<?> visitConstantExpression(JetConstantExpression expression, Void nothing) {
@@ -34,6 +34,7 @@ import org.jetbrains.jet.lang.resolve.calls.util.CallMaker;
import org.jetbrains.jet.lang.resolve.calls.CallResolver;
import org.jetbrains.jet.lang.resolve.calls.results.OverloadResolutionResults;
import org.jetbrains.jet.lang.resolve.calls.autocasts.DataFlowInfo;
import org.jetbrains.jet.lang.resolve.constants.CompileTimeConstant;
import org.jetbrains.jet.lang.resolve.scopes.*;
import org.jetbrains.jet.lang.resolve.scopes.receivers.ReceiverValue;
import org.jetbrains.jet.lang.types.*;
@@ -696,6 +697,13 @@ public class BodyResolver {
JetExpression defaultValue = jetParameter.getDefaultValue();
if (defaultValue != null) {
expressionTypingServices.getType(declaringScope, defaultValue, valueParameterDescriptor.getType(), DataFlowInfo.EMPTY, trace);
if (DescriptorUtils.isAnnotationClass(DescriptorUtils.getContainingClass(declaringScope))) {
CompileTimeConstant<?> constant =
annotationResolver.resolveAnnotationArgument(defaultValue, valueParameterDescriptor.getType(), trace);
if (constant != null) {
trace.record(BindingContext.COMPILE_TIME_VALUE, defaultValue, constant);
}
}
}
}
}
@@ -289,7 +289,7 @@ public class DescriptorUtils {
return isKindOf(descriptor, ClassKind.ENUM_CLASS);
}
public static boolean isAnnotationClass(@NotNull DeclarationDescriptor descriptor) {
public static boolean isAnnotationClass(@Nullable DeclarationDescriptor descriptor) {
return isKindOf(descriptor, ClassKind.ANNOTATION_CLASS);
}
@@ -0,0 +1,36 @@
import java.lang.annotation.Retention
import java.lang.annotation.RetentionPolicy
Retention(RetentionPolicy.RUNTIME)
annotation class Ann(
val i: Int = 1,
val s: String = "a",
val a: Ann2 = Ann2(),
val e: MyEnum = MyEnum.A,
val c: Class<*> = javaClass<A>(),
val ia: IntArray = intArray(1, 2),
val sa: Array<String> = array("a", "b")
)
fun box(): String {
val ann = javaClass<MyClass>().getAnnotation(javaClass<Ann>())
if (ann == null) return "fail: cannot find Ann on MyClass}"
if (ann.i != 1) return "fail: annotation parameter i should be 1, but was ${ann.i}"
if (ann.s != "a") return "fail: annotation parameter s should be \"a\", but was ${ann.s}"
if (ann.a.toString() != "@Ann2()") return "fail: annotation parameter a should be of class Ann2, but was ${ann.a}"
if (ann.e != MyEnum.A) return "fail: annotation parameter e should be MyEnum.A, but was ${ann.e}"
if (ann.c != javaClass<A>()) return "fail: annotation parameter c should be of class A, but was ${ann.c}"
if (ann.ia[0] != 1 || ann.ia[1] != 2) return "fail: annotation parameter ia should be [1, 2], but was ${ann.ia}"
if (ann.sa[0] != "a" || ann.sa[1] != "b") return "fail: annotation parameter ia should be [\"a\", \"b\"], but was ${ann.sa}"
return "OK"
}
annotation class Ann2
enum class MyEnum {
A
}
class A
Ann class MyClass
@@ -36,12 +36,17 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode
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("defaultParameterValues.kt")
public void testDefaultParameterValues() throws Exception {
doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/defaultParameterValues.kt");
}
@TestMetadata("varargInAnnotationParameter.kt")
public void testVarargInAnnotationParameter() throws Exception {