Fix checking repeatablilty of use-site target annotations. KT-26638 fixed

This commit is contained in:
Dmitriy Novozhilov
2019-02-21 15:09:11 +03:00
parent cfda468f13
commit 92bd907983
10 changed files with 91 additions and 6 deletions
@@ -213,6 +213,7 @@ public interface Errors {
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);
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);
// Annotations
@@ -128,6 +128,7 @@ public class DefaultErrorMessages {
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);
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(INAPPLICABLE_TARGET_ON_PROPERTY, "''@{0}:'' annotations could be applied only to property declarations", TO_STRING);
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.resolve
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings
import org.jetbrains.kotlin.descriptors.ClassDescriptor
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.diagnostics.Errors
import org.jetbrains.kotlin.diagnostics.reportDiagnosticOnce
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.psiUtil.getAnnotationEntries
@@ -36,6 +38,9 @@ class AnnotationChecker(
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
val actualTargets = getActualTargetList(annotated, descriptor, trace.bindingContext)
checkEntries(annotated.annotationEntries, actualTargets, trace, annotated)
if (annotated is KtProperty) {
checkPropertyUseSiteTargetAnnotations(annotated, trace)
}
if (annotated is KtCallableDeclaration) {
annotated.typeReference?.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) {
is KtParameter ->
if (ownerFunction is KtPrimaryConstructor) UseSiteTargetsList.T_CONSTRUCTOR_PARAMETER else emptyList()
@@ -1,21 +1,22 @@
// !DIAGNOSTICS: -UNUSED_PARAMETER
// !LANGUAGE: -ProhibitRepeatedUseSiteTargetAnnotations
// Ann is not repeatable
annotation class Ann(val x: Int)
@get:Ann(10)
<!REPEATED_ANNOTATION_WARNING!>@get:Ann(10)<!>
val a: String
@Ann(20) get() = "foo"
@set:Ann(10)
<!REPEATED_ANNOTATION_WARNING!>@set:Ann(10)<!>
var b: String = ""
@Ann(20) set(value) { field = value }
@setparam:Ann(10)
<!REPEATED_ANNOTATION_WARNING!>@setparam:Ann(10)<!>
var c = " "
set(@Ann(20) x) {}
@get:Ann(10)
<!REPEATED_ANNOTATION!>@get:Ann(20)<!>
<!REPEATED_ANNOTATION_WARNING!>@get:Ann(10)<!>
<!REPEATED_ANNOTATION, REPEATED_ANNOTATION_WARNING!>@get:Ann(20)<!>
val d: String
@Ann(30) <!REPEATED_ANNOTATION!>@Ann(40)<!> get() = "foo"
@@ -1,6 +1,9 @@
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 constructor Ann(/*0*/ x: kotlin.Int)
@@ -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"
@@ -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");
}
@TestMetadata("kt26638_after.kt")
public void testKt26638_after() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/kt26638_after.kt");
}
@TestMetadata("ParamAnnotations.kt")
public void testParamAnnotations() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/ParamAnnotations.kt");
@@ -1444,6 +1444,11 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
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")
public void testParamAnnotations() throws Exception {
runTest("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/ParamAnnotations.kt");
@@ -98,6 +98,7 @@ enum class LanguageFeature(
ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses(KOTLIN_1_4, kind = BUG_FIX),
ProhibitTypeParametersInAnonymousObjects(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),
// Temporarily disabled, see KT-27084/KT-22379