diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 445c375e314..83fcdc1bed6 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -118,16 +118,7 @@ public class PropertyCodegen { if (CodegenContextUtil.isImplClassOwner(context)) { assert declaration != null : "Declaration is null for different context: " + context; - boolean hasBackingField = hasBackingField(declaration, descriptor); - - AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS, - descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(false, descriptor.isVar(), hasBackingField)); - - Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); - Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); - - generateBackingField(declaration, descriptor, fieldAnnotations); - generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations); + genBackingFieldAndAnnotations(declaration, descriptor, false); } if (isAccessorNeeded(declaration, descriptor, getter)) { @@ -140,6 +131,21 @@ public class PropertyCodegen { context.recordSyntheticAccessorIfNeeded(descriptor, bindingContext); } + private void genBackingFieldAndAnnotations(@NotNull KtNamedDeclaration declaration, @NotNull PropertyDescriptor descriptor, boolean isParameter) { + boolean hasBackingField = hasBackingField(declaration, descriptor); + + AnnotationSplitter annotationSplitter = + AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS, + descriptor.getAnnotations(), + AnnotationSplitter.getTargetSet(isParameter, descriptor.isVar(), hasBackingField)); + + Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); + Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); + + generateBackingField(declaration, descriptor, fieldAnnotations); + generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations); + } + /** * Determines if it's necessary to generate an accessor to the property, i.e. if this property can be referenced via getter/setter * for any reason @@ -174,21 +180,20 @@ public class PropertyCodegen { return true; } - public void generatePrimaryConstructorProperty(KtParameter p, PropertyDescriptor descriptor) { - AnnotationSplitter annotationSplitter = AnnotationSplitter.create(LockBasedStorageManager.NO_LOCKS, - descriptor.getAnnotations(), AnnotationSplitter.getTargetSet(true, descriptor.isVar(), hasBackingField(p, descriptor))); + private static boolean areAccessorsNeededForPrimaryConstructorProperty( + @NotNull PropertyDescriptor descriptor + ) { + if (hasJvmFieldAnnotation(descriptor)) return false; - Annotations fieldAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.FIELD); - Annotations propertyAnnotations = annotationSplitter.getAnnotationsForTarget(AnnotationUseSiteTarget.PROPERTY); + return !Visibilities.isPrivate(descriptor.getVisibility()); + } - generateBackingField(p, descriptor, fieldAnnotations); - generateSyntheticMethodIfNeeded(descriptor, propertyAnnotations); + public void generatePrimaryConstructorProperty(@NotNull KtParameter p, @NotNull PropertyDescriptor descriptor) { + genBackingFieldAndAnnotations(p, descriptor, true); - if (!Visibilities.isPrivate(descriptor.getVisibility())) { + if (areAccessorsNeededForPrimaryConstructorProperty(descriptor)) { generateGetter(p, descriptor, null); - if (descriptor.isVar()) { - generateSetter(p, descriptor, null); - } + generateSetter(p, descriptor, null); } } diff --git a/compiler/testData/codegen/boxWithJava/jvmField/constructorProperty/Test.java b/compiler/testData/codegen/boxWithJava/jvmField/constructorProperty/Test.java new file mode 100644 index 00000000000..6158f269fb6 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/jvmField/constructorProperty/Test.java @@ -0,0 +1,6 @@ +public class Test { + public static String invokeMethodWithPublicField() { + C c = new C("OK"); + return c.foo; + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/jvmField/constructorProperty/simple.kt b/compiler/testData/codegen/boxWithJava/jvmField/constructorProperty/simple.kt new file mode 100644 index 00000000000..5cf5feca94f --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/jvmField/constructorProperty/simple.kt @@ -0,0 +1,7 @@ +class C(@JvmField val foo: String) { + +} + +fun box(): String { + return Test.invokeMethodWithPublicField() +} diff --git a/compiler/testData/codegen/bytecodeText/jvmField.kt b/compiler/testData/codegen/bytecodeText/jvmField.kt new file mode 100644 index 00000000000..94e8a7c36af --- /dev/null +++ b/compiler/testData/codegen/bytecodeText/jvmField.kt @@ -0,0 +1,9 @@ +class C(@JvmField var foo: String) { + @JvmField var bar: String = "123" +} + + +// 0 getFoo +// 0 setFoo +// 0 getBar +// 0 setBar \ No newline at end of file diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvmFieldInConstructor.A.kt b/compiler/testData/compileKotlinAgainstKotlin/jvmFieldInConstructor.A.kt new file mode 100644 index 00000000000..7fd9b50deb6 --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/jvmFieldInConstructor.A.kt @@ -0,0 +1,5 @@ +open class A(@JvmField public val publicField: String = "1", + @JvmField internal val internalField: String = "2", + @JvmField protected val protectedfield: String = "3") + +open class B : A() \ No newline at end of file diff --git a/compiler/testData/compileKotlinAgainstKotlin/jvmFieldInConstructor.B.kt b/compiler/testData/compileKotlinAgainstKotlin/jvmFieldInConstructor.B.kt new file mode 100644 index 00000000000..375138cbd7e --- /dev/null +++ b/compiler/testData/compileKotlinAgainstKotlin/jvmFieldInConstructor.B.kt @@ -0,0 +1,9 @@ +open class C : B() { + fun test(): String { + return super.publicField + super.internalField + super.protectedfield + } +} + +fun main(args: Array) { + C().test() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java index 2594b8584dd..a1c29943e7e 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BytecodeTextTestGenerated.java @@ -161,6 +161,12 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest { doTest(fileName); } + @TestMetadata("jvmField.kt") + public void testJvmField() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/jvmField.kt"); + doTest(fileName); + } + @TestMetadata("kt2202.kt") public void testKt2202() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeText/kt2202.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 4ff90861ab7..fc0e4a632b2 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -393,6 +393,12 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithJava/jvmField"), Pattern.compile("^([^\\.]+)$"), true); } + @TestMetadata("constructorProperty") + public void testConstructorProperty() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/jvmField/constructorProperty/"); + doTestWithJava(fileName); + } + @TestMetadata("simple") public void testSimple() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/jvmField/simple/"); diff --git a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java index b8ae632df71..3a085c7b10c 100644 --- a/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/jvm/compiler/CompileKotlinAgainstKotlinTestGenerated.java @@ -107,6 +107,12 @@ public class CompileKotlinAgainstKotlinTestGenerated extends AbstractCompileKotl doTest(fileName); } + @TestMetadata("jvmFieldInConstructor.A.kt") + public void testJvmFieldInConstructor() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/jvmFieldInConstructor.A.kt"); + doTest(fileName); + } + @TestMetadata("JvmNameOnAccessor.A.kt") public void testJvmNameOnAccessor() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/compileKotlinAgainstKotlin/JvmNameOnAccessor.A.kt");