FIR: support CONDITION_TYPE_MISMATCH diagnostic
We report CONDITION_TYPE_MISMATCH on - loop conditions - when branch conditions - binary logic arguments
This commit is contained in:
+2
-2
@@ -101,9 +101,9 @@ fun test(
|
||||
for (i in <!HAS_NEXT_MISSING, NEXT_MISSING!>notRange2<!>);
|
||||
for (i in <!NEXT_MISSING!>notRange3<!>);
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange4<!>);
|
||||
for (i in notRange5);
|
||||
<!CONDITION_TYPE_MISMATCH!>for (i in notRange5)<!>;
|
||||
for (i in notRange6);
|
||||
for (i in notRange7);
|
||||
<!CONDITION_TYPE_MISMATCH!>for (i in notRange7)<!>;
|
||||
for (i in <!HAS_NEXT_MISSING!>notRange8<!>);
|
||||
for (i in <!OPERATOR_MODIFIER_REQUIRED, OPERATOR_MODIFIER_REQUIRED, OPERATOR_MODIFIER_REQUIRED!>notRange9<!>);
|
||||
for (i in range0);
|
||||
|
||||
+2
@@ -28,6 +28,8 @@ fun main(args: Array<String>) {
|
||||
alias<FirVariableAssignment>("VariableAssignmentChecker")
|
||||
alias<FirTryExpression>("TryExpressionChecker")
|
||||
alias<FirWhenExpression>("WhenExpressionChecker")
|
||||
alias<FirLoop>("LoopExpressionChecker")
|
||||
alias<FirBinaryLogicExpression>("LogicExpressionChecker")
|
||||
alias<FirReturnExpression>("ReturnExpressionChecker")
|
||||
alias<FirBlock>("BlockChecker")
|
||||
alias<FirAnnotationCall>("AnnotationCallChecker")
|
||||
|
||||
+8
@@ -25,6 +25,10 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _tryExpressionCheckers
|
||||
override val whenExpressionCheckers: Set<FirWhenExpressionChecker>
|
||||
get() = _whenExpressionCheckers
|
||||
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
|
||||
get() = _loopExpressionCheckers
|
||||
override val logicExpressionCheckers: Set<FirLogicExpressionChecker>
|
||||
get() = _logicExpressionCheckers
|
||||
override val returnExpressionCheckers: Set<FirReturnExpressionChecker>
|
||||
get() = _returnExpressionCheckers
|
||||
override val blockCheckers: Set<FirBlockChecker>
|
||||
@@ -56,6 +60,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
private val _variableAssignmentCheckers: MutableSet<FirVariableAssignmentChecker> = mutableSetOf()
|
||||
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = mutableSetOf()
|
||||
private val _whenExpressionCheckers: MutableSet<FirWhenExpressionChecker> = mutableSetOf()
|
||||
private val _loopExpressionCheckers: MutableSet<FirLoopExpressionChecker> = mutableSetOf()
|
||||
private val _logicExpressionCheckers: MutableSet<FirLogicExpressionChecker> = mutableSetOf()
|
||||
private val _returnExpressionCheckers: MutableSet<FirReturnExpressionChecker> = mutableSetOf()
|
||||
private val _blockCheckers: MutableSet<FirBlockChecker> = mutableSetOf()
|
||||
private val _annotationCallCheckers: MutableSet<FirAnnotationCallChecker> = mutableSetOf()
|
||||
@@ -77,6 +83,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
_variableAssignmentCheckers += checkers.variableAssignmentCheckers
|
||||
_tryExpressionCheckers += checkers.tryExpressionCheckers
|
||||
_whenExpressionCheckers += checkers.whenExpressionCheckers
|
||||
_loopExpressionCheckers += checkers.loopExpressionCheckers
|
||||
_logicExpressionCheckers += checkers.logicExpressionCheckers
|
||||
_returnExpressionCheckers += checkers.returnExpressionCheckers
|
||||
_blockCheckers += checkers.blockCheckers
|
||||
_annotationCallCheckers += checkers.annotationCallCheckers
|
||||
|
||||
+4
@@ -23,6 +23,8 @@ abstract class ExpressionCheckers {
|
||||
open val variableAssignmentCheckers: Set<FirVariableAssignmentChecker> = emptySet()
|
||||
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
|
||||
open val whenExpressionCheckers: Set<FirWhenExpressionChecker> = emptySet()
|
||||
open val loopExpressionCheckers: Set<FirLoopExpressionChecker> = emptySet()
|
||||
open val logicExpressionCheckers: Set<FirLogicExpressionChecker> = emptySet()
|
||||
open val returnExpressionCheckers: Set<FirReturnExpressionChecker> = emptySet()
|
||||
open val blockCheckers: Set<FirBlockChecker> = emptySet()
|
||||
open val annotationCallCheckers: Set<FirAnnotationCallChecker> = emptySet()
|
||||
@@ -42,6 +44,8 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allVariableAssignmentCheckers: Set<FirVariableAssignmentChecker> get() = variableAssignmentCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> get() = tryExpressionCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> get() = whenExpressionCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allLoopExpressionCheckers: Set<FirLoopExpressionChecker> get() = loopExpressionCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allLogicExpressionCheckers: Set<FirLogicExpressionChecker> get() = logicExpressionCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allReturnExpressionCheckers: Set<FirReturnExpressionChecker> get() = returnExpressionCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allBlockCheckers: Set<FirBlockChecker> get() = blockCheckers + basicExpressionCheckers
|
||||
@CheckersComponentInternal internal val allAnnotationCallCheckers: Set<FirAnnotationCallChecker> get() = annotationCallCheckers + basicExpressionCheckers
|
||||
|
||||
+4
@@ -12,12 +12,14 @@ package org.jetbrains.kotlin.fir.analysis.checkers.expression
|
||||
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.FirAnnotationCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBlock
|
||||
import org.jetbrains.kotlin.fir.expressions.FirCheckNotNullCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirElvisExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirEqualityOperatorCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirFunctionCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirGetClassCall
|
||||
import org.jetbrains.kotlin.fir.expressions.FirLoop
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
import org.jetbrains.kotlin.fir.expressions.FirReturnExpression
|
||||
@@ -35,6 +37,8 @@ typealias FirFunctionCallChecker = FirExpressionChecker<FirFunctionCall>
|
||||
typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignment>
|
||||
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>
|
||||
typealias FirWhenExpressionChecker = FirExpressionChecker<FirWhenExpression>
|
||||
typealias FirLoopExpressionChecker = FirExpressionChecker<FirLoop>
|
||||
typealias FirLogicExpressionChecker = FirExpressionChecker<FirBinaryLogicExpression>
|
||||
typealias FirReturnExpressionChecker = FirExpressionChecker<FirReturnExpression>
|
||||
typealias FirBlockChecker = FirExpressionChecker<FirBlock>
|
||||
typealias FirAnnotationCallChecker = FirExpressionChecker<FirAnnotationCall>
|
||||
|
||||
@@ -568,4 +568,13 @@ fun checkTypeMismatch(
|
||||
reporter.report(diagnosticFactory.on(source, lValueType, rValueType), context)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
internal fun checkCondition(condition: FirExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val coneType = condition.typeRef.coneType.lowerBoundIfFlexible()
|
||||
if (coneType !is ConeKotlinErrorType &&
|
||||
!coneType.isSubtypeOf(context.session.typeContext, context.session.builtinTypes.booleanType.type)
|
||||
) {
|
||||
reporter.reportOn(condition.source, FirErrors.CONDITION_TYPE_MISMATCH, coneType, context)
|
||||
}
|
||||
}
|
||||
|
||||
+18
@@ -0,0 +1,18 @@
|
||||
/*
|
||||
* 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.checkCondition
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.expressions.FirBinaryLogicExpression
|
||||
|
||||
object FirLogicExpressionTypeChecker : FirLogicExpressionChecker() {
|
||||
override fun check(expression: FirBinaryLogicExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
checkCondition(expression.leftOperand, context, reporter)
|
||||
checkCondition(expression.rightOperand, context, reporter)
|
||||
}
|
||||
}
|
||||
+23
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* 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.checkCondition
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
||||
import org.jetbrains.kotlin.fir.expressions.FirErrorLoop
|
||||
import org.jetbrains.kotlin.fir.expressions.FirLoop
|
||||
|
||||
object FirLoopConditionChecker : FirLoopExpressionChecker() {
|
||||
override fun check(expression: FirLoop, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
if (expression is FirErrorLoop) return
|
||||
val condition = expression.condition
|
||||
withSuppressedDiagnostics(condition, context) {
|
||||
checkCondition(condition, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
+25
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* 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.checkCondition
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.withSuppressedDiagnostics
|
||||
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.impl.FirElseIfTrueCondition
|
||||
|
||||
object FirWhenConditionChecker : FirWhenExpressionChecker() {
|
||||
override fun check(expression: FirWhenExpression, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
for (branch in expression.branches) {
|
||||
val condition = branch.condition
|
||||
if (condition is FirElseIfTrueCondition) continue
|
||||
withSuppressedDiagnostics(condition, context) {
|
||||
checkCondition(condition, context, reporter)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+13
-2
@@ -11,7 +11,6 @@ import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.ExpressionCheckers
|
||||
import org.jetbrains.kotlin.fir.analysis.checkers.expression.FirExpressionChecker
|
||||
import org.jetbrains.kotlin.fir.analysis.checkersComponent
|
||||
import org.jetbrains.kotlin.fir.analysis.collectors.AbstractDiagnosticCollector
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
|
||||
import org.jetbrains.kotlin.fir.declarations.FirAnonymousFunction
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
@@ -63,8 +62,20 @@ class ExpressionCheckersDiagnosticComponent(
|
||||
checkers.allWhenExpressionCheckers.check(whenExpression, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitWhileLoop(whileLoop: FirWhileLoop, data: CheckerContext) {
|
||||
checkers.allLoopExpressionCheckers.check(whileLoop, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitDoWhileLoop(doWhileLoop: FirDoWhileLoop, data: CheckerContext) {
|
||||
checkers.allLoopExpressionCheckers.check(doWhileLoop, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitErrorLoop(errorLoop: FirErrorLoop, data: CheckerContext) {
|
||||
checkers.allLoopExpressionCheckers.check(errorLoop, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitBinaryLogicExpression(binaryLogicExpression: FirBinaryLogicExpression, data: CheckerContext) {
|
||||
checkers.allBasicExpressionCheckers.check(binaryLogicExpression, data, reporter)
|
||||
checkers.allLogicExpressionCheckers.check(binaryLogicExpression, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitArrayOfCall(arrayOfCall: FirArrayOfCall, data: CheckerContext) {
|
||||
|
||||
+12
-1
@@ -56,7 +56,18 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
|
||||
override val whenExpressionCheckers: Set<FirWhenExpressionChecker>
|
||||
get() = setOf(
|
||||
FirExhaustiveWhenChecker
|
||||
FirExhaustiveWhenChecker,
|
||||
FirWhenConditionChecker,
|
||||
)
|
||||
|
||||
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
|
||||
get() = setOf(
|
||||
FirLoopConditionChecker,
|
||||
)
|
||||
|
||||
override val logicExpressionCheckers: Set<FirLogicExpressionChecker>
|
||||
get() = setOf(
|
||||
FirLogicExpressionTypeChecker,
|
||||
)
|
||||
|
||||
override val returnExpressionCheckers: Set<FirReturnExpressionChecker>
|
||||
|
||||
Reference in New Issue
Block a user