[FIR] Implement DIVISION_BY_ZERO diagnostics, fix tests
This commit is contained in:
committed by
TeamCityServer
parent
964bba3530
commit
847ab40707
+1
-1
@@ -58,7 +58,7 @@ enum class PositioningStrategy(private val strategy: String? = null) {
|
|||||||
RETURN_WITH_LABEL,
|
RETURN_WITH_LABEL,
|
||||||
INT_LITERAL_OUT_OF_RANGE,
|
INT_LITERAL_OUT_OF_RANGE,
|
||||||
FLOAT_LITERAL_OUT_OF_RANGE,
|
FLOAT_LITERAL_OUT_OF_RANGE,
|
||||||
LONG_LITERAL_SUFFIX,
|
LONG_LITERAL_SUFFIX
|
||||||
|
|
||||||
;
|
;
|
||||||
|
|
||||||
|
|||||||
+1
@@ -64,6 +64,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() {
|
|||||||
val INT_LITERAL_OUT_OF_RANGE by error<FirSourceElement, PsiElement>()
|
val INT_LITERAL_OUT_OF_RANGE by error<FirSourceElement, PsiElement>()
|
||||||
val FLOAT_LITERAL_OUT_OF_RANGE by error<FirSourceElement, PsiElement>()
|
val FLOAT_LITERAL_OUT_OF_RANGE by error<FirSourceElement, PsiElement>()
|
||||||
val WRONG_LONG_SUFFIX by error<FirSourceElement, KtElement>(PositioningStrategy.LONG_LITERAL_SUFFIX)
|
val WRONG_LONG_SUFFIX by error<FirSourceElement, KtElement>(PositioningStrategy.LONG_LITERAL_SUFFIX)
|
||||||
|
val DIVISION_BY_ZERO by warning<FirSourceElement, KtExpression>()
|
||||||
}
|
}
|
||||||
|
|
||||||
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
val UNRESOLVED by object : DiagnosticGroup("Unresolved") {
|
||||||
|
|||||||
@@ -89,6 +89,7 @@ object FirErrors {
|
|||||||
val INT_LITERAL_OUT_OF_RANGE by error0<FirSourceElement, PsiElement>()
|
val INT_LITERAL_OUT_OF_RANGE by error0<FirSourceElement, PsiElement>()
|
||||||
val FLOAT_LITERAL_OUT_OF_RANGE by error0<FirSourceElement, PsiElement>()
|
val FLOAT_LITERAL_OUT_OF_RANGE by error0<FirSourceElement, PsiElement>()
|
||||||
val WRONG_LONG_SUFFIX by error0<FirSourceElement, KtElement>(SourceElementPositioningStrategies.LONG_LITERAL_SUFFIX)
|
val WRONG_LONG_SUFFIX by error0<FirSourceElement, KtElement>(SourceElementPositioningStrategies.LONG_LITERAL_SUFFIX)
|
||||||
|
val DIVISION_BY_ZERO by warning0<FirSourceElement, KtExpression>()
|
||||||
|
|
||||||
// Unresolved
|
// Unresolved
|
||||||
val HIDDEN by error1<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
val HIDDEN by error1<FirSourceElement, PsiElement, AbstractFirBasedSymbol<*>>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED)
|
||||||
|
|||||||
+34
@@ -0,0 +1,34 @@
|
|||||||
|
/*
|
||||||
|
* 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.FirConstExpression
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||||
|
import org.jetbrains.kotlin.fir.expressions.arguments
|
||||||
|
import org.jetbrains.kotlin.fir.references.FirResolvedNamedReference
|
||||||
|
import org.jetbrains.kotlin.fir.symbols.impl.FirNamedFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.name.FqName
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
object FirDivisionByZeroChecker : FirFunctionCallChecker() {
|
||||||
|
private val defaultPackageName = FqName("kotlin")
|
||||||
|
private val defaultDivName = Name.identifier("div")
|
||||||
|
|
||||||
|
override fun check(expression: FirFunctionCall, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||||
|
val firstValue = (expression.arguments.singleOrNull() as? FirConstExpression<*>)?.value
|
||||||
|
if (firstValue != null && (firstValue == 0L || firstValue == 0.0f || firstValue == 0.0)) {
|
||||||
|
val callableId =
|
||||||
|
((expression.calleeReference as? FirResolvedNamedReference)?.resolvedSymbol as? FirNamedFunctionSymbol)?.callableId
|
||||||
|
if (callableId != null && callableId.packageName == defaultPackageName && callableId.callableName == defaultDivName) {
|
||||||
|
reporter.reportOn(expression.source, FirErrors.DIVISION_BY_ZERO, context)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+1
@@ -32,6 +32,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
|||||||
|
|
||||||
override val functionCallCheckers: Set<FirFunctionCallChecker> = setOf(
|
override val functionCallCheckers: Set<FirFunctionCallChecker> = setOf(
|
||||||
FirConventionFunctionCallChecker,
|
FirConventionFunctionCallChecker,
|
||||||
|
FirDivisionByZeroChecker
|
||||||
)
|
)
|
||||||
|
|
||||||
override val tryExpressionCheckers: Set<FirTryExpressionChecker> = setOf(
|
override val tryExpressionCheckers: Set<FirTryExpressionChecker> = setOf(
|
||||||
|
|||||||
@@ -1217,7 +1217,8 @@ open class RawFirBuilder(
|
|||||||
this.source = source
|
this.source = source
|
||||||
constructedTypeRef = delegatedType.copyWithNewSourceKind(FirFakeSourceElementKind.ImplicitTypeRef)
|
constructedTypeRef = delegatedType.copyWithNewSourceKind(FirFakeSourceElementKind.ImplicitTypeRef)
|
||||||
this.isThis = isThis
|
this.isThis = isThis
|
||||||
val calleeKind = if (isImplicit)FirFakeSourceElementKind.ImplicitConstructor else FirFakeSourceElementKind.DelegatingConstructorCall
|
val calleeKind =
|
||||||
|
if (isImplicit) FirFakeSourceElementKind.ImplicitConstructor else FirFakeSourceElementKind.DelegatingConstructorCall
|
||||||
val calleeSource = this@convert.calleeExpression?.toFirSourceElement(calleeKind)
|
val calleeSource = this@convert.calleeExpression?.toFirSourceElement(calleeKind)
|
||||||
?: source.fakeElement(calleeKind)
|
?: source.fakeElement(calleeKind)
|
||||||
this.calleeReference = if (isThis) {
|
this.calleeReference = if (isThis) {
|
||||||
|
|||||||
+1
-1
@@ -15,7 +15,7 @@ fun test3() {}
|
|||||||
@Foo(c = [1f], b = [""], a = [1])
|
@Foo(c = [1f], b = [""], a = [1])
|
||||||
fun test4() {}
|
fun test4() {}
|
||||||
|
|
||||||
@Foo([1 + 2], ["Hello, " + "Kotlin"], [1 / 0f])
|
@Foo([1 + 2], ["Hello, " + "Kotlin"], [<!DIVISION_BY_ZERO!>1 / 0f<!>])
|
||||||
fun test5() {}
|
fun test5() {}
|
||||||
|
|
||||||
const val ONE = 1
|
const val ONE = 1
|
||||||
|
|||||||
Vendored
+1
-1
@@ -23,7 +23,7 @@ fun test1_2() {}
|
|||||||
@Ann2(*[])
|
@Ann2(*[])
|
||||||
fun test2() {}
|
fun test2() {}
|
||||||
|
|
||||||
@Ann3(a = *[0f, 1 / 0f])
|
@Ann3(a = *[0f, <!DIVISION_BY_ZERO!>1 / 0f<!>])
|
||||||
fun test3() {}
|
fun test3() {}
|
||||||
|
|
||||||
@Ann5(Ann4(*["/"]))
|
@Ann5(Ann4(*["/"]))
|
||||||
|
|||||||
@@ -2,17 +2,21 @@
|
|||||||
// !WITH_NEW_INFERENCE
|
// !WITH_NEW_INFERENCE
|
||||||
|
|
||||||
val a1 = 0
|
val a1 = 0
|
||||||
val a2 = 1 / 0
|
val a2 = <!DIVISION_BY_ZERO!>1 / 0<!>
|
||||||
val a3 = 1 / a1
|
val a3 = 1 / a1
|
||||||
val a4 = 1 / a2
|
val a4 = 1 / a2
|
||||||
val a5 = 2 * (1 / 0)
|
val a5 = 2 * (<!DIVISION_BY_ZERO!>1 / 0<!>)
|
||||||
|
|
||||||
val a6 = 1.div(0)
|
val a6 = <!DIVISION_BY_ZERO!>1.div(0)<!>
|
||||||
val a7 = 1.div(a1)
|
val a7 = 1.div(a1)
|
||||||
val a8 = 1.div(a2)
|
val a8 = 1.div(a2)
|
||||||
val a9 = 2 * (1.div(0))
|
val a9 = 2 * (<!DIVISION_BY_ZERO!>1.div(0)<!>)
|
||||||
|
|
||||||
val b1: Byte = 1 / 0
|
val a10 = <!DIVISION_BY_ZERO!>1 / 0.0f<!>
|
||||||
@Ann(1 / 0) val b2 = 1
|
val a11 = <!DIVISION_BY_ZERO!>1 / 0.0<!>
|
||||||
|
val a12 = <!DIVISION_BY_ZERO!>1L / 0<!>
|
||||||
|
|
||||||
|
val b1: Byte = <!DIVISION_BY_ZERO!>1 / 0<!>
|
||||||
|
@Ann(<!DIVISION_BY_ZERO!>1 / 0<!>) val b2 = 1
|
||||||
|
|
||||||
annotation class Ann(val i : Int)
|
annotation class Ann(val i : Int)
|
||||||
@@ -12,6 +12,10 @@ val a7 = <!DIVISION_BY_ZERO!>1.div(a1)<!>
|
|||||||
val a8 = 1.div(a2)
|
val a8 = 1.div(a2)
|
||||||
val a9 = 2 * (<!DIVISION_BY_ZERO!>1.div(0)<!>)
|
val a9 = 2 * (<!DIVISION_BY_ZERO!>1.div(0)<!>)
|
||||||
|
|
||||||
|
val a10 = <!DIVISION_BY_ZERO!>1 / 0.0f<!>
|
||||||
|
val a11 = <!DIVISION_BY_ZERO!>1 / 0.0<!>
|
||||||
|
val a12 = <!DIVISION_BY_ZERO!>1L / 0<!>
|
||||||
|
|
||||||
val b1: Byte = <!DIVISION_BY_ZERO, TYPE_MISMATCH!>1 / 0<!>
|
val b1: Byte = <!DIVISION_BY_ZERO, TYPE_MISMATCH!>1 / 0<!>
|
||||||
@Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, DIVISION_BY_ZERO!>1 / 0<!>) val b2 = 1
|
@Ann(<!ANNOTATION_ARGUMENT_MUST_BE_CONST, DIVISION_BY_ZERO!>1 / 0<!>) val b2 = 1
|
||||||
|
|
||||||
|
|||||||
@@ -1,6 +1,9 @@
|
|||||||
package
|
package
|
||||||
|
|
||||||
public val a1: kotlin.Int = 0
|
public val a1: kotlin.Int = 0
|
||||||
|
public val a10: kotlin.Float = Infinity.toFloat()
|
||||||
|
public val a11: kotlin.Double = Infinity.toDouble()
|
||||||
|
public val a12: kotlin.Long
|
||||||
public val a2: kotlin.Int
|
public val a2: kotlin.Int
|
||||||
public val a3: kotlin.Int
|
public val a3: kotlin.Int
|
||||||
public val a4: kotlin.Int
|
public val a4: kotlin.Int
|
||||||
@@ -19,3 +22,4 @@ public final annotation class Ann : kotlin.Annotation {
|
|||||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
+6
@@ -167,6 +167,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
|||||||
token,
|
token,
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
add(FirErrors.DIVISION_BY_ZERO) { firDiagnostic ->
|
||||||
|
DivisionByZeroImpl(
|
||||||
|
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),
|
||||||
|
|||||||
+4
@@ -136,6 +136,10 @@ sealed class KtFirDiagnostic<PSI: PsiElement> : KtDiagnosticWithPsi<PSI> {
|
|||||||
override val diagnosticClass get() = WrongLongSuffix::class
|
override val diagnosticClass get() = WrongLongSuffix::class
|
||||||
}
|
}
|
||||||
|
|
||||||
|
abstract class DivisionByZero : KtFirDiagnostic<KtExpression>() {
|
||||||
|
override val diagnosticClass get() = DivisionByZero::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
|
||||||
|
|||||||
+7
@@ -194,6 +194,13 @@ internal class WrongLongSuffixImpl(
|
|||||||
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
internal class DivisionByZeroImpl(
|
||||||
|
firDiagnostic: FirPsiDiagnostic<*>,
|
||||||
|
override val token: ValidityToken,
|
||||||
|
) : KtFirDiagnostic.DivisionByZero(), KtAbstractFirDiagnostic<KtExpression> {
|
||||||
|
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<*>,
|
||||||
|
|||||||
Reference in New Issue
Block a user