From 2445d043381c5c2a64000b20f914b73ebcb87576 Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Wed, 9 Oct 2013 23:09:17 +0400 Subject: [PATCH] Fix synthetic method generation for extension properties If several annotated extension properties with the same name were declared in one class, JVM issued a ClassFormatError, since we generated a synthetic method for each of them with the same name and signature. Make the signature of this synthetic method depend on a receiver parameter, if a property has one --- .../jet/codegen/PropertyCodegen.java | 4 +++- ...ExtensionPropertiesWithoutBackingFields.kt | 9 ++++++++ .../ExtensionPropertiesWithSameNameNoField.kt | 16 +++++++++++++ ...ExtensionPropertiesWithSameNameNoField.txt | 23 +++++++++++++++++++ .../ExtensionPropertiesWithSameNameNoField.kt | 14 +++++++++++ ...ExtensionPropertiesWithSameNameNoField.txt | 20 ++++++++++++++++ .../jet/codegen/PropertyGenTest.java | 2 +- .../BlackBoxCodegenTestGenerated.java | 5 ++++ .../LoadCompiledKotlinTestGenerated.java | 10 ++++++++ ...esolveNamespaceComparingTestGenerated.java | 10 ++++++++ .../jet/lang/resolve/java/JvmAbi.java | 5 ++-- 11 files changed, 114 insertions(+), 4 deletions(-) create mode 100644 compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt create mode 100644 compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.kt create mode 100644 compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.txt create mode 100644 compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.kt create mode 100644 compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.txt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java index 5998d8a4a66..2c18adf449a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/PropertyCodegen.java @@ -144,7 +144,9 @@ public class PropertyCodegen extends GenerationStateAware { else if (!propertyDescriptor.getAnnotations().isEmpty()) { // 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 - Method method = JvmAbi.getSyntheticMethodSignatureForAnnotatedProperty(propertyDescriptor.getName()); + ReceiverParameterDescriptor receiver = propertyDescriptor.getReceiverParameter(); + Type receiverAsmType = receiver == null ? null : typeMapper.mapType(receiver.getType()); + Method method = JvmAbi.getSyntheticMethodSignatureForAnnotatedProperty(propertyDescriptor.getName(), receiverAsmType); MethodVisitor mv = v.newMethod(null, ACC_DEPRECATED | ACC_FINAL | ACC_PRIVATE | ACC_STATIC | ACC_SYNTHETIC, diff --git a/compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt b/compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt new file mode 100644 index 00000000000..757416a35f2 --- /dev/null +++ b/compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt @@ -0,0 +1,9 @@ +annotation class Anno + +[Anno] val Int.foo: Int + get() = this + +[Anno] val String.foo: Int + get() = 42 + +fun box() = if (42.foo == 42 && "OK".foo == 42) "OK" else "Fail" diff --git a/compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.kt b/compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.kt new file mode 100644 index 00000000000..49d1174efaa --- /dev/null +++ b/compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.kt @@ -0,0 +1,16 @@ +package test + +annotation class IntAnno +annotation class StringAnno +annotation class DoubleAnno + +class Class { + [IntAnno] val Int.extension: Int + get() = this + + [StringAnno] val String.extension: String + get() = this + + [DoubleAnno] val Double.extension: Int + get() = 42 +} diff --git a/compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.txt b/compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.txt new file mode 100644 index 00000000000..475c0c41b6d --- /dev/null +++ b/compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.txt @@ -0,0 +1,23 @@ +package test + +internal final class Class { + /*primary*/ public constructor Class() + test.DoubleAnno() internal final val jet.Double.extension: jet.Int + internal final fun jet.Double.(): jet.Int + test.IntAnno() internal final val jet.Int.extension: jet.Int + internal final fun jet.Int.(): jet.Int + test.StringAnno() internal final val jet.String.extension: jet.String + internal final fun jet.String.(): jet.String +} + +internal final annotation class DoubleAnno : jet.Annotation { + /*primary*/ public constructor DoubleAnno() +} + +internal final annotation class IntAnno : jet.Annotation { + /*primary*/ public constructor IntAnno() +} + +internal final annotation class StringAnno : jet.Annotation { + /*primary*/ public constructor StringAnno() +} diff --git a/compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.kt b/compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.kt new file mode 100644 index 00000000000..aa994c1847a --- /dev/null +++ b/compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.kt @@ -0,0 +1,14 @@ +package test + +annotation class IntAnno +annotation class StringAnno +annotation class DoubleAnno + +[IntAnno] val Int.extension: Int + get() = this + +[StringAnno] val String.extension: String + get() = this + +[DoubleAnno] val Double.extension: Int + get() = 42 diff --git a/compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.txt b/compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.txt new file mode 100644 index 00000000000..cc621b21055 --- /dev/null +++ b/compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.txt @@ -0,0 +1,20 @@ +package test + +test.DoubleAnno() internal val jet.Double.extension: jet.Int + internal fun jet.Double.(): jet.Int +test.IntAnno() internal val jet.Int.extension: jet.Int + internal fun jet.Int.(): jet.Int +test.StringAnno() internal val jet.String.extension: jet.String + internal fun jet.String.(): jet.String + +internal final annotation class DoubleAnno : jet.Annotation { + /*primary*/ public constructor DoubleAnno() +} + +internal final annotation class IntAnno : jet.Annotation { + /*primary*/ public constructor IntAnno() +} + +internal final annotation class StringAnno : jet.Annotation { + /*primary*/ public constructor StringAnno() +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java index e1a3d016f2e..2790ba90913 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/PropertyGenTest.java @@ -266,7 +266,7 @@ public class PropertyGenTest extends CodegenTestCase { } private static final String TEST_SYNTHETIC_METHOD_NAME = - JvmAbi.getSyntheticMethodSignatureForAnnotatedProperty(Name.identifier("property")).getName(); + JvmAbi.getSyntheticMethodSignatureForAnnotatedProperty(Name.identifier("property"), null).getName(); public void testAnnotatedClassPropertyNoField() { loadFile("properties/annotatedClassPropertyNoField.kt"); diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index 38a763f61e6..e22fe5545ba 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -3895,6 +3895,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/properties/traitExtendsClass.kt"); } + @TestMetadata("twoAnnotatedExtensionPropertiesWithoutBackingFields.kt") + public void testTwoAnnotatedExtensionPropertiesWithoutBackingFields() throws Exception { + doTest("compiler/testData/codegen/box/properties/twoAnnotatedExtensionPropertiesWithoutBackingFields.kt"); + } + } @TestMetadata("compiler/testData/codegen/box/reflection") diff --git a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java index ac3d02faf36..29b585aee36 100644 --- a/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/jvm/compiler/LoadCompiledKotlinTestGenerated.java @@ -70,6 +70,11 @@ public class LoadCompiledKotlinTestGenerated extends AbstractLoadCompiledKotlinT doTestWithAccessors("compiler/testData/loadKotlin/annotations/classMembers/EnumArgument.kt"); } + @TestMetadata("ExtensionPropertiesWithSameNameNoField.kt") + public void testExtensionPropertiesWithSameNameNoField() throws Exception { + doTestWithAccessors("compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.kt"); + } + @TestMetadata("Function.kt") public void testFunction() throws Exception { doTestWithAccessors("compiler/testData/loadKotlin/annotations/classMembers/Function.kt"); @@ -171,6 +176,11 @@ public class LoadCompiledKotlinTestGenerated extends AbstractLoadCompiledKotlinT doTestWithAccessors("compiler/testData/loadKotlin/annotations/packageMembers/EnumArgument.kt"); } + @TestMetadata("ExtensionPropertiesWithSameNameNoField.kt") + public void testExtensionPropertiesWithSameNameNoField() throws Exception { + doTestWithAccessors("compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.kt"); + } + @TestMetadata("Function.kt") public void testFunction() throws Exception { doTestWithAccessors("compiler/testData/loadKotlin/annotations/packageMembers/Function.kt"); diff --git a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java index 83acbb40c6b..828f47b90ae 100644 --- a/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/lang/resolve/lazy/LazyResolveNamespaceComparingTestGenerated.java @@ -72,6 +72,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/annotations/classMembers/EnumArgument.kt"); } + @TestMetadata("ExtensionPropertiesWithSameNameNoField.kt") + public void testExtensionPropertiesWithSameNameNoField() throws Exception { + doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/annotations/classMembers/ExtensionPropertiesWithSameNameNoField.kt"); + } + @TestMetadata("Function.kt") public void testFunction() throws Exception { doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/annotations/classMembers/Function.kt"); @@ -173,6 +178,11 @@ public class LazyResolveNamespaceComparingTestGenerated extends AbstractLazyReso doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/annotations/packageMembers/EnumArgument.kt"); } + @TestMetadata("ExtensionPropertiesWithSameNameNoField.kt") + public void testExtensionPropertiesWithSameNameNoField() throws Exception { + doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/annotations/packageMembers/ExtensionPropertiesWithSameNameNoField.kt"); + } + @TestMetadata("Function.kt") public void testFunction() throws Exception { doTestCheckingPrimaryConstructorsAndAccessors("compiler/testData/loadKotlin/annotations/packageMembers/Function.kt"); diff --git a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java index 3f1c18088e8..fc72992ff29 100644 --- a/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java +++ b/core/descriptor.loader.java/src/org/jetbrains/jet/lang/resolve/java/JvmAbi.java @@ -17,6 +17,7 @@ package org.jetbrains.jet.lang.resolve.java; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.asm4.Type; import org.jetbrains.asm4.commons.Method; import org.jetbrains.jet.lang.resolve.name.FqName; @@ -57,11 +58,11 @@ public final class JvmAbi { } @NotNull - public static Method getSyntheticMethodSignatureForAnnotatedProperty(@NotNull Name propertyName) { + public static Method getSyntheticMethodSignatureForAnnotatedProperty(@NotNull Name propertyName, @Nullable Type receiver) { return new Method( propertyName.asString() + ANNOTATED_PROPERTY_METHOD_NAME_SUFFIX, Type.VOID_TYPE, - new Type[0] + receiver == null ? new Type[0] : new Type[] {receiver} ); }