diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSyntheticApplicabilityChecker.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSyntheticApplicabilityChecker.kt new file mode 100644 index 00000000000..de2be9da09a --- /dev/null +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/checkers/JvmSyntheticApplicabilityChecker.kt @@ -0,0 +1,40 @@ +/* + * Copyright 2010-2016 JetBrains s.r.o. + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + +package org.jetbrains.kotlin.resolve.jvm.checkers + +import org.jetbrains.kotlin.descriptors.DeclarationDescriptor +import org.jetbrains.kotlin.diagnostics.DiagnosticSink +import org.jetbrains.kotlin.psi.KtDeclaration +import org.jetbrains.kotlin.psi.KtProperty +import org.jetbrains.kotlin.resolve.BindingContext +import org.jetbrains.kotlin.resolve.DeclarationChecker +import org.jetbrains.kotlin.resolve.DescriptorToSourceUtils +import org.jetbrains.kotlin.resolve.annotations.findJvmSyntheticAnnotation +import org.jetbrains.kotlin.resolve.jvm.diagnostics.ErrorsJvm + +class JvmSyntheticApplicabilityChecker : DeclarationChecker { + + override fun check(declaration: KtDeclaration, descriptor: DeclarationDescriptor, + diagnosticHolder: DiagnosticSink, bindingContext: BindingContext + ) { + val annotation = descriptor.findJvmSyntheticAnnotation() ?: return + if (declaration is KtProperty && declaration.hasDelegate()) { + val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) ?: return + diagnosticHolder.report(ErrorsJvm.JVM_SYNTHETIC_ON_DELEGATE.on(annotationEntry)) + } + } +} \ No newline at end of file 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 73199a7e585..a57a1213785 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 @@ -102,6 +102,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(ErrorsJvm.INAPPLICABLE_JVM_FIELD, "{0}", Renderers.TO_STRING); + MAP.put(ErrorsJvm.JVM_SYNTHETIC_ON_DELEGATE, "''@JvmSynthetic'' annotation cannot be used on delegated properties"); + MAP.put(ErrorsJvm.SUPER_CALL_WITH_DEFAULT_PARAMETERS, "Super-calls with default arguments are not allowed. Please specify all arguments of ''super.{0}'' explicitly", Renderers.TO_STRING); } 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 b3dfc5b57ad..1d181a575a1 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 @@ -51,6 +51,8 @@ public interface ErrorsJvm { DiagnosticFactory1 INAPPLICABLE_JVM_FIELD = DiagnosticFactory1.create(ERROR); + DiagnosticFactory0 JVM_SYNTHETIC_ON_DELEGATE = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 VOLATILE_ON_VALUE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 VOLATILE_ON_DELEGATE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 SYNCHRONIZED_ON_ABSTRACT = DiagnosticFactory0.create(ERROR); diff --git a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt index 348ba1bbdd3..a80f0ae44f4 100644 --- a/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt +++ b/compiler/frontend.java/src/org/jetbrains/kotlin/resolve/jvm/platform/JvmPlatformConfigurator.kt @@ -41,7 +41,8 @@ object JvmPlatformConfigurator : PlatformConfigurator( NativeFunChecker(), OverloadsAnnotationChecker(), JvmFieldApplicabilityChecker(), - TypeParameterBoundIsNotArrayChecker() + TypeParameterBoundIsNotArrayChecker(), + JvmSyntheticApplicabilityChecker() ), additionalCallCheckers = listOf( diff --git a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt index 6f8ece88f0e..ca3c379490a 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt +++ b/compiler/frontend/src/org/jetbrains/kotlin/resolve/AnnotationUtil.kt @@ -33,11 +33,10 @@ fun DeclarationDescriptor.hasJvmStaticAnnotation(): Boolean { private val JVM_SYNTHETIC_ANNOTATION_FQ_NAME = FqName("kotlin.jvm.JvmSynthetic") -fun DeclarationDescriptor.hasJvmSyntheticAnnotation(): Boolean { - val jvmSyntheticName = JVM_SYNTHETIC_ANNOTATION_FQ_NAME - return annotations.findAnnotation(jvmSyntheticName) != null || - Annotations.findUseSiteTargetedAnnotation(annotations, AnnotationUseSiteTarget.FIELD, jvmSyntheticName) != null -} +fun DeclarationDescriptor.hasJvmSyntheticAnnotation() = findJvmSyntheticAnnotation() != null + +fun DeclarationDescriptor.findJvmSyntheticAnnotation() = + DescriptorUtils.getAnnotationByFqName(annotations, JVM_SYNTHETIC_ANNOTATION_FQ_NAME) fun CallableDescriptor.isPlatformStaticInObjectOrClass(): Boolean = isPlatformStaticIn { DescriptorUtils.isNonCompanionObject(it) || DescriptorUtils.isClassOrEnumClass(it) } diff --git a/compiler/testData/codegen/bytecodeListing/annotations/JvmSynthetic.txt b/compiler/testData/codegen/bytecodeListing/annotations/JvmSynthetic.txt index 7739ec4a3ea..b8f9f2fc9f1 100644 --- a/compiler/testData/codegen/bytecodeListing/annotations/JvmSynthetic.txt +++ b/compiler/testData/codegen/bytecodeListing/annotations/JvmSynthetic.txt @@ -8,8 +8,8 @@ public final class Example { public final @org.jetbrains.annotations.NotNull method getProp(): java.lang.String public synthetic final method getProp2(): int public final method getUseSite(): int - public final method getUseSite2(): int + public synthetic final method getUseSite2(): int public synthetic final method job(): void public synthetic final method setProp2(p0: int): void - public final method setUseSite2(p0: int): void + public synthetic final method setUseSite2(p0: int): void } \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt new file mode 100644 index 00000000000..cd3bf91c917 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt @@ -0,0 +1,9 @@ +import kotlin.properties.Delegates + +class My { + @delegate:JvmSynthetic val s: String by lazy { "s" } + + // Both Ok + @get:JvmSynthetic val t: String by lazy { "t" } + @set:JvmSynthetic var z: String by Delegates.observable("?") { prop, old, new -> old.hashCode() } +} \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.txt b/compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.txt new file mode 100644 index 00000000000..460a8dbe08d --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.txt @@ -0,0 +1,11 @@ +package + +public final class My { + public constructor My() + @delegate:kotlin.jvm.JvmSynthetic() public final val s: kotlin.String + public final val t: kotlin.String + 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/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java index 054c99da2c1..4619caee51f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -151,6 +151,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW doTest(fileName); } + @TestMetadata("JvmSyntheticOnDelegate.kt") + public void testJvmSyntheticOnDelegate() throws Exception { + String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/JvmSyntheticOnDelegate.kt"); + doTest(fileName); + } + @TestMetadata("qualifiedCallValue.kt") public void testQualifiedCallValue() throws Exception { String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/qualifiedCallValue.kt");