Prohibit JvmOverloads on constructors of annotation classes

In LV >= 1.4 & -progressive

 #KT-25702 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2018-12-24 01:55:57 +03:00
parent 958aeff94b
commit e4a4d1169e
14 changed files with 99 additions and 4 deletions
@@ -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 }) {
@@ -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");
@@ -54,6 +54,9 @@ public interface ErrorsJvm {
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_INTERFACE = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_PRIVATE = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_LOCAL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING = DiagnosticFactory0.create(WARNING);
DiagnosticFactory0<KtAnnotationEntry> OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<KtDeclaration> EXTERNAL_DECLARATION_CANNOT_BE_ABSTRACT = DiagnosticFactory0.create(ERROR, ABSTRACT_MODIFIER);
DiagnosticFactory0<KtDeclaration> EXTERNAL_DECLARATION_CANNOT_HAVE_BODY = DiagnosticFactory0.create(ERROR, DECLARATION_SIGNATURE);
@@ -0,0 +1,4 @@
// !LANGUAGE: -ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
annotation class A1 <!OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING!>@JvmOverloads<!> constructor(val x: Int = 1)
annotation class A2 <!OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR_WARNING!>@JvmOverloads<!> constructor()
@@ -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
}
@@ -0,0 +1,4 @@
// !LANGUAGE: +ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses
annotation class A1 <!OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR!>@JvmOverloads<!> constructor(val x: Int = 1)
annotation class A2 <!OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR!>@JvmOverloads<!> constructor()
@@ -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
}
@@ -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");
@@ -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");
@@ -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
@@ -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)
@@ -0,0 +1,4 @@
// "Remove @JvmOverloads annotation" "true"
// WITH_RUNTIME
annotation class A <caret>@JvmOverloads constructor(val x: Int = 1)
@@ -0,0 +1,4 @@
// "Remove @JvmOverloads annotation" "true"
// WITH_RUNTIME
annotation class A constructor(val x: Int = 1)
@@ -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")