From ec909d07751e2dc78a6fa20c82ab1e9c169f4bc6 Mon Sep 17 00:00:00 2001 From: Mikhail Glukhikh Date: Fri, 15 Jan 2016 13:34:22 +0300 Subject: [PATCH] Volatile forbidden for delegated properties (and checked for other use-site targets) --- .../resolve/jvm/checkers/declarationCheckers.kt | 12 +++++++++--- .../jvm/diagnostics/DefaultErrorMessagesJvm.java | 1 + .../kotlin/resolve/jvm/diagnostics/ErrorsJvm.java | 1 + .../testsWithStdLib/annotations/Volatile.kt | 5 +++++ .../testsWithStdLib/annotations/Volatile.txt | 2 ++ .../jetbrains/kotlin/resolve/DescriptorUtils.java | 14 +++++++------- 6 files changed, 25 insertions(+), 10 deletions(-) diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt index 3b182f5a70d..264c8a31ef1 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/declarationCheckers.kt @@ -143,9 +143,15 @@ class VolatileAnnotationChecker : DeclarationChecker { bindingContext: BindingContext ) { val volatileAnnotation = DescriptorUtils.getVolatileAnnotation(descriptor) - if (volatileAnnotation != null && descriptor is PropertyDescriptor && !descriptor.isVar) { - val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(volatileAnnotation) ?: return - diagnosticHolder.report(ErrorsJvm.VOLATILE_ON_VALUE.on(annotationEntry)) + if (volatileAnnotation != null) { + if (descriptor is PropertyDescriptor && !descriptor.isVar) { + val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(volatileAnnotation) ?: return + diagnosticHolder.report(ErrorsJvm.VOLATILE_ON_VALUE.on(annotationEntry)) + } + if (declaration is KtProperty && declaration.hasDelegate()) { + val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(volatileAnnotation) ?: return + diagnosticHolder.report(ErrorsJvm.VOLATILE_ON_DELEGATE.on(annotationEntry)) + } } } } diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java index bfc5c235c16..73199a7e585 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/DefaultErrorMessagesJvm.java @@ -64,6 +64,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(ErrorsJvm.INAPPLICABLE_JVM_NAME, "''@JvmName'' annotation is not applicable to this declaration"); MAP.put(ErrorsJvm.ILLEGAL_JVM_NAME, "Illegal JVM name"); MAP.put(ErrorsJvm.VOLATILE_ON_VALUE, "''@Volatile'' annotation cannot be used on immutable properties"); + MAP.put(ErrorsJvm.VOLATILE_ON_DELEGATE, "''@Volatile'' annotation cannot be used on delegated properties"); MAP.put(ErrorsJvm.SYNCHRONIZED_ON_ABSTRACT, "''@Synchronized'' annotation cannot be used on abstract functions"); MAP.put(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT, "External declaration can not be abstract"); MAP.put(ErrorsJvm.EXTERNAL_DECLARATION_CANNOT_HAVE_BODY, "External declaration can not have a body"); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java index 653a3f4ceb5..b3dfc5b57ad 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/diagnostics/ErrorsJvm.java @@ -52,6 +52,7 @@ public interface ErrorsJvm { DiagnosticFactory1 INAPPLICABLE_JVM_FIELD = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 VOLATILE_ON_VALUE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 VOLATILE_ON_DELEGATE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 SYNCHRONIZED_ON_ABSTRACT = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS = DiagnosticFactory0.create(WARNING, DECLARATION_SIGNATURE); diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt index 47af0490450..086da16157d 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.kt @@ -1,7 +1,12 @@ import kotlin.jvm.Volatile +import kotlin.properties.Delegates class My { @Volatile val x = 0 // ok @Volatile var y = 1 + + @delegate:Volatile var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() } + + @field:Volatile val w = 2 } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.txt b/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.txt index afe159569a1..b3b0443b924 100644 --- a/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.txt +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/Volatile.txt @@ -2,8 +2,10 @@ package public final class My { public constructor My() + @field:kotlin.jvm.Volatile() public final val w: kotlin.Int = 2 @kotlin.jvm.Volatile() public final val x: kotlin.Int = 0 @kotlin.jvm.Volatile() public final var y: kotlin.Int + @delegate:kotlin.jvm.Volatile() public final var z: kotlin.String public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String diff --git a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java index 9eff647e331..2e7a84755d1 100644 --- a/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java +++ b/core/descriptors/src/org/jetbrains/kotlin/resolve/DescriptorUtils.java @@ -507,7 +507,7 @@ public class DescriptorUtils { @Nullable public static String getJvmName(@NotNull Annotated annotated) { - AnnotationDescriptor jvmNameAnnotation = getJvmNameAnnotation(annotated.getAnnotations()); + AnnotationDescriptor jvmNameAnnotation = getAnnotationByFqName(annotated.getAnnotations(), JVM_NAME); if (jvmNameAnnotation == null) return null; Map> arguments = jvmNameAnnotation.getAllValueArguments(); @@ -520,24 +520,24 @@ public class DescriptorUtils { } @Nullable - public static AnnotationDescriptor getJvmNameAnnotation(@NotNull Annotations annotations) { - AnnotationWithTarget jvmName = Annotations.Companion.findAnyAnnotation(annotations, JVM_NAME); - return jvmName == null ? null : jvmName.getAnnotation(); + public static AnnotationDescriptor getAnnotationByFqName(@NotNull Annotations annotations, @NotNull FqName name) { + AnnotationWithTarget annotationWithTarget = Annotations.Companion.findAnyAnnotation(annotations, name); + return annotationWithTarget == null ? null : annotationWithTarget.getAnnotation(); } @Nullable public static AnnotationDescriptor getJvmNameAnnotation(@NotNull Annotated annotated) { - return getJvmNameAnnotation(annotated.getAnnotations()); + return getAnnotationByFqName(annotated.getAnnotations(), JVM_NAME); } @Nullable public static AnnotationDescriptor getVolatileAnnotation(@NotNull Annotated annotated) { - return annotated.getAnnotations().findAnnotation(VOLATILE); + return getAnnotationByFqName(annotated.getAnnotations(), VOLATILE); } @Nullable public static AnnotationDescriptor getSynchronizedAnnotation(@NotNull Annotated annotated) { - return annotated.getAnnotations().findAnnotation(SYNCHRONIZED); + return getAnnotationByFqName(annotated.getAnnotations(), SYNCHRONIZED); } @NotNull