Introduce Language Feature for annotations with wrong targets
#KT-9580 Fixed
This commit is contained in:
@@ -206,6 +206,7 @@ public interface Errors {
|
||||
DiagnosticFactory0<KtParameter> INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<KtAnnotationEntry, String> WRONG_ANNOTATION_TARGET = DiagnosticFactory1.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);
|
||||
DiagnosticFactory0<KtAnnotationEntry> REPEATED_ANNOTATION = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory0<KtAnnotationEntry> NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
|
||||
+2
@@ -149,6 +149,8 @@ public class DefaultErrorMessages {
|
||||
MAP.put(INLINE_SUSPEND_FUNCTION_TYPE_UNSUPPORTED, "Inline lambda parameters of suspend function type are not fully supported. Add 'noinline' modifier.");
|
||||
MAP.put(WRONG_ANNOTATION_TARGET, "This annotation is not applicable to target ''{0}''", TO_STRING);
|
||||
MAP.put(WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET, "This annotation is not applicable to target ''{0}'' and use site target ''@{1}''", TO_STRING, TO_STRING);
|
||||
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(NON_SOURCE_ANNOTATION_ON_INLINED_LAMBDA_EXPRESSION, "The lambda expression here is an inlined argument so this annotation cannot be stored anywhere");
|
||||
|
||||
|
||||
@@ -17,6 +17,8 @@
|
||||
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
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
@@ -38,7 +40,10 @@ import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils
|
||||
import org.jetbrains.kotlin.types.isError
|
||||
|
||||
class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnotationChecker>) {
|
||||
class AnnotationChecker(
|
||||
private val additionalCheckers: Iterable<AdditionalAnnotationChecker>,
|
||||
private val languageVersionSettings: LanguageVersionSettings
|
||||
) {
|
||||
|
||||
fun check(annotated: KtAnnotated, trace: BindingTrace, descriptor: DeclarationDescriptor? = null) {
|
||||
val actualTargets = getActualTargetList(annotated, descriptor, trace)
|
||||
@@ -144,15 +149,30 @@ class AnnotationChecker(private val additionalCheckers: Iterable<AdditionalAnnot
|
||||
}
|
||||
}
|
||||
|
||||
fun applicableWithUseSiteTarget() = useSiteTarget != null && actualTargets.onlyWithUseSiteTarget.any {
|
||||
it in applicableTargets && KotlinTarget.USE_SITE_MAPPING[useSiteTarget] == it
|
||||
fun checkWithUseSiteTargets(additionalTarget: KotlinTarget? = null, useDeprecatedTargets: Boolean = false): Boolean {
|
||||
if (useSiteTarget == null) return false
|
||||
|
||||
val useSiteMapping = KotlinTarget.USE_SITE_MAPPING[useSiteTarget].let {
|
||||
if (useDeprecatedTargets && it == RECEIVER) KotlinTarget.VALUE_PARAMETER else it
|
||||
}
|
||||
|
||||
val allTargets = actualTargets.onlyWithUseSiteTarget + listOfNotNull(additionalTarget)
|
||||
return allTargets.any { it in applicableTargets && it == useSiteMapping }
|
||||
}
|
||||
|
||||
if (check(actualTargets.defaultTargets) || check(actualTargets.canBeSubstituted) || applicableWithUseSiteTarget()) {
|
||||
if (check(actualTargets.defaultTargets) || check(actualTargets.canBeSubstituted) || checkWithUseSiteTargets()) {
|
||||
checkUselessFunctionLiteralAnnotation()
|
||||
return
|
||||
}
|
||||
|
||||
if (!languageVersionSettings.supportsFeature(LanguageFeature.RestrictionOfWrongAnnotationsWithUseSiteTargetsOnTypes)) {
|
||||
val isAnnotationOnType = TargetLists.T_TYPE_REFERENCE == actualTargets
|
||||
if (isAnnotationOnType && checkWithUseSiteTargets(KotlinTarget.VALUE_PARAMETER, true)) {
|
||||
trace.report(Errors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE.on(entry, useSiteTarget!!.renderName))
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
if (useSiteTarget != null) {
|
||||
trace.report(Errors.WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET.on(
|
||||
entry, actualTargets.defaultTargets.firstOrNull()?.description ?: "unidentified target", useSiteTarget.renderName))
|
||||
|
||||
Vendored
+7
-10
@@ -1,15 +1,12 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun test1(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) {}
|
||||
fun test2(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@param:Suppress<!> Int) {}
|
||||
fun test3(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@receiver:Suppress<!> Int) {}
|
||||
fun test4(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@field:Suppress<!> Int) {}
|
||||
fun test5(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@set:Suppress<!> Int) {}
|
||||
fun test1(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE!>@setparam:Suppress<!> Int) {}
|
||||
fun test2(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE!>@param:Suppress<!> Int) {}
|
||||
fun test3(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE!>@receiver:Suppress<!> Int) {}
|
||||
|
||||
fun test6(): <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int = TODO()
|
||||
fun test7(i: (<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) -> Unit) {}
|
||||
fun test4(): <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE!>@setparam:Suppress<!> Int = TODO()
|
||||
fun test5(i: (<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE!>@setparam:Suppress<!> Int) -> Unit) {}
|
||||
|
||||
fun <!INAPPLICABLE_TARGET_ON_PROPERTY, WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int.test8() {}
|
||||
fun ((<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) -> Unit).test9() {}
|
||||
fun ((<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE!>@setparam:Suppress<!> Int) -> Unit).test6() {}
|
||||
|
||||
fun test10(): ((<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) -> Unit) = TODO()
|
||||
fun test7(): ((<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET_ON_TYPE!>@setparam:Suppress<!> Int) -> Unit) = TODO()
|
||||
Vendored
+4
-7
@@ -1,12 +1,9 @@
|
||||
package
|
||||
|
||||
public fun test1(/*0*/ i: @setparam:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test10(): (@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit
|
||||
public fun test2(/*0*/ i: @param:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test3(/*0*/ i: @receiver:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test4(/*0*/ i: @field:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test5(/*0*/ i: @set:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test6(): @setparam:kotlin.Suppress(names = {}) kotlin.Int
|
||||
public fun test7(/*0*/ i: (@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit): kotlin.Unit
|
||||
public fun @setparam:kotlin.Suppress(names = {}) kotlin.Int.test8(): kotlin.Unit
|
||||
public fun ((@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit).test9(): kotlin.Unit
|
||||
public fun test4(): @setparam:kotlin.Suppress(names = {}) kotlin.Int
|
||||
public fun test5(/*0*/ i: (@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit): kotlin.Unit
|
||||
public fun test7(): (@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit
|
||||
public fun ((@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit).test6(): kotlin.Unit
|
||||
|
||||
+13
@@ -0,0 +1,13 @@
|
||||
// !LANGUAGE: +RestrictionOfWrongAnnotationsWithUseSiteTargetsOnTypes
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
fun test1(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) {}
|
||||
fun test2(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@param:Suppress<!> Int) {}
|
||||
fun test3(i: <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@receiver:Suppress<!> Int) {}
|
||||
|
||||
fun test4(): <!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int = TODO()
|
||||
fun test5(i: (<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) -> Unit) {}
|
||||
|
||||
fun ((<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) -> Unit).test6() {}
|
||||
|
||||
fun test7(): ((<!WRONG_ANNOTATION_TARGET_WITH_USE_SITE_TARGET!>@setparam:Suppress<!> Int) -> Unit) = TODO()
|
||||
+9
@@ -0,0 +1,9 @@
|
||||
package
|
||||
|
||||
public fun test1(/*0*/ i: @setparam:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test2(/*0*/ i: @param:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test3(/*0*/ i: @receiver:kotlin.Suppress(names = {}) kotlin.Int): kotlin.Unit
|
||||
public fun test4(): @setparam:kotlin.Suppress(names = {}) kotlin.Int
|
||||
public fun test5(/*0*/ i: (@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit): kotlin.Unit
|
||||
public fun test7(): (@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit
|
||||
public fun ((@setparam:kotlin.Suppress(names = {}) kotlin.Int) -> kotlin.Unit).test6(): kotlin.Unit
|
||||
@@ -1688,6 +1688,12 @@ public class DiagnosticsTestGenerated extends AbstractDiagnosticsTest {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/wrongParamAnnotationsOnTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("wrongParamAnnotationsOnTypesError.kt")
|
||||
public void testWrongParamAnnotationsOnTypesError() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/wrongParamAnnotationsOnTypesError.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+6
@@ -1688,6 +1688,12 @@ public class DiagnosticsUsingJavacTestGenerated extends AbstractDiagnosticsUsing
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/wrongParamAnnotationsOnTypes.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("wrongParamAnnotationsOnTypesError.kt")
|
||||
public void testWrongParamAnnotationsOnTypesError() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/annotations/withUseSiteTarget/wrongParamAnnotationsOnTypesError.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -64,6 +64,7 @@ enum class LanguageFeature(
|
||||
|
||||
RestrictionOfValReassignmentViaBackingField(KOTLIN_1_3),
|
||||
NestedClassesInEnumEntryShouldBeInner(KOTLIN_1_3),
|
||||
RestrictionOfWrongAnnotationsWithUseSiteTargetsOnTypes(KOTLIN_1_3),
|
||||
|
||||
// Experimental features
|
||||
|
||||
|
||||
Reference in New Issue
Block a user