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:
@@ -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,
|
||||
|
||||
+9
@@ -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"
|
||||
+16
@@ -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
|
||||
}
|
||||
+23
@@ -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()
|
||||
}
|
||||
+14
@@ -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
|
||||
+20
@@ -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");
|
||||
|
||||
+10
@@ -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}
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user