diff --git a/.idea/codeStyleSettings.xml b/.idea/codeStyleSettings.xml
index 43b243577ce..d7a8bdafbff 100644
--- a/.idea/codeStyleSettings.xml
+++ b/.idea/codeStyleSettings.xml
@@ -158,6 +158,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java
index 7d101c06e95..537014e74ca 100644
--- a/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java
+++ b/compiler/backend/src/org/jetbrains/jet/codegen/AnnotationCodegen.java
@@ -17,7 +17,6 @@
package org.jetbrains.jet.codegen;
import com.intellij.psi.PsiElement;
-import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethod;
import org.jetbrains.jet.codegen.intrinsics.IntrinsicMethods;
import org.jetbrains.jet.lang.descriptors.*;
import org.jetbrains.jet.lang.descriptors.annotations.Annotated;
@@ -37,15 +36,22 @@ import java.util.Map;
* @author alex.tkachman
*/
public abstract class AnnotationCodegen {
- public void genAnnotations(Annotated annotated, JetTypeMapper typeMapper) {
+ final JetTypeMapper typeMapper;
+ final BindingContext bindingContext;
+
+ protected AnnotationCodegen(JetTypeMapper mapper) {
+ typeMapper = mapper;
+ bindingContext = typeMapper.bindingContext;
+ }
+
+ public void genAnnotations(Annotated annotated) {
if(annotated == null)
return;
if(!(annotated instanceof DeclarationDescriptor))
return;
- BindingContext bindingContext = typeMapper.bindingContext;
- PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, (DeclarationDescriptor) annotated);
+ PsiElement psiElement = bindingContext.get(BindingContext.DESCRIPTOR_TO_DECLARATION, (DeclarationDescriptor)annotated);
JetModifierList modifierList = null;
if(annotated instanceof ConstructorDescriptor && psiElement instanceof JetClass) {
@@ -67,83 +73,118 @@ public abstract class AnnotationCodegen {
assert annotationDescriptor != null;
JetType type = annotationDescriptor.getType();
- ClassifierDescriptor classifierDescriptor = type.getConstructor().getDeclarationDescriptor();
- RetentionPolicy rp = getRetentionPolicy(classifierDescriptor, typeMapper);
- if(rp != RetentionPolicy.SOURCE) {
- String internalName = typeMapper.mapType(type).getDescriptor();
- AnnotationVisitor annotationVisitor = visitAnnotation(internalName, rp == RetentionPolicy.RUNTIME);
+ genAnnotation(resolvedCall, type);
+ }
+ }
- for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) {
- ResolvedValueArgument valueArgument = entry.getValue();
- if (!(valueArgument instanceof DefaultValueArgument)) {
- List valueArguments = valueArgument.getArguments();
- assert valueArguments.size() == 1 : "Number of arguments on " + resolvedCall.getResultingDescriptor() + " = " + valueArguments.size(); // todo
- CompileTimeConstant> compileTimeConstant =
- bindingContext.get(BindingContext.COMPILE_TIME_VALUE, valueArguments.get(0).getArgumentExpression());
+ private void genAnnotation(ResolvedCall extends CallableDescriptor> resolvedCall,
+ JetType type) {
+ ClassifierDescriptor classifierDescriptor = type.getConstructor().getDeclarationDescriptor();
+ RetentionPolicy rp = getRetentionPolicy(classifierDescriptor, typeMapper);
+ if (rp == RetentionPolicy.SOURCE) {
+ return;
+ }
- String keyName = entry.getKey().getName();
- if(compileTimeConstant != null) {
- Object value = compileTimeConstant.getValue();
- annotationVisitor.visit(keyName, value);
- continue;
- }
+ String internalName = typeMapper.mapType(type).getDescriptor();
+ AnnotationVisitor annotationVisitor = visitAnnotation(internalName, rp == RetentionPolicy.RUNTIME);
- ExpressionValueArgument expressionValueArgument = (ExpressionValueArgument)valueArgument;
- JetExpression expression = expressionValueArgument.getArguments().get(0).getArgumentExpression();
- if(expression instanceof JetDotQualifiedExpression) {
- JetDotQualifiedExpression qualifiedExpression = (JetDotQualifiedExpression)expression;
- ResolvedCall extends CallableDescriptor> 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.getReturnType()).getDescriptor(),descriptor.getName());
- continue;
- }
- }
- }
- else {
- if(expression instanceof JetCallExpression) {
- JetCallExpression callExpression = (JetCallExpression)expression;
- ResolvedCall extends CallableDescriptor> 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) {
- if("Intrinsic".equals(annotation.getType().getConstructor().getDeclarationDescriptor().getName())) {
- value = (String) annotation.getValueArguments().get(0).getValue();
- break;
- }
- }
- }
- if(IntrinsicMethods.KOTLIN_JAVA_CLASS_FUNCTION.equals(value)) {
- annotationVisitor.visit(keyName, typeMapper.mapType(call.getResultingDescriptor().getReturnType().getArguments().get(0).getType()));
- continue;
- }
- 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()) {
- CompileTimeConstant> constant =
- bindingContext.get(BindingContext.COMPILE_TIME_VALUE, argument.getArgumentExpression());
- visitor.visit(null, constant.getValue());
- }
- visitor.visitEnd();
- continue;
- }
- }
- }
- }
+ getAnnotation(resolvedCall, annotationVisitor);
- throw new IllegalStateException("Don't know how to compile annotation value");
- }
+ annotationVisitor.visitEnd();
+ }
+
+ private void getAnnotation(ResolvedCall extends CallableDescriptor> resolvedCall, AnnotationVisitor annotationVisitor) {
+ for (Map.Entry entry : resolvedCall.getValueArguments().entrySet()) {
+ ResolvedValueArgument valueArgument = entry.getValue();
+ if (valueArgument instanceof DefaultValueArgument) {
+ continue;
+ }
+
+ String keyName = entry.getKey().getName();
+ genAnnotationValueArgument(annotationVisitor, valueArgument, keyName);
+ }
+ }
+
+ 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());
+ }
+ 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, String keyName, JetExpression expression) {
+ CompileTimeConstant> compileTimeConstant =
+ bindingContext.get(BindingContext.COMPILE_TIME_VALUE, expression);
+
+ if(compileTimeConstant != null) {
+ Object value = compileTimeConstant.getValue();
+ annotationVisitor.visit(keyName, value);
+ return;
+ }
+
+ if(expression instanceof JetDotQualifiedExpression) {
+ JetDotQualifiedExpression qualifiedExpression = (JetDotQualifiedExpression)expression;
+ ResolvedCall extends CallableDescriptor> 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.getReturnType()).getDescriptor(),descriptor.getName());
+ return;
}
-
- annotationVisitor.visitEnd();
}
}
+ else {
+ if(expression instanceof JetCallExpression) {
+ JetCallExpression callExpression = (JetCallExpression)expression;
+ ResolvedCall extends CallableDescriptor> 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) {
+ if("Intrinsic".equals(annotation.getType().getConstructor().getDeclarationDescriptor().getName())) {
+ value = (String) annotation.getValueArguments().get(0).getValue();
+ break;
+ }
+ }
+ }
+ if(IntrinsicMethods.KOTLIN_JAVA_CLASS_FUNCTION.equals(value)) {
+ 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().getDefaultType()).getDescriptor());
+ getAnnotation(call, visitor);
+ visitor.visitEnd();
+ return;
+ }
+ }
+ }
+ }
+
+ throw new IllegalStateException("Don't know how to compile annotation value");
}
private static RetentionPolicy getRetentionPolicy(ClassifierDescriptor descriptor, JetTypeMapper typeMapper) {
@@ -164,8 +205,8 @@ public abstract class AnnotationCodegen {
abstract AnnotationVisitor visitAnnotation(String descr, boolean visible);
- public static AnnotationCodegen forClass(final ClassVisitor cv) {
- return new AnnotationCodegen() {
+ public static AnnotationCodegen forClass(final ClassVisitor cv, JetTypeMapper mapper) {
+ return new AnnotationCodegen(mapper) {
@Override
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return cv.visitAnnotation(descr, visible);
@@ -173,8 +214,8 @@ public abstract class AnnotationCodegen {
};
}
- public static AnnotationCodegen forMethod(final MethodVisitor mv) {
- return new AnnotationCodegen() {
+ public static AnnotationCodegen forMethod(final MethodVisitor mv, JetTypeMapper mapper) {
+ return new AnnotationCodegen(mapper) {
@Override
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return mv.visitAnnotation(descr, visible);
@@ -182,8 +223,8 @@ public abstract class AnnotationCodegen {
};
}
- public static AnnotationCodegen forField(final FieldVisitor fv) {
- return new AnnotationCodegen() {
+ public static AnnotationCodegen forField(final FieldVisitor fv, JetTypeMapper mapper) {
+ return new AnnotationCodegen(mapper) {
@Override
AnnotationVisitor visitAnnotation(String descr, boolean visible) {
return fv.visitAnnotation(descr, visible);
diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java
index 99716fa4766..e4d7dc8ada6 100644
--- a/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java
+++ b/compiler/backend/src/org/jetbrains/jet/codegen/FunctionCodegen.java
@@ -118,7 +118,7 @@ public class FunctionCodegen {
if (isAbstract) flags |= ACC_ABSTRACT;
final MethodVisitor mv = v.newMethod(fun, flags, jvmSignature.getAsmMethod().getName(), jvmSignature.getAsmMethod().getDescriptor(), jvmSignature.getGenericsSignature(), null);
- AnnotationCodegen.forMethod(mv).genAnnotations(functionDescriptor, state.getInjector().getJetTypeMapper());
+ AnnotationCodegen.forMethod(mv, state.getInjector().getJetTypeMapper()).genAnnotations(functionDescriptor);
if(v.generateCode() != ClassBuilder.Mode.SIGNATURES) {
int start = 0;
if (needJetAnnotations) {
diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java
index 3dec9fbf4cd..0530f9df131 100644
--- a/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java
+++ b/compiler/backend/src/org/jetbrains/jet/codegen/ImplementationBodyCodegen.java
@@ -154,7 +154,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
v.visitInnerClass(outerClassInernalName + JvmAbi.CLASS_OBJECT_SUFFIX, outerClassInernalName, JvmAbi.CLASS_OBJECT_CLASS_NAME, innerClassAccess);
}
- AnnotationCodegen.forClass(v.getVisitor()).genAnnotations(descriptor, typeMapper);
+ AnnotationCodegen.forClass(v.getVisitor(), typeMapper).genAnnotations(descriptor);
if (signature.getKotlinGenericSignature() != null) {
AnnotationVisitor annotationVisitor = v.newAnnotation(myClass, JvmStdlibNames.JET_CLASS.getDescriptor(), true);
@@ -519,7 +519,7 @@ public class ImplementationBodyCodegen extends ClassBodyCodegen {
}
jetConstructorVisitor.visitEnd();
- AnnotationCodegen.forMethod(mv).genAnnotations(constructorDescriptor, typeMapper);
+ AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(constructorDescriptor);
if (constructorDescriptor != null) {
int i = 0;
diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java
index ff09feb49e1..d5321f9b329 100644
--- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java
+++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java
@@ -98,7 +98,7 @@ public class PropertyCodegen {
modifiers |= Opcodes.ACC_VOLATILE;
}
FieldVisitor fieldVisitor = v.newField(p, modifiers, p.getName(), state.getInjector().getJetTypeMapper().mapType(propertyDescriptor.getType()).getDescriptor(), null, value);
- AnnotationCodegen.forField(fieldVisitor).genAnnotations(propertyDescriptor, state.getInjector().getJetTypeMapper());
+ AnnotationCodegen.forField(fieldVisitor, state.getInjector().getJetTypeMapper()).genAnnotations(propertyDescriptor);
}
}
@@ -172,7 +172,7 @@ public class PropertyCodegen {
if(propertyDescriptor.getGetter() != null) {
assert !propertyDescriptor.getGetter().hasBody();
- AnnotationCodegen.forMethod(mv).genAnnotations(propertyDescriptor.getGetter(), state.getInjector().getJetTypeMapper());
+ AnnotationCodegen.forMethod(mv, state.getInjector().getJetTypeMapper()).genAnnotations(propertyDescriptor.getGetter());
}
if (v.generateCode() != ClassBuilder.Mode.SIGNATURES && (!isTrait || kind instanceof OwnerKind.DelegateKind)) {
@@ -246,7 +246,7 @@ public class PropertyCodegen {
if(propertyDescriptor.getSetter() != null) {
assert !propertyDescriptor.getSetter().hasBody();
- AnnotationCodegen.forMethod(mv).genAnnotations(propertyDescriptor.getSetter(), state.getInjector().getJetTypeMapper());
+ AnnotationCodegen.forMethod(mv, state.getInjector().getJetTypeMapper()).genAnnotations(propertyDescriptor.getSetter());
}
if (v.generateCode() != ClassBuilder.Mode.SIGNATURES && (!isTrait || kind instanceof OwnerKind.DelegateKind)) {
diff --git a/compiler/tests/org/jetbrains/jet/codegen/AnnotationGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/AnnotationGenTest.java
index 211d49d5418..cc68c573163 100644
--- a/compiler/tests/org/jetbrains/jet/codegen/AnnotationGenTest.java
+++ b/compiler/tests/org/jetbrains/jet/codegen/AnnotationGenTest.java
@@ -18,9 +18,7 @@ package org.jetbrains.jet.codegen;
import jet.JetObject;
-import java.lang.annotation.Annotation;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.*;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
@@ -120,4 +118,42 @@ public class AnnotationGenTest extends CodegenTestCase {
assertEquals("239", methods[0].invoke(bClassAnnotation));
}
+
+ public void testAnnotationClassWithAnnotationProperty()
+ throws
+ NoSuchFieldException,
+ NoSuchMethodException,
+ ClassNotFoundException,
+ IllegalAccessException,
+ InstantiationException,
+ InvocationTargetException {
+ loadText("import java.lang.annotation.*\n" +
+ "" +
+ "annotation class C(val c: String)\n" +
+ "Retention(RetentionPolicy.RUNTIME) annotation class A(val a: C)\n" +
+ "" +
+ "A(C(\"239\")) class B()");
+ Class aClass = generateClass("A");
+
+ Retention annotation = (Retention)aClass.getAnnotation(Retention.class);
+ RetentionPolicy value = annotation.value();
+ assertEquals(RetentionPolicy.RUNTIME, value);
+
+ Method[] methods = aClass.getDeclaredMethods();
+ assertEquals(1, methods.length);
+ assertEquals("a", methods[0].getName());
+ assertEquals("C", methods[0].getReturnType().getName());
+ assertEquals(0, methods[0].getParameterTypes().length);
+ assertTrue(aClass.isAnnotation());
+
+ Class> bClass = aClass.getClassLoader().loadClass("B");
+ Annotation bClassAnnotation = bClass.getAnnotation(aClass);
+ assertNotNull(bClassAnnotation);
+
+ Object invoke = methods[0].invoke(bClassAnnotation);
+ // there is some Proxy here
+ Class> cClass = invoke.getClass().getInterfaces()[0];
+ assertEquals("C", cClass.getName());
+ assertEquals("239", cClass.getDeclaredMethod("c").invoke(invoke));
+ }
}
\ No newline at end of file
diff --git a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java
index 459ae563804..b2366b64fee 100644
--- a/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java
+++ b/compiler/tests/org/jetbrains/jet/codegen/StdlibTest.java
@@ -20,9 +20,7 @@ import org.jetbrains.jet.compiler.CompileEnvironment;
import org.jetbrains.jet.lang.psi.JetPsiUtil;
import java.io.File;
-import java.lang.annotation.Annotation;
-import java.lang.annotation.Retention;
-import java.lang.annotation.RetentionPolicy;
+import java.lang.annotation.*;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.net.MalformedURLException;
@@ -269,4 +267,55 @@ public class StdlibTest extends CodegenTestCase {
assertEquals(239, ((int[])invoke)[0]);
assertEquals(932, ((int[])invoke)[1]);
}
+
+ public void testAnnotationClassWithEnumArrayProperty()
+ throws
+ NoSuchFieldException,
+ NoSuchMethodException,
+ ClassNotFoundException,
+ IllegalAccessException,
+ InstantiationException,
+ InvocationTargetException {
+ loadText("import java.lang.annotation.*\n" +
+ "" +
+ "Target(ElementType.TYPE, ElementType.METHOD) annotation class A");
+ Class aClass = generateClass("A");
+
+ Target annotation = (Target)aClass.getAnnotation(Target.class);
+ ElementType[] value = annotation.value();
+ assertEquals(2, value.length);
+
+ assertEquals(ElementType.TYPE, value[0]);
+ assertEquals(ElementType.METHOD, value[1]);
+ }
+
+ public void testAnnotationClassWithAnnotationArrayProperty()
+ throws
+ NoSuchFieldException,
+ NoSuchMethodException,
+ ClassNotFoundException,
+ IllegalAccessException,
+ InstantiationException,
+ InvocationTargetException {
+ loadText("import java.lang.annotation.*\n" +
+ "" +
+ "Retention(RetentionPolicy.RUNTIME) annotation class A(val a: Array)\n" +
+ "" +
+ "A(array(Retention(RetentionPolicy.RUNTIME),Retention(RetentionPolicy.SOURCE))) class B()");
+ Class aClass = generateClass("A");
+
+ Method[] methods = aClass.getDeclaredMethods();
+ assertEquals(1, methods.length);
+ assertEquals("a", methods[0].getName());
+
+ Class> bClass = aClass.getClassLoader().loadClass("B");
+ Annotation bClassAnnotation = bClass.getAnnotation(aClass);
+ assertNotNull(bClassAnnotation);
+
+ Object invoke = methods[0].invoke(bClassAnnotation);
+ Retention[] invoke1 = (Retention[])invoke;
+ assertEquals(2, invoke1.length);
+ assertEquals(invoke1[0].value(), RetentionPolicy.RUNTIME);
+ assertEquals(invoke1[1].value(), RetentionPolicy.SOURCE);
+ }
}