Fix checking repeatablilty of use-site target annotations. KT-26638 fixed
This commit is contained in:
@@ -213,6 +213,7 @@ public interface Errors {
|
|||||||
DiagnosticFactory2<KtAnnotationEntry, String, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET = DiagnosticFactory2.create(ERROR);
|
DiagnosticFactory2<KtAnnotationEntry, String, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET = DiagnosticFactory2.create(ERROR);
|
||||||
DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE = DiagnosticFactory1.create(WARNING);
|
DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE = DiagnosticFactory1.create(WARNING);
|
||||||
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
|
||||||
|
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION_WARNING = DiagnosticFactory0.create(WARNING);
|
||||||
DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(ERROR);
|
DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(ERROR);
|
||||||
|
|
||||||
// Annotations
|
// Annotations
|
||||||
|
|||||||
+1
@@ -128,6 +128,7 @@ public class DefaultErrorMessages {
|
|||||||
MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE,
|
MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE,
|
||||||
"Use of this annotation with target ''type'' and use site target ''@{0}'' is deprecated", TO_STRING);
|
"Use of this annotation with target ''type'' and use site target ''@{0}'' is deprecated", TO_STRING);
|
||||||
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
|
MAP.put(REPEATED_ANNOTATION, "This annotation is not repeatable");
|
||||||
|
MAP.put(REPEATED_ANNOTATION_WARNING, "This annotation is not repeatable");
|
||||||
MAP.put(NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION, "The lambda expression here is an inlined argument so this annotation cannot be stored anywhere");
|
MAP.put(NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION, "The lambda expression here is an inlined argument so this annotation cannot be stored anywhere");
|
||||||
|
|
||||||
MAP.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}:'' annotations could be applied only to property declarations", TO_STRING);
|
MAP.put(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}:'' annotations could be applied only to property declarations", TO_STRING);
|
||||||
|
|||||||
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.resolve
|
package org.jetbrains.kotlin.resolve
|
||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
|
import org.jetbrains.kotlin.config.LanguageFeature
|
||||||
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
@@ -16,6 +17,7 @@ import org.jetbrains.kotlin.descriptors.annotations.KotlinRetention
|
|||||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget
|
||||||
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
import org.jetbrains.kotlin.descriptors.annotations.KotlinTarget.*
|
||||||
import org.jetbrains.kotlin.diagnostics.Errors
|
import org.jetbrains.kotlin.diagnostics.Errors
|
||||||
|
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
|
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
|
||||||
@@ -36,6 +38,9 @@ class AnnotationChecker(
|
|||||||
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
|
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
|
||||||
val actualTargets = getActualTargetList(annotated, descriptor, trace.bindingContext)
|
val actualTargets = getActualTargetList(annotated, descriptor, trace.bindingContext)
|
||||||
checkEntries(annotated.annotationEntries, actualTargets, trace, annotated)
|
checkEntries(annotated.annotationEntries, actualTargets, trace, annotated)
|
||||||
|
if (annotated is KtProperty) {
|
||||||
|
checkPropertyUseSiteTargetAnnotations(annotated, trace)
|
||||||
|
}
|
||||||
if (annotated is KtCallableDeclaration) {
|
if (annotated is KtCallableDeclaration) {
|
||||||
annotated.typeReference?.let { check(it, trace) }
|
annotated.typeReference?.let { check(it, trace) }
|
||||||
annotated.receiverTypeReference?.let { check(it, trace) }
|
annotated.receiverTypeReference?.let { check(it, trace) }
|
||||||
@@ -72,6 +77,33 @@ class AnnotationChecker(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun checkPropertyUseSiteTargetAnnotations(property: KtProperty, trace: BindingTrace) {
|
||||||
|
fun List<KtAnnotationEntry>?.getDescriptors() = this?.mapNotNull { trace.get(BindingContext.ANNOTATION, it)?.annotationClass } ?: listOf()
|
||||||
|
|
||||||
|
val reportError = languageVersionSettings.supportsFeature(LanguageFeature.ProhibitRepeatedUseSiteTargetAnnotations)
|
||||||
|
|
||||||
|
val propertyAnnotations = mapOf(
|
||||||
|
AnnotationUseSiteTarget.PROPERTY_GETTER to property.getter?.annotationEntries.getDescriptors(),
|
||||||
|
AnnotationUseSiteTarget.PROPERTY_SETTER to property.setter?.annotationEntries.getDescriptors(),
|
||||||
|
AnnotationUseSiteTarget.SETTER_PARAMETER to property.setter?.parameter?.annotationEntries.getDescriptors()
|
||||||
|
)
|
||||||
|
|
||||||
|
for (entry in property.annotationEntries) {
|
||||||
|
val descriptor = trace.get(BindingContext.ANNOTATION, entry) ?: continue
|
||||||
|
val classDescriptor = descriptor.annotationClass ?: continue
|
||||||
|
|
||||||
|
val useSiteTarget = entry.useSiteTarget?.getAnnotationUseSiteTarget() ?: property.getDefaultUseSiteTarget(descriptor)
|
||||||
|
val existingAnnotations = propertyAnnotations.get(useSiteTarget) ?: continue
|
||||||
|
if (classDescriptor in existingAnnotations && !classDescriptor.isRepeatableAnnotation()) {
|
||||||
|
if (reportError) {
|
||||||
|
trace.reportDiagnosticOnce(Errors.REPEATED_ANNOTATION.on(entry))
|
||||||
|
} else {
|
||||||
|
trace.report(Errors.REPEATED_ANNOTATION_WARNING.on(entry))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
private fun KtAnnotated?.getImplicitUseSiteTargetList(): List<AnnotationUseSiteTarget> = when (this) {
|
private fun KtAnnotated?.getImplicitUseSiteTargetList(): List<AnnotationUseSiteTarget> = when (this) {
|
||||||
is KtParameter ->
|
is KtParameter ->
|
||||||
if (ownerFunction is KtPrimaryConstructor) UseSiteTargetsList.T_CONSTRUCTOR_PARAMETER else emptyList()
|
if (ownerFunction is KtPrimaryConstructor) UseSiteTargetsList.T_CONSTRUCTOR_PARAMETER else emptyList()
|
||||||
|
|||||||
+6
-5
@@ -1,21 +1,22 @@
|
|||||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// !LANGUAGE: -ProhibitRepeatedUseSiteTargetAnnotations
|
||||||
|
|
||||||
// Ann is not repeatable
|
// Ann is not repeatable
|
||||||
annotation class Ann(val x: Int)
|
annotation class Ann(val x: Int)
|
||||||
|
|
||||||
@get:Ann(10)
|
<!REPEATED_ANNOTATION_WARNING!>@get:Ann(10)<!>
|
||||||
val a: String
|
val a: String
|
||||||
@Ann(20) get() = "foo"
|
@Ann(20) get() = "foo"
|
||||||
|
|
||||||
@set:Ann(10)
|
<!REPEATED_ANNOTATION_WARNING!>@set:Ann(10)<!>
|
||||||
var b: String = ""
|
var b: String = ""
|
||||||
@Ann(20) set(value) { field = value }
|
@Ann(20) set(value) { field = value }
|
||||||
|
|
||||||
@setparam:Ann(10)
|
<!REPEATED_ANNOTATION_WARNING!>@setparam:Ann(10)<!>
|
||||||
var c = " "
|
var c = " "
|
||||||
set(@Ann(20) x) {}
|
set(@Ann(20) x) {}
|
||||||
|
|
||||||
@get:Ann(10)
|
<!REPEATED_ANNOTATION_WARNING!>@get:Ann(10)<!>
|
||||||
<!REPEATED_ANNOTATION!>@get:Ann(20)<!>
|
<!REPEATED_ANNOTATION, REPEATED_ANNOTATION_WARNING!>@get:Ann(20)<!>
|
||||||
val d: String
|
val d: String
|
||||||
@Ann(30) <!REPEATED_ANNOTATION!>@Ann(40)<!> get() = "foo"
|
@Ann(30) <!REPEATED_ANNOTATION!>@Ann(40)<!> get() = "foo"
|
||||||
+4
-1
@@ -1,6 +1,9 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
@setparam:Ann(x = 20) @setparam:Ann(x = 10) public var a: kotlin.String
|
@get:Ann(x = 10) @get:Ann(x = 20) public val a: kotlin.String
|
||||||
|
@set:Ann(x = 10) @set:Ann(x = 20) public var b: kotlin.String
|
||||||
|
@setparam:Ann(x = 20) @setparam:Ann(x = 10) public var c: kotlin.String
|
||||||
|
@get:Ann(x = 10) @get:Ann(x = 20) @get:Ann(x = 30) @get:Ann(x = 40) public val d: kotlin.String
|
||||||
|
|
||||||
public final annotation class Ann : kotlin.Annotation {
|
public final annotation class Ann : kotlin.Annotation {
|
||||||
public constructor Ann(/*0*/ x: kotlin.Int)
|
public constructor Ann(/*0*/ x: kotlin.Int)
|
||||||
|
|||||||
+22
@@ -0,0 +1,22 @@
|
|||||||
|
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||||
|
// !LANGUAGE: +ProhibitRepeatedUseSiteTargetAnnotations
|
||||||
|
|
||||||
|
// Ann is not repeatable
|
||||||
|
annotation class Ann(val x: Int)
|
||||||
|
|
||||||
|
<!REPEATED_ANNOTATION!>@get:Ann(10)<!>
|
||||||
|
val a: String
|
||||||
|
@Ann(20) get() = "foo"
|
||||||
|
|
||||||
|
<!REPEATED_ANNOTATION!>@set:Ann(10)<!>
|
||||||
|
var b: String = ""
|
||||||
|
@Ann(20) set(value) { field = value }
|
||||||
|
|
||||||
|
<!REPEATED_ANNOTATION!>@setparam:Ann(10)<!>
|
||||||
|
var c = " "
|
||||||
|
set(@Ann(20) x) {}
|
||||||
|
|
||||||
|
<!REPEATED_ANNOTATION!>@get:Ann(10)<!>
|
||||||
|
<!REPEATED_ANNOTATION!>@get:Ann(20)<!>
|
||||||
|
val d: String
|
||||||
|
@Ann(30) <!REPEATED_ANNOTATION!>@Ann(40)<!> get() = "foo"
|
||||||
+14
@@ -0,0 +1,14 @@
|
|||||||
|
package
|
||||||
|
|
||||||
|
@get:Ann(x = 10) @get:Ann(x = 20) public val a: kotlin.String
|
||||||
|
@set:Ann(x = 10) @set:Ann(x = 20) public var b: kotlin.String
|
||||||
|
@setparam:Ann(x = 20) @setparam:Ann(x = 10) public var c: kotlin.String
|
||||||
|
@get:Ann(x = 10) @get:Ann(x = 20) @get:Ann(x = 30) @get:Ann(x = 40) public val d: kotlin.String
|
||||||
|
|
||||||
|
public final annotation class Ann : kotlin.Annotation {
|
||||||
|
public constructor Ann(/*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
|
||||||
|
}
|
||||||
@@ -1449,6 +1449,11 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
|||||||
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/kt26638.kt");
|
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/kt26638.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt26638_after.kt")
|
||||||
|
public void testKt26638_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/kt26638_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ParamAnnotations.kt")
|
@TestMetadata("ParamAnnotations.kt")
|
||||||
public void testParamAnnotations() throws Exception {
|
public void testParamAnnotations() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/ParamAnnotations.kt");
|
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/ParamAnnotations.kt");
|
||||||
|
|||||||
Generated
+5
@@ -1444,6 +1444,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
|||||||
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/kt26638.kt");
|
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/kt26638.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt26638_after.kt")
|
||||||
|
public void testKt26638_after() throws Exception {
|
||||||
|
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/kt26638_after.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("ParamAnnotations.kt")
|
@TestMetadata("ParamAnnotations.kt")
|
||||||
public void testParamAnnotations() throws Exception {
|
public void testParamAnnotations() throws Exception {
|
||||||
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/ParamAnnotations.kt");
|
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/ParamAnnotations.kt");
|
||||||
|
|||||||
@@ -98,6 +98,7 @@ enum class LanguageFeature(
|
|||||||
ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses(KOTLIN_1_4, kind = BUG_FIX),
|
ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
ProhibitTypeParametersInAnonymousObjects(KOTLIN_1_4, kind = BUG_FIX),
|
ProhibitTypeParametersInAnonymousObjects(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
ProperInlineFromHigherPlatformDiagnostic(KOTLIN_1_4, kind = BUG_FIX),
|
ProperInlineFromHigherPlatformDiagnostic(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
|
ProhibitRepeatedUseSiteTargetAnnotations(KOTLIN_1_4, kind = BUG_FIX),
|
||||||
|
|
||||||
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
|
ProperVisibilityForCompanionObjectInstanceField(sinceVersion = null, kind = BUG_FIX),
|
||||||
// Temporarily disabled, see KT-27084/KT-22379
|
// Temporarily disabled, see KT-27084/KT-22379
|
||||||
|
|||||||
Reference in New Issue
Block a user