[FIR] Add POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION

This commit is contained in:
Ivan Kochurkin
2021-09-06 23:26:14 +03:00
committed by teamcityserver
parent dd46c36b24
commit e97933a9e5
17 changed files with 56 additions and 47 deletions
@@ -9,7 +9,7 @@ public @interface Ann {
// FILE: main.kt
@Ann(x = 10, s = "")
<!REPEATED_ANNOTATION!>@Ann(<!ARGUMENT_TYPE_MISMATCH!>10<!>, <!ARGUMENT_TYPE_MISMATCH!>""<!>)<!>
<!REPEATED_ANNOTATION!>@Ann(<!ARGUMENT_TYPE_MISMATCH, POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>10<!>, <!ARGUMENT_TYPE_MISMATCH, POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>""<!>)<!>
<!REPEATED_ANNOTATION!>@Ann(x = 10, s = "", y = 10)<!>
class A
@@ -11,7 +11,7 @@ public @interface Nls {
import some.Nls.Capitalization.*
import some.Nls
@Nls(Title)
@Nls(<!POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>Title<!>)
fun f() {
}
}
@@ -69,6 +69,8 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error<KtAnnotationEntry>()
val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error<KtExpression>()
}
val SUPER by object : DiagnosticGroup("Super") {
@@ -60,6 +60,7 @@ object FirJvmErrors {
val JVM_PACKAGE_NAME_CANNOT_BE_EMPTY by error0<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_MUST_BE_VALID_NAME by error0<KtAnnotationEntry>()
val JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES by error0<KtAnnotationEntry>()
val POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION by error0<KtExpression>()
// Super
val SUPER_CALL_WITH_DEFAULT_PARAMETERS by error1<PsiElement, String>()
@@ -27,7 +27,7 @@ object JvmExpressionCheckers : ExpressionCheckers() {
override val annotationCheckers: Set<FirAnnotationChecker>
get() = setOf(
FirDeprecatedJavaAnnotationsChecker,
FirJavaAnnotationsChecker,
FirJvmPackageNameAnnotationsChecker,
)
}
@@ -9,17 +9,23 @@ import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.fir.FirRealSourceElementKind
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationChecker
import org.jetbrains.kotlin.fir.analysis.checkers.toRegularClassSymbol
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.declarations.FirDeclarationOrigin
import org.jetbrains.kotlin.fir.expressions.FirAnnotation
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirWrappedArgumentExpression
import org.jetbrains.kotlin.fir.expressions.impl.FirResolvedArgumentList
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.coneTypeSafe
import org.jetbrains.kotlin.load.java.JvmAnnotationNames
import org.jetbrains.kotlin.load.java.JvmAnnotationNames.DEFAULT_ANNOTATION_MEMBER_NAME
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName
object FirDeprecatedJavaAnnotationsChecker : FirAnnotationChecker() {
object FirJavaAnnotationsChecker : FirAnnotationChecker() {
private val javaToKotlinNameMap: Map<ClassId, FqName> =
mapOf(
@@ -31,10 +37,23 @@ object FirDeprecatedJavaAnnotationsChecker : FirAnnotationChecker() {
override fun check(expression: FirAnnotation, context: CheckerContext, reporter: DiagnosticReporter) {
if (context.containingDeclarations.lastOrNull()?.source?.kind != FirRealSourceElementKind) return
val callableSymbol = expression.annotationTypeRef.toRegularClassSymbol(context.session)
if (callableSymbol?.origin != FirDeclarationOrigin.Java) return
val lookupTag = expression.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return
javaToKotlinNameMap[lookupTag.classId]?.let { betterName ->
reporter.reportOn(expression.source, FirJvmErrors.DEPRECATED_JAVA_ANNOTATION, betterName, context)
}
if (expression is FirAnnotationCall) {
val argumentList = expression.argumentList
if (argumentList is FirResolvedArgumentList) {
for ((key, value) in argumentList.mapping) {
if (value.name != DEFAULT_ANNOTATION_MEMBER_NAME && key !is FirWrappedArgumentExpression) {
reporter.reportOn(key.source, FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION, context)
}
}
}
}
}
}
@@ -59,6 +59,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_PRIVATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERLOADS_WITHOUT_DEFAULT_ARGUMENTS
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.OVERRIDE_CANNOT_BE_STATIC
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_ANNOTATION_HAS_NESTED_CLASS_NAMED_CONTAINER
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_NON_DEFAULT_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors.REPEATABLE_CONTAINER_HAS_SHORTER_RETENTION
@@ -98,6 +99,7 @@ object FirJvmDefaultErrorMessages {
"'@JvmOverloads' annotation cannot be used on constructors of annotation classes"
)
map.put(DEPRECATED_JAVA_ANNOTATION, "This annotation is deprecated in Kotlin. Use ''@{0}'' instead", TO_STRING)
map.put(POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION, "Only named arguments are available for Java annotations")
map.put(JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, "''@JvmPackageName'' annotation value cannot be empty")
map.put(
JVM_PACKAGE_NAME_MUST_BE_VALID_NAME,
@@ -25,5 +25,5 @@ public @interface A {
@A fun test8() {}
@<!INAPPLICABLE_CANDIDATE!>A<!>(x = Any::class, *arrayOf("5", "6"), "7", y = 3) fun test9() {}
@<!INAPPLICABLE_CANDIDATE!>A<!>(x = Any::class, value = ["5", "6"], "7", y = 3) fun test10() {}
@<!INAPPLICABLE_CANDIDATE!>A<!>(x = Any::class, value = ["5", "6"], <!POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>"7"<!>, y = 3) fun test10() {}
@A(x = Any::class, value = ["5", "6", "7"], y = 3) fun test11() {}
@@ -6,6 +6,6 @@ public @interface A {
}
// FILE: b.kt
@A(false,
1.0,
false, <!TOO_MANY_ARGUMENTS!>1<!>, <!TOO_MANY_ARGUMENTS!>2<!>) fun foo1() {}
@A(<!POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>false<!>,
<!POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>1.0<!>,
<!POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>false<!>, <!TOO_MANY_ARGUMENTS!>1<!>, <!TOO_MANY_ARGUMENTS!>2<!>) fun foo1() {}
@@ -6,8 +6,8 @@ public @interface A {
}
// FILE: b.kt
@A(<!ARGUMENT_TYPE_MISMATCH!>false<!>,
1.0,
false) fun foo1() {}
@A(<!ARGUMENT_TYPE_MISMATCH, POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>false<!>,
<!POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>1.0<!>,
<!POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>false<!>) fun foo1() {}
@A(<!ARGUMENT_TYPE_MISMATCH!>2.0<!>, x = true, b = 2.0) fun foo2() {}
@A(<!ARGUMENT_TYPE_MISMATCH, POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION!>2.0<!>, x = true, b = 2.0) fun foo2() {}
@@ -1,17 +0,0 @@
// FILE: A.java
public @interface A {
int a();
double b();
String value();
boolean x();
}
// FILE: b.kt
@A("v1", 1,
1.0,
false) fun foo1() {}
@A("v2", 2, x = true, b = 2.0) fun foo2() {}
@A("v2", x = true, b = 3.0, a = 4) fun foo3() {}
@A(value = "v2", x = true, b = 3.0, a = 4) fun foo4() {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: A.java
public @interface A {
int a();
@@ -1,17 +0,0 @@
// FILE: A.java
public @interface A {
int a();
double b();
boolean x();
}
// FILE: b.kt
@A(1,
1.0,
false) fun foo1() {}
@A(2, x = true, b = 2.0) fun foo2() {}
@A(x = true, b = 3.0, a = 4) fun foo3() {}
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
// FILE: A.java
public @interface A {
int a();
@@ -3743,6 +3743,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirJvmErrors.POSITIONED_VALUE_ARGUMENT_FOR_JAVA_ANNOTATION) { firDiagnostic ->
PositionedValueArgumentForJavaAnnotationImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirJvmErrors.LOCAL_JVM_RECORD) { firDiagnostic ->
LocalJvmRecordImpl(
firDiagnostic as FirPsiDiagnostic,
@@ -2604,6 +2604,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = JvmPackageNameNotSupportedInFilesWithClasses::class
}
abstract class PositionedValueArgumentForJavaAnnotation : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = PositionedValueArgumentForJavaAnnotation::class
}
abstract class LocalJvmRecord : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = LocalJvmRecord::class
}
@@ -4231,6 +4231,13 @@ internal class JvmPackageNameNotSupportedInFilesWithClassesImpl(
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class PositionedValueArgumentForJavaAnnotationImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.PositionedValueArgumentForJavaAnnotation(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
}
internal class LocalJvmRecordImpl(
firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,