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
This commit is contained in:
Alexander Udalov
2013-10-09 23:09:17 +04:00
parent 806d264771
commit 2445d04338
11 changed files with 114 additions and 4 deletions
@@ -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,
@@ -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"
@@ -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
}
@@ -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.<get-extension>(): jet.Int
test.IntAnno() internal final val jet.Int.extension: jet.Int
internal final fun jet.Int.<get-extension>(): jet.Int
test.StringAnno() internal final val jet.String.extension: jet.String
internal final fun jet.String.<get-extension>(): 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()
}
@@ -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
@@ -0,0 +1,20 @@
package test
test.DoubleAnno() internal val jet.Double.extension: jet.Int
internal fun jet.Double.<get-extension>(): jet.Int
test.IntAnno() internal val jet.Int.extension: jet.Int
internal fun jet.Int.<get-extension>(): jet.Int
test.StringAnno() internal val jet.String.extension: jet.String
internal fun jet.String.<get-extension>(): 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()
}
@@ -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");
@@ -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")
@@ -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");
@@ -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");
@@ -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}
);
}