[FIR] Implement INVALID_CHARACTERS
This commit is contained in:
+5
-2
@@ -1068,8 +1068,11 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
parameter<ConeKotlinType>("actualType")
|
||||
}
|
||||
|
||||
val UNDERSCORE_IS_RESERVED by error<PsiElement>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<PsiElement>(PositioningStrategy.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_IS_RESERVED by error<PsiElement>(PositioningStrategy.NAME_IDENTIFIER)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error<PsiElement>(PositioningStrategy.NAME_IDENTIFIER)
|
||||
val INVALID_CHARACTERS by error<KtNamedDeclaration>(PositioningStrategy.NAME_IDENTIFIER) {
|
||||
parameter<String>("message")
|
||||
}
|
||||
|
||||
val EQUALITY_NOT_APPLICABLE by error<KtBinaryExpression> {
|
||||
parameter<String>("operator")
|
||||
|
||||
+1
-1
@@ -69,7 +69,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
||||
FUN_MODIFIER,
|
||||
SUSPEND_MODIFIER,
|
||||
FUN_INTERFACE,
|
||||
RESERVED_UNDERSCORE,
|
||||
NAME_IDENTIFIER,
|
||||
QUESTION_MARK_BY_TYPE,
|
||||
ANNOTATION_USE_SITE,
|
||||
ASSIGNMENT_LHS,
|
||||
|
||||
+3
-2
@@ -554,8 +554,9 @@ object FirErrors {
|
||||
val DELEGATE_SPECIAL_FUNCTION_AMBIGUITY by error2<KtExpression, String, Collection<FirBasedSymbol<*>>>()
|
||||
val DELEGATE_SPECIAL_FUNCTION_NONE_APPLICABLE by error2<KtExpression, String, Collection<FirBasedSymbol<*>>>()
|
||||
val DELEGATE_SPECIAL_FUNCTION_RETURN_TYPE_MISMATCH by error3<KtExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val UNDERSCORE_IS_RESERVED by error0<PsiElement>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<PsiElement>(SourceElementPositioningStrategies.RESERVED_UNDERSCORE)
|
||||
val UNDERSCORE_IS_RESERVED by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||
val UNDERSCORE_USAGE_WITHOUT_BACKTICKS by error0<PsiElement>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||
val INVALID_CHARACTERS by error1<KtNamedDeclaration, String>(SourceElementPositioningStrategies.NAME_IDENTIFIER)
|
||||
val EQUALITY_NOT_APPLICABLE by error3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val EQUALITY_NOT_APPLICABLE_WARNING by warning3<KtBinaryExpression, String, ConeKotlinType, ConeKotlinType>()
|
||||
val INCOMPATIBLE_ENUM_COMPARISON_ERROR by error2<KtElement, ConeKotlinType, ConeKotlinType>()
|
||||
|
||||
+2
-1
@@ -30,7 +30,8 @@ object CommonDeclarationCheckers : DeclarationCheckers() {
|
||||
FirInfixFunctionDeclarationChecker,
|
||||
FirExposedVisibilityDeclarationChecker,
|
||||
FirCyclicTypeBoundsChecker,
|
||||
FirExpectActualDeclarationChecker
|
||||
FirExpectActualDeclarationChecker,
|
||||
FirInvalidCharactersChecker
|
||||
)
|
||||
|
||||
override val functionCheckers: Set<FirFunctionChecker>
|
||||
|
||||
+50
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.declaration
|
||||
|
||||
import org.jetbrains.kotlin.KtNodeTypes
|
||||
import org.jetbrains.kotlin.fir.FirFakeSourceElementKind
|
||||
import org.jetbrains.kotlin.fir.FirSourceElement
|
||||
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.declarations.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
object FirInvalidCharactersChecker : FirBasicDeclarationChecker() {
|
||||
private val INVALID_CHARS = setOf('.', ';', '[', ']', '/', '<', '>', ':', '\\')
|
||||
|
||||
override fun check(declaration: FirDeclaration, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val source = declaration.source
|
||||
when (declaration) {
|
||||
is FirRegularClass -> checkNameAndReport(declaration.name, source, context, reporter)
|
||||
is FirSimpleFunction -> checkNameAndReport(declaration.name, source, context, reporter)
|
||||
is FirTypeParameter -> checkNameAndReport(declaration.name, source, context, reporter)
|
||||
is FirProperty -> checkNameAndReport(declaration.name, source, context, reporter)
|
||||
is FirTypeAlias -> checkNameAndReport(declaration.name, source, context, reporter)
|
||||
is FirValueParameter -> checkNameAndReport(declaration.name, source, context, reporter)
|
||||
else -> return
|
||||
}
|
||||
}
|
||||
|
||||
private fun checkNameAndReport(name: Name, source: FirSourceElement?, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val nameString = name.asString()
|
||||
if (source != null &&
|
||||
source.kind !is FirFakeSourceElementKind &&
|
||||
source.elementType != KtNodeTypes.DESTRUCTURING_DECLARATION &&
|
||||
!name.isSpecial &&
|
||||
nameString.any { it in INVALID_CHARS }
|
||||
) {
|
||||
reporter.reportOn(
|
||||
source,
|
||||
FirErrors.INVALID_CHARACTERS,
|
||||
"contains illegal characters: ${INVALID_CHARS.intersect(nameString.toSet()).joinToString("")}",
|
||||
context
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
+6
@@ -228,6 +228,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_INSID
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INNER_CLASS_OF_GENERIC_THROWABLE_SUBCLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INSTANCE_ACCESS_BEFORE_SUPER_CALL
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INTERFACE_WITH_SUPERCLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_CHARACTERS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_IF_AS_EXPRESSION
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVALID_TYPE_OF_ANNOTATION_MEMBER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.INVISIBLE_REFERENCE
|
||||
@@ -1398,6 +1399,11 @@ class FirDefaultErrorMessages {
|
||||
UNDERSCORE_USAGE_WITHOUT_BACKTICKS,
|
||||
"Names _, __, ___, ... can be used only in back-ticks (`_`, `__`, `___`, ...)"
|
||||
)
|
||||
map.put(
|
||||
INVALID_CHARACTERS,
|
||||
"Name {0}",
|
||||
STRING
|
||||
)
|
||||
map.put(
|
||||
EQUALITY_NOT_APPLICABLE,
|
||||
"Operator ''{0}'' cannot be applied to ''{1}'' and ''{2}''",
|
||||
|
||||
+1
-1
@@ -708,7 +708,7 @@ object LightTreePositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
val RESERVED_UNDERSCORE: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
val NAME_IDENTIFIER: LightTreePositioningStrategy = object : LightTreePositioningStrategy() {
|
||||
override fun mark(
|
||||
node: LighterASTNode,
|
||||
startOffset: Int,
|
||||
|
||||
+3
-3
@@ -238,9 +238,9 @@ object SourceElementPositioningStrategies {
|
||||
PositioningStrategies.TYPE_PARAMETERS_LIST
|
||||
)
|
||||
|
||||
val RESERVED_UNDERSCORE = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.RESERVED_UNDERSCORE,
|
||||
PositioningStrategies.RESERVED_UNDERSCORE
|
||||
val NAME_IDENTIFIER = SourceElementPositioningStrategy(
|
||||
LightTreePositioningStrategies.NAME_IDENTIFIER,
|
||||
PositioningStrategies.NAME_IDENTIFIER
|
||||
)
|
||||
|
||||
val QUESTION_MARK_BY_TYPE = SourceElementPositioningStrategy(
|
||||
|
||||
@@ -837,18 +837,13 @@ object PositioningStrategies {
|
||||
}
|
||||
}
|
||||
|
||||
val RESERVED_UNDERSCORE: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
override fun mark(element: PsiElement): List<TextRange> {
|
||||
if (element is PsiNameIdentifierOwner) {
|
||||
val nameIdentifier = element.nameIdentifier
|
||||
if (nameIdentifier != null) {
|
||||
return super.mark(nameIdentifier)
|
||||
}
|
||||
} else if (element is KtLabelReferenceExpression) {
|
||||
return super.mark(element.getReferencedNameElement())
|
||||
}
|
||||
|
||||
return super.mark(element)
|
||||
val NAME_IDENTIFIER: PositioningStrategy<PsiElement> = object : PositioningStrategy<PsiElement>() {
|
||||
private fun KtTypeElement.getReferencedTypeExpression(): KtElement? {
|
||||
return when (this) {
|
||||
is KtUserType -> referenceExpression
|
||||
is KtNullableType -> innerType?.getReferencedTypeExpression()
|
||||
is KtDefinitelyNotNullType -> innerType?.getReferencedTypeExpression()
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -1,94 +0,0 @@
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER
|
||||
// TODO Uncomment all the examples when there will be no problems with light classes
|
||||
//package `foo.bar`
|
||||
|
||||
// TODO: Uncomment after fixing KT-9416
|
||||
//import kotlin.Deprecated as `deprecate\entity`
|
||||
|
||||
//@`deprecate\entity`("") data class Pair(val x: Int, val y: Int)
|
||||
|
||||
// Names should not contains characters: '.', ';', '[', ']', '/', '<', '>', ':', '\\'
|
||||
//class `class.name`
|
||||
class `class;name`
|
||||
class `class[name`
|
||||
class `class]name`
|
||||
//class `class/name`
|
||||
class `class<name`
|
||||
class `class>name`
|
||||
class `class:name`
|
||||
class `class\name`
|
||||
|
||||
class ` ` {}
|
||||
class ` `
|
||||
|
||||
//val `val.X` = 10
|
||||
val `val;X` = 10
|
||||
val `val[X` = 10
|
||||
val `val]X` = 10
|
||||
//val `val/X` = 10
|
||||
val `val<X` = 10
|
||||
val `val>X` = 10
|
||||
val `val:X` = 10
|
||||
val `val\X` = 10
|
||||
|
||||
val `;` = 1
|
||||
val `[` = 2
|
||||
val `]` = 3
|
||||
val `<` = 4
|
||||
|
||||
val `>` = 5
|
||||
val `:` = 6
|
||||
val `\` = 7
|
||||
val `<>` = 8
|
||||
|
||||
val `[]` = 9
|
||||
val `[;]` = 10
|
||||
|
||||
// TODO Uncomment when there will be no problems with light classes (Error: Invalid formal type parameter (must be a valid Java identifier))
|
||||
//class AWithTypeParameter<`T:K`> {}
|
||||
//fun <`T/K`> genericFun(x: `T/K`) {}
|
||||
|
||||
class B(val `a:b`: Int, val `c:d`: Int)
|
||||
|
||||
val ff: (`x:X`: Int) -> Unit = {}
|
||||
val fg: ((`x:X`: Int) -> Unit) -> Unit = {}
|
||||
val fh: ((Int) -> ((`x:X`: Int) -> Unit) -> Unit) = {{}}
|
||||
|
||||
fun f(x: Int, g: (Int) -> Unit) = g(x)
|
||||
|
||||
data class Data(val x: Int, val y: Int)
|
||||
|
||||
class A() {
|
||||
init {
|
||||
val `a:b` = 10
|
||||
}
|
||||
|
||||
fun g(`x:y`: Int) {
|
||||
val `s:` = 30
|
||||
}
|
||||
}
|
||||
|
||||
fun `foo:bar`(`\arg`: Int): Int {
|
||||
val (`a:b`, c) = Data(10, 20)
|
||||
val `a\b` = 10
|
||||
|
||||
fun localFun() {}
|
||||
|
||||
for (`x/y` in 0..10) {
|
||||
}
|
||||
|
||||
f(10) {
|
||||
`x:z`: Int -> localFun()
|
||||
}
|
||||
|
||||
f(20, fun(`x:z`: Int): Unit {})
|
||||
|
||||
try {
|
||||
val `a:` = 10
|
||||
}
|
||||
catch (`e:a`: Exception) {
|
||||
val `b:` = 20
|
||||
}
|
||||
|
||||
return `\arg`
|
||||
}
|
||||
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
// !DIAGNOSTICS: -UNUSED_VARIABLE -UNUSED_PARAMETER -UNUSED_ANONYMOUS_PARAMETER
|
||||
// TODO Uncomment all the examples when there will be no problems with light classes
|
||||
//package `foo.bar`
|
||||
|
||||
+7
@@ -2876,6 +2876,13 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.INVALID_CHARACTERS) { firDiagnostic ->
|
||||
InvalidCharactersImpl(
|
||||
firDiagnostic.a,
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.EQUALITY_NOT_APPLICABLE) { firDiagnostic ->
|
||||
EqualityNotApplicableImpl(
|
||||
firDiagnostic.a,
|
||||
|
||||
+5
@@ -2011,6 +2011,11 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = UnderscoreUsageWithoutBackticks::class
|
||||
}
|
||||
|
||||
abstract class InvalidCharacters : KtFirDiagnostic<KtNamedDeclaration>() {
|
||||
override val diagnosticClass get() = InvalidCharacters::class
|
||||
abstract val message: String
|
||||
}
|
||||
|
||||
abstract class EqualityNotApplicable : KtFirDiagnostic<KtBinaryExpression>() {
|
||||
override val diagnosticClass get() = EqualityNotApplicable::class
|
||||
abstract val operator: String
|
||||
|
||||
+8
@@ -3239,6 +3239,14 @@ internal class UnderscoreUsageWithoutBackticksImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class InvalidCharactersImpl(
|
||||
override val message: String,
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.InvalidCharacters(), KtAbstractFirDiagnostic<KtNamedDeclaration> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class EqualityNotApplicableImpl(
|
||||
override val operator: String,
|
||||
override val leftType: KtType,
|
||||
|
||||
Reference in New Issue
Block a user