[FIR] Implement WRONG_LONG_SUFFIX diagnostics, fix tests

This commit is contained in:
Ivan Kochurkin
2021-04-07 14:04:55 +03:00
committed by TeamCityServer
parent 62ffc0033d
commit fb06da2d75
19 changed files with 60 additions and 34 deletions
@@ -5,7 +5,7 @@ fun takeAny(x: Any) {}
fun takeString(x: String) {} fun takeString(x: String) {}
fun test_0() { fun test_0() {
1l 1L
1 1
10000000000 10000000000
} }
@@ -56,6 +56,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
VALUE_ARGUMENTS, VALUE_ARGUMENTS,
SUPERTYPES_LIST, SUPERTYPES_LIST,
RETURN_WITH_LABEL, RETURN_WITH_LABEL,
LONG_LITERAL_SUFFIX,
; ;
@@ -61,6 +61,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
val EMPTY_CHARACTER_LITERAL by error<FirSourceElement, PsiElement>() val EMPTY_CHARACTER_LITERAL by error<FirSourceElement, PsiElement>()
val TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL by error<FirSourceElement, PsiElement>() val TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL by error<FirSourceElement, PsiElement>()
val ILLEGAL_ESCAPE by error<FirSourceElement, PsiElement>() val ILLEGAL_ESCAPE by error<FirSourceElement, PsiElement>()
val WRONG_LONG_SUFFIX by error<FirSourceElement, KtElement>(PositioningStrategy.LONG_LITERAL_SUFFIX)
} }
val UNRESOLVED by object : DiagnosticGroup("Unresolved") { val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
@@ -86,6 +86,7 @@ object FirErrors {
val EMPTY_CHARACTER_LITERAL by error0<FirSourceElement, PsiElement>() val EMPTY_CHARACTER_LITERAL by error0<FirSourceElement, PsiElement>()
val TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL by error0<FirSourceElement, PsiElement>() val TOO_MANY_CHARACTERS_IN_CHARACTER_LITERAL by error0<FirSourceElement, PsiElement>()
val ILLEGAL_ESCAPE by error0<FirSourceElement, PsiElement>() val ILLEGAL_ESCAPE by error0<FirSourceElement, PsiElement>()
val WRONG_LONG_SUFFIX by error0<FirSourceElement, KtElement>(SourceElementPositioningStrategies.LONG_LITERAL_SUFFIX)
// Unresolved // Unresolved
val HIDDEN by error1<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) val HIDDEN by error1<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
@@ -522,6 +522,9 @@ object LightTreePositioningStrategies {
return markElement(tree.returnKeyword(node) ?: node, startOffset, endOffset, tree) return markElement(tree.returnKeyword(node) ?: node, startOffset, endOffset, tree)
} }
} }
val LONG_LITERAL_SUFFIX = object : LightTreePositioningStrategy() {
}
} }
fun FirSourceElement.hasValOrVar(): Boolean = fun FirSourceElement.hasValOrVar(): Boolean =
@@ -177,4 +177,9 @@ object SourceElementPositioningStrategies {
LightTreePositioningStrategies.RETURN_WITH_LABEL, LightTreePositioningStrategies.RETURN_WITH_LABEL,
PositioningStrategies.RETURN_WITH_LABEL PositioningStrategies.RETURN_WITH_LABEL
) )
val LONG_LITERAL_SUFFIX = SourceElementPositioningStrategy(
LightTreePositioningStrategies.LONG_LITERAL_SUFFIX,
PositioningStrategies.LONG_LITERAL_SUFFIX
)
} }
@@ -179,6 +179,7 @@ private fun ConeSimpleDiagnostic.getFactory(): FirDiagnosticFactory0<FirSourceEl
DiagnosticKind.UnknownCallableKind -> FirErrors.UNKNOWN_CALLABLE_KIND DiagnosticKind.UnknownCallableKind -> FirErrors.UNKNOWN_CALLABLE_KIND
DiagnosticKind.IllegalProjectionUsage -> FirErrors.ILLEGAL_PROJECTION_USAGE DiagnosticKind.IllegalProjectionUsage -> FirErrors.ILLEGAL_PROJECTION_USAGE
DiagnosticKind.MissingStdlibClass -> FirErrors.MISSING_STDLIB_CLASS DiagnosticKind.MissingStdlibClass -> FirErrors.MISSING_STDLIB_CLASS
DiagnosticKind.WrongLongSuffix -> FirErrors.WRONG_LONG_SUFFIX
DiagnosticKind.Other -> FirErrors.OTHER_ERROR DiagnosticKind.Other -> FirErrors.OTHER_ERROR
DiagnosticKind.IncorrectCharacterLiteral -> FirErrors.INCORRECT_CHARACTER_LITERAL DiagnosticKind.IncorrectCharacterLiteral -> FirErrors.INCORRECT_CHARACTER_LITERAL
DiagnosticKind.EmptyCharacterLiteral -> FirErrors.EMPTY_CHARACTER_LITERAL DiagnosticKind.EmptyCharacterLiteral -> FirErrors.EMPTY_CHARACTER_LITERAL
@@ -291,20 +291,37 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
} }
return when (type) { return when (type) {
INTEGER_CONSTANT -> { INTEGER_CONSTANT -> {
var diagnostic: DiagnosticKind = DiagnosticKind.IllegalConstExpression
val number: Long?
val kind = when { val kind = when {
convertedText !is Long -> return reportIncorrectConstant(DiagnosticKind.IllegalConstExpression) convertedText !is Long -> return reportIncorrectConstant(DiagnosticKind.IllegalConstExpression)
hasUnsignedLongSuffix(text) -> { hasUnsignedLongSuffix(text) -> {
if (text.endsWith("l")) {
diagnostic = DiagnosticKind.WrongLongSuffix
number = null
} else {
number = convertedText
}
ConstantValueKind.UnsignedLong ConstantValueKind.UnsignedLong
} }
hasLongSuffix(text) -> { hasLongSuffix(text) -> {
if (text.endsWith("l")) {
diagnostic = DiagnosticKind.WrongLongSuffix
number = null
} else {
number = convertedText
}
ConstantValueKind.Long ConstantValueKind.Long
} }
hasUnsignedSuffix(text) -> { hasUnsignedSuffix(text) -> {
number = convertedText
ConstantValueKind.UnsignedIntegerLiteral ConstantValueKind.UnsignedIntegerLiteral
} }
else -> { else -> {
number = convertedText
ConstantValueKind.IntegerLiteral ConstantValueKind.IntegerLiteral
} }
} }
@@ -312,8 +329,8 @@ abstract class BaseFirBuilder<T>(val baseSession: FirSession, val context: Conte
buildConstOrErrorExpression( buildConstOrErrorExpression(
sourceElement, sourceElement,
kind, kind,
convertedText, number,
ConeSimpleDiagnostic("Incorrect integer literal: $text", DiagnosticKind.IllegalConstExpression) ConeSimpleDiagnostic("Incorrect integer literal: $text", diagnostic)
) )
} }
FLOAT_CONSTANT -> FLOAT_CONSTANT ->
@@ -36,5 +36,7 @@ enum class DiagnosticKind {
TooManyCharactersInCharacterLiteral, TooManyCharactersInCharacterLiteral,
IllegalEscape, IllegalEscape,
WrongLongSuffix,
Other Other
} }
@@ -1,10 +0,0 @@
val a1: Int = 1l
val a2: Int = 0x1l
val a3: Int = 0X1l
val a4: Int = 0b1l
val a5: Int = 0B1l
val a6: Long = 1l
val a7: Long = 0x1l
val a8: Long = 0X1l
val a9: Long = 0b1l
val a10: Long = 0B1l
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
val a1: Int = 1<!WRONG_LONG_SUFFIX!>l<!> val a1: Int = 1<!WRONG_LONG_SUFFIX!>l<!>
val a2: Int = 0x1<!WRONG_LONG_SUFFIX!>l<!> val a2: Int = 0x1<!WRONG_LONG_SUFFIX!>l<!>
val a3: Int = 0X1<!WRONG_LONG_SUFFIX!>l<!> val a3: Int = 0X1<!WRONG_LONG_SUFFIX!>l<!>
@@ -1,4 +0,0 @@
val a1 = 1ul
val a2 = 0x1ul
val a3 = 0B1ul
val a4 = 1Ul
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
val a1 = 1u<!WRONG_LONG_SUFFIX!>l<!> val a1 = 1u<!WRONG_LONG_SUFFIX!>l<!>
val a2 = 0x1u<!WRONG_LONG_SUFFIX!>l<!> val a2 = 0x1u<!WRONG_LONG_SUFFIX!>l<!>
val a3 = 0B1u<!WRONG_LONG_SUFFIX!>l<!> val a3 = 0B1u<!WRONG_LONG_SUFFIX!>l<!>
@@ -1,11 +0,0 @@
// TESTCASE NUMBER: 1
val value_1 = 0l
// TESTCASE NUMBER: 2
val value_2 = 1000000000000000l
// TESTCASE NUMBER: 3
val value_3 = 0X0l
// TESTCASE NUMBER: 4
val value_4 = 0b101l
@@ -1,3 +1,4 @@
// FIR_IDENTICAL
/* /*
* KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE) * KOTLIN DIAGNOSTICS SPEC TEST (NEGATIVE)
* *
@@ -2,10 +2,10 @@
// TESTCASE NUMBER: 1 // TESTCASE NUMBER: 1
fun case_1() { fun case_1() {
0l checkType { check<Long>() } 0<!WRONG_LONG_SUFFIX!>l<!> <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!NONE_APPLICABLE!>check<!><Long>() }
10000000000000l checkType { check<Long>() } 10000000000000<!WRONG_LONG_SUFFIX!>l<!> <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!NONE_APPLICABLE!>check<!><Long>() }
0X000Af10cDl checkType { check<Long>() } 0X000Af10cD<!WRONG_LONG_SUFFIX!>l<!> <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!NONE_APPLICABLE!>check<!><Long>() }
0x0_0l checkType { check<Long>() } 0x0_0<!WRONG_LONG_SUFFIX!>l<!> <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!NONE_APPLICABLE!>check<!><Long>() }
0b100_000_111_111l checkType { check<Long>() } 0b100_000_111_111<!WRONG_LONG_SUFFIX!>l<!> <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!NONE_APPLICABLE!>check<!><Long>() }
0b0l checkType { check<Long>() } 0b0<!WRONG_LONG_SUFFIX!>l<!> <!INAPPLICABLE_CANDIDATE!>checkType<!> { <!NONE_APPLICABLE!>check<!><Long>() }
} }
@@ -149,6 +149,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.WRONG_LONG_SUFFIX) { firDiagnostic ->
WrongLongSuffixImpl(
firDiagnostic as FirPsiDiagnostic<*>,
token,
)
}
add(FirErrors.HIDDEN) { firDiagnostic -> add(FirErrors.HIDDEN) { firDiagnostic ->
HiddenImpl( HiddenImpl(
firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration), firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration),
@@ -124,6 +124,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = IllegalEscape::class override val diagnosticClass get() = IllegalEscape::class
} }
abstract class WrongLongSuffix : KtFirDiagnostic<KtElement>() {
override val diagnosticClass get() = WrongLongSuffix::class
}
abstract class Hidden : KtFirDiagnostic<PsiElement>() { abstract class Hidden : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = Hidden::class override val diagnosticClass get() = Hidden::class
abstract val hidden: KtSymbol abstract val hidden: KtSymbol
@@ -173,6 +173,13 @@ internal class IllegalEscapeImpl(
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
} }
internal class WrongLongSuffixImpl(
firDiagnostic: FirPsiDiagnostic<*>,
override val token: ValidityToken,
) : KtFirDiagnostic.WrongLongSuffix(), KtAbstractFirDiagnostic<KtElement> {
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
}
internal class HiddenImpl( internal class HiddenImpl(
override val hidden: KtSymbol, override val hidden: KtSymbol,
firDiagnostic: FirPsiDiagnostic<*>, firDiagnostic: FirPsiDiagnostic<*>,