[FIR] JVM_PACKAGE_NAME* diagnostics
This commit is contained in:
committed by
TeamCityServer
parent
ae558c0290
commit
4661656b8c
+4
@@ -45,6 +45,10 @@ object JVM_DIAGNOSTICS_LIST : DiagnosticList("FirJvmErrors") {
|
||||
val DEPRECATED_JAVA_ANNOTATION by warning<KtAnnotationEntry>() {
|
||||
parameter<FqName>("kotlinName")
|
||||
}
|
||||
|
||||
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>()
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+3
@@ -39,5 +39,8 @@ object FirJvmErrors {
|
||||
val OVERLOADS_ANNOTATION_CLASS_CONSTRUCTOR by deprecationError0<KtAnnotationEntry>(ProhibitJvmOverloadsOnConstructorsOfAnnotationClasses)
|
||||
val OVERLOADS_PRIVATE by warning0<KtAnnotationEntry>()
|
||||
val DEPRECATED_JAVA_ANNOTATION by warning1<KtAnnotationEntry, FqName>()
|
||||
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>()
|
||||
|
||||
}
|
||||
|
||||
+2
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallCh
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirFunctionCallChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirDeprecatedJavaAnnotationsChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirJavaGenericVarianceViolationTypeChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.jvm.checkers.expression.FirJvmPackageNameAnnotationsChecker
|
||||
|
||||
object JvmExpressionCheckers : ExpressionCheckers() {
|
||||
override val functionCallCheckers: Set<FirFunctionCallChecker>
|
||||
@@ -20,5 +21,6 @@ object JvmExpressionCheckers : ExpressionCheckers() {
|
||||
override val annotationCallCheckers: Set<FirAnnotationCallChecker>
|
||||
get() = setOf(
|
||||
FirDeprecatedJavaAnnotationsChecker,
|
||||
FirJvmPackageNameAnnotationsChecker,
|
||||
)
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
/*
|
||||
* 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.jvm.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirAnnotationCallChecker
|
||||
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.FirClass
|
||||
import org.jetbrains.kotlin.fir.declarations.FirFile
|
||||
import org.jetbrains.kotlin.fir.declarations.getStringArgument
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.types.ConeClassLikeType
|
||||
import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.*
|
||||
|
||||
object FirJvmPackageNameAnnotationsChecker : FirAnnotationCallChecker() {
|
||||
|
||||
private val jvmPackageNameClassId = ClassId.topLevel(FqName("kotlin.jvm.JvmPackageName"))
|
||||
private val stringParameterName = Name.identifier("name")
|
||||
|
||||
override fun check(expression: FirAnnotationCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val lookupTag = expression.annotationTypeRef.coneTypeSafe<ConeClassLikeType>()?.lookupTag ?: return
|
||||
if (lookupTag.classId != jvmPackageNameClassId) return
|
||||
|
||||
val nameValue = expression.getStringArgument(stringParameterName) ?: return
|
||||
if (nameValue.isEmpty()) {
|
||||
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY, context)
|
||||
} else if (!isValidJavaFqName(nameValue)) {
|
||||
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME, context)
|
||||
}
|
||||
|
||||
val file = context.containingDeclarations.firstOrNull() as? FirFile ?: return
|
||||
if (file.declarations.any { it is FirClass }) {
|
||||
reporter.reportOn(expression.source, FirJvmErrors.JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES, context)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.fir.types.coneTypeSafe
|
||||
import org.jetbrains.kotlin.name.ClassId
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
private val RETENTION_CLASS_ID = ClassId.fromString("kotlin/annotation/Retention")
|
||||
private val TARGET_CLASS_ID = ClassId.fromString("kotlin/annotation/Target")
|
||||
@@ -125,3 +126,8 @@ fun FirAnnotationCall.findArgumentByName(name: Name): FirExpression? {
|
||||
// TODO: this line is still needed. However it should be replaced with 'return null'
|
||||
return arguments.singleOrNull()
|
||||
}
|
||||
|
||||
fun FirAnnotationCall.getStringArgument(name: Name): String? =
|
||||
findArgumentByName(name)?.let { expression ->
|
||||
expression.safeAs<FirConstExpression<*>>()?.value as? String
|
||||
}
|
||||
|
||||
@@ -90,11 +90,6 @@ private fun FirBasedSymbol<*>.getDeprecationForCallSite(
|
||||
return (deprecations ?: EmptyDeprecationsPerUseSite).forUseSite(*sites)
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.getStringArgument(name: Name): String? =
|
||||
findArgumentByName(name)?.let { expression ->
|
||||
expression.safeAs<FirConstExpression<*>>()?.value as? String
|
||||
}
|
||||
|
||||
private fun FirAnnotationCall.getVersionFromArgument(name: Name): ApiVersion? =
|
||||
getStringArgument(name)?.let { ApiVersion.parse(it) }
|
||||
|
||||
|
||||
+3
-3
@@ -1,17 +1,17 @@
|
||||
// !DIAGNOSTICS: -INVISIBLE_MEMBER -INVISIBLE_REFERENCE
|
||||
|
||||
// FILE: b.kt
|
||||
@file:JvmPackageName("")
|
||||
<!JVM_PACKAGE_NAME_CANNOT_BE_EMPTY!>@file:JvmPackageName("")<!>
|
||||
package b
|
||||
fun b() {}
|
||||
|
||||
// FILE: c.kt
|
||||
@file:JvmPackageName("invalid-fq-name")
|
||||
<!JVM_PACKAGE_NAME_MUST_BE_VALID_NAME!>@file:JvmPackageName("invalid-fq-name")<!>
|
||||
package c
|
||||
fun c() {}
|
||||
|
||||
// FILE: d.kt
|
||||
@file:JvmPackageName("d")
|
||||
<!JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES!>@file:JvmPackageName("d")<!>
|
||||
package d
|
||||
class D
|
||||
fun d() {}
|
||||
|
||||
+18
@@ -3532,4 +3532,22 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.JVM_PACKAGE_NAME_CANNOT_BE_EMPTY) { firDiagnostic ->
|
||||
JvmPackageNameCannotBeEmptyImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.JVM_PACKAGE_NAME_MUST_BE_VALID_NAME) { firDiagnostic ->
|
||||
JvmPackageNameMustBeValidNameImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirJvmErrors.JVM_PACKAGE_NAME_NOT_SUPPORTED_IN_FILES_WITH_CLASSES) { firDiagnostic ->
|
||||
JvmPackageNameNotSupportedInFilesWithClassesImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
+12
@@ -2461,4 +2461,16 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
abstract val kotlinName: FqName
|
||||
}
|
||||
|
||||
abstract class JvmPackageNameCannotBeEmpty : KtFirDiagnostic<KtAnnotationEntry>() {
|
||||
override val diagnosticClass get() = JvmPackageNameCannotBeEmpty::class
|
||||
}
|
||||
|
||||
abstract class JvmPackageNameMustBeValidName : KtFirDiagnostic<KtAnnotationEntry>() {
|
||||
override val diagnosticClass get() = JvmPackageNameMustBeValidName::class
|
||||
}
|
||||
|
||||
abstract class JvmPackageNameNotSupportedInFilesWithClasses : KtFirDiagnostic<KtAnnotationEntry>() {
|
||||
override val diagnosticClass get() = JvmPackageNameNotSupportedInFilesWithClasses::class
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+21
@@ -3986,3 +3986,24 @@ internal class DeprecatedJavaAnnotationImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class JvmPackageNameCannotBeEmptyImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.JvmPackageNameCannotBeEmpty(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class JvmPackageNameMustBeValidNameImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.JvmPackageNameMustBeValidName(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class JvmPackageNameNotSupportedInFilesWithClassesImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.JvmPackageNameNotSupportedInFilesWithClasses(), KtAbstractFirDiagnostic<KtAnnotationEntry> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user