diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java index 672ffac46aa..94acfe9cb26 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/PropertyCodegen.java @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.psi.psiUtil.PsiUtilPackage; import org.jetbrains.kotlin.resolve.BindingContext; import org.jetbrains.kotlin.resolve.DescriptorFactory; import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils; +import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.jvm.jvmSignature.JvmMethodSignature; @@ -256,9 +257,19 @@ public class PropertyCodegen { ClassBuilder builder = v; + boolean hasPublicFieldAnnotation = AnnotationsPackage.findPublicFieldAnnotation(propertyDescriptor) != null; + FieldOwnerContext backingFieldContext = context; if (AsmUtil.isInstancePropertyWithStaticBackingField(propertyDescriptor) ) { - modifiers |= ACC_STATIC | getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate); + modifiers |= ACC_STATIC; + + if (hasPublicFieldAnnotation && !isDelegate) { + modifiers |= ACC_PUBLIC; + } + else { + modifiers |= getVisibilityForSpecialPropertyBackingField(propertyDescriptor, isDelegate); + } + if (AsmUtil.isPropertyWithBackingFieldInOuterClass(propertyDescriptor)) { ImplementationBodyCodegen codegen = (ImplementationBodyCodegen) memberCodegen.getParentCodegen(); builder = codegen.v; @@ -266,6 +277,9 @@ public class PropertyCodegen { v.getSerializationBindings().put(STATIC_FIELD_IN_OUTER_CLASS, propertyDescriptor); } } + else if (!isDelegate && hasPublicFieldAnnotation) { + modifiers |= ACC_PUBLIC; + } else if (kind != OwnerKind.PACKAGE || isDelegate) { modifiers |= ACC_PRIVATE; } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index 078556686d8..7a440bd1f1e 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -114,6 +114,7 @@ public interface Errors { DiagnosticFactory2 REDUNDANT_MODIFIER = DiagnosticFactory2.create(WARNING); DiagnosticFactory0 INAPPLICABLE_ANNOTATION = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 INAPPLICABLE_PLATFORM_NAME = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 INAPPLICABLE_PUBLIC_FIELD = DiagnosticFactory0.create(ERROR); // Annotations diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 5eed0c12740..587e4c7f0ec 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -137,6 +137,7 @@ public class DefaultErrorMessages { MAP.put(REPEATED_MODIFIER, "Repeated ''{0}''", TO_STRING); MAP.put(INAPPLICABLE_ANNOTATION, "This annotation is only applicable to top level functions"); MAP.put(INAPPLICABLE_PLATFORM_NAME, "platformName annotation is not applicable to this declaration"); + MAP.put(INAPPLICABLE_PUBLIC_FIELD, "publicField annotation is not applicable to this declaration"); MAP.put(REDUNDANT_MODIFIER, "Modifier ''{0}'' is redundant because ''{1}'' is present", TO_STRING, TO_STRING); MAP.put(ABSTRACT_MODIFIER_IN_TRAIT, "Modifier ''abstract'' is redundant in interface"); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt index 74ea88afe34..390c2556b0a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt @@ -32,6 +32,10 @@ public fun DeclarationDescriptor.hasPlatformStaticAnnotation(): Boolean { return getAnnotations().findAnnotation(FqName("kotlin.platform.platformStatic")) != null } +public fun DeclarationDescriptor.findPublicFieldAnnotation(): AnnotationDescriptor? { + return getAnnotations().findAnnotation(FqName("kotlin.jvm.publicField")) +} + public fun DeclarationDescriptor.hasIntrinsicAnnotation(): Boolean { return getAnnotations().findAnnotation(FqName("kotlin.jvm.internal.Intrinsic")) != null } diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java index 18154c9e66c..dd667a41bbc 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/ModifiersChecker.java @@ -32,6 +32,7 @@ import org.jetbrains.kotlin.lexer.JetTokens; import org.jetbrains.kotlin.name.FqName; import org.jetbrains.kotlin.name.Name; import org.jetbrains.kotlin.psi.*; +import org.jetbrains.kotlin.resolve.annotations.AnnotationsPackage; import org.jetbrains.kotlin.resolve.constants.CompileTimeConstant; import org.jetbrains.kotlin.resolve.constants.StringValue; @@ -149,6 +150,7 @@ public class ModifiersChecker { checkVarargsModifiers(modifierListOwner, descriptor); } checkPlatformNameApplicability(descriptor); + checkPublicFieldApplicability(descriptor); runDeclarationCheckers(modifierListOwner, descriptor); } @@ -162,6 +164,7 @@ public class ModifiersChecker { reportIllegalModalityModifiers(modifierListOwner); reportIllegalVisibilityModifiers(modifierListOwner); checkPlatformNameApplicability(descriptor); + checkPublicFieldApplicability(descriptor); runDeclarationCheckers(modifierListOwner, descriptor); } @@ -320,6 +323,24 @@ public class ModifiersChecker { } + private void checkPublicFieldApplicability(@NotNull DeclarationDescriptor descriptor) { + AnnotationDescriptor annotation = AnnotationsPackage.findPublicFieldAnnotation(descriptor); + if (annotation == null) return; + + JetAnnotationEntry annotationEntry = trace.get(BindingContext.ANNOTATION_DESCRIPTOR_TO_PSI_ELEMENT, annotation); + if (annotationEntry == null) return; + + if (!(descriptor instanceof PropertyDescriptor)) { + trace.report(INAPPLICABLE_PUBLIC_FIELD.on(annotationEntry)); + return; + } + + PropertyDescriptor propertyDescriptor = (PropertyDescriptor) descriptor; + if (Boolean.FALSE.equals(trace.getBindingContext().get(BindingContext.BACKING_FIELD_REQUIRED, propertyDescriptor))) { + trace.report(INAPPLICABLE_PUBLIC_FIELD.on(annotationEntry)); + } + } + private static boolean isRenamableDeclaration(@NotNull DeclarationDescriptor descriptor) { DeclarationDescriptor containingDescriptor = descriptor.getContainingDeclaration(); diff --git a/libraries/stdlib/src/kotlin/jvm/JvmPlatformAnnotations.kt b/libraries/stdlib/src/kotlin/jvm/JvmPlatformAnnotations.kt index aa5ebf2d062..b4f75925e36 100644 --- a/libraries/stdlib/src/kotlin/jvm/JvmPlatformAnnotations.kt +++ b/libraries/stdlib/src/kotlin/jvm/JvmPlatformAnnotations.kt @@ -27,3 +27,9 @@ import java.lang.annotation.RetentionPolicy */ Retention(RetentionPolicy.CLASS) public annotation class jvmOverloads + +/** + * Instructs the Kotlin compiler to generate a public backing field for this property. + */ +Retention(RetentionPolicy.SOURCE) +public annotation class publicField \ No newline at end of file