[FIR] Implement NEWER_VERSION_IN_SINCE_KOTLIN diagnostics, fix tests

This commit is contained in:
Ivan Kochurkin
2021-05-06 22:54:26 +03:00
committed by TeamCityServer
parent 1be02e3ac4
commit 5c086e2321
9 changed files with 49 additions and 4 deletions
@@ -154,6 +154,9 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
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 NEWER_VERSION_IN_SINCE_KOTLIN by warning<KtExpression> {
parameter<String>("specifiedVersion")
}
}
val EXPOSED_VISIBILITY by object : DiagnosticGroup("Exposed visibility") {
@@ -162,6 +162,7 @@ object FirErrors {
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>()
val NEWER_VERSION_IN_SINCE_KOTLIN by warning1<KtExpression, String>()
// Exposed visibility
val EXPOSED_TYPEALIAS_EXPANDED_TYPE by error3<KtNamedDeclaration, EffectiveVisibility, FirMemberDeclaration, EffectiveVisibility>(SourceElementPositioningStrategies.DECLARATION_NAME)
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.fir.analysis.checkers.expression
import org.jetbrains.kotlin.config.ApiVersion
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
@@ -13,6 +14,7 @@ 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.languageVersionSettings
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
import org.jetbrains.kotlin.fir.types.FirResolvedTypeRef
import org.jetbrains.kotlin.name.ClassId
@@ -20,10 +22,11 @@ import org.jetbrains.kotlin.resolve.RequireKotlinConstants
object FirAnnotationChecker : FirAnnotationCallChecker() {
private val deprecatedSinceKotlinClassId = ClassId.fromString("kotlin/DeprecatedSinceKotlin")
private val sinceKotlinClassId = ClassId.fromString("kotlin/SinceKotlin")
private val annotationClassIdsWithVersion = setOf(
ClassId.fromString("kotlin/internal/RequireKotlin"),
ClassId.fromString("kotlin/SinceKotlin"),
sinceKotlinClassId,
deprecatedSinceKotlinClassId
)
@@ -40,8 +43,20 @@ object FirAnnotationChecker : FirAnnotationCallChecker() {
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 stringValue = constExpression?.value as? String
if (stringValue != null) {
if (!stringValue.matches(RequireKotlinConstants.VERSION_REGEX)) {
reporter.reportOn(argSource, FirErrors.ILLEGAL_KOTLIN_VERSION_STRING_VALUE, context)
} else if (classId == sinceKotlinClassId) {
val version = ApiVersion.parse(stringValue)
val specified = context.session.languageVersionSettings.apiVersion
if (version != null && version > specified) {
reporter.report(
FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.on(argSource, specified.versionString),
context
)
}
}
}
}
}
@@ -174,6 +174,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_ARGUMENTS_N
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAMED_PARAMETER_NOT_FOUND
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NAME_IN_CONSTRAINT_IS_NOT_A_TYPE_PARAMETER
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NESTED_CLASS_NOT_ALLOWED
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NEXT_AMBIGUITY
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NONE_APPLICABLE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.NON_ABSTRACT_FUNCTION_WITH_NO_BODY
@@ -423,6 +424,7 @@ class FirDefaultErrorMessages : DefaultErrorMessages.Extension {
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')")
map.put(NEWER_VERSION_IN_SINCE_KOTLIN, "The version is greater than the specified API version {0}", NULLABLE_STRING)
// Exposed visibility group // #
map.put(
@@ -70,5 +70,5 @@ fun ok2() {}
@SinceKotlin("0.0.0")
fun ok3() {}
@SinceKotlin("123456789012345678901234567890.123456789012345678901234567890.123456789012345678901234567890")
@SinceKotlin(<!NEWER_VERSION_IN_SINCE_KOTLIN!>"123456789012345678901234567890.123456789012345678901234567890.123456789012345678901234567890"<!>)
fun ok4() {}
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.resolve.AnalyzingUtils
import org.jetbrains.kotlin.test.directives.AdditionalFilesDirectives
import org.jetbrains.kotlin.test.directives.DiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.FirDiagnosticsDirectives
import org.jetbrains.kotlin.test.directives.LanguageSettingsDirectives
import org.jetbrains.kotlin.test.directives.model.DirectivesContainer
import org.jetbrains.kotlin.test.frontend.fir.FirOutputArtifact
import org.jetbrains.kotlin.test.model.TestFile
@@ -76,6 +77,9 @@ class FirDiagnosticsHandler(testServices: TestServices) : FirAnalysisHandler(tes
if (AdditionalFilesDirectives.CHECK_TYPE in module.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.UNDERSCORE_USAGE_WITHOUT_BACKTICKS.name }
}
if (LanguageSettingsDirectives.API_VERSION in module.directives) {
diagnostics = diagnostics.filter { it.factory.name != FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN.name }
}
val diagnosticsMetadataInfos = diagnostics.mapNotNull { diagnostic ->
if (!diagnosticsService.shouldRenderDiagnostic(module, diagnostic.factory.name)) return@mapNotNull null
// SYNTAX errors will be reported later
@@ -520,6 +520,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token,
)
}
add(FirErrors.NEWER_VERSION_IN_SINCE_KOTLIN) { firDiagnostic ->
NewerVersionInSinceKotlinImpl(
firDiagnostic.a,
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.EXPOSED_TYPEALIAS_EXPANDED_TYPE) { firDiagnostic ->
ExposedTypealiasExpandedTypeImpl(
firDiagnostic.a,
@@ -375,6 +375,11 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = IllegalKotlinVersionStringValue::class
}
abstract class NewerVersionInSinceKotlin : KtFirDiagnostic<KtExpression>() {
override val diagnosticClass get() = NewerVersionInSinceKotlin::class
abstract val specifiedVersion: String
}
abstract class ExposedTypealiasExpandedType : KtFirDiagnostic<KtNamedDeclaration>() {
override val diagnosticClass get() = ExposedTypealiasExpandedType::class
abstract val elementVisibility: EffectiveVisibility
@@ -604,6 +604,14 @@ internal class IllegalKotlinVersionStringValueImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class NewerVersionInSinceKotlinImpl(
override val specifiedVersion: String,
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.NewerVersionInSinceKotlin(), KtAbstractFirDiagnostic<KtExpression> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class ExposedTypealiasExpandedTypeImpl(
override val elementVisibility: EffectiveVisibility,
override val restrictingDeclaration: KtSymbol,