Write default values for annotation parameters
#KT-3197 Fixed
This commit is contained in:
@@ -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
|
||||
+6
-1
@@ -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 {
|
||||
|
||||
Reference in New Issue
Block a user