Introduce Language Feature for annotations with wrong targets

#KT-9580 Fixed
This commit is contained in:
Mikhail Zarechenskiy
2017-09-11 01:15:38 +03:00
parent a4766cc293
commit 2048a74302
10 changed files with 73 additions and 21 deletions
@@ -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);
@@ -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))
@@ -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()
@@ -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
@@ -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()
@@ -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);
}
}
}
@@ -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