delegate use-site targeted annotations: parser, front-end, codegen with some tests #KT-10502 Fixed

This commit is contained in:
Mikhail Glukhikh
2016-01-14 16:28:29 +03:00
parent 474076a550
commit b78d481bb1
29 changed files with 366 additions and 51 deletions
@@ -130,16 +130,18 @@ public class PropertyCodegen {
private void genBackingFieldAndAnnotations(@NotNull KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter) {
boolean hasBackingField = hasBackingField(declaration, descriptor);
boolean hasDelegate = declaration instanceof KtProperty && ((KtProperty) declaration).hasDelegate();
AnnotationSplitter annotationSplitter =
AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS,
descriptor.getAnnotations(),
AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField));
AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField, hasDelegate));
Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD);
Annotations delegateAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD);
Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY);
generateBackingField(declaration, descriptor, fieldAnnotations);
generateBackingField(declaration, descriptor, fieldAnnotations, delegateAnnotations);
generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations);
}
@@ -228,17 +230,18 @@ public class PropertyCodegen {
private boolean generateBackingField(
@NotNull KtNamedDeclaration p,
@NotNull PropertyDescriptor descriptor,
@NotNull Annotations annotations
@NotNull Annotations backingFieldAnnotations,
@NotNull Annotations delegateAnnotations
) {
if (isJvmInterface(descriptor.getContainingDeclaration()) || kind == OwnerKind.DEFAULT_IMPLS) {
return false;
}
if (p instanceof KtProperty && ((KtProperty) p).hasDelegate()) {
generatePropertyDelegateAccess((KtProperty) p, descriptor, annotations);
generatePropertyDelegateAccess((KtProperty) p, descriptor, delegateAnnotations);
}
else if (Boolean.TRUE.equals(bindingContext.get(BindingContext.BACKING_FIELD_REQUIRED, descriptor))) {
generateBackingFieldAccess(p, descriptor, annotations);
generateBackingFieldAccess(p, descriptor, backingFieldAnnotations);
}
else {
return false;
@@ -327,7 +330,8 @@ public class PropertyCodegen {
typeMapper.mapFieldSignature(jetType, propertyDescriptor), defaultValue);
Annotated fieldAnnotated = new AnnotatedWithFakeAnnotations(propertyDescriptor, annotations);
AnnotationCodegen.forField(fv, typeMapper).genAnnotations(fieldAnnotated, type, AnnotationUseSiteTarget.FIELD);
AnnotationCodegen.forField(fv, typeMapper).genAnnotations(
fieldAnnotated, type, isDelegate ? AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD : AnnotationUseSiteTarget.FIELD);
}
private void generatePropertyDelegateAccess(KtProperty p, PropertyDescriptor propertyDescriptor, Annotations annotations) {
@@ -20,6 +20,8 @@ import org.jetbrains.kotlin.descriptors.PropertyDescriptor
import org.jetbrains.kotlin.resolve.AnnotationChecker
import org.jetbrains.kotlin.descriptors.annotations.AnnotationUseSiteTarget.*
import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.storage.StorageManager
import org.jetbrains.kotlin.storage.getValue
@@ -54,22 +56,24 @@ class AnnotationSplitter(
}
@JvmStatic fun getTargetSet(parameter: Boolean, context: BindingContext, wrapper: PropertyWrapper): Set<AnnotationUseSiteTarget> {
val property = wrapper.property
assert(property != null)
val hasBackingField = context[BindingContext.BACKING_FIELD_REQUIRED, property] ?: false
return getTargetSet(parameter, property!!.isVar, hasBackingField)
val descriptor = wrapper.descriptor
assert(descriptor != null)
val hasBackingField = context[BindingContext.BACKING_FIELD_REQUIRED, descriptor] ?: false
val hasDelegate = wrapper.declaration is KtProperty && wrapper.declaration.hasDelegate()
return getTargetSet(parameter, descriptor!!.isVar, hasBackingField, hasDelegate)
}
@JvmStatic fun getTargetSet(parameter: Boolean, isVar: Boolean, hasBackingField: Boolean): Set<AnnotationUseSiteTarget> {
return hashSetOf(PROPERTY, PROPERTY_GETTER).apply {
if (parameter) add(CONSTRUCTOR_PARAMETER)
if (hasBackingField) add(FIELD)
if (isVar) add(PROPERTY_SETTER)
}
@JvmStatic fun getTargetSet(
parameter: Boolean, isVar: Boolean, hasBackingField: Boolean, hasDelegate: Boolean
): Set<AnnotationUseSiteTarget> = hashSetOf(PROPERTY, PROPERTY_GETTER).apply {
if (parameter) add(CONSTRUCTOR_PARAMETER)
if (hasBackingField) add(FIELD)
if (isVar) add(PROPERTY_SETTER)
if (hasDelegate) add(PROPERTY_DELEGATE_FIELD)
}
}
class PropertyWrapper(var property: PropertyDescriptor? = null)
class PropertyWrapper @JvmOverloads constructor(val declaration: KtDeclaration, var descriptor: PropertyDescriptor? = null)
private val splitAnnotations = storageManager.createLazyValue {
val map = hashMapOf<AnnotationUseSiteTarget, MutableList<AnnotationWithTarget>>()
@@ -167,7 +167,9 @@ public interface Errors {
DiagnosticFactory0<KtExpression> NON_CONST_VAL_USED_IN_CONSTANT_EXPRESSION = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> INAPPLICABLE_TARGET_ON_PROPERTY = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE = DiagnosticFactory1.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_RECEIVER_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<PsiElement> INAPPLICABLE_PARAM_TARGET = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<PsiElement, String> REDUNDANT_ANNOTATION_TARGET = DiagnosticFactory1.create(WARNING);
@@ -157,8 +157,10 @@ public class DefaultErrorMessages {
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
MAP.put(NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION, "The lambda expression here is an inlined argument so this annotation cannot be stored anywhere");
MAP.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}'' annotations could be applied only to property declarations", TO_STRING);
MAP.put(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, "Property must be mutable");
MAP.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}:'' annotations could be applied only to property declarations", TO_STRING);
MAP.put(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE, "''@{0}:'' annotations could be applied only to mutable properties", TO_STRING);
MAP.put(INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, "''@delegate:'' annotations could be applied only to delegated properties");
MAP.put(INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD, "''@field:'' annotations could be applied only to properties with backing fields");
MAP.put(INAPPLICABLE_RECEIVER_TARGET, "''@receiver:'' annotations could be applied only to extension function or extension property declarations");
MAP.put(INAPPLICABLE_PARAM_TARGET, "''@param:'' annotations could be applied only to primary constructor parameters");
MAP.put(REDUNDANT_ANNOTATION_TARGET, "Redundant annotation target ''{0}''", STRING);
@@ -142,6 +142,7 @@ public interface KtTokens {
KtKeywordToken RECEIVER_KEYWORD = KtKeywordToken.softKeyword("receiver");
KtKeywordToken PARAM_KEYWORD = KtKeywordToken.softKeyword("param");
KtKeywordToken SETPARAM_KEYWORD = KtKeywordToken.softKeyword("setparam");
KtKeywordToken DELEGATE_KEYWORD = KtKeywordToken.softKeyword("delegate");
KtKeywordToken IMPORT_KEYWORD = KtKeywordToken.softKeyword("import");
KtKeywordToken WHERE_KEYWORD = KtKeywordToken.softKeyword("where");
KtKeywordToken BY_KEYWORD = KtKeywordToken.softKeyword("by");
@@ -203,6 +204,7 @@ public interface KtTokens {
CATCH_KEYWORD, FINALLY_KEYWORD, OUT_KEYWORD, FINAL_KEYWORD, VARARG_KEYWORD, REIFIED_KEYWORD,
DYNAMIC_KEYWORD, COMPANION_KEYWORD, CONSTRUCTOR_KEYWORD, INIT_KEYWORD, SEALED_KEYWORD,
FIELD_KEYWORD, PROPERTY_KEYWORD, RECEIVER_KEYWORD, PARAM_KEYWORD, SETPARAM_KEYWORD,
DELEGATE_KEYWORD,
LATEINIT_KEYWORD,
DATA_KEYWORD, INLINE_KEYWORD, NOINLINE_KEYWORD, TAILREC_KEYWORD, EXTERNAL_KEYWORD,
ANNOTATION_KEYWORD, CROSSINLINE_KEYWORD, CONST_KEYWORD, OPERATOR_KEYWORD, INFIX_KEYWORD
@@ -64,7 +64,8 @@ public class KotlinParsing extends AbstractKotlinParsing {
TokenSet.orSet(TokenSet.create(IDENTIFIER, LBRACKET), MODIFIER_KEYWORDS);
private static final TokenSet SOFT_KEYWORDS_AT_MEMBER_START = TokenSet.create(CONSTRUCTOR_KEYWORD, INIT_KEYWORD);
private static final TokenSet ANNOTATION_TARGETS = TokenSet.create(
FILE_KEYWORD, FIELD_KEYWORD, GET_KEYWORD, SET_KEYWORD, PROPERTY_KEYWORD, RECEIVER_KEYWORD, PARAM_KEYWORD, SETPARAM_KEYWORD);
FILE_KEYWORD, FIELD_KEYWORD, GET_KEYWORD, SET_KEYWORD, PROPERTY_KEYWORD,
RECEIVER_KEYWORD, PARAM_KEYWORD, SETPARAM_KEYWORD, DELEGATE_KEYWORD);
static KotlinParsing createForTopLevel(SemanticWhitespaceAwarePsiBuilder builder) {
KotlinParsing jetParsing = new KotlinParsing(builder);
@@ -54,6 +54,7 @@ class KtAnnotationUseSiteTarget : KtElementImplStub<KotlinAnnotationUseSiteTarge
KtTokens.RECEIVER_KEYWORD -> AnnotationUseSiteTarget.RECEIVER
KtTokens.PARAM_KEYWORD -> AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER
KtTokens.SETPARAM_KEYWORD -> AnnotationUseSiteTarget.SETTER_PARAMETER
KtTokens.DELEGATE_KEYWORD -> AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD
else -> throw IllegalStateException("Unknown annotation target " + node.getText())
}
}
@@ -179,9 +179,9 @@ class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnot
if (annotated.isLocal)
TargetLists.T_LOCAL_VARIABLE
else if (annotated.parent is KtClassOrObject || annotated.parent is KtClassBody)
TargetLists.T_MEMBER_PROPERTY(descriptor.hasBackingField(trace))
TargetLists.T_MEMBER_PROPERTY(descriptor.hasBackingField(trace), annotated.hasDelegate())
else
TargetLists.T_TOP_LEVEL_PROPERTY(descriptor.hasBackingField(trace))
TargetLists.T_TOP_LEVEL_PROPERTY(descriptor.hasBackingField(trace), annotated.hasDelegate())
}
is KtParameter -> {
if (annotated.hasValOrVar())
@@ -224,19 +224,31 @@ class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnot
val T_DESTRUCTURING_DECLARATION = targetList(DESTRUCTURING_DECLARATION)
fun T_MEMBER_PROPERTY(backingField: Boolean) =
targetList(if (backingField) MEMBER_PROPERTY_WITH_FIELD else MEMBER_PROPERTY_WITHOUT_FIELD,
MEMBER_PROPERTY, PROPERTY) {
fun TargetListBuilder.propertyTargets(backingField: Boolean, delegate: Boolean) {
if (backingField) extraTargets(FIELD)
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
if (delegate) {
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER, FIELD)
}
else {
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
}
}
fun T_TOP_LEVEL_PROPERTY(backingField: Boolean) =
targetList(if (backingField) TOP_LEVEL_PROPERTY_WITH_FIELD else TOP_LEVEL_PROPERTY_WITHOUT_FIELD,
fun T_MEMBER_PROPERTY(backingField: Boolean, delegate: Boolean) =
targetList(if (backingField) MEMBER_PROPERTY_WITH_BACKING_FIELD
else if (delegate) MEMBER_PROPERTY_WITH_DELEGATE
else MEMBER_PROPERTY_WITHOUT_FIELD_OR_DELEGATE,
MEMBER_PROPERTY, PROPERTY) {
propertyTargets(backingField, delegate)
}
fun T_TOP_LEVEL_PROPERTY(backingField: Boolean, delegate: Boolean) =
targetList(if (backingField) TOP_LEVEL_PROPERTY_WITH_BACKING_FIELD
else if (delegate) TOP_LEVEL_PROPERTY_WITH_DELEGATE
else TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE,
TOP_LEVEL_PROPERTY, PROPERTY) {
if (backingField) extraTargets(FIELD)
onlyWithUseSiteTarget(VALUE_PARAMETER, PROPERTY_GETTER, PROPERTY_SETTER)
}
propertyTargets(backingField, delegate)
}
val T_PROPERTY_GETTER = targetList(PROPERTY_GETTER)
val T_PROPERTY_SETTER = targetList(PROPERTY_SETTER)
@@ -28,6 +28,7 @@ object AnnotationUseSiteTargetChecker {
if (annotated is KtFunction) {
for (parameter in annotated.valueParameters) {
if (parameter.hasValOrVar()) continue
val parameterDescriptor = trace.bindingContext[BindingContext.VALUE_PARAMETER, parameter] ?: continue
trace.checkDeclaration(parameter, parameterDescriptor)
}
@@ -45,6 +46,7 @@ object AnnotationUseSiteTargetChecker {
when (target) {
AnnotationUseSiteTarget.RECEIVER -> {}
AnnotationUseSiteTarget.FIELD,
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD,
AnnotationUseSiteTarget.PROPERTY,
AnnotationUseSiteTarget.PROPERTY_GETTER,
AnnotationUseSiteTarget.PROPERTY_SETTER,
@@ -62,9 +64,10 @@ object AnnotationUseSiteTargetChecker {
val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget() ?: continue
when (target) {
AnnotationUseSiteTarget.FIELD,
AnnotationUseSiteTarget.FIELD -> checkIfHasBackingField(annotated, descriptor, annotation)
AnnotationUseSiteTarget.PROPERTY,
AnnotationUseSiteTarget.PROPERTY_GETTER -> {}
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD -> checkIfDelegatedProperty(annotated, annotation)
AnnotationUseSiteTarget.PROPERTY_SETTER -> checkIfMutableProperty(annotated, annotation)
AnnotationUseSiteTarget.CONSTRUCTOR_PARAMETER -> {
if (annotated !is KtParameter) {
@@ -87,6 +90,22 @@ object AnnotationUseSiteTargetChecker {
}
}
private fun BindingTrace.checkIfDelegatedProperty(annotated: KtAnnotated, annotation: KtAnnotationEntry) {
if (annotated is KtProperty && !annotated.hasDelegate() || annotated is KtParameter && annotated.hasValOrVar()) {
report(INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE.on(annotation))
}
}
private fun BindingTrace.checkIfHasBackingField(annotated: KtAnnotated, descriptor: DeclarationDescriptor, annotation: KtAnnotationEntry) {
if (annotated is KtProperty && annotated.hasDelegate() &&
descriptor is PropertyDescriptor && get(BindingContext.BACKING_FIELD_REQUIRED, descriptor) != true) {
report(INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD.on(annotation))
}
}
private fun KtAnnotationEntry.useSiteDescription() =
useSiteTarget?.getAnnotationUseSiteTarget()?.renderName ?: "unknown target" // should not happen
private fun BindingTrace.checkIfMutableProperty(annotated: KtAnnotated, annotation: KtAnnotationEntry) {
if (!checkIfProperty(annotated, annotation)) return
@@ -96,7 +115,9 @@ object AnnotationUseSiteTargetChecker {
annotated.isMutable
else false
if (!isMutable) report(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE.on(annotation))
if (!isMutable) {
report(INAPPLICABLE_TARGET_PROPERTY_IMMUTABLE.on(annotation, annotation.useSiteDescription()))
}
}
private fun BindingTrace.checkIfProperty(annotated: KtAnnotated, annotation: KtAnnotationEntry): Boolean {
@@ -106,8 +127,7 @@ object AnnotationUseSiteTargetChecker {
annotated.hasValOrVar()
else false
val target = annotation.useSiteTarget?.getAnnotationUseSiteTarget()?.renderName ?: "unknown target" // should not happen
if (!isProperty) report(INAPPLICABLE_TARGET_ON_PROPERTY.on(annotation, target))
if (!isProperty) report(INAPPLICABLE_TARGET_ON_PROPERTY.on(annotation, annotation.useSiteDescription()))
return isProperty
}
}
@@ -676,7 +676,7 @@ public class DescriptorResolver {
? resolveModalityFromModifiers(property, getDefaultModality(containingDeclaration, visibility, hasBody))
: Modality.FINAL;
final AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper();
final AnnotationSplitter.PropertyWrapper wrapper = new AnnotationSplitter.PropertyWrapper(property);
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, modifierList, trace);
AnnotationSplitter annotationSplitter =
@@ -688,7 +688,7 @@ public class DescriptorResolver {
});
Annotations propertyAnnotations = new CompositeAnnotations(CollectionsKt.listOf(
annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD),
annotationSplitter.getAnnotationsForTargets(PROPERTY, FIELD, PROPERTY_DELEGATE_FIELD),
annotationSplitter.getOtherAnnotations()));
PropertyDescriptorImpl propertyDescriptor = PropertyDescriptorImpl.create(
@@ -703,7 +703,7 @@ public class DescriptorResolver {
modifierList != null && modifierList.hasModifier(KtTokens.LATEINIT_KEYWORD),
modifierList != null && modifierList.hasModifier(KtTokens.CONST_KEYWORD)
);
wrapper.setProperty(propertyDescriptor);
wrapper.setDescriptor(propertyDescriptor);
List<TypeParameterDescriptorImpl> typeParameterDescriptors;
LexicalScope scopeWithTypeParameters;
@@ -938,7 +938,7 @@ public class DescriptorResolver {
}
}
final AnnotationSplitter.PropertyWrapper propertyWrapper = new AnnotationSplitter.PropertyWrapper();
final AnnotationSplitter.PropertyWrapper propertyWrapper = new AnnotationSplitter.PropertyWrapper(parameter);
Annotations allAnnotations = annotationResolver.resolveAnnotationsWithoutArguments(scope, parameter.getModifierList(), trace);
AnnotationSplitter annotationSplitter =
new AnnotationSplitter(storageManager, allAnnotations, new Function0<Set<AnnotationUseSiteTarget>>() {
@@ -964,7 +964,7 @@ public class DescriptorResolver {
/* lateInit = */ false,
/* isConst = */ false
);
propertyWrapper.setProperty(propertyDescriptor);
propertyWrapper.setDescriptor(propertyDescriptor);
propertyDescriptor.setType(type, Collections.<TypeParameterDescriptor>emptyList(),
getDispatchReceiverParameterIfNeeded(classDescriptor), (ReceiverParameterDescriptor) null);
@@ -1,8 +1,14 @@
import java.lang.reflect.Modifier
import kotlin.reflect.KProperty
class CustomDelegate {
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String = prop.name
}
class C {
@Volatile var vol = 1
@Transient val tra = 1
@delegate:Transient val del: String by CustomDelegate()
@Strictfp fun str() {}
@Synchronized fun sync() {}
@@ -13,6 +19,7 @@ fun box(): String {
if (c.getDeclaredField("vol").getModifiers() and Modifier.VOLATILE == 0) return "Fail: volatile"
if (c.getDeclaredField("tra").getModifiers() and Modifier.TRANSIENT == 0) return "Fail: transient"
if (c.getDeclaredField("del\$delegate").getModifiers() and Modifier.TRANSIENT == 0) return "Fail: delegate transient"
if (c.getDeclaredMethod("str").getModifiers() and Modifier.STRICT == 0) return "Fail: strict"
if (c.getDeclaredMethod("sync").getModifiers() and Modifier.SYNCHRONIZED == 0) return "Fail: synchronized"
@@ -1,13 +1,23 @@
import kotlin.reflect.KProperty
annotation class AnnProp
annotation class AnnField
annotation class AnnProp2
annotation class AnnGetter
annotation class AnnSetter
annotation class AnnParam
annotation class AnnDelegate
class CustomDelegate {
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String = prop.name
}
public class A(@AnnParam @field:AnnField @property:AnnProp2 val x: Int, @param:AnnParam @get:AnnGetter @set:AnnSetter var y: Int) {
@AnnProp @field:AnnField @property:AnnProp2 @get:AnnGetter @set:AnnSetter @setparam:AnnParam
var p: Int = 0
@AnnProp @property:AnnProp2 @delegate:AnnDelegate @property:AnnDelegate
val s: String by CustomDelegate()
}
@@ -1,18 +1,27 @@
@kotlin.jvm.internal.KotlinClass
public final class A {
private synthetic final static field $$delegatedProperties: kotlin.reflect.KProperty[]
private @AnnField field p: int
private final @AnnDelegate @org.jetbrains.annotations.NotNull field s$delegate: CustomDelegate
private final @AnnField field x: int
private field y: int
static method <clinit>(): void
public method <init>(@AnnParam p0: int, @AnnParam p1: int): void
public final @AnnGetter method getP(): int
public final @org.jetbrains.annotations.NotNull method getS(): java.lang.String
public final method getX(): int
public final @AnnGetter method getY(): int
private synthetic deprecated final static @AnnProp @AnnProp2 method p$annotations(): void
private synthetic deprecated final static @AnnProp @AnnProp2 @AnnDelegate method s$annotations(): void
public final @AnnSetter method setP(@AnnParam p0: int): void
public final @AnnSetter method setY(p0: int): void
private synthetic deprecated final static @AnnProp2 method x$annotations(): void
}
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnDelegate
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnField
@@ -35,4 +44,10 @@ public abstract class AnnProp2
@java.lang.annotation.Retention
@kotlin.jvm.internal.KotlinClass
public abstract class AnnSetter
public abstract class AnnSetter
@kotlin.jvm.internal.KotlinClass
public final class CustomDelegate {
public method <init>(): void
public final @org.jetbrains.annotations.NotNull method getValue(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.NotNull p1: kotlin.reflect.KProperty): java.lang.String
}
@@ -0,0 +1,33 @@
import kotlin.reflect.KProperty
@Target(AnnotationTarget.FIELD) annotation class Field
@Target(AnnotationTarget.PROPERTY) annotation class Prop
class CustomDelegate {
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String = prop.name
}
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Field<!>
class SomeClass {
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Field<!>
constructor()
<!INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE!>@delegate:Field<!> <!INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Prop<!>
protected val simpleProperty: String = "text"
@delegate:Field <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Prop<!>
protected val delegatedProperty: String by CustomDelegate()
<!INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Field<!> <!INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Prop<!>
val propertyWithCustomGetter: Int
get() = 5
}
class WithPrimaryConstructor(<!INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE!>@delegate:Field<!> <!INAPPLICABLE_TARGET_PROPERTY_HAS_NO_DELEGATE, WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Prop<!> val a: String,
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@param:Field<!> <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@param:Prop<!> val b: String)
fun foo(<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Field<!> <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@delegate:Prop<!> x: Int) = x
@@ -0,0 +1,44 @@
package
public fun foo(/*0*/ @delegate:Field() @delegate:Prop() x: kotlin.Int): kotlin.Int
public final class CustomDelegate {
public constructor CustomDelegate()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ prop: kotlin.reflect.KProperty<*>): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.FIELD}) public final annotation class Field : kotlin.Annotation {
public constructor Field()
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 toString(): kotlin.String
}
@kotlin.annotation.Target(allowedTargets = {AnnotationTarget.PROPERTY}) public final annotation class Prop : kotlin.Annotation {
public constructor Prop()
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 toString(): kotlin.String
}
@delegate:Field() public final class SomeClass {
@delegate:Field() public constructor SomeClass()
@delegate:Field() @delegate:Prop() protected final val delegatedProperty: kotlin.String
@delegate:Field() @delegate:Prop() public final val propertyWithCustomGetter: kotlin.Int
@delegate:Field() @delegate:Prop() protected final val simpleProperty: kotlin.String = "text"
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 toString(): kotlin.String
}
public final class WithPrimaryConstructor {
public constructor WithPrimaryConstructor(/*0*/ a: kotlin.String, /*1*/ @param:Field() @param:Prop() b: kotlin.String)
@delegate:Field() @delegate:Prop() public final val a: kotlin.String
public final val b: kotlin.String
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 toString(): kotlin.String
}
@@ -18,7 +18,7 @@ class SomeClass {
@field:[Ann]
protected val simplePropertyWithAnnotationList: String = "text"
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@field:Ann<!>
<!INAPPLICABLE_TARGET_PROPERTY_HAS_NO_BACKING_FIELD!>@field:Ann<!>
protected val delegatedProperty: String by CustomDelegate()
<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@field:Ann<!>
@@ -1,8 +1,14 @@
import kotlin.reflect.KProperty
@Retention(AnnotationRetention.SOURCE)
@Repeatable
annotation class RepeatableAnn
annotation class Ann
class CustomDelegate {
operator fun getValue(thisRef: Any?, prop: KProperty<*>): String = prop.name
}
public class A(@param:Ann <!REPEATED_ANNOTATION!>@Ann<!> val x: Int, @param: RepeatableAnn @Ann val y: Int) {
@field:Ann @property:Ann @RepeatableAnn @property:RepeatableAnn
@@ -17,4 +23,20 @@ public class A(@param:Ann <!REPEATED_ANNOTATION!>@Ann<!> val x: Int, @param: Rep
@property:RepeatableAnn @RepeatableAnn
val d: Int = 0
@property:RepeatableAnn @RepeatableAnn @delegate:RepeatableAnn
val e: String by CustomDelegate()
@property:Ann @delegate:Ann
val f: String by CustomDelegate()
// Ideally we should not have repeated anotation here and below
// (because @Ann should go to the property and the second annotation to its related field)
@Ann <!REPEATED_ANNOTATION!>@delegate:Ann<!>
val g: String by CustomDelegate()
@Ann <!REPEATED_ANNOTATION!>@field:Ann<!>
val h: String = ""
@property:Ann @field:Ann
val i: String = ""
}
@@ -6,6 +6,11 @@ public final class A {
@Ann() @property:Ann() @field:Ann() public final val b: kotlin.Int = 0
@field:RepeatableAnn() @field:RepeatableAnn() public final val c: kotlin.Int = 0
@property:RepeatableAnn() @RepeatableAnn() public final val d: kotlin.Int = 0
@property:RepeatableAnn() @RepeatableAnn() @delegate:RepeatableAnn() public final val e: kotlin.String
@property:Ann() @delegate:Ann() public final val f: kotlin.String
@Ann() @delegate:Ann() public final val g: kotlin.String
@Ann() @field:Ann() public final val h: kotlin.String = ""
@property:Ann() @field:Ann() public final val i: kotlin.String = ""
public final val x: kotlin.Int
public final val y: kotlin.Int
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -20,6 +25,14 @@ public final annotation class Ann : kotlin.Annotation {
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
public final class CustomDelegate {
public constructor CustomDelegate()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
public final operator fun getValue(/*0*/ thisRef: kotlin.Any?, /*1*/ prop: kotlin.reflect.KProperty<*>): kotlin.String
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
}
@kotlin.annotation.Retention(value = AnnotationRetention.SOURCE) @kotlin.annotation.Repeatable() public final annotation class RepeatableAnn : kotlin.Annotation {
public constructor RepeatableAnn()
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
@@ -0,0 +1,5 @@
class C {
val plainField: Int = 1
@delegate:Transient
val lazy by lazy { 1 }
}
@@ -0,0 +1,10 @@
package
public final class C {
public constructor C()
@delegate:kotlin.jvm.Transient() public final val lazy: kotlin.Int
public final val plainField: kotlin.Int = 1
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 toString(): kotlin.String
}
@@ -0,0 +1,7 @@
class C {
@delegate:Transient
val plainField: Int = 1
@delegate:Transient
val lazy by lazy { 1 }
}
@@ -0,0 +1,77 @@
JetFile: delegate.kt
PACKAGE_DIRECTIVE
<empty list>
IMPORT_LIST
<empty list>
CLASS
PsiElement(class)('class')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('C')
PsiWhiteSpace(' ')
CLASS_BODY
PsiElement(LBRACE)('{')
PsiWhiteSpace('\n ')
PROPERTY
MODIFIER_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
ANNOTATION_TARGET
PsiElement(delegate)('delegate')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Transient')
PsiWhiteSpace('\n ')
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('plainField')
PsiElement(COLON)(':')
PsiWhiteSpace(' ')
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Int')
PsiWhiteSpace(' ')
PsiElement(EQ)('=')
PsiWhiteSpace(' ')
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiWhiteSpace('\n\n ')
PROPERTY
MODIFIER_LIST
ANNOTATION_ENTRY
PsiElement(AT)('@')
ANNOTATION_TARGET
PsiElement(delegate)('delegate')
PsiElement(COLON)(':')
CONSTRUCTOR_CALLEE
TYPE_REFERENCE
USER_TYPE
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('Transient')
PsiWhiteSpace('\n ')
PsiElement(val)('val')
PsiWhiteSpace(' ')
PsiElement(IDENTIFIER)('lazy')
PsiWhiteSpace(' ')
PROPERTY_DELEGATE
PsiElement(by)('by')
PsiWhiteSpace(' ')
CALL_EXPRESSION
REFERENCE_EXPRESSION
PsiElement(IDENTIFIER)('lazy')
PsiWhiteSpace(' ')
LAMBDA_ARGUMENT
LAMBDA_EXPRESSION
FUNCTION_LITERAL
PsiElement(LBRACE)('{')
PsiWhiteSpace(' ')
BLOCK
INTEGER_CONSTANT
PsiElement(INTEGER_LITERAL)('1')
PsiWhiteSpace(' ')
PsiElement(RBRACE)('}')
PsiWhiteSpace('\n')
PsiElement(RBRACE)('}')
@@ -1436,6 +1436,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget"), Pattern.compile("^(.+)\\.kt$"), true);
}
@TestMetadata("DelegateAnnotations.kt")
public void testDelegateAnnotations() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/DelegateAnnotations.kt");
doTest(fileName);
}
@TestMetadata("FieldAnnotations.kt")
public void testFieldAnnotations() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/FieldAnnotations.kt");
@@ -169,6 +169,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
doTest(fileName);
}
@TestMetadata("TransientOnDelegate.kt")
public void testTransientOnDelegate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/TransientOnDelegate.kt");
doTest(fileName);
}
@TestMetadata("Volatile.kt")
public void testVolatile() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt");
@@ -1003,6 +1003,12 @@ public class ParsingTestGenerated extends AbstractParsingTest {
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/psi/annotation/targeted/onField"), Pattern.compile("^(.*)\\.kts?$"), true);
}
@TestMetadata("delegate.kt")
public void testDelegate() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/annotation/targeted/onField/delegate.kt");
doParsingTest(fileName);
}
@TestMetadata("fqName.kt")
public void testFqName() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/psi/annotation/targeted/onField/fqName.kt");
@@ -26,7 +26,8 @@ enum class AnnotationUseSiteTarget(renderName: String? = null) {
PROPERTY_SETTER("set"),
RECEIVER(),
CONSTRUCTOR_PARAMETER("param"),
SETTER_PARAMETER("setparam");
SETTER_PARAMETER("setparam"),
PROPERTY_DELEGATE_FIELD("delegate");
val renderName: String = renderName ?: name.toLowerCase()
@@ -57,12 +57,14 @@ enum class KotlinTarget(val description: String, val isDefault: Boolean = true)
MEMBER_FUNCTION("member function", false),
TOP_LEVEL_FUNCTION("top level function", false),
MEMBER_PROPERTY("member property", false), // includes PROPERTY_PARAMETER, with and without field
MEMBER_PROPERTY_WITH_FIELD("member property with backing field", false),
MEMBER_PROPERTY_WITHOUT_FIELD("member property without backing field", false),
TOP_LEVEL_PROPERTY("top level property", false), // with and without field
TOP_LEVEL_PROPERTY_WITH_FIELD("top level property with backing field", false),
TOP_LEVEL_PROPERTY_WITHOUT_FIELD("top level property without backing field", false),
MEMBER_PROPERTY("member property", false), // includes PROPERTY_PARAMETER, with and without field/delegate
MEMBER_PROPERTY_WITH_BACKING_FIELD("member property with backing field", false),
MEMBER_PROPERTY_WITH_DELEGATE("member property with delegate", false),
MEMBER_PROPERTY_WITHOUT_FIELD_OR_DELEGATE("member property without backing field or delegate", false),
TOP_LEVEL_PROPERTY("top level property", false), // with and without field/delegate
TOP_LEVEL_PROPERTY_WITH_BACKING_FIELD("top level property with backing field", false),
TOP_LEVEL_PROPERTY_WITH_DELEGATE("top level property with delegate", false),
TOP_LEVEL_PROPERTY_WITHOUT_FIELD_OR_DELEGATE("top level property without backing field or delegate", false),
INITIALIZER("initializer", false),
DESTRUCTURING_DECLARATION("destructuring declaration", false),
@@ -125,7 +127,8 @@ enum class KotlinTarget(val description: String, val isDefault: Boolean = true)
AnnotationUseSiteTarget.PROPERTY_GETTER to PROPERTY_GETTER,
AnnotationUseSiteTarget.PROPERTY_SETTER to PROPERTY_SETTER,
AnnotationUseSiteTarget.RECEIVER to VALUE_PARAMETER,
AnnotationUseSiteTarget.SETTER_PARAMETER to VALUE_PARAMETER)
AnnotationUseSiteTarget.SETTER_PARAMETER to VALUE_PARAMETER,
AnnotationUseSiteTarget.PROPERTY_DELEGATE_FIELD to FIELD)
}
}
+1
View File
@@ -8,4 +8,5 @@
// EXIST: { itemText: "setparam:" }
// EXIST: { itemText: "property:" }
// EXIST: { itemText: "receiver:" }
// EXIST: { itemText: "delegate:" }
// NOTHING_ELSE
@@ -11,4 +11,5 @@ class Completion(@get:Ann val p1: String, @<caret>)
/*TODO: in fact is not applicable */
// EXIST: receiver
// EXIST: delegate
// NOTHING_ELSE