diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt index f03de538130..ff80304e680 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/DiagnosticData.kt @@ -58,7 +58,7 @@ enum class PositioningStrategy(private val strategy: String? = null) { RETURN_WITH_LABEL, INT_LITERAL_OUT_OF_RANGE, FLOAT_LITERAL_OUT_OF_RANGE, - LONG_LITERAL_SUFFIX, + LONG_LITERAL_SUFFIX ; diff --git a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt index c2182300d73..0575d5d1ec7 100644 --- a/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt +++ b/compiler/fir/checkers/checkers-component-generator/src/org/jetbrains/kotlin/fir/checkers/generator/diagnostics/FirDiagnosticsList.kt @@ -64,6 +64,7 @@ object DIAGNOSTICS_LIST : DiagnosticList() { val INT_LITERAL_OUT_OF_RANGE by error() val FLOAT_LITERAL_OUT_OF_RANGE by error() val WRONG_LONG_SUFFIX by error(PositioningStrategy.LONG_LITERAL_SUFFIX) + val DIVISION_BY_ZERO by warning() } val UNRESOLVED by object : DiagnosticGroup("Unresolved") { diff --git a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt index 4aefe91be30..b47dd83c477 100644 --- a/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt +++ b/compiler/fir/checkers/gen/org/jetbrains/kotlin/fir/analysis/diagnostics/FirErrors.kt @@ -89,6 +89,7 @@ object FirErrors { val INT_LITERAL_OUT_OF_RANGE by error0() val FLOAT_LITERAL_OUT_OF_RANGE by error0() val WRONG_LONG_SUFFIX by error0(SourceElementPositioningStrategies.LONG_LITERAL_SUFFIX) + val DIVISION_BY_ZERO by warning0() // Unresolved val HIDDEN by error1>(SourceElementPositioningStrategies.REFERENCE_BY_QUALIFIED) diff --git a/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDivisionByZeroChecker.kt b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDivisionByZeroChecker.kt new file mode 100644 index 00000000000..7fcaff01558 --- /dev/null +++ b/compiler/fir/checkers/src/org/jetbrains/kotlin/fir/analysis/checkers/expression/FirDivisionByZeroChecker.kt @@ -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) + } + } + } +} \ No newline at end of file diff --git a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt index 290ae0a9743..a8fc29a2f63 100644 --- a/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt +++ b/compiler/fir/entrypoint/src/org/jetbrains/kotlin/fir/checkers/CommonExpressionCheckers.kt @@ -32,6 +32,7 @@ object CommonExpressionCheckers : ExpressionCheckers() { override val functionCallCheckers: Set = setOf( FirConventionFunctionCallChecker, + FirDivisionByZeroChecker ) override val tryExpressionCheckers: Set = setOf( diff --git a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt index ba7ed885f91..41bae7baf83 100644 --- a/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt +++ b/compiler/fir/raw-fir/psi2fir/src/org/jetbrains/kotlin/fir/builder/RawFirBuilder.kt @@ -1217,7 +1217,8 @@ open class RawFirBuilder( this.source = source constructedTypeRef = delegatedType.copyWithNewSourceKind(FirFakeSourceElementKind.ImplicitTypeRef) 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) ?: source.fakeElement(calleeKind) this.calleeReference = if (isThis) { diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt index 4e31748b737..532aac7e625 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/argumentsOfAnnotation.fir.kt @@ -15,7 +15,7 @@ fun test3() {} @Foo(c = [1f], b = [""], a = [1]) fun test4() {} -@Foo([1 + 2], ["Hello, " + "Kotlin"], [1 / 0f]) +@Foo([1 + 2], ["Hello, " + "Kotlin"], [1 / 0f]) fun test5() {} const val ONE = 1 diff --git a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt index a49fcf77409..6585f71592a 100644 --- a/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt +++ b/compiler/testData/diagnostics/tests/collectionLiterals/collectionLiteralsWithVarargs.fir.kt @@ -23,7 +23,7 @@ fun test1_2() {} @Ann2(*[]) fun test2() {} -@Ann3(a = *[0f, 1 / 0f]) +@Ann3(a = *[0f, 1 / 0f]) fun test3() {} @Ann5(Ann4(*["/"])) diff --git a/compiler/testData/diagnostics/tests/evaluate/divisionByZero.fir.kt b/compiler/testData/diagnostics/tests/evaluate/divisionByZero.fir.kt index 3f87f1f39a9..f99b1402648 100644 --- a/compiler/testData/diagnostics/tests/evaluate/divisionByZero.fir.kt +++ b/compiler/testData/diagnostics/tests/evaluate/divisionByZero.fir.kt @@ -2,17 +2,21 @@ // !WITH_NEW_INFERENCE val a1 = 0 -val a2 = 1 / 0 +val a2 = 1 / 0 val a3 = 1 / a1 val a4 = 1 / a2 -val a5 = 2 * (1 / 0) +val a5 = 2 * (1 / 0) -val a6 = 1.div(0) +val a6 = 1.div(0) val a7 = 1.div(a1) val a8 = 1.div(a2) -val a9 = 2 * (1.div(0)) +val a9 = 2 * (1.div(0)) -val b1: Byte = 1 / 0 -@Ann(1 / 0) val b2 = 1 +val a10 = 1 / 0.0f +val a11 = 1 / 0.0 +val a12 = 1L / 0 -annotation class Ann(val i : Int) \ No newline at end of file +val b1: Byte = 1 / 0 +@Ann(1 / 0) val b2 = 1 + +annotation class Ann(val i : Int) diff --git a/compiler/testData/diagnostics/tests/evaluate/divisionByZero.kt b/compiler/testData/diagnostics/tests/evaluate/divisionByZero.kt index f58114b824e..96e181a510f 100644 --- a/compiler/testData/diagnostics/tests/evaluate/divisionByZero.kt +++ b/compiler/testData/diagnostics/tests/evaluate/divisionByZero.kt @@ -12,6 +12,10 @@ val a7 = 1.div(a1) val a8 = 1.div(a2) val a9 = 2 * (1.div(0)) +val a10 = 1 / 0.0f +val a11 = 1 / 0.0 +val a12 = 1L / 0 + val b1: Byte = 1 / 0 @Ann(1 / 0) val b2 = 1 diff --git a/compiler/testData/diagnostics/tests/evaluate/divisionByZero.txt b/compiler/testData/diagnostics/tests/evaluate/divisionByZero.txt index 76bd7a68056..8b82c013745 100644 --- a/compiler/testData/diagnostics/tests/evaluate/divisionByZero.txt +++ b/compiler/testData/diagnostics/tests/evaluate/divisionByZero.txt @@ -1,6 +1,9 @@ package 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 a3: 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 toString(): kotlin.String } + diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt index d22b0a3ca90..3258521c4b1 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDataClassConverters.kt @@ -167,6 +167,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert token, ) } + add(FirErrors.DIVISION_BY_ZERO) { firDiagnostic -> + DivisionByZeroImpl( + firDiagnostic as FirPsiDiagnostic<*>, + token, + ) + } add(FirErrors.HIDDEN) { firDiagnostic -> HiddenImpl( firSymbolBuilder.buildSymbol(firDiagnostic.a.fir as FirDeclaration), diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt index 7e7682a6f7b..446d85e68a2 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnostics.kt @@ -136,6 +136,10 @@ sealed class KtFirDiagnostic : KtDiagnosticWithPsi { override val diagnosticClass get() = WrongLongSuffix::class } + abstract class DivisionByZero : KtFirDiagnostic() { + override val diagnosticClass get() = DivisionByZero::class + } + abstract class Hidden : KtFirDiagnostic() { override val diagnosticClass get() = Hidden::class abstract val hidden: KtSymbol diff --git a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt index e0251c1a87c..3a077237440 100644 --- a/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt +++ b/idea/idea-frontend-fir/src/org/jetbrains/kotlin/idea/frontend/api/fir/diagnostics/KtFirDiagnosticsImpl.kt @@ -194,6 +194,13 @@ internal class WrongLongSuffixImpl( override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) } +internal class DivisionByZeroImpl( + firDiagnostic: FirPsiDiagnostic<*>, + override val token: ValidityToken, +) : KtFirDiagnostic.DivisionByZero(), KtAbstractFirDiagnostic { + override val firDiagnostic: FirPsiDiagnostic<*> by weakRef(firDiagnostic) +} + internal class HiddenImpl( override val hidden: KtSymbol, firDiagnostic: FirPsiDiagnostic<*>,