Implementation of Kotlin's 'target' annotation mapping to Java's 'Target' annotation + tests

This commit is contained in:
Mikhail Glukhikh
2015-07-14 19:42:05 +03:00
parent 2a1058ed63
commit af5e7f58da
62 changed files with 547 additions and 54 deletions
@@ -24,8 +24,10 @@ import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.Annotated; import org.jetbrains.kotlin.descriptors.annotations.Annotated;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationArgumentVisitor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor; import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationTarget;
import org.jetbrains.kotlin.load.java.JvmAnnotationNames; import org.jetbrains.kotlin.load.java.JvmAnnotationNames;
import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.FqName;
import org.jetbrains.kotlin.resolve.AnnotationTargetChecker;
import org.jetbrains.kotlin.resolve.constants.*; import org.jetbrains.kotlin.resolve.constants.*;
import org.jetbrains.kotlin.resolve.constants.StringValue; import org.jetbrains.kotlin.resolve.constants.StringValue;
import org.jetbrains.kotlin.types.Flexibility; import org.jetbrains.kotlin.types.Flexibility;
@@ -34,8 +36,10 @@ import org.jetbrains.kotlin.types.TypeUtils;
import org.jetbrains.kotlin.types.TypesPackage; import org.jetbrains.kotlin.types.TypesPackage;
import org.jetbrains.org.objectweb.asm.*; import org.jetbrains.org.objectweb.asm.*;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy; import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.util.*; import java.util.*;
import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getClassObjectType; import static org.jetbrains.kotlin.resolve.descriptorUtil.DescriptorUtilPackage.getClassObjectType;
@@ -123,6 +127,7 @@ public abstract class AnnotationCodegen {
ClassDescriptor classDescriptor = (ClassDescriptor) annotated; ClassDescriptor classDescriptor = (ClassDescriptor) annotated;
if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) { if (classDescriptor.getKind() == ClassKind.ANNOTATION_CLASS) {
generateRetentionAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent); generateRetentionAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
generateTargetAnnotation(classDescriptor, annotationDescriptorsAlreadyPresent);
} }
} }
} }
@@ -166,6 +171,47 @@ public abstract class AnnotationCodegen {
generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass); generateAnnotationIfNotPresent(annotationDescriptorsAlreadyPresent, annotationClass);
} }
private static final Map<AnnotationTarget, ElementType> annotationTargetMap =
new EnumMap<AnnotationTarget, ElementType>(AnnotationTarget.class);
static {
annotationTargetMap.put(AnnotationTarget.PACKAGE, ElementType.PACKAGE);
annotationTargetMap.put(AnnotationTarget.CLASSIFIER, ElementType.TYPE);
annotationTargetMap.put(AnnotationTarget.ANNOTATION_CLASS, ElementType.ANNOTATION_TYPE);
annotationTargetMap.put(AnnotationTarget.CONSTRUCTOR, ElementType.CONSTRUCTOR);
annotationTargetMap.put(AnnotationTarget.LOCAL_VARIABLE, ElementType.LOCAL_VARIABLE);
annotationTargetMap.put(AnnotationTarget.FUNCTION, ElementType.METHOD);
annotationTargetMap.put(AnnotationTarget.PROPERTY_GETTER, ElementType.METHOD);
annotationTargetMap.put(AnnotationTarget.PROPERTY_SETTER, ElementType.METHOD);
annotationTargetMap.put(AnnotationTarget.FIELD, ElementType.FIELD);
annotationTargetMap.put(AnnotationTarget.VALUE_PARAMETER, ElementType.PARAMETER);
}
private void generateTargetAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
String descriptor = Type.getType(Target.class).getDescriptor();
if (!annotationDescriptorsAlreadyPresent.add(descriptor)) return;
Set<AnnotationTarget> targets = AnnotationTargetChecker.INSTANCE$.possibleTargetSet(classDescriptor);
Set<ElementType> javaTargets;
if (targets == null) {
javaTargets = getJavaTargetList(classDescriptor);
if (javaTargets == null) return;
}
else {
javaTargets = EnumSet.noneOf(ElementType.class);
for (AnnotationTarget target : targets) {
if (annotationTargetMap.get(target) == null) continue;
javaTargets.add(annotationTargetMap.get(target));
}
}
AnnotationVisitor visitor = visitAnnotation(descriptor, true);
AnnotationVisitor arrayVisitor = visitor.visitArray("value");
for (ElementType javaTarget : javaTargets) {
arrayVisitor.visitEnum(null, Type.getType(ElementType.class).getDescriptor(), javaTarget.name());
}
arrayVisitor.visitEnd();
visitor.visitEnd();
}
private void generateRetentionAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) { private void generateRetentionAnnotation(@NotNull ClassDescriptor classDescriptor, @NotNull Set<String> annotationDescriptorsAlreadyPresent) {
RetentionPolicy policy = getRetentionPolicy(classDescriptor); RetentionPolicy policy = getRetentionPolicy(classDescriptor);
String descriptor = Type.getType(Retention.class).getDescriptor(); String descriptor = Type.getType(Retention.class).getDescriptor();
@@ -337,18 +383,46 @@ public abstract class AnnotationCodegen {
} }
} }
@Nullable
private Set<ElementType> getJavaTargetList(ClassDescriptor descriptor) {
AnnotationDescriptor targetAnnotation = descriptor.getAnnotations().findAnnotation(new FqName(Target.class.getName()));
if (targetAnnotation != null) {
Collection<ConstantValue<?>> valueArguments = targetAnnotation.getAllValueArguments().values();
if (!valueArguments.isEmpty()) {
ConstantValue<?> compileTimeConstant = valueArguments.iterator().next();
if (compileTimeConstant instanceof ArrayValue) {
List<? extends ConstantValue<?>> values = ((ArrayValue) compileTimeConstant).getValue();
Set<ElementType> result = EnumSet.noneOf(ElementType.class);
for (ConstantValue<?> value : values) {
if (value instanceof EnumValue) {
ClassDescriptor enumEntry = ((EnumValue) value).getValue();
JetType classObjectType = getClassObjectType(enumEntry);
if (classObjectType != null) {
if ("java/lang/annotation/ElementType".equals(typeMapper.mapType(classObjectType).getInternalName())) {
result.add(ElementType.valueOf(enumEntry.getName().asString()));
}
}
}
}
return result;
}
}
}
return null;
}
@NotNull @NotNull
private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) { private RetentionPolicy getRetentionPolicy(@NotNull Annotated descriptor) {
AnnotationDescriptor kotlinAnnotation = descriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation); AnnotationDescriptor kotlinAnnotation = descriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.annotation);
if (kotlinAnnotation != null) { if (kotlinAnnotation != null) {
for (Map.Entry<ValueParameterDescriptor, ConstantValue<?>> argument: kotlinAnnotation.getAllValueArguments().entrySet()) { for (Map.Entry<ValueParameterDescriptor, ConstantValue<?>> argument : kotlinAnnotation.getAllValueArguments().entrySet()) {
if ("retention".equals(argument.getKey().getName().asString()) && argument.getValue() instanceof EnumValue) { if ("retention".equals(argument.getKey().getName().asString()) && argument.getValue() instanceof EnumValue) {
ClassDescriptor enumEntry = ((EnumValue) argument.getValue()).getValue(); ClassDescriptor enumEntry = ((EnumValue) argument.getValue()).getValue();
JetType classObjectType = getClassObjectType(enumEntry); JetType classObjectType = getClassObjectType(enumEntry);
if (classObjectType != null) { if (classObjectType != null) {
if ("kotlin/annotation/AnnotationRetention".equals(typeMapper.mapType(classObjectType).getInternalName())) { if ("kotlin/annotation/AnnotationRetention".equals(typeMapper.mapType(classObjectType).getInternalName())) {
String entryName = enumEntry.getName().asString(); String entryName = enumEntry.getName().asString();
for (KotlinRetention retention: KotlinRetention.values()) { for (KotlinRetention retention : KotlinRetention.values()) {
if (retention.name().equals(entryName)) return retention.mapped; if (retention.name().equals(entryName)) return retention.mapped;
} }
} }
@@ -27,33 +27,13 @@ import org.jetbrains.kotlin.resolve.constants.ArrayValue
import org.jetbrains.kotlin.resolve.constants.EnumValue import org.jetbrains.kotlin.resolve.constants.EnumValue
import org.jetbrains.kotlin.types.JetType import org.jetbrains.kotlin.types.JetType
import org.jetbrains.kotlin.types.TypeUtils import org.jetbrains.kotlin.types.TypeUtils
import java.lang.annotation.ElementType
import java.util.* import java.util.*
import org.jetbrains.kotlin.descriptors.annotations.AnnotationTarget
import kotlin.annotation
public object AnnotationTargetChecker { public object AnnotationTargetChecker {
// NOTE: this enum must have the same entries with kotlin.annotation.AnnotationTarget
public enum class Target(val description: String, val isDefault: Boolean = true) {
PACKAGE("package"),
CLASSIFIER("classifier"),
ANNOTATION_CLASS("annotation class"),
TYPE_PARAMETER("type parameter", false),
PROPERTY("property"),
FIELD("field"),
LOCAL_VARIABLE("local variable"),
VALUE_PARAMETER("value parameter"),
CONSTRUCTOR("constructor"),
FUNCTION("function"),
PROPERTY_GETTER("getter"),
PROPERTY_SETTER("setter"),
TYPE("type usage", false),
EXPRESSION("expression", false),
FILE("file", false)
}
private val DEFAULT_TARGET_LIST = Target.values().filter { it.isDefault }.map { it.name() }
private val ALL_TARGET_LIST = Target.values().map { it.name() }
public fun check(annotated: JetAnnotated, trace: BindingTrace, descriptor: ClassDescriptor? = null) { public fun check(annotated: JetAnnotated, trace: BindingTrace, descriptor: ClassDescriptor? = null) {
if (annotated is JetTypeParameter) return // TODO: support type parameter annotations if (annotated is JetTypeParameter) return // TODO: support type parameter annotations
val actualTargets = getActualTargetList(annotated, descriptor) val actualTargets = getActualTargetList(annotated, descriptor)
@@ -82,7 +62,7 @@ public object AnnotationTargetChecker {
public fun checkExpression(expression: JetExpression, trace: BindingTrace) { public fun checkExpression(expression: JetExpression, trace: BindingTrace) {
for (entry in expression.getAnnotationEntries()) { for (entry in expression.getAnnotationEntries()) {
checkAnnotationEntry(entry, listOf(Target.EXPRESSION), trace) checkAnnotationEntry(entry, listOf(AnnotationTarget.EXPRESSION), trace)
} }
if (expression is JetFunctionLiteralExpression) { if (expression is JetFunctionLiteralExpression) {
for (parameter in expression.getValueParameters()) { for (parameter in expression.getValueParameters()) {
@@ -91,51 +71,55 @@ public object AnnotationTargetChecker {
} }
} }
private fun possibleTargetList(entry: JetAnnotationEntry, trace: BindingTrace): List<String> { public fun possibleTargetSet(classDescriptor: ClassDescriptor): Set<AnnotationTarget>? {
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return DEFAULT_TARGET_LIST
// For descriptor with error type, all targets are considered as possible
if (descriptor.getType().isError()) return ALL_TARGET_LIST
val classDescriptor = TypeUtils.getClassDescriptor(descriptor.getType()) ?: return DEFAULT_TARGET_LIST
val targetEntryDescriptor = classDescriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.target) val targetEntryDescriptor = classDescriptor.getAnnotations().findAnnotation(KotlinBuiltIns.FQ_NAMES.target)
?: return DEFAULT_TARGET_LIST ?: return null
val valueArguments = targetEntryDescriptor.getAllValueArguments() val valueArguments = targetEntryDescriptor.getAllValueArguments()
val valueArgument = valueArguments.entrySet().firstOrNull()?.getValue() as? ArrayValue ?: return DEFAULT_TARGET_LIST val valueArgument = valueArguments.entrySet().firstOrNull()?.getValue() as? ArrayValue ?: return null
return valueArgument.value.filterIsInstance<EnumValue>().map { it.value.getName().asString() } return valueArgument.value.filterIsInstance<EnumValue>().map {
AnnotationTarget.valueOrNull(it.value.getName().asString())
}.filterNotNull().toSet()
} }
private fun checkAnnotationEntry(entry: JetAnnotationEntry, actualTargets: List<Target>, trace: BindingTrace) { private fun possibleTargetSet(entry: JetAnnotationEntry, trace: BindingTrace): Set<AnnotationTarget> {
val possibleTargets = possibleTargetList(entry, trace) val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: return AnnotationTarget.DEFAULT_TARGET_SET
for (actualTarget in actualTargets) { // For descriptor with error type, all targets are considered as possible
if (actualTarget.name() in possibleTargets) return if (descriptor.getType().isError()) return AnnotationTarget.ALL_TARGET_SET
} val classDescriptor = TypeUtils.getClassDescriptor(descriptor.getType()) ?: return AnnotationTarget.DEFAULT_TARGET_SET
return possibleTargetSet(classDescriptor) ?: AnnotationTarget.DEFAULT_TARGET_SET
}
private fun checkAnnotationEntry(entry: JetAnnotationEntry, actualTargets: List<AnnotationTarget>, trace: BindingTrace) {
val possibleTargets = possibleTargetSet(entry, trace)
if (actualTargets.any { it in possibleTargets }) return
trace.report(Errors.WRONG_ANNOTATION_TARGET.on(entry, actualTargets.firstOrNull()?.description ?: "unidentified target")) trace.report(Errors.WRONG_ANNOTATION_TARGET.on(entry, actualTargets.firstOrNull()?.description ?: "unidentified target"))
} }
private fun getActualTargetList(annotated: JetAnnotated, descriptor: ClassDescriptor?): List<Target> { private fun getActualTargetList(annotated: JetAnnotated, descriptor: ClassDescriptor?): List<AnnotationTarget> {
if (annotated is JetClassOrObject) { if (annotated is JetClassOrObject) {
if (annotated is JetEnumEntry) return listOf(Target.PROPERTY, Target.FIELD) if (annotated is JetEnumEntry) return listOf(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD)
return if (descriptor?.getKind() == ClassKind.ANNOTATION_CLASS) { return if (descriptor?.getKind() == ClassKind.ANNOTATION_CLASS) {
listOf(Target.ANNOTATION_CLASS, Target.CLASSIFIER) listOf(AnnotationTarget.ANNOTATION_CLASS, AnnotationTarget.CLASSIFIER)
} }
else { else {
listOf(Target.CLASSIFIER) listOf(AnnotationTarget.CLASSIFIER)
} }
} }
if (annotated is JetProperty) { if (annotated is JetProperty) {
return if (annotated.isLocal()) listOf(Target.LOCAL_VARIABLE) else listOf(Target.PROPERTY, Target.FIELD) return if (annotated.isLocal()) listOf(AnnotationTarget.LOCAL_VARIABLE) else listOf(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD)
} }
if (annotated is JetParameter) { if (annotated is JetParameter) {
return if (annotated.hasValOrVar()) listOf(Target.PROPERTY, Target.FIELD) else listOf(Target.VALUE_PARAMETER) return if (annotated.hasValOrVar()) listOf(AnnotationTarget.PROPERTY, AnnotationTarget.FIELD) else listOf(AnnotationTarget.VALUE_PARAMETER)
} }
if (annotated is JetConstructor<*>) return listOf(Target.CONSTRUCTOR) if (annotated is JetConstructor<*>) return listOf(AnnotationTarget.CONSTRUCTOR)
if (annotated is JetFunction) return listOf(Target.FUNCTION) if (annotated is JetFunction) return listOf(AnnotationTarget.FUNCTION)
if (annotated is JetPropertyAccessor) { if (annotated is JetPropertyAccessor) {
return if (annotated.isGetter()) listOf(Target.PROPERTY_GETTER) else listOf(Target.PROPERTY_SETTER) return if (annotated.isGetter()) listOf(AnnotationTarget.PROPERTY_GETTER) else listOf(AnnotationTarget.PROPERTY_SETTER)
} }
if (annotated is JetPackageDirective) return listOf(Target.PACKAGE) if (annotated is JetPackageDirective) return listOf(AnnotationTarget.PACKAGE)
if (annotated is JetTypeReference) return listOf(Target.TYPE) if (annotated is JetTypeReference) return listOf(AnnotationTarget.TYPE)
if (annotated is JetFile) return listOf(Target.FILE) if (annotated is JetFile) return listOf(AnnotationTarget.FILE)
if (annotated is JetTypeParameter) return listOf(Target.TYPE_PARAMETER) if (annotated is JetTypeParameter) return listOf(AnnotationTarget.TYPE_PARAMETER)
return listOf() return listOf()
} }
} }
@@ -0,0 +1,9 @@
package test;
@meta @interface MyAnn {
}
@meta class My {
}
@@ -0,0 +1,2 @@
annotation.java:7:1:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.ANNOTATION_CLASS)
annotation class meta
@@ -0,0 +1,9 @@
package test
test.meta() public/*package*/ final class MyAnn : kotlin.Annotation {
public/*package*/ constructor MyAnn()
}
kotlin.annotation.target(allowedTargets = {AnnotationTarget.ANNOTATION_CLASS}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.ANNOTATION_TYPE}) internal final class meta : kotlin.Annotation {
public constructor meta()
}
@@ -0,0 +1,8 @@
package test;
@base class My {
@base int foo(@base int i) {
return i + 1;
}
}
@@ -0,0 +1,3 @@
package test
annotation class base
@@ -0,0 +1,10 @@
package test
test.base() public/*package*/ open class My {
public/*package*/ constructor My()
test.base() public/*package*/ open fun foo(/*0*/ test.base() kotlin.Int): kotlin.Int
}
kotlin.annotation.annotation() internal final class base : kotlin.Annotation {
public constructor base()
}
@@ -0,0 +1,8 @@
package test;
@classifier class My {
@classifier int foo() {
return 1;
}
}
@@ -0,0 +1 @@
classifier.java:5:5:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.CLASSIFIER)
annotation class classifier
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.CLASSIFIER}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.TYPE}) internal final class classifier : kotlin.Annotation {
public constructor classifier()
}
@@ -0,0 +1,10 @@
package test;
class My {
@constructor My() {}
@constructor int foo() {
return 1;
}
}
@@ -0,0 +1,3 @@
constructor.java:7:5:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.CONSTRUCTOR)
annotation class constructor
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.CONSTRUCTOR}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.CONSTRUCTOR}) internal final class constructor : kotlin.Annotation {
public constructor constructor()
}
@@ -0,0 +1,8 @@
package test;
@empty class My {
@empty int foo(@empty int i) {
return i + 1;
}
}
@@ -0,0 +1,4 @@
empty.java:3:1:compiler.err.annotation.type.not.applicable
empty.java:5:20:compiler.err.annotation.type.not.applicable
empty.java:5:5:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target()
annotation class empty
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {}) internal final class empty : kotlin.Annotation {
public constructor empty()
}
@@ -0,0 +1,7 @@
package test;
class My {
@field int prop;
@field int get() { return prop; }
}
@@ -0,0 +1,4 @@
field.java:6:5:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.FIELD)
annotation class field
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.FIELD}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.FIELD}) internal final class field : kotlin.Annotation {
public constructor field()
}
@@ -0,0 +1,8 @@
package test;
@function class My {
@function int foo() {
return 1;
}
}
@@ -0,0 +1,2 @@
function.java:3:1:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.FUNCTION)
annotation class function
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.FUNCTION}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.METHOD}) internal final class function : kotlin.Annotation {
public constructor function()
}
@@ -0,0 +1,8 @@
package test;
@getter class My {
@getter int foo() {
return 1;
}
}
@@ -0,0 +1,3 @@
getter.java:3:1:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.PROPERTY_GETTER)
annotation class getter
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.PROPERTY_GETTER}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.METHOD}) internal final class getter : kotlin.Annotation {
public constructor getter()
}
@@ -0,0 +1,9 @@
package test;
class My {
int foo(@local int i) {
@local int j = i + 1;
return j;
}
}
@@ -0,0 +1,3 @@
local.java:5:13:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.LOCAL_VARIABLE)
annotation class local
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.LOCAL_VARIABLE}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.LOCAL_VARIABLE}) internal final class local : kotlin.Annotation {
public constructor local()
}
@@ -0,0 +1,8 @@
package test;
@multiple class My {
@multiple int foo(@multiple int i) {
return i + 1;
}
}
@@ -0,0 +1,2 @@
multiple.java:5:23:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.CLASSIFIER, AnnotationTarget.FUNCTION)
annotation class multiple
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.CLASSIFIER, AnnotationTarget.FUNCTION}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.TYPE, ElementType.METHOD}) internal final class multiple : kotlin.Annotation {
public constructor multiple()
}
@@ -0,0 +1,5 @@
@pck package test;
@pck class My {
}
@@ -0,0 +1,2 @@
package-info.java:3:1:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.PACKAGE)
annotation class pck
@@ -0,0 +1,8 @@
package test
test.pck() public/*package*/ interface `package-info` {
}
kotlin.annotation.target(allowedTargets = {AnnotationTarget.PACKAGE}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.PACKAGE}) internal final class pck : kotlin.Annotation {
public constructor pck()
}
@@ -0,0 +1,8 @@
package test;
@parameter class My {
@parameter int foo(@parameter int i) {
return i + 1;
}
}
@@ -0,0 +1,2 @@
parameter.java:3:1:compiler.err.annotation.type.not.applicable
parameter.java:5:5:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.VALUE_PARAMETER)
annotation class parameter
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.VALUE_PARAMETER}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.PARAMETER}) internal final class parameter : kotlin.Annotation {
public constructor parameter()
}
@@ -0,0 +1,7 @@
package test;
class My {
@property int prop;
@property int get() { return prop; }
}
@@ -0,0 +1,4 @@
property.java:4:5:compiler.err.annotation.type.not.applicable
property.java:6:5:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.PROPERTY)
annotation class property
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.PROPERTY}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {}) internal final class property : kotlin.Annotation {
public constructor property()
}
@@ -0,0 +1,8 @@
package test;
@setter class My {
@setter int foo() {
return 1;
}
}
@@ -0,0 +1,3 @@
setter.java:3:1:compiler.err.annotation.type.not.applicable
@@ -0,0 +1,4 @@
package test
target(AnnotationTarget.PROPERTY_SETTER)
annotation class setter
@@ -0,0 +1,5 @@
package test
kotlin.annotation.target(allowedTargets = {AnnotationTarget.PROPERTY_SETTER}) kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.METHOD}) internal final class setter : kotlin.Annotation {
public constructor setter()
}
@@ -7,7 +7,7 @@ kotlin.annotation.annotation() internal final class my : kotlin.Annotation {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
} }
kotlin.annotation.annotation() java.lang.annotation.Target(value = {ElementType.ANNOTATION_TYPE, ElementType.CONSTRUCTOR}) internal final class my1 : kotlin.Annotation { kotlin.annotation.annotation() internal final class my1 : kotlin.Annotation {
public constructor my1() public constructor my1()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
@@ -2,7 +2,7 @@ package test
public interface ArrayOfEnumInParam { public interface ArrayOfEnumInParam {
java.lang.annotation.Target(value = {ElementType.FIELD, ElementType.CONSTRUCTOR}) public final class targetAnnotation : kotlin.Annotation { public final class targetAnnotation : kotlin.Annotation {
public constructor targetAnnotation(/*0*/ value: kotlin.String) public constructor targetAnnotation(/*0*/ value: kotlin.String)
public final val value: kotlin.String public final val value: kotlin.String
public abstract fun value(): kotlin.String public abstract fun value(): kotlin.String
@@ -553,4 +553,97 @@ public class CompileJavaAgainstKotlinTestGenerated extends AbstractCompileJavaAg
doTest(fileName); doTest(fileName);
} }
} }
@TestMetadata("compiler/testData/compileJavaAgainstKotlin/targets")
@TestDataPath("$PROJECT_ROOT")
@RunWith(JUnit3RunnerWithInners.class)
public static class Targets extends AbstractCompileJavaAgainstKotlinTest {
public void testAllFilesPresentInTargets() throws Exception {
JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/compileJavaAgainstKotlin/targets"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("annotation.kt")
public void testAnnotation() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/annotation.kt");
doTest(fileName);
}
@TestMetadata("base.kt")
public void testBase() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/base.kt");
doTest(fileName);
}
@TestMetadata("classifier.kt")
public void testClassifier() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/classifier.kt");
doTest(fileName);
}
@TestMetadata("constructor.kt")
public void testConstructor() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/constructor.kt");
doTest(fileName);
}
@TestMetadata("empty.kt")
public void testEmpty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/empty.kt");
doTest(fileName);
}
@TestMetadata("field.kt")
public void testField() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/field.kt");
doTest(fileName);
}
@TestMetadata("function.kt")
public void testFunction() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/function.kt");
doTest(fileName);
}
@TestMetadata("getter.kt")
public void testGetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/getter.kt");
doTest(fileName);
}
@TestMetadata("local.kt")
public void testLocal() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/local.kt");
doTest(fileName);
}
@TestMetadata("multiple.kt")
public void testMultiple() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/multiple.kt");
doTest(fileName);
}
@TestMetadata("package-info.kt")
public void testPackage_info() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/package-info.kt");
doTest(fileName);
}
@TestMetadata("parameter.kt")
public void testParameter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/parameter.kt");
doTest(fileName);
}
@TestMetadata("property.kt")
public void testProperty() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/property.kt");
doTest(fileName);
}
@TestMetadata("setter.kt")
public void testSetter() throws Exception {
String fileName = JetTestUtils.navigationMetadata("compiler/testData/compileJavaAgainstKotlin/targets/setter.kt");
doTest(fileName);
}
}
} }
@@ -41,6 +41,7 @@ import org.junit.Assert;
import java.io.File; import java.io.File;
import java.lang.annotation.Retention; import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.util.*; import java.util.*;
import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry; import static org.jetbrains.kotlin.resolve.DescriptorUtils.isEnumEntry;
@@ -52,6 +53,7 @@ public class RecursiveDescriptorComparator {
static { static {
excludedAnnotations.add(new FqName(ExpectedLoadErrorsUtil.ANNOTATION_CLASS_NAME)); excludedAnnotations.add(new FqName(ExpectedLoadErrorsUtil.ANNOTATION_CLASS_NAME));
excludedAnnotations.add(new FqName(Retention.class.getName())); excludedAnnotations.add(new FqName(Retention.class.getName()));
excludedAnnotations.add(new FqName(Target.class.getName()));
} }
private static final DescriptorRenderer DEFAULT_RENDERER = DescriptorRenderer.Companion.withOptions( private static final DescriptorRenderer DEFAULT_RENDERER = DescriptorRenderer.Companion.withOptions(
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2015 JetBrains s.r.o.
*
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
* You may obtain a copy of the License at
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing, software
* distributed under the License is distributed on an "AS IS" BASIS,
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
* See the License for the specific language governing permissions and
* limitations under the License.
*/
package org.jetbrains.kotlin.descriptors.annotations
import java.util.*
import kotlin.annotation
// NOTE: this enum must have the same entries with kotlin.annotation.AnnotationTarget
public enum class AnnotationTarget(val description: String, val isDefault: Boolean = true) {
PACKAGE("package"),
CLASSIFIER("classifier"),
ANNOTATION_CLASS("annotation class"),
TYPE_PARAMETER("type parameter", false),
PROPERTY("property"),
FIELD("field"),
LOCAL_VARIABLE("local variable"),
VALUE_PARAMETER("value parameter"),
CONSTRUCTOR("constructor"),
FUNCTION("function"),
PROPERTY_GETTER("getter"),
PROPERTY_SETTER("setter"),
TYPE("type usage", false),
EXPRESSION("expression", false),
FILE("file", false);
companion object {
private val map = HashMap<String, AnnotationTarget>()
init {
for (target in AnnotationTarget.values()) {
map[target.name()] = target
}
}
public fun valueOrNull(name: String): AnnotationTarget? = map[name]
public val DEFAULT_TARGET_SET: Set<AnnotationTarget> = values().filter { it.isDefault }.toSet()
public val ALL_TARGET_SET: Set<AnnotationTarget> = values().toSet()
}
}