delegate use-site targeted annotations: parser, front-end, codegen with some tests #KT-10502 Fixed
This commit is contained in:
@@ -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
|
||||
}
|
||||
+33
@@ -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
|
||||
|
||||
+44
@@ -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
|
||||
}
|
||||
+1
-1
@@ -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<!>
|
||||
|
||||
+22
@@ -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 = ""
|
||||
}
|
||||
+13
@@ -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
|
||||
|
||||
+5
@@ -0,0 +1,5 @@
|
||||
class C {
|
||||
val plainField: Int = 1
|
||||
@delegate:Transient
|
||||
val lazy by lazy { 1 }
|
||||
}
|
||||
+10
@@ -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)('}')
|
||||
Reference in New Issue
Block a user