Fix deserialization of default property accessor flags

In MemberDeserializer.loadProperty, we incorrectly passed 0 to
getAnnotations when loading annotations on property accessors in case
the protobuf field getter_flags/setter_flags was not present. The
correct behavior, as described in metadata.proto, was to pass a special
"default accessor flags" value, constructed from the main property
flags. Otherwise in case there were annotations both on the property and
on the accessor (as in PropertyAndAccessor.kt) and the accessor was
otherwise default, we would assume that it had no annotations and would
not load them in compiler and reflection

 #KT-25499 In Progress
This commit is contained in:
Alexander Udalov
2018-08-31 18:26:23 +02:00
parent a432704c4f
commit 06ce0cb0f0
17 changed files with 142 additions and 34 deletions
@@ -166,7 +166,7 @@ class DescriptorSerializer private constructor(
val hasAnnotations =
hasAnnotations(descriptor) || hasAnnotations(descriptor.backingField) || hasAnnotations(descriptor.delegateField)
val propertyFlags = Flags.getAccessorFlags(
val defaultAccessorFlags = Flags.getAccessorFlags(
hasAnnotations,
ProtoEnumFlags.visibility(normalizeVisibility(descriptor)),
ProtoEnumFlags.modality(descriptor.modality),
@@ -177,7 +177,7 @@ class DescriptorSerializer private constructor(
if (getter != null) {
hasGetter = true
val accessorFlags = getAccessorFlags(getter)
if (accessorFlags != propertyFlags) {
if (accessorFlags != defaultAccessorFlags) {
builder.getterFlags = accessorFlags
}
}
@@ -186,7 +186,7 @@ class DescriptorSerializer private constructor(
if (setter != null) {
hasSetter = true
val accessorFlags = getAccessorFlags(setter)
if (accessorFlags != propertyFlags) {
if (accessorFlags != defaultAccessorFlags) {
builder.setterFlags = accessorFlags
}
@@ -3,25 +3,6 @@
// Please make sure that this test is consistent with the diagnostic test "annotationsTargetingNonExistentAccessor.kt"
// FILE: Temporary.java
// see https://youtrack.jetbrains.com/issue/KT-25499
class Temporary {
public static void checkX2FromStaticsHasAnnotations() {
try {
if (Statics.Companion.getClass().getDeclaredMethod("getX2").getAnnotations().length == 0) {
throw new RuntimeException("there are no annotations");
}
}
catch (NoSuchMethodException e) {
throw new RuntimeException(e);
}
}
}
// FILE: test.kt
import kotlin.reflect.KAnnotatedElement
import kotlin.reflect.KProperty
@@ -152,9 +133,9 @@ class Statics {
check(::x0.getter, annotationExists = false)
check(::x1.getter, annotationExists = false)
check(::x2.getter, annotationExists = false) // https://youtrack.jetbrains.com/issue/KT-25499
check(::x2.setter, annotationExists = false)
check(::x2.setter.parameters.first(), annotationExists = false)
check(::x2.getter, annotationExists = true)
check(::x2.setter, annotationExists = true)
check(::x2.setter.parameters.first(), annotationExists = false /* TODO */)
check(::x3.getter, annotationExists = false)
@@ -185,7 +166,6 @@ fun box(): String {
PrivateProperties(0, "").test()
EffetivelyPrivate.test()
Statics().test()
Temporary.checkX2FromStaticsHasAnnotations()
Delegate().test()
return "OK"
}
@@ -0,0 +1,21 @@
// WITH_REFLECT
// IGNORE_BACKEND: JVM_IR, JS_IR, JS, NATIVE
import kotlin.test.assertEquals
annotation class Ann1
annotation class Ann2
class Foo {
@setparam:Ann1
var delegate = " "
set(@Ann2 value) {}
}
fun box(): String {
val setterParameters = Foo::delegate.setter.parameters
assertEquals(2, setterParameters.size)
assertEquals("[]", setterParameters.first().annotations.toString())
assertEquals("[@Ann2(), @Ann1()]", setterParameters.last().annotations.toString())
return "OK"
}
@@ -0,0 +1,18 @@
package test
annotation class A(val value: String)
annotation class B(val value: Array<String>)
interface I {
@A("property")
@get:B(["getter"])
var propertyAndGetter: Int
@A("property")
@set:B(["setter"])
var propertyAndSetter: Int
@get:A("getter")
@set:B(["setter"])
var getterAndSetter: Int
}
@@ -0,0 +1,25 @@
package test
public final annotation class A : kotlin.Annotation {
/*primary*/ public constructor A(/*0*/ value: kotlin.String)
public final val value: kotlin.String
public final fun <get-value>(): kotlin.String
}
public final annotation class B : kotlin.Annotation {
/*primary*/ public constructor B(/*0*/ value: kotlin.Array<kotlin.String>)
public final val value: kotlin.Array<kotlin.String>
public final fun <get-value>(): kotlin.Array<kotlin.String>
}
public interface I {
public abstract var getterAndSetter: kotlin.Int
@test.A(value = "getter") public abstract fun <get-getterAndSetter>(): kotlin.Int
@test.B(value = {"setter"}) public abstract fun <set-getterAndSetter>(/*0*/ <set-?>: kotlin.Int): kotlin.Unit
@test.A(value = "property") public abstract var propertyAndGetter: kotlin.Int
@test.B(value = {"getter"}) public abstract fun <get-propertyAndGetter>(): kotlin.Int
public abstract fun <set-propertyAndGetter>(/*0*/ <set-?>: kotlin.Int): kotlin.Unit
@test.A(value = "property") public abstract var propertyAndSetter: kotlin.Int
public abstract fun <get-propertyAndSetter>(): kotlin.Int
@test.B(value = {"setter"}) public abstract fun <set-propertyAndSetter>(/*0*/ <set-?>: kotlin.Int): kotlin.Unit
}
@@ -17555,6 +17555,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/reflection/annotations/retentions.kt");
}
@TestMetadata("setparam.kt")
public void testSetparam() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/setparam.kt");
}
@TestMetadata("simpleClassAnnotation.kt")
public void testSimpleClassAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/simpleClassAnnotation.kt");
@@ -17555,6 +17555,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/reflection/annotations/retentions.kt");
}
@TestMetadata("setparam.kt")
public void testSetparam() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/setparam.kt");
}
@TestMetadata("simpleClassAnnotation.kt")
public void testSimpleClassAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/simpleClassAnnotation.kt");
@@ -17555,6 +17555,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/reflection/annotations/retentions.kt");
}
@TestMetadata("setparam.kt")
public void testSetparam() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/setparam.kt");
}
@TestMetadata("simpleClassAnnotation.kt")
public void testSimpleClassAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/simpleClassAnnotation.kt");
@@ -2147,6 +2147,11 @@ public class LoadJavaTestGenerated extends AbstractLoadJavaTest {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/FieldTarget.kt");
}
@TestMetadata("PropertyAndAccessor.kt")
public void testPropertyAndAccessor() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/PropertyAndAccessor.kt");
}
@TestMetadata("ReceiverTarget.kt")
public void testReceiverTarget() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
@@ -491,6 +491,11 @@ public class LoadKotlinWithTypeTableTestGenerated extends AbstractLoadKotlinWith
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/FieldTarget.kt");
}
@TestMetadata("PropertyAndAccessor.kt")
public void testPropertyAndAccessor() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/PropertyAndAccessor.kt");
}
@TestMetadata("ReceiverTarget.kt")
public void testReceiverTarget() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
@@ -2147,6 +2147,11 @@ public class LoadJavaUsingJavacTestGenerated extends AbstractLoadJavaUsingJavacT
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/FieldTarget.kt");
}
@TestMetadata("PropertyAndAccessor.kt")
public void testPropertyAndAccessor() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/PropertyAndAccessor.kt");
}
@TestMetadata("ReceiverTarget.kt")
public void testReceiverTarget() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
@@ -493,6 +493,11 @@ public class JvmRuntimeDescriptorLoaderTestGenerated extends AbstractJvmRuntimeD
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/FieldTarget.kt");
}
@TestMetadata("PropertyAndAccessor.kt")
public void testPropertyAndAccessor() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/PropertyAndAccessor.kt");
}
@TestMetadata("ReceiverTarget.kt")
public void testReceiverTarget() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
@@ -67,11 +67,20 @@ class MemberDeserializer(private val c: DeserializationContext) {
}
)
// Per documentation on Property.getter_flags in metadata.proto, if an accessor flags field is absent, its value should be computed
// by taking hasAnnotations/visibility/modality from property flags, and using false for the rest
val defaultAccessorFlags = Flags.getAccessorFlags(
Flags.HAS_ANNOTATIONS.get(flags),
Flags.VISIBILITY.get(flags),
Flags.MODALITY.get(flags),
false, false, false
)
val getter = if (hasGetter) {
val getterFlags = proto.getterFlags
val isNotDefault = proto.hasGetterFlags() && Flags.IS_NOT_DEFAULT.get(getterFlags)
val isExternal = proto.hasGetterFlags() && Flags.IS_EXTERNAL_ACCESSOR.get(getterFlags)
val isInline = proto.hasGetterFlags() && Flags.IS_INLINE_ACCESSOR.get(getterFlags)
val getterFlags = if (proto.hasGetterFlags()) proto.getterFlags else defaultAccessorFlags
val isNotDefault = Flags.IS_NOT_DEFAULT.get(getterFlags)
val isExternal = Flags.IS_EXTERNAL_ACCESSOR.get(getterFlags)
val isInline = Flags.IS_INLINE_ACCESSOR.get(getterFlags)
val annotations = getAnnotations(proto, getterFlags, AnnotatedCallableKind.PROPERTY_GETTER)
val getter = if (isNotDefault) {
PropertyGetterDescriptorImpl(
@@ -94,10 +103,10 @@ class MemberDeserializer(private val c: DeserializationContext) {
}
val setter = if (Flags.HAS_SETTER.get(flags)) {
val setterFlags = proto.setterFlags
val isNotDefault = proto.hasSetterFlags() && Flags.IS_NOT_DEFAULT.get(setterFlags)
val isExternal = proto.hasSetterFlags() && Flags.IS_EXTERNAL_ACCESSOR.get(setterFlags)
val isInline = proto.hasSetterFlags() && Flags.IS_INLINE_ACCESSOR.get(setterFlags)
val setterFlags = if (proto.hasSetterFlags()) proto.setterFlags else defaultAccessorFlags
val isNotDefault = Flags.IS_NOT_DEFAULT.get(setterFlags)
val isExternal = Flags.IS_EXTERNAL_ACCESSOR.get(setterFlags)
val isInline = Flags.IS_INLINE_ACCESSOR.get(setterFlags)
val annotations = getAnnotations(proto, setterFlags, AnnotatedCallableKind.PROPERTY_SETTER)
if (isNotDefault) {
val setter = PropertySetterDescriptorImpl(
@@ -491,6 +491,11 @@ public class LoadJavaClsStubTestGenerated extends AbstractLoadJavaClsStubTest {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/FieldTarget.kt");
}
@TestMetadata("PropertyAndAccessor.kt")
public void testPropertyAndAccessor() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/PropertyAndAccessor.kt");
}
@TestMetadata("ReceiverTarget.kt")
public void testReceiverTarget() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
@@ -491,6 +491,11 @@ public class ResolveByStubTestGenerated extends AbstractResolveByStubTest {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/FieldTarget.kt");
}
@TestMetadata("PropertyAndAccessor.kt")
public void testPropertyAndAccessor() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/PropertyAndAccessor.kt");
}
@TestMetadata("ReceiverTarget.kt")
public void testReceiverTarget() throws Exception {
runTest("compiler/testData/loadJava/compiledKotlin/annotations/withUseSiteTarget/ReceiverTarget.kt");
@@ -15695,6 +15695,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/annotations/retentions.kt");
}
@TestMetadata("setparam.kt")
public void testSetparam() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/setparam.kt");
}
@TestMetadata("simpleClassAnnotation.kt")
public void testSimpleClassAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/simpleClassAnnotation.kt");
@@ -16760,6 +16760,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/reflection/annotations/retentions.kt");
}
@TestMetadata("setparam.kt")
public void testSetparam() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/setparam.kt");
}
@TestMetadata("simpleClassAnnotation.kt")
public void testSimpleClassAnnotation() throws Exception {
runTest("compiler/testData/codegen/box/reflection/annotations/simpleClassAnnotation.kt");