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 30ec93e8a98..97a94dd37e7 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 @@ -33,6 +33,7 @@ import org.jetbrains.kotlin.resolve.annotations.hasJvmStaticAnnotation import org.jetbrains.kotlin.resolve.calls.components.isActualParameterWithCorrespondingExpectedDefault import org.jetbrains.kotlin.resolve.checkers.DeclarationChecker import org.jetbrains.kotlin.resolve.checkers.DeclarationCheckerContext +import org.jetbrains.kotlin.resolve.descriptorUtil.isAnnotationConstructor import org.jetbrains.kotlin.resolve.inline.InlineUtil import org.jetbrains.kotlin.resolve.isInlineClass import org.jetbrains.kotlin.resolve.jvm.annotations.VOLATILE_ANNOTATION_FQ_NAME @@ -194,21 +195,34 @@ class OverloadsAnnotationChecker: DeclarationChecker { descriptor.findJvmOverloadsAnnotation()?.let { annotation -> val annotationEntry = DescriptorToSourceUtils.getSourceFromAnnotation(annotation) if (annotationEntry != null) { - checkDeclaration(annotationEntry, descriptor, context.trace) + checkDeclaration(annotationEntry, descriptor, context) } } } - private fun checkDeclaration(annotationEntry: KtAnnotationEntry, descriptor: DeclarationDescriptor, diagnosticHolder: DiagnosticSink) { + private fun checkDeclaration( + annotationEntry: KtAnnotationEntry, + descriptor: DeclarationDescriptor, + context: DeclarationCheckerContext + ) { + val diagnosticHolder = context.trace + if (descriptor !is CallableDescriptor) { return - } - if ((descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE) { + } else if ((descriptor.containingDeclaration as? ClassDescriptor)?.kind == ClassKind.INTERFACE) { diagnosticHolder.report(ErrorsJvm.OVERLOADS_INTERFACE.on(annotationEntry)) } else if (descriptor is FunctionDescriptor && descriptor.modality == Modality.ABSTRACT) { diagnosticHolder.report(ErrorsJvm.OVERLOADS_ABSTRACT.on(annotationEntry)) } else if (DescriptorUtils.isLocal(descriptor)) { diagnosticHolder.report(ErrorsJvm.OVERLOADS_LOCAL.on(annotationEntry)) + } else if (descriptor.isAnnotationConstructor()) { + val diagnostic = + if (context.languageVersionSettings.supportsFeature(LanguageFeature.ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)) + ErrorsJvm.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR + else + ErrorsJvm.OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING + + diagnosticHolder.report(diagnostic.on(annotationEntry)) } else if (!descriptor.visibility.isPublicAPI && descriptor.visibility != Visibilities.INTERNAL) { diagnosticHolder.report(ErrorsJvm.OVERLOADS_PRIVATE.on(annotationEntry)) } else if (descriptor.valueParameters.none { it.declaresDefaultValue() || it.isActualParameterWithCorrespondingExpectedDefault }) { 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 4d05b24ff41..d6dbaebd639 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 @@ -50,6 +50,8 @@ public class DefaultErrorMessagesJvm implements DefaultErrorMessages.Extension { MAP.put(OVERLOADS_INTERFACE, "'@JvmOverloads' annotation cannot be used on interface methods"); MAP.put(OVERLOADS_PRIVATE, "'@JvmOverloads' annotation has no effect on private declarations"); MAP.put(OVERLOADS_LOCAL, "'@JvmOverloads' annotation cannot be used on local declarations"); + MAP.put(OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING, "'@JvmOverloads' annotation on constructors of annotation classes is deprecated"); + MAP.put(OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR, "'@JvmOverloads' annotation cannot be used on constructors of annotation classes"); MAP.put(INAPPLICABLE_JVM_NAME, "'@JvmName' annotation is not applicable to this declaration"); MAP.put(ILLEGAL_JVM_NAME, "Illegal JVM name"); MAP.put(VOLATILE_ON_VALUE, "'@Volatile' annotation cannot be used on immutable properties"); 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 8b50eb45909..70606807577 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 @@ -54,6 +54,9 @@ public interface ErrorsJvm { DiagnosticFactory0 OVERLOADS_INTERFACE = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 OVERLOADS_PRIVATE = DiagnosticFactory0.create(WARNING); DiagnosticFactory0 OVERLOADS_LOCAL = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING = DiagnosticFactory0.create(WARNING); + DiagnosticFactory0 OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT = DiagnosticFactory0.create(ERROR, ABSTRACT_MODIFIER); DiagnosticFactory0 EXTERNAL_DECLARATION_CANNOT_HAVE_BODY = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE); diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.kt new file mode 100644 index 00000000000..eca392c64b8 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.kt @@ -0,0 +1,4 @@ +// !LANGUAGE: -ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses + +annotation class A1 @JvmOverloads constructor(val x: Int = 1) +annotation class A2 @JvmOverloads constructor() diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.txt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.txt new file mode 100644 index 00000000000..e9452696aee --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.txt @@ -0,0 +1,16 @@ +package + +public final annotation class A1 : kotlin.Annotation { + @kotlin.jvm.JvmOverloads public constructor A1(/*0*/ x: kotlin.Int = ...) + public final val x: kotlin.Int + 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 +} + +public final annotation class A2 : kotlin.Annotation { + @kotlin.jvm.JvmOverloads public constructor A2() + 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/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.kt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.kt new file mode 100644 index 00000000000..9fb1cd93da6 --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.kt @@ -0,0 +1,4 @@ +// !LANGUAGE: +ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses + +annotation class A1 @JvmOverloads constructor(val x: Int = 1) +annotation class A2 @JvmOverloads constructor() \ No newline at end of file diff --git a/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.txt b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.txt new file mode 100644 index 00000000000..e9452696aee --- /dev/null +++ b/compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.txt @@ -0,0 +1,16 @@ +package + +public final annotation class A1 : kotlin.Annotation { + @kotlin.jvm.JvmOverloads public constructor A1(/*0*/ x: kotlin.Int = ...) + public final val x: kotlin.Int + 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 +} + +public final annotation class A2 : kotlin.Annotation { + @kotlin.jvm.JvmOverloads public constructor A2() + 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 bb0d0611dc8..de1b2bbcf71 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/DiagnosticsTestWithStdLibGenerated.java @@ -604,6 +604,16 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAbstractMethods.kt"); } + @TestMetadata("jvmOverloadsOnAnnotationClassConstructor_1_3.kt") + public void testJvmOverloadsOnAnnotationClassConstructor_1_3() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.kt"); + } + + @TestMetadata("jvmOverloadsOnAnnotationClassConstructor_1_4.kt") + public void testJvmOverloadsOnAnnotationClassConstructor_1_4() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.kt"); + } + @TestMetadata("jvmOverloadsOnPrivate.kt") public void testJvmOverloadsOnPrivate() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnPrivate.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java index 2f4f7d582c8..1534c1a2a1f 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/javac/DiagnosticsTestWithStdLibUsingJavacGenerated.java @@ -604,6 +604,16 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAbstractMethods.kt"); } + @TestMetadata("jvmOverloadsOnAnnotationClassConstructor_1_3.kt") + public void testJvmOverloadsOnAnnotationClassConstructor_1_3() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_3.kt"); + } + + @TestMetadata("jvmOverloadsOnAnnotationClassConstructor_1_4.kt") + public void testJvmOverloadsOnAnnotationClassConstructor_1_4() throws Exception { + runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnAnnotationClassConstructor_1_4.kt"); + } + @TestMetadata("jvmOverloadsOnPrivate.kt") public void testJvmOverloadsOnPrivate() throws Exception { runTest("compiler/testData/diagnostics/testsWithStdLib/annotations/jvmOverloads/jvmOverloadsOnPrivate.kt"); diff --git a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt index 5eade519c99..0f0da571a48 100644 --- a/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt +++ b/compiler/util/src/org/jetbrains/kotlin/config/LanguageVersionSettings.kt @@ -95,6 +95,7 @@ enum class LanguageFeature( PolymorphicSignature(KOTLIN_1_4), ProhibitConcurrentHashMapContains(KOTLIN_1_4, kind = BUG_FIX), ProhibitTypeParametersForLocalVariables(KOTLIN_1_4, kind = BUG_FIX), + ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses(KOTLIN_1_4, kind = BUG_FIX), ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX), // Temporarily disabled, see KT-27084/KT-22379 diff --git a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt index 46eb09c964b..7a060a38642 100644 --- a/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt +++ b/idea/src/org/jetbrains/kotlin/idea/quickfix/QuickFixRegistrar.kt @@ -513,6 +513,8 @@ class QuickFixRegistrar : QuickFixContributor { OVERLOADS_PRIVATE.registerFactory(RemoveAnnotationFix.JvmOverloads) OVERLOADS_LOCAL.registerFactory(RemoveAnnotationFix.JvmOverloads) OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS.registerFactory(RemoveAnnotationFix.JvmOverloads) + OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR.registerFactory(RemoveAnnotationFix.JvmOverloads) + OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING.registerFactory(RemoveAnnotationFix.JvmOverloads) ACTUAL_WITHOUT_EXPECT.registerFactory(RemoveModifierFix.createRemoveModifierFromListOwnerFactory(ACTUAL_KEYWORD)) ACTUAL_WITHOUT_EXPECT.registerFactory(CreateExpectedFix) diff --git a/idea/testData/quickfix/removeAnnotation/jvmOverloadsOnAnnotationClassConstructor.kt b/idea/testData/quickfix/removeAnnotation/jvmOverloadsOnAnnotationClassConstructor.kt new file mode 100644 index 00000000000..0e27b2c0a77 --- /dev/null +++ b/idea/testData/quickfix/removeAnnotation/jvmOverloadsOnAnnotationClassConstructor.kt @@ -0,0 +1,4 @@ +// "Remove @JvmOverloads annotation" "true" +// WITH_RUNTIME + +annotation class A @JvmOverloads constructor(val x: Int = 1) \ No newline at end of file diff --git a/idea/testData/quickfix/removeAnnotation/jvmOverloadsOnAnnotationClassConstructor.kt.after b/idea/testData/quickfix/removeAnnotation/jvmOverloadsOnAnnotationClassConstructor.kt.after new file mode 100644 index 00000000000..2633cdcf8b5 --- /dev/null +++ b/idea/testData/quickfix/removeAnnotation/jvmOverloadsOnAnnotationClassConstructor.kt.after @@ -0,0 +1,4 @@ +// "Remove @JvmOverloads annotation" "true" +// WITH_RUNTIME + +annotation class A constructor(val x: Int = 1) \ No newline at end of file diff --git a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java index b497b0b033e..3a0260693aa 100644 --- a/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java +++ b/idea/tests/org/jetbrains/kotlin/idea/quickfix/QuickFixTestGenerated.java @@ -9381,6 +9381,11 @@ public class QuickFixTestGenerated extends AbstractQuickFixTest { public void testJvmOverloads() throws Exception { runTest("idea/testData/quickfix/removeAnnotation/jvmOverloads.kt"); } + + @TestMetadata("jvmOverloadsOnAnnotationClassConstructor.kt") + public void testJvmOverloadsOnAnnotationClassConstructor() throws Exception { + runTest("idea/testData/quickfix/removeAnnotation/jvmOverloadsOnAnnotationClassConstructor.kt"); + } } @TestMetadata("idea/testData/quickfix/removeAtFromAnnotationArgument")