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 68273bc1c6c..14ce10e0ee2 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 @@ -61,6 +61,7 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(ErrorsJvm.DEPRECATED_ANNOTATION_METHOD_CALL, "Annotation methods are deprecated. Use property instead"); MAP.put(ErrorsJvm.DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''{0}'' instead", Renderers.TO_STRING); MAP.put(ErrorsJvm.NON_SOURCE_REPEATED_ANNOTATION, "Only annotations with SOURCE retention can be repeated on JVM version before 1.8"); + MAP.put(ErrorsJvm.ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES, "Annotation {0} is not applicable to the multi-file classes", Renderers.TO_STRING); MAP.put(ErrorsJvm.NO_REFLECTION_IN_CLASS_PATH, "Call uses reflection API which is not found in compilation classpath. " + "Make sure you have kotlin-reflect.jar in the classpath"); 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 2d85315c1cb..c9b410a86df 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 @@ -55,10 +55,11 @@ public interface ErrorsJvm { DiagnosticFactory0 EXTERNAL_DECLARATION_IN_TRAIT = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE); DiagnosticFactory0 EXTERNAL_DECLARATION_CANNOT_BE_INLINED = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE); - DiagnosticFactory0 POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION = DiagnosticFactory0.create(ERROR); - DiagnosticFactory0 DEPRECATED_ANNOTATION_METHOD_CALL = DiagnosticFactory0.create(WARNING); + DiagnosticFactory0 POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 DEPRECATED_ANNOTATION_METHOD_CALL = DiagnosticFactory0.create(WARNING); DiagnosticFactory1 DEPRECATED_JAVA_ANNOTATION = DiagnosticFactory1.create(WARNING); - DiagnosticFactory0 NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 NON_SOURCE_REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR); + DiagnosticFactory1 ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES = DiagnosticFactory1.create(ERROR); DiagnosticFactory0 TRAIT_CANT_CALL_DEFAULT_METHOD_VIA_SUPER = 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 86d632ca70d..929f592c0e8 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 @@ -28,6 +28,7 @@ import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget import org.jetbrains.kotlin.diagnostics.DiagnosticSink import org.jetbrains.kotlin.diagnostics.Errors +import org.jetbrains.kotlin.fileClasses.JvmFileClassUtil import org.jetbrains.kotlin.jvm.RuntimeAssertionsTypeChecker import org.jetbrains.kotlin.lexer.JetTokens import org.jetbrains.kotlin.load.java.lazy.types.isMarkedNotNull @@ -49,6 +50,7 @@ import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowInfo import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValue import org.jetbrains.kotlin.resolve.calls.smartcasts.DataFlowValueFactory import org.jetbrains.kotlin.resolve.calls.smartcasts.Nullability +import org.jetbrains.kotlin.resolve.descriptorUtil.classId import org.jetbrains.kotlin.resolve.descriptorUtil.getAnnotationRetention import org.jetbrains.kotlin.resolve.descriptorUtil.isRepeatableAnnotation import org.jetbrains.kotlin.resolve.jvm.annotations.hasJvmOverloadsAnnotation @@ -92,7 +94,10 @@ public object JvmPlatformConfigurator : PlatformConfigurator( additionalSymbolUsageValidators = listOf(), - additionalAnnotationCheckers = listOf(RepeatableAnnotationChecker) + additionalAnnotationCheckers = listOf( + RepeatableAnnotationChecker, + FileClassAnnotationsChecker + ) ) { override fun configure(container: StorageComponentContainer) { @@ -126,6 +131,34 @@ public object RepeatableAnnotationChecker: AdditionalAnnotationChecker { } } +public object FileClassAnnotationsChecker: AdditionalAnnotationChecker { + // JvmName & JvmMultifileClass annotations are applicable to multi-file class parts regardless of their retention. + private val ALWAYS_APPLICABLE = hashSetOf(JvmFileClassUtil.JVM_NAME, JvmFileClassUtil.JVM_MULTIFILE_CLASS) + + override fun checkEntries(entries: List, actualTargets: List, trace: BindingTrace) { + val fileAnnotationsToCheck = arrayListOf>() + for (entry in entries) { + if (entry.useSiteTarget?.getAnnotationUseSiteTarget() != AnnotationUseSiteTarget.FILE) continue + val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue + val classDescriptor = TypeUtils.getClassDescriptor(descriptor.type) ?: continue + // This check matters for the applicable annotations only. + val applicableTargets = AnnotationChecker.applicableTargetSet(classDescriptor) + if (applicableTargets == null || !applicableTargets.contains(KotlinTarget.FILE)) continue + fileAnnotationsToCheck.add(Pair(entry, classDescriptor)) + } + + if (!fileAnnotationsToCheck.any { it.second.classId.asSingleFqName() == JvmFileClassUtil.JVM_MULTIFILE_CLASS }) return + + for ((entry, classDescriptor) in fileAnnotationsToCheck) { + val classFqName = classDescriptor.classId.asSingleFqName() + if (ALWAYS_APPLICABLE.contains(classFqName)) continue + if (classDescriptor.getAnnotationRetention() != KotlinRetention.SOURCE) { + trace.report(ErrorsJvm.ANNOTATION_IS_NOT_APPLICABLE_TO_MULTIFILE_CLASSES.on(entry, classFqName)) + } + } + } +} + public class LocalFunInlineChecker : DeclarationChecker { override fun check( diff --git a/compiler/testData/compileJavaAgainstKotlin/method/platformName/PlatformName.txt b/compiler/testData/compileJavaAgainstKotlin/method/platformName/PlatformName.txt index dbf0ce5099f..9a4eba338a5 100644 --- a/compiler/testData/compileJavaAgainstKotlin/method/platformName/PlatformName.txt +++ b/compiler/testData/compileJavaAgainstKotlin/method/platformName/PlatformName.txt @@ -1,6 +1,6 @@ package test -@kotlin.jvm.JvmName(name = "bar") public fun foo(): kotlin.Unit +public fun foo(): kotlin.Unit public open class PlatformName { public constructor PlatformName() diff --git a/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/FileAnnotations.kt b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/FileAnnotations.kt new file mode 100644 index 00000000000..131bb0c4a63 --- /dev/null +++ b/compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/FileAnnotations.kt @@ -0,0 +1,12 @@ +// FILE: annotations.kt +@Target(AnnotationTarget.CLASS) +public annotation class ClassAnn + +@Target(AnnotationTarget.FILE) +public annotation class FileAnn + +// FILE: 1.kt +@file:ClassAnn + +// FILE: 2.kr +@file:FileAnn \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPart.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPart.kt new file mode 100644 index 00000000000..772f80896d5 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPart.kt @@ -0,0 +1,19 @@ +@file:JvmName("MultifileClass") +@file:JvmMultifileClass +@file:FileAnn +@file:FileBinaryAnn +@file:FileSourceAnn + +@Target(AnnotationTarget.FILE) +@Retention(AnnotationRetention.RUNTIME) +public annotation class FileAnn + +@Target(AnnotationTarget.FILE) +@Retention(AnnotationRetention.BINARY) +public annotation class FileBinaryAnn + +@Target(AnnotationTarget.FILE) +@Retention(AnnotationRetention.SOURCE) +public annotation class FileSourceAnn + + diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPartWithJavaAnnotation.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPartWithJavaAnnotation.kt new file mode 100644 index 00000000000..d2d63d8c024 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPartWithJavaAnnotation.kt @@ -0,0 +1,40 @@ +// FILE: test.kt +@file:JvmName("MultifileClass") +@file:JvmMultifileClass +@file:JavaAnn +@file:JavaClassAnn +@file:JavaSourceAnn + +// FILE: JavaAnn.java +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.RUNTIME) +public @interface JavaAnn { +} + +// FILE: JavaClassAnn.java +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.CLASS) +public @interface JavaClassAnn { +} + +// FILE: JavaSourceAnn.java +import java.lang.annotation.ElementType; +import java.lang.annotation.Retention; +import java.lang.annotation.RetentionPolicy; +import java.lang.annotation.Target; + +@Target(ElementType.TYPE) +@Retention(RetentionPolicy.SOURCE) +public @interface JavaSourceAnn { +} + diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index 2d8b0afc953..96c0be38e59 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -1232,6 +1232,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("FileAnnotations.kt") + public void testFileAnnotations() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/FileAnnotations.kt"); + doTest(fileName); + } + @TestMetadata("GetterAnnotations.kt") public void testGetterAnnotations() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/GetterAnnotations.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java index 838d0ad17c8..998baaafe9b 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestWithStdLibGenerated.java @@ -128,6 +128,18 @@ public class JetDiagnosticsTestWithStdLibGenerated extends AbstractJetDiagnostic String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/jvmName.kt"); doTest(fileName); } + + @TestMetadata("multifileClassPart.kt") + public void testMultifileClassPart() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPart.kt"); + doTest(fileName); + } + + @TestMetadata("multifileClassPartWithJavaAnnotation.kt") + public void testMultifileClassPartWithJavaAnnotation() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationApplicability/multifileClassPartWithJavaAnnotation.kt"); + doTest(fileName); + } } @TestMetadata("compiler/testData/diagnostics/testsWithStdLib/annotations/annotationParameterMustBeConstant")