[FIR] Implement ILLEGAL_KOTLIN_VERSION_STRING_VALUE diagnostics, fix tests

This commit is contained in:
Ivan Kochurkin
2021-04-30 19:52:30 +03:00
committed by TeamCityServer
parent cb0b80253c
commit 1be02e3ac4
12 changed files with 113 additions and 58 deletions
@@ -153,6 +153,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val VAR_ANNOTATION_PARAMETER by error<KtParameter>(PositioningStrategy.VAL_OR_VAR_NODE)
val SUPERTYPES_FOR_ANNOTATION_CLASS by error<KtClass>(PositioningStrategy.SUPERTYPES_LIST)
val ANNOTATION_USED_AS_ANNOTATION_ARGUMENT by error<KtAnnotation>()
val ILLEGAL_KOTLIN_VERSION_STRING_VALUE by error<KtExpression>()
}
val EXPOSED_VISIBILITY by object : DiagnosticGroup("Exposed visibility") {
@@ -161,6 +161,7 @@ object FirErrors {
val VAR_ANNOTATION_PARAMETER by error0<KtParameter>(SourceElementPositioningStrategies.VAL_OR_VAR_NODE)
val SUPERTYPES_FOR_ANNOTATION_CLASS by error0<KtClass>(SourceElementPositioningStrategies.SUPERTYPES_LIST)
val ANNOTATION_USED_AS_ANNOTATION_ARGUMENT by error0<KtAnnotation>()
val ILLEGAL_KOTLIN_VERSION_STRING_VALUE by error0<KtExpression>()
// Exposed visibility
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<KtNamedDeclaration, EffectiveVisibility, FirMemberDeclaration, EffectiveVisibility>(SourceElementPositioningStrategies.DECLARATION_NAME)
@@ -0,0 +1,57 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.FirConstExpression
import org.jetbrains.kotlin.fir.expressions.FirNamedArgumentExpression
import org.jetbrains.kotlin.fir.expressions.unwrapArgument
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.resolve.RequireKotlinConstants
object FirAnnotationChecker : FirAnnotationCallChecker() {
private val deprecatedSinceKotlinClassId = ClassId.fromString("kotlin/DeprecatedSinceKotlin")
private val annotationClassIdsWithVersion = setOf(
ClassId.fromString("kotlin/internal/RequireKotlin"),
ClassId.fromString("kotlin/SinceKotlin"),
deprecatedSinceKotlinClassId
)
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
val classId = ((expression.annotationTypeRef as? FirResolvedTypeRef)?.type as? ConeClassLikeType)?.lookupTag?.classId
if (annotationClassIdsWithVersion.contains(classId)) {
for (argIndex in expression.argumentList.arguments.withIndex()) {
if (argIndex.index > 0 && classId != deprecatedSinceKotlinClassId) {
continue
}
val arg = argIndex.value
val argSource = arg.source
if (argSource != null) {
val constExpression = (arg as? FirConstExpression<*>)
?: ((arg as? FirNamedArgumentExpression)?.expression as? FirConstExpression<*>)
if ((constExpression?.value as? String)?.matches(RequireKotlinConstants.VERSION_REGEX) == false) {
reporter.reportOn(argSource, FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE, context)
}
}
}
}
val args = expression.argumentList.arguments
for (arg in args) {
for (ann in arg.unwrapArgument().annotations) {
reporter.reportOn(ann.source, FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT, context)
}
}
}
}
@@ -1,24 +0,0 @@
/*
* Copyright 2010-2021 JetBrains s.r.o. and Kotlin Programming Language contributors.
* Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
import org.jetbrains.kotlin.fir.expressions.unwrapArgument
object FirAnnotationUsedAsAnnotationArgumentChecker : FirAnnotationCallChecker() {
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
val args = expression.argumentList.arguments
for (arg in args) {
for (ann in arg.unwrapArgument().annotations) {
reporter.reportOn(ann.source, FirErrors.ANNOTATION_USED_AS_ANNOTATION_ARGUMENT, context)
}
}
}
}
@@ -127,6 +127,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GENERIC_THROWABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.GETTER_VISIBILITY_DIFFERS_FROM_PROPERTY_VISIBILITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.HAS_NEXT_FUNCTION_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_CONST_EXPRESSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ILLEGAL_UNDERSCORE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_CANDIDATE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INAPPLICABLE_INFIX_MODIFIER
@@ -421,6 +422,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
map.put(VAR_ANNOTATION_PARAMETER, "An annotation parameter cannot be 'var'")
map.put(NOT_AN_ANNOTATION_CLASS, "Illegal annotation class: {0}", NULLABLE_STRING)
map.put(SUPERTYPES_FOR_ANNOTATION_CLASS, "Annotation class cannot have supertypes")
map.put(ILLEGAL_KOTLIN_VERSION_STRING_VALUE, "Invalid value in version annotation (should be 'major.minor' or 'major.minor.patch')")
// Exposed visibility group // #
map.put(
@@ -11,8 +11,8 @@ import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirAnonymousFunctionSyn
object CommonExpressionCheckers : ExpressionCheckers() {
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
get() = setOf(
FirAnnotationArgumentChecker,
FirAnnotationUsedAsAnnotationArgumentChecker,
FirAnnotationChecker,
FirAnnotationArgumentChecker
)
override val basicExpressionCheckers: Set<FirBasicExpressionChecker>
@@ -1,30 +1,31 @@
// FIR_IDENTICAL
@file:Suppress("INVISIBLE_MEMBER", "INVISIBLE_REFERENCE")
package test
import kotlin.internal.RequireKotlin
@RequireKotlin("")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>""<!>)
fun f01() {}
@RequireKotlin("x")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"x"<!>)
fun f02() {}
@RequireKotlin("1")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1"<!>)
fun f03() {}
@RequireKotlin("1.0-beta")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.0-beta"<!>)
fun f04() {}
@RequireKotlin("1.1.0-dev-1111")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.1.0-dev-1111"<!>)
fun f05() {}
@RequireKotlin("1.5.3.7")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.5.3.7"<!>)
fun f06() {}
@RequireKotlin("1..0")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1..0"<!>)
fun f07() {}
@RequireKotlin(" 1.0")
@RequireKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>" 1.0"<!>)
fun f08() {}
@@ -1,61 +1,61 @@
@SinceKotlin("")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>""<!>)
fun f01() {}
@SinceKotlin("x")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"x"<!>)
fun f02() {}
@SinceKotlin("1")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1"<!>)
fun f03() {}
@SinceKotlin("1,0")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1,0"<!>)
fun f04() {}
@SinceKotlin("1,0,1")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1,0,1"<!>)
fun f05() {}
@SinceKotlin("a.b")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"a.b"<!>)
fun f06() {}
@SinceKotlin("1.a")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.a"<!>)
fun f07() {}
@SinceKotlin("1.0.a")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.0.a"<!>)
fun f08() {}
@SinceKotlin("1.0-beta")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.0-beta"<!>)
fun f09() {}
@SinceKotlin("1.1.0-dev-1111")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.1.0-dev-1111"<!>)
fun f10() {}
@SinceKotlin("1.1.0+rc")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.1.0+rc"<!>)
fun f11() {}
@SinceKotlin("1.5.3.7")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.5.3.7"<!>)
fun f12() {}
@SinceKotlin("01.1")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"01.1"<!>)
fun f13() {}
@SinceKotlin("1.01")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.01"<!>)
fun f14() {}
@SinceKotlin("-1.0")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"-1.0"<!>)
fun f15() {}
@SinceKotlin("1.-1.0")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.-1.0"<!>)
fun f16() {}
@SinceKotlin("0.00.1")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"0.00.1"<!>)
fun f17() {}
@SinceKotlin("1..0")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1..0"<!>)
fun f18() {}
@SinceKotlin(" 1.0")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>" 1.0"<!>)
fun f19() {}
@SinceKotlin("1.0 ")
@SinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.0 "<!>)
fun f20() {}
@@ -1,19 +1,19 @@
package kotlin
@Deprecated("")
@DeprecatedSinceKotlin("", errorSince = "1.0")
@DeprecatedSinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>""<!>, errorSince = "1.0")
fun test1() {}
@Deprecated("")
@DeprecatedSinceKotlin("")
@DeprecatedSinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>""<!>)
fun test2() {}
@Deprecated("")
@DeprecatedSinceKotlin("", "", "")
@DeprecatedSinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>""<!>, <!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>""<!>, <!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>""<!>)
fun test3() {}
@Deprecated("")
@DeprecatedSinceKotlin("1.4-M2")
@DeprecatedSinceKotlin(<!ILLEGAL_KOTLIN_VERSION_STRING_VALUE!>"1.4-M2"<!>)
fun test4() {}
@Deprecated("")
@@ -514,6 +514,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE) { firDiagnostic ->
IllegalKotlinVersionStringValueImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE) { firDiagnostic ->
ExposedTypealiasExpandedTypeImpl(
firDiagnostic.a,
@@ -371,6 +371,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = AnnotationUsedAsAnnotationArgument::class
}
abstract class IllegalKotlinVersionStringValue : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = IllegalKotlinVersionStringValue::class
}
abstract class ExposedTypealiasExpandedType : KtFirDiagnostic<KtNamedDeclaration>() {
override val diagnosticClass get() = ExposedTypealiasExpandedType::class
abstract val elementVisibility: EffectiveVisibility
@@ -597,6 +597,13 @@ internal class AnnotationUsedAsAnnotationArgumentImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class IllegalKotlinVersionStringValueImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.IllegalKotlinVersionStringValue(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ExposedTypealiasExpandedTypeImpl(
override val elementVisibility: EffectiveVisibility,
override val restrictingDeclaration: KtSymbol,