diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java index 44e1e4e7da7..921b3c3e4d5 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationResolver.java @@ -44,6 +44,7 @@ import java.util.List; import java.util.Map; import static org.jetbrains.jet.lang.resolve.BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT; +import static org.jetbrains.jet.lang.resolve.BindingContext.COMPILE_TIME_INITIALIZER; import static org.jetbrains.jet.lang.types.TypeUtils.NO_EXPECTED_TYPE; public class AnnotationResolver { @@ -274,6 +275,9 @@ public class AnnotationResolver { if (isEnumProperty(propertyDescriptor)) { return new EnumValue(propertyDescriptor); } + if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) { + return trace.getBindingContext().get(COMPILE_TIME_INITIALIZER, propertyDescriptor); + } } } return null; diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java index 8c298ec0284..35ef85149fb 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/AnnotationUtils.java @@ -17,8 +17,7 @@ package org.jetbrains.jet.lang.resolve; import org.jetbrains.annotations.NotNull; -import org.jetbrains.jet.lang.descriptors.ClassDescriptor; -import org.jetbrains.jet.lang.descriptors.VariableDescriptor; +import org.jetbrains.jet.lang.descriptors.*; import org.jetbrains.jet.lang.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.jet.lang.psi.JetParameter; import org.jetbrains.jet.lang.psi.JetTypeReference; @@ -33,8 +32,7 @@ import java.util.List; import static org.jetbrains.jet.lang.diagnostics.Errors.INVALID_TYPE_OF_ANNOTATION_MEMBER; import static org.jetbrains.jet.lang.diagnostics.Errors.NULLABLE_TYPE_OF_ANNOTATION_MEMBER; import static org.jetbrains.jet.lang.resolve.BindingContext.VALUE_PARAMETER; -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isAnnotationClass; -import static org.jetbrains.jet.lang.resolve.DescriptorUtils.isEnumClass; +import static org.jetbrains.jet.lang.resolve.DescriptorUtils.*; public class AnnotationUtils { @@ -116,6 +114,17 @@ public class AnnotationUtils { return false; } + public static boolean isPropertyAcceptableAsAnnotationParameter(@NotNull PropertyDescriptor descriptor) { + if (descriptor.isVar()) { + return false; + } + if (isClassObject(descriptor.getContainingDeclaration()) || isTopLevelDeclaration(descriptor)) { + JetType type = descriptor.getType(); + return KotlinBuiltIns.getInstance().isPrimitiveType(type) || KotlinBuiltIns.getInstance().getStringType().equals(type); + } + return false; + } + private static boolean isJavaLangClass(ClassDescriptor descriptor) { return "java.lang.Class".equals(DescriptorUtils.getFQName(descriptor).asString()); } diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java index 1fce91e3081..530749a1dd8 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BindingContext.java @@ -74,6 +74,8 @@ public interface BindingContext { Slices.sliceBuilder().setOpposite(ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT).build(); WritableSlice> COMPILE_TIME_VALUE = Slices.createSimpleSlice(); + WritableSlice> COMPILE_TIME_INITIALIZER = Slices.createSimpleSlice(); + WritableSlice TYPE = Slices.createSimpleSlice(); WritableSlice EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); WritableSlice EXPECTED_EXPRESSION_TYPE = new BasicWritableSlice(DO_NOTHING); diff --git a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java index dee4c9d5605..8979ae35bb9 100644 --- a/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java +++ b/compiler/frontend/src/org/jetbrains/jet/lang/resolve/BodyResolver.java @@ -133,9 +133,9 @@ public class BodyResolver { context = bodiesResolveContext; resolveDelegationSpecifierLists(); - resolveClassAnnotations(); resolvePropertyDeclarationBodies(); + resolveClassAnnotations(); resolveAnonymousInitializers(); resolvePrimaryConstructorParameters(); @@ -626,6 +626,12 @@ public class BodyResolver { scope, propertyDescriptor.getTypeParameters(), NO_RECEIVER_PARAMETER, trace); JetType expectedTypeForInitializer = property.getTypeRef() != null ? propertyDescriptor.getType() : NO_EXPECTED_TYPE; expressionTypingServices.getType(propertyDeclarationInnerScope, initializer, expectedTypeForInitializer, DataFlowInfo.EMPTY, trace); + if (AnnotationUtils.isPropertyAcceptableAsAnnotationParameter(propertyDescriptor)) { + CompileTimeConstant constant = annotationResolver.resolveExpressionToCompileTimeValue(initializer, expectedTypeForInitializer, trace); + if (constant != null) { + trace.record(BindingContext.COMPILE_TIME_INITIALIZER, propertyDescriptor, constant); + } + } } @NotNull diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/kotlinPropertyFromClassObjectAsParameter.kt b/compiler/testData/codegen/boxWithStdlib/annotations/kotlinPropertyFromClassObjectAsParameter.kt new file mode 100644 index 00000000000..8c242aa3353 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/kotlinPropertyFromClassObjectAsParameter.kt @@ -0,0 +1,46 @@ +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy + +Ann(Foo.i, Foo.s, Foo.f, Foo.d, Foo.l, Foo.b, Foo.bool, Foo.c, Foo.str) class MyClass + +fun box(): String { + val ann = javaClass().getAnnotation(javaClass()) + if (ann == null) return "fail: cannot find Ann on MyClass}" + if (ann.i != 2) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.s != 2.toShort()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.f != 2.toFloat()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.d != 2.toDouble()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.l != 2.toLong()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.b != 2.toByte()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (!ann.bool) return "fail: annotation parameter i should be true, but was ${ann.i}" + if (ann.c != 'c') return "fail: annotation parameter i should be c, but was ${ann.i}" + if (ann.str != "str") return "fail: annotation parameter i should be str, but was ${ann.i}" + return "OK" +} + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann( + val i: Int, + val s: Short, + val f: Float, + val d: Double, + val l: Long, + val b: Byte, + val bool: Boolean, + val c: Char, + val str: String +) + +class Foo { + class object { + val i: Int = 2 + val s: Short = 2 + val f: Float = 2.0 + val d: Double = 2.0 + val l: Long = 2 + val b: Byte = 2 + val bool: Boolean = true + val c: Char = 'c' + val str: String = "str" + } +} diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/kotlinTopLevelPropertyAsParameter.kt b/compiler/testData/codegen/boxWithStdlib/annotations/kotlinTopLevelPropertyAsParameter.kt new file mode 100644 index 00000000000..5cb03a8bcb5 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/kotlinTopLevelPropertyAsParameter.kt @@ -0,0 +1,42 @@ +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy + +Ann(i, s, f, d, l, b, bool, c, str) class MyClass + +fun box(): String { + val ann = javaClass().getAnnotation(javaClass()) + if (ann == null) return "fail: cannot find Ann on MyClass}" + if (ann.i != 2) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.s != 2.toShort()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.f != 2.toFloat()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.d != 2.toDouble()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.l != 2.toLong()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (ann.b != 2.toByte()) return "fail: annotation parameter i should be 2, but was ${ann.i}" + if (!ann.bool) return "fail: annotation parameter i should be true, but was ${ann.i}" + if (ann.c != 'c') return "fail: annotation parameter i should be c, but was ${ann.i}" + if (ann.str != "str") return "fail: annotation parameter i should be str, but was ${ann.i}" + return "OK" +} + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann( + val i: Int, + val s: Short, + val f: Float, + val d: Double, + val l: Long, + val b: Byte, + val bool: Boolean, + val c: Char, + val str: String +) + +val i: Int = 2 +val s: Short = 2 +val f: Float = 2.0 +val d: Double = 2.0 +val l: Long = 2 +val b: Byte = 2 +val bool: Boolean = true +val c: Char = 'c' +val str: String = "str" \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/nestedClassPropertyAsParameter.kt b/compiler/testData/codegen/boxWithStdlib/annotations/nestedClassPropertyAsParameter.kt new file mode 100644 index 00000000000..d58b8d32670 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/nestedClassPropertyAsParameter.kt @@ -0,0 +1,22 @@ +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy + +Ann(A.B.i) class MyClass + +fun box(): String { + val ann = javaClass().getAnnotation(javaClass()) + 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}" + return "OK" +} + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann(val i: Int) + +class A { + class B { + class object { + val i = 1 + } + } +} diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/propertyWithPropertyInInitializerAsParameter.kt b/compiler/testData/codegen/boxWithStdlib/annotations/propertyWithPropertyInInitializerAsParameter.kt new file mode 100644 index 00000000000..97afafad53c --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/propertyWithPropertyInInitializerAsParameter.kt @@ -0,0 +1,17 @@ +import java.lang.annotation.Retention +import java.lang.annotation.RetentionPolicy + +Ann(i) class MyClass + +fun box(): String { + val ann = javaClass().getAnnotation(javaClass()) + 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}" + return "OK" +} + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann(val i: Int) + +val i2: Int = 1 +val i: Int = i2 diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 58dd57a23f2..a338f2cf7b1 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -48,11 +48,31 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/defaultParameterValues.kt"); } + @TestMetadata("kotlinPropertyFromClassObjectAsParameter.kt") + public void testKotlinPropertyFromClassObjectAsParameter() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/kotlinPropertyFromClassObjectAsParameter.kt"); + } + + @TestMetadata("kotlinTopLevelPropertyAsParameter.kt") + public void testKotlinTopLevelPropertyAsParameter() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/kotlinTopLevelPropertyAsParameter.kt"); + } + + @TestMetadata("nestedClassPropertyAsParameter.kt") + public void testNestedClassPropertyAsParameter() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/nestedClassPropertyAsParameter.kt"); + } + @TestMetadata("parameterWithPrimitiveType.kt") public void testParameterWithPrimitiveType() throws Exception { doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/parameterWithPrimitiveType.kt"); } + @TestMetadata("propertyWithPropertyInInitializerAsParameter.kt") + public void testPropertyWithPropertyInInitializerAsParameter() throws Exception { + doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/propertyWithPropertyInInitializerAsParameter.kt"); + } + @TestMetadata("varargInAnnotationParameter.kt") public void testVarargInAnnotationParameter() throws Exception { doTestWithStdlib("compiler/testData/codegen/boxWithStdlib/annotations/varargInAnnotationParameter.kt");