Support @property annotations

This commit is contained in:
Yan Zhulanow
2015-07-16 18:36:29 +03:00
parent b1a28bcc6a
commit 93579564c8
6 changed files with 17 additions and 5 deletions
@@ -24,6 +24,7 @@ import org.jetbrains.kotlin.codegen.context.*;
import org.jetbrains.kotlin.codegen.state.GenerationState;
import org.jetbrains.kotlin.codegen.state.JetTypeMapper;
import org.jetbrains.kotlin.descriptors.*;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor;
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget;
import org.jetbrains.kotlin.load.java.JvmAbi;
import org.jetbrains.kotlin.psi.*;
@@ -110,8 +111,12 @@ public class PropertyCodegen {
}
else {
assert declaration != null : "Declaration is null for different context: " + context;
if (!generateBackingField(declaration, descriptor)) {
generateSyntheticMethodIfNeeded(descriptor);
List<AnnotationDescriptor> propertyTargetedAnnotations =
descriptor.getAnnotations().getUseSiteTargetedAnnotations(AnnotationUseSiteTarget.PROPERTY);
if (!generateBackingField(declaration, descriptor) || !propertyTargetedAnnotations.isEmpty()) {
generateSyntheticMethodIfNeeded(descriptor, !propertyTargetedAnnotations.isEmpty());
}
}
@@ -210,8 +215,8 @@ public class PropertyCodegen {
// Annotations on properties without backing fields are stored in bytecode on an empty synthetic method. This way they're still
// accessible via reflection, and 'deprecated' and 'private' flags prevent this method from being called accidentally
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor) {
if (descriptor.getAnnotations().isEmpty()) return;
private void generateSyntheticMethodIfNeeded(@NotNull PropertyDescriptor descriptor, boolean hasPropertyTargetedAnnotations) {
if (descriptor.getAnnotations().isEmpty() && !hasPropertyTargetedAnnotations) return;
ReceiverParameterDescriptor receiver = descriptor.getExtensionReceiverParameter();
String name = JvmAbi.getSyntheticMethodNameForAnnotatedProperty(descriptor.getName());
@@ -220,7 +225,7 @@ public class PropertyCodegen {
if (!isTrait(context.getContextDescriptor()) || kind == OwnerKind.TRAIT_IMPL) {
int flags = ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC;
MethodVisitor mv = v.newMethod(OtherOrigin(descriptor), flags, name, desc, null, null);
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(descriptor, Type.VOID_TYPE);
AnnotationCodegen.forMethod(mv, typeMapper).genAnnotations(descriptor, Type.VOID_TYPE, AnnotationUseSiteTarget.PROPERTY);
mv.visitCode();
mv.visitInsn(Opcodes.RETURN);
mv.visitEnd();
@@ -133,6 +133,7 @@ public interface Errors {
DiagnosticFactory0<PsiElement> INAPPLICABLE_FIELD_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_PROPERTY_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_GET_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_SET_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE = DiagnosticFactory0.create(ERROR);
@@ -126,6 +126,7 @@ public class DefaultErrorMessages {
MAP.put(INAPPLICABLE_FIELD_TARGET, "''@field:'' annotations could be applied only to property declarations");
MAP.put(INAPPLICABLE_FIELD_TARGET_NO_BACKING_FIELD, "Property has neither a backing field nor a delegate");
MAP.put(INAPPLICABLE_PROPERTY_TARGET, "''@property:'' annotations could be applied only to property declarations");
MAP.put(INAPPLICABLE_GET_TARGET, "''@get:'' annotations could be applied only to property declarations");
MAP.put(INAPPLICABLE_SET_TARGET, "''@set:'' annotations could be applied only to property declarations");
MAP.put(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, "Property must be mutable");
@@ -38,6 +38,7 @@ public class JetAnnotationUseSiteTarget : JetElementImplStub<KotlinPlaceHolderSt
return when (node.getElementType()) {
JetTokens.FIELD_KEYWORD -> AnnotationUseSiteTarget.FIELD
JetTokens.FILE_KEYWORD -> AnnotationUseSiteTarget.FILE
JetTokens.PROPERTY_KEYWORD -> AnnotationUseSiteTarget.PROPERTY
JetTokens.GET_KEYWORD -> AnnotationUseSiteTarget.PROPERTY_GETTER
JetTokens.SET_KEYWORD -> AnnotationUseSiteTarget.PROPERTY_SETTER
else -> throw IllegalStateException("Unknown annotation target " + node.getText())
@@ -234,6 +234,9 @@ public class ModifiersChecker {
break;
case FILE:
throw new IllegalArgumentException("@file annotations are not allowed here");
case PROPERTY:
reportIfNotPropertyDescriptor(descriptor, annotation, INAPPLICABLE_PROPERTY_TARGET);
break;
case PROPERTY_GETTER:
reportIfNotPropertyDescriptor(descriptor, annotation, INAPPLICABLE_GET_TARGET);
break;
@@ -19,6 +19,7 @@ package org.jetbrains.kotlin.descriptors.annotations
public enum class AnnotationUseSiteTarget(renderName: String? = null) {
FIELD(),
FILE(),
PROPERTY(),
PROPERTY_GETTER("get"),
PROPERTY_SETTER("set");