提交 9d752561 编写于 作者: A Alex Tkachman

almost full support for annotations

上级 b5114d5f
......@@ -158,6 +158,41 @@
<option name="TAB_SIZE" value="8" />
</indentOptions>
</codeStyleSettings>
<codeStyleSettings language="jet">
<option name="LINE_COMMENT_AT_FIRST_COLUMN" value="false" />
<option name="BLOCK_COMMENT_AT_FIRST_COLUMN" value="false" />
<option name="KEEP_BLANK_LINES_BEFORE_RBRACE" value="0" />
<option name="ELSE_ON_NEW_LINE" value="true" />
<option name="WHILE_ON_NEW_LINE" value="true" />
<option name="CATCH_ON_NEW_LINE" value="true" />
<option name="FINALLY_ON_NEW_LINE" value="true" />
<option name="ALIGN_MULTILINE_PARAMETERS_IN_CALLS" value="true" />
<option name="ALIGN_MULTILINE_BINARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_ASSIGNMENT" value="true" />
<option name="ALIGN_MULTILINE_TERNARY_OPERATION" value="true" />
<option name="ALIGN_MULTILINE_THROWS_LIST" value="true" />
<option name="ALIGN_MULTILINE_EXTENDS_LIST" value="true" />
<option name="ALIGN_MULTILINE_PARENTHESIZED_EXPRESSION" value="true" />
<option name="CALL_PARAMETERS_WRAP" value="1" />
<option name="METHOD_PARAMETERS_WRAP" value="5" />
<option name="EXTENDS_LIST_WRAP" value="1" />
<option name="THROWS_LIST_WRAP" value="5" />
<option name="EXTENDS_KEYWORD_WRAP" value="1" />
<option name="THROWS_KEYWORD_WRAP" value="1" />
<option name="METHOD_CALL_CHAIN_WRAP" value="1" />
<option name="BINARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_WRAP" value="5" />
<option name="TERNARY_OPERATION_SIGNS_ON_NEXT_LINE" value="true" />
<option name="FOR_STATEMENT_WRAP" value="5" />
<option name="ARRAY_INITIALIZER_WRAP" value="1" />
<option name="ASSIGNMENT_WRAP" value="1" />
<option name="IF_BRACE_FORCE" value="1" />
<option name="DOWHILE_BRACE_FORCE" value="1" />
<option name="WHILE_BRACE_FORCE" value="1" />
<option name="FOR_BRACE_FORCE" value="1" />
<option name="FIELD_ANNOTATION_WRAP" value="0" />
<option name="PARENT_SETTINGS_INSTALLED" value="true" />
</codeStyleSettings>
</value>
</option>
<option name="USE_PER_PROJECT_SETTINGS" value="true" />
......
......@@ -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);
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> entry : resolvedCall.getValueArguments().entrySet()) {
ResolvedValueArgument valueArgument = entry.getValue();
if (!(valueArgument instanceof DefaultValueArgument)) {
List<ValueArgument> 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());
String keyName = entry.getKey().getName();
if(compileTimeConstant != null) {
Object value = compileTimeConstant.getValue();
annotationVisitor.visit(keyName, value);
continue;
}
genAnnotation(resolvedCall, type);
}
}
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 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;
}
getAnnotation(resolvedCall, annotationVisitor);
annotationVisitor.visitEnd();
}
private void getAnnotation(ResolvedCall<? extends CallableDescriptor> resolvedCall, AnnotationVisitor annotationVisitor) {
for (Map.Entry<ValueParameterDescriptor, ResolvedValueArgument> 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<ValueArgument> 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;
}
}
}
else {
if(expression instanceof JetCallExpression) {
JetCallExpression callExpression = (JetCallExpression)expression;
ResolvedCall<? extends CallableDescriptor> call =
bindingContext.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression());
if(call != null) {
List<AnnotationDescriptor> 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;
}
}
else {
if(expression instanceof JetCallExpression) {
JetCallExpression callExpression = (JetCallExpression)expression;
ResolvedCall<? extends CallableDescriptor> call =
bindingContext.get(BindingContext.RESOLVED_CALL, callExpression.getCalleeExpression());
if(call != null) {
List<AnnotationDescriptor> 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;
}
}
}
}
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());
}
throw new IllegalStateException("Don't know how to compile annotation value");
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;
}
}
annotationVisitor.visitEnd();
}
}
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);
......
......@@ -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) {
......
......@@ -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;
......
......@@ -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)) {
......
......@@ -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
......@@ -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<Retention>)\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);
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册