[FIR] Prohibit confusing syntax inside when branches

^KT-48385
This commit is contained in:
Dmitriy Novozhilov
2021-10-21 14:50:14 +03:00
committed by teamcityserver
parent bf453674b9
commit 94664694df
22 changed files with 280 additions and 262 deletions
@@ -5,64 +5,13 @@
package org.jetbrains.kotlin.analysis.api.fir.diagnostics package org.jetbrains.kotlin.analysis.api.fir.diagnostics
import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic import org.jetbrains.kotlin.fir.analysis.diagnostics.FirPsiDiagnostic
import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors import org.jetbrains.kotlin.fir.analysis.diagnostics.jvm.FirJvmErrors
import org.jetbrains.kotlin.fir.declarations.FirCallableDeclaration
import org.jetbrains.kotlin.fir.declarations.FirClass import org.jetbrains.kotlin.fir.declarations.FirClass
import org.jetbrains.kotlin.fir.declarations.FirDeclaration
import org.jetbrains.kotlin.fir.declarations.FirProperty
import org.jetbrains.kotlin.fir.declarations.FirRegularClass
import org.jetbrains.kotlin.fir.declarations.FirSimpleFunction
import org.jetbrains.kotlin.fir.declarations.FirTypeParameter
import org.jetbrains.kotlin.fir.declarations.FirVariable
import org.jetbrains.kotlin.fir.psi import org.jetbrains.kotlin.fir.psi
import org.jetbrains.kotlin.psi.KtAnnotationEntry
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBackingField
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.KtConstructorDelegationCall
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtExpression import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtVariableDeclaration
import org.jetbrains.kotlin.psi.KtWhenCondition
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
/* /*
* This file was generated automatically * This file was generated automatically
@@ -3157,6 +3106,18 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
token, token,
) )
} }
add(FirErrors.CONFUSING_BRANCH_CONDITION.errorFactory) { firDiagnostic ->
ConfusingBranchConditionErrorImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.CONFUSING_BRANCH_CONDITION.warningFactory) { firDiagnostic ->
ConfusingBranchConditionWarningImpl(
firDiagnostic as FirPsiDiagnostic,
token,
)
}
add(FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION) { firDiagnostic -> add(FirErrors.TYPE_PARAMETER_IS_NOT_AN_EXPRESSION) { firDiagnostic ->
TypeParameterIsNotAnExpressionImpl( TypeParameterIsNotAnExpressionImpl(
firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir), firSymbolBuilder.classifierBuilder.buildTypeParameterSymbol(firDiagnostic.a.fir),
@@ -8,13 +8,7 @@ package org.jetbrains.kotlin.analysis.api.fir.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi import org.jetbrains.kotlin.analysis.api.diagnostics.KtDiagnosticWithPsi
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableSymbol
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageVersionSettings import org.jetbrains.kotlin.config.LanguageVersionSettings
@@ -30,49 +24,7 @@ import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBackingField
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.KtConstructorDelegationCall
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtVariableDeclaration
import org.jetbrains.kotlin.psi.KtWhenCondition
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
@@ -2203,6 +2155,14 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
override val diagnosticClass get() = DuplicateLabelInWhen::class override val diagnosticClass get() = DuplicateLabelInWhen::class
} }
abstract class ConfusingBranchConditionError : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ConfusingBranchConditionError::class
}
abstract class ConfusingBranchConditionWarning : KtFirDiagnostic<PsiElement>() {
override val diagnosticClass get() = ConfusingBranchConditionWarning::class
}
abstract class TypeParameterIsNotAnExpression : KtFirDiagnostic<KtSimpleNameExpression>() { abstract class TypeParameterIsNotAnExpression : KtFirDiagnostic<KtSimpleNameExpression>() {
override val diagnosticClass get() = TypeParameterIsNotAnExpression::class override val diagnosticClass get() = TypeParameterIsNotAnExpression::class
abstract val typeParameter: KtTypeParameterSymbol abstract val typeParameter: KtTypeParameterSymbol
@@ -7,13 +7,7 @@ package org.jetbrains.kotlin.analysis.api.fir.diagnostics
import com.intellij.psi.PsiElement import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.analysis.api.symbols.KtCallableSymbol import org.jetbrains.kotlin.analysis.api.symbols.*
import org.jetbrains.kotlin.analysis.api.symbols.KtClassLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtFunctionLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtTypeParameterSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableLikeSymbol
import org.jetbrains.kotlin.analysis.api.symbols.KtVariableSymbol
import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken import org.jetbrains.kotlin.analysis.api.tokens.ValidityToken
import org.jetbrains.kotlin.analysis.api.types.KtType import org.jetbrains.kotlin.analysis.api.types.KtType
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
@@ -31,49 +25,7 @@ import org.jetbrains.kotlin.name.CallableId
import org.jetbrains.kotlin.name.ClassId import org.jetbrains.kotlin.name.ClassId
import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.FqName
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.KtAnnotationEntry import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.psi.KtAnonymousInitializer
import org.jetbrains.kotlin.psi.KtArrayAccessExpression
import org.jetbrains.kotlin.psi.KtBackingField
import org.jetbrains.kotlin.psi.KtBinaryExpression
import org.jetbrains.kotlin.psi.KtBinaryExpressionWithTypeRHS
import org.jetbrains.kotlin.psi.KtCallExpression
import org.jetbrains.kotlin.psi.KtClass
import org.jetbrains.kotlin.psi.KtClassOrObject
import org.jetbrains.kotlin.psi.KtConstructor
import org.jetbrains.kotlin.psi.KtConstructorDelegationCall
import org.jetbrains.kotlin.psi.KtDeclaration
import org.jetbrains.kotlin.psi.KtDeclarationWithBody
import org.jetbrains.kotlin.psi.KtDelegatedSuperTypeEntry
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtElement
import org.jetbrains.kotlin.psi.KtEnumEntry
import org.jetbrains.kotlin.psi.KtExpression
import org.jetbrains.kotlin.psi.KtExpressionWithLabel
import org.jetbrains.kotlin.psi.KtFunction
import org.jetbrains.kotlin.psi.KtIfExpression
import org.jetbrains.kotlin.psi.KtImportDirective
import org.jetbrains.kotlin.psi.KtModifierListOwner
import org.jetbrains.kotlin.psi.KtNameReferenceExpression
import org.jetbrains.kotlin.psi.KtNamedDeclaration
import org.jetbrains.kotlin.psi.KtNamedFunction
import org.jetbrains.kotlin.psi.KtObjectDeclaration
import org.jetbrains.kotlin.psi.KtParameter
import org.jetbrains.kotlin.psi.KtPrimaryConstructor
import org.jetbrains.kotlin.psi.KtProperty
import org.jetbrains.kotlin.psi.KtPropertyAccessor
import org.jetbrains.kotlin.psi.KtReturnExpression
import org.jetbrains.kotlin.psi.KtSimpleNameExpression
import org.jetbrains.kotlin.psi.KtSuperExpression
import org.jetbrains.kotlin.psi.KtTypeAlias
import org.jetbrains.kotlin.psi.KtTypeParameter
import org.jetbrains.kotlin.psi.KtTypeProjection
import org.jetbrains.kotlin.psi.KtTypeReference
import org.jetbrains.kotlin.psi.KtValueArgument
import org.jetbrains.kotlin.psi.KtVariableDeclaration
import org.jetbrains.kotlin.psi.KtWhenCondition
import org.jetbrains.kotlin.psi.KtWhenEntry
import org.jetbrains.kotlin.psi.KtWhenExpression
import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget import org.jetbrains.kotlin.resolve.ForbiddenNamedArgumentsTarget
import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo import org.jetbrains.kotlin.resolve.deprecation.DeprecationInfo
import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible import org.jetbrains.kotlin.resolve.multiplatform.ExpectActualCompatibility.Incompatible
@@ -2655,6 +2607,16 @@ internal class DuplicateLabelInWhenImpl(
override val token: ValidityToken, override val token: ValidityToken,
) : KtFirDiagnostic.DuplicateLabelInWhen(), KtAbstractFirDiagnostic<KtElement> ) : KtFirDiagnostic.DuplicateLabelInWhen(), KtAbstractFirDiagnostic<KtElement>
internal class ConfusingBranchConditionErrorImpl(
override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.ConfusingBranchConditionError(), KtAbstractFirDiagnostic<PsiElement>
internal class ConfusingBranchConditionWarningImpl(
override val firDiagnostic: FirPsiDiagnostic,
override val token: ValidityToken,
) : KtFirDiagnostic.ConfusingBranchConditionWarning(), KtAbstractFirDiagnostic<PsiElement>
internal class TypeParameterIsNotAnExpressionImpl( internal class TypeParameterIsNotAnExpressionImpl(
override val typeParameter: KtTypeParameterSymbol, override val typeParameter: KtTypeParameterSymbol,
override val firDiagnostic: FirPsiDiagnostic, override val firDiagnostic: FirPsiDiagnostic,
@@ -1117,6 +1117,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
} }
val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error<PsiElement>(PositioningStrategy.COMMAS) val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error<PsiElement>(PositioningStrategy.COMMAS)
val DUPLICATE_LABEL_IN_WHEN by warning<KtElement>() val DUPLICATE_LABEL_IN_WHEN by warning<KtElement>()
val CONFUSING_BRANCH_CONDITION by deprecationError<PsiElement>(LanguageFeature.ProhibitConfusingSyntaxInWhenBranches)
} }
val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") { val CONTEXT_TRACKING by object : DiagnosticGroup("Context tracking") {
@@ -9,6 +9,7 @@ import com.intellij.psi.PsiElement
import com.intellij.psi.impl.source.tree.LeafPsiElement import com.intellij.psi.impl.source.tree.LeafPsiElement
import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageFeature
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm import org.jetbrains.kotlin.config.LanguageFeature.ProhibitAssigningSingleElementsToVarargsInNamedForm
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitConfusingSyntaxInWhenBranches
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses import org.jetbrains.kotlin.config.LanguageFeature.ProhibitInvisibleAbstractMethodsInSuperclasses
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments import org.jetbrains.kotlin.config.LanguageFeature.ProhibitNonReifiedArraysAsReifiedTypeArguments
import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes import org.jetbrains.kotlin.config.LanguageFeature.ProhibitUseSiteTargetAnnotationsOnSuperTypes
@@ -596,6 +597,7 @@ object FirErrors {
val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>() val ILLEGAL_DECLARATION_IN_WHEN_SUBJECT by error1<KtElement, String>()
val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error0<PsiElement>(SourceElementPositioningStrategies.COMMAS) val COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT by error0<PsiElement>(SourceElementPositioningStrategies.COMMAS)
val DUPLICATE_LABEL_IN_WHEN by warning0<KtElement>() val DUPLICATE_LABEL_IN_WHEN by warning0<KtElement>()
val CONFUSING_BRANCH_CONDITION by deprecationError0<PsiElement>(ProhibitConfusingSyntaxInWhenBranches)
// Context tracking // Context tracking
val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>() val TYPE_PARAMETER_IS_NOT_AN_EXPRESSION by error1<KtSimpleNameExpression, FirTypeParameterSymbol>()
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.fir.analysis.checkers
import org.jetbrains.kotlin.fir.analysis.checkers.expression.* import org.jetbrains.kotlin.fir.analysis.checkers.expression.*
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirCommaInWhenConditionChecker import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirCommaInWhenConditionChecker
import org.jetbrains.kotlin.fir.analysis.checkers.syntax.FirConfusingWhenBranchSyntaxChecker
object CommonExpressionCheckers : ExpressionCheckers() { object CommonExpressionCheckers : ExpressionCheckers() {
override val annotationCallCheckers: Set<FirAnnotationCallChecker> override val annotationCallCheckers: Set<FirAnnotationCallChecker>
@@ -77,6 +78,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
FirWhenConditionChecker, FirWhenConditionChecker,
FirWhenSubjectChecker, FirWhenSubjectChecker,
FirCommaInWhenConditionChecker, FirCommaInWhenConditionChecker,
FirConfusingWhenBranchSyntaxChecker,
) )
override val loopExpressionCheckers: Set<FirLoopExpressionChecker> override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
@@ -0,0 +1,118 @@
/*
* 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.syntax
import com.intellij.lang.LighterASTNode
import com.intellij.psi.PsiElement
import com.intellij.psi.tree.TokenSet
import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.ElementTypeUtils.getOperationSymbol
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.fir.FirLightSourceElement
import org.jetbrains.kotlin.fir.FirPsiSourceElement
import org.jetbrains.kotlin.fir.FirRealPsiSourceElement
import org.jetbrains.kotlin.fir.FirSourceElement
import org.jetbrains.kotlin.fir.analysis.checkers.context.CheckerContext
import org.jetbrains.kotlin.fir.analysis.checkers.getChildren
import org.jetbrains.kotlin.fir.analysis.diagnostics.DiagnosticReporter
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors
import org.jetbrains.kotlin.fir.analysis.diagnostics.isExpression
import org.jetbrains.kotlin.fir.analysis.diagnostics.reportOn
import org.jetbrains.kotlin.fir.expressions.FirWhenExpression
import org.jetbrains.kotlin.lexer.KtTokens.*
import org.jetbrains.kotlin.psi.*
object FirConfusingWhenBranchSyntaxChecker : FirExpressionSyntaxChecker<FirWhenExpression, PsiElement>() {
private val prohibitedTokens = TokenSet.create(
IN_KEYWORD, NOT_IN,
LT, LTEQ, GT, GTEQ,
EQEQ, EXCLEQ, EQEQEQ, EXCLEQEQEQ,
ANDAND, OROR
)
override fun checkLightTree(
element: FirWhenExpression,
source: FirSourceElement,
context: CheckerContext,
reporter: DiagnosticReporter
) {
if (element.subject == null && element.subjectVariable == null) return
val tree = source.treeStructure
val entries = source.lighterASTNode.getChildren(tree).filter { it.tokenType == WHEN_ENTRY }
val offset = source.startOffset - source.lighterASTNode.startOffset
for (entry in entries) {
for (node in entry.getChildren(tree)) {
val expression = when (node.tokenType) {
WHEN_CONDITION_EXPRESSION -> node.getChildren(tree).firstOrNull { it.isExpression() }
WHEN_CONDITION_IN_RANGE -> node.getChildren(tree)
.firstOrNull { it.tokenType != OPERATION_REFERENCE && it.isExpression()}
else -> null
} ?: continue
checkConditionExpression(offset, expression, tree, context, reporter)
}
}
}
private fun checkConditionExpression(
offset: Int,
expression: LighterASTNode,
tree: FlyweightCapableTreeStructure<LighterASTNode>,
context: CheckerContext,
reporter: DiagnosticReporter
) {
val shouldReport = when (expression.tokenType) {
IS_EXPRESSION -> true
BINARY_EXPRESSION -> {
val operationTokenName = expression.getChildren(tree).first { it.tokenType == OPERATION_REFERENCE }.toString()
val operationToken = operationTokenName.getOperationSymbol()
operationToken in prohibitedTokens
}
else -> false
}
if (shouldReport) {
val source = FirLightSourceElement(expression, offset + expression.startOffset, offset + expression.endOffset, tree)
reporter.reportOn(source, FirErrors.CONFUSING_BRANCH_CONDITION, context)
}
}
override fun checkPsi(
element: FirWhenExpression,
source: FirPsiSourceElement,
psi: PsiElement,
context: CheckerContext,
reporter: DiagnosticReporter
) {
if (element.subject == null && element.subjectVariable == null) return
val whenExpression = psi as KtWhenExpression
if (whenExpression.subjectExpression == null && whenExpression.subjectVariable == null) return
for (entry in whenExpression.entries) {
for (condition in entry.conditions) {
checkCondition(condition, context, reporter)
}
}
}
private fun checkCondition(condition: KtWhenCondition, context: CheckerContext, reporter: DiagnosticReporter) {
when (condition) {
is KtWhenConditionWithExpression -> checkConditionExpression(condition.expression, context, reporter)
is KtWhenConditionInRange -> checkConditionExpression(condition.rangeExpression, context, reporter)
}
}
private fun checkConditionExpression(rawExpression: KtExpression?, context: CheckerContext, reporter: DiagnosticReporter) {
if (rawExpression == null) return
if (rawExpression is KtParenthesizedExpression) return
val shouldReport = when (val expression = KtPsiUtil.safeDeparenthesize(rawExpression)) {
is KtIsExpression -> true
is KtBinaryExpression -> expression.operationToken in prohibitedTokens
else -> false
}
if (shouldReport) {
val source = FirRealPsiSourceElement(rawExpression)
reporter.reportOn(source, FirErrors.CONFUSING_BRANCH_CONDITION, context)
}
}
}
@@ -107,6 +107,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_OVERL
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_PROJECTION_IN_TYPEALIAS_EXPANSION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_UPPER_BOUNDS import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFLICTING_UPPER_BOUNDS
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONFUSING_BRANCH_CONDITION
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_INTERFACE
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONSTRUCTOR_IN_OBJECT
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CONST_VAL_NOT_TOP_LEVEL_OR_OBJECT
@@ -1520,6 +1521,10 @@ class FirDefaultErrorMessages {
) )
map.put(COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT, "Deprecated syntax. Use '||' instead of commas in when-condition for 'when' without argument") map.put(COMMA_IN_WHEN_CONDITION_WITHOUT_ARGUMENT, "Deprecated syntax. Use '||' instead of commas in when-condition for 'when' without argument")
map.put(DUPLICATE_LABEL_IN_WHEN, "Duplicate label in when") map.put(DUPLICATE_LABEL_IN_WHEN, "Duplicate label in when")
map.put(
CONFUSING_BRANCH_CONDITION,
"The logical expressions may be understood ambiguously in when with subject branches. Please wrap it with parenthesis"
)
// Context tracking // Context tracking
map.put(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION, "Type parameter ''{0}'' is not an expression", SYMBOL) map.put(TYPE_PARAMETER_IS_NOT_AN_EXPRESSION, "Type parameter ''{0}'' is not an expression", SYMBOL)
@@ -10,6 +10,7 @@ import com.intellij.openapi.util.Ref
import com.intellij.psi.TokenType import com.intellij.psi.TokenType
import com.intellij.psi.tree.IElementType import com.intellij.psi.tree.IElementType
import com.intellij.util.diff.FlyweightCapableTreeStructure import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.ElementTypeUtils.isExpression
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.fir.* import org.jetbrains.kotlin.fir.*
import org.jetbrains.kotlin.fir.builder.BaseFirBuilder import org.jetbrains.kotlin.fir.builder.BaseFirBuilder
@@ -6,8 +6,6 @@
package org.jetbrains.kotlin.fir.lightTree.converter package org.jetbrains.kotlin.fir.lightTree.converter
import com.intellij.lang.LighterASTNode import com.intellij.lang.LighterASTNode
import com.intellij.psi.tree.IElementType
import org.jetbrains.kotlin.KtNodeType
import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
@@ -20,25 +18,16 @@ import org.jetbrains.kotlin.fir.declarations.builder.buildProperty
import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl import org.jetbrains.kotlin.fir.declarations.impl.FirDeclarationStatusImpl
import org.jetbrains.kotlin.fir.expressions.FirBlock import org.jetbrains.kotlin.fir.expressions.FirBlock
import org.jetbrains.kotlin.fir.expressions.FirExpression import org.jetbrains.kotlin.fir.expressions.FirExpression
import org.jetbrains.kotlin.fir.expressions.builder.* import org.jetbrains.kotlin.fir.expressions.builder.FirCallBuilder
import org.jetbrains.kotlin.fir.expressions.builder.buildArgumentList
import org.jetbrains.kotlin.fir.expressions.builder.buildBlock
import org.jetbrains.kotlin.fir.expressions.builder.buildComponentCall
import org.jetbrains.kotlin.fir.fakeElement import org.jetbrains.kotlin.fir.fakeElement
import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration import org.jetbrains.kotlin.fir.lightTree.fir.DestructuringDeclaration
import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol import org.jetbrains.kotlin.fir.symbols.impl.FirPropertySymbol
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.parsing.KotlinExpressionParsing
import org.jetbrains.kotlin.psi.KtPsiUtil import org.jetbrains.kotlin.psi.KtPsiUtil
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
import org.jetbrains.kotlin.psi.stubs.elements.KtStringTemplateExpressionElementType
private val expressionSet = listOf(
REFERENCE_EXPRESSION,
DOT_QUALIFIED_EXPRESSION,
LAMBDA_EXPRESSION,
FUN
)
fun String?.nameAsSafeName(defaultName: String = ""): Name { fun String?.nameAsSafeName(defaultName: String = ""): Name {
return when { return when {
@@ -48,28 +37,10 @@ fun String?.nameAsSafeName(defaultName: String = ""): Name {
} }
} }
fun String.getOperationSymbol(): IElementType {
KotlinExpressionParsing.ALL_OPERATIONS.types.forEach {
if (it is KtSingleValueToken && it.value == this) return it
}
if (this == "as?") return KtTokens.AS_SAFE
return KtTokens.IDENTIFIER
}
fun LighterASTNode.getAsStringWithoutBacktick(): String { fun LighterASTNode.getAsStringWithoutBacktick(): String {
return this.toString().replace("`", "") return this.toString().replace("`", "")
} }
fun LighterASTNode.isExpression(): Boolean {
return when (this.tokenType) {
is KtNodeType,
is KtConstantExpressionElementType,
is KtStringTemplateExpressionElementType,
in expressionSet -> true
else -> false
}
}
fun <T : FirCallBuilder> T.extractArgumentsFrom(container: List<FirExpression>): T { fun <T : FirCallBuilder> T.extractArgumentsFrom(container: List<FirExpression>): T {
argumentList = buildArgumentList { argumentList = buildArgumentList {
arguments += container arguments += container
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.fir.lightTree.converter
import com.intellij.lang.LighterASTNode import com.intellij.lang.LighterASTNode
import com.intellij.psi.TokenType import com.intellij.psi.TokenType
import com.intellij.util.diff.FlyweightCapableTreeStructure import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.ElementTypeUtils.isExpression
import org.jetbrains.kotlin.KtNodeTypes import org.jetbrains.kotlin.KtNodeTypes
import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.builtins.StandardNames import org.jetbrains.kotlin.builtins.StandardNames
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.fir.lightTree.converter
import com.intellij.lang.LighterASTNode import com.intellij.lang.LighterASTNode
import com.intellij.psi.TokenType import com.intellij.psi.TokenType
import com.intellij.util.diff.FlyweightCapableTreeStructure import com.intellij.util.diff.FlyweightCapableTreeStructure
import org.jetbrains.kotlin.ElementTypeUtils.getOperationSymbol
import org.jetbrains.kotlin.ElementTypeUtils.isExpression
import org.jetbrains.kotlin.KtNodeTypes.* import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
@@ -837,7 +839,7 @@ class ExpressionsConverter(
it.tokenType == OPERATION_REFERENCE -> { it.tokenType == OPERATION_REFERENCE -> {
conditionSource = it.toFirSourceElement() conditionSource = it.toFirSourceElement()
} }
else -> if (it.isExpression()) firExpression = getAsFirExpression(it) else -> if (it.isExpression()) firExpression = getAsFirExpression(it, "No range in condition with range")
} }
} }
@@ -5,9 +5,16 @@
package org.jetbrains.kotlin package org.jetbrains.kotlin
import com.intellij.lang.LighterASTNode
import com.intellij.psi.tree.IElementType
import com.intellij.psi.tree.IErrorCounterReparseableElementType import com.intellij.psi.tree.IErrorCounterReparseableElementType
import org.jetbrains.kotlin.KtNodeTypes.*
import org.jetbrains.kotlin.lexer.KotlinLexer import org.jetbrains.kotlin.lexer.KotlinLexer
import org.jetbrains.kotlin.lexer.KtSingleValueToken
import org.jetbrains.kotlin.lexer.KtTokens import org.jetbrains.kotlin.lexer.KtTokens
import org.jetbrains.kotlin.parsing.KotlinExpressionParsing
import org.jetbrains.kotlin.psi.stubs.elements.KtConstantExpressionElementType
import org.jetbrains.kotlin.psi.stubs.elements.KtStringTemplateExpressionElementType
object ElementTypeUtils { object ElementTypeUtils {
@JvmStatic @JvmStatic
@@ -32,4 +39,29 @@ object ElementTypeUtils {
} }
return balance return balance
} }
}
fun String.getOperationSymbol(): IElementType {
KotlinExpressionParsing.ALL_OPERATIONS.types.forEach {
if (it is KtSingleValueToken && it.value == this) return it
}
if (this == "as?") return KtTokens.AS_SAFE
return KtTokens.IDENTIFIER
}
private val expressionSet = listOf(
REFERENCE_EXPRESSION,
DOT_QUALIFIED_EXPRESSION,
LAMBDA_EXPRESSION,
FUN
)
fun LighterASTNode.isExpression(): Boolean {
return when (this.tokenType) {
is KtNodeType,
is KtConstantExpressionElementType,
is KtStringTemplateExpressionElementType,
in expressionSet -> true
else -> false
}
}
}
@@ -55,18 +55,18 @@ fun testWithSubject_ok(x: A, y: A?, any: Any, z: B) {
fun testWithSubject_bad_1(x: A) { fun testWithSubject_bad_1(x: A) {
// bad // bad
when (x) { when (x) {
x in x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x in x<!> -> {}
x !in x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x !in x<!> -> {}
x is String -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x is String<!> -> {}
x !is String -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x !is String<!> -> {}
x < x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x < x<!> -> {}
x > x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x > x<!> -> {}
x <= x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x <= x<!> -> {}
x >= x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x >= x<!> -> {}
x == x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x == x<!> -> {}
x != x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x != x<!> -> {}
x === x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x === x<!> -> {}
x !== x -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>x !== x<!> -> {}
} }
// ok // ok
when (x) { when (x) {
@@ -88,8 +88,8 @@ fun testWithSubject_bad_1(x: A) {
fun testWithSubject_bad_2(b: Boolean) { fun testWithSubject_bad_2(b: Boolean) {
// bad // bad
when (b) { when (b) {
b && b -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>b && b<!> -> {}
b || b -> {} <!CONFUSING_BRANCH_CONDITION_ERROR!>b || b<!> -> {}
} }
// ok // ok
when (b) { when (b) {
@@ -159,18 +159,18 @@ fun testWithRange_ok(x: A, y: A?, any: Any, z: B) {
fun testWithRange_bad_1(x: A) { fun testWithRange_bad_1(x: A) {
// bad // bad
when (x) { when (x) {
in x in x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x in x<!> -> {}
in x !in x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x !in x<!> -> {}
in x is String -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x is String<!> -> {}
in x !is String -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x !is String<!> -> {}
in x < x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x < x<!> -> {}
in x > x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x > x<!> -> {}
in x <= x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x <= x<!> -> {}
in x >= x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x >= x<!> -> {}
in x == x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x == x<!> -> {}
in x != x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x != x<!> -> {}
in x === x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x === x<!> -> {}
in x !== x -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>x !== x<!> -> {}
} }
// ok // ok
when (x) { when (x) {
@@ -192,8 +192,8 @@ fun testWithRange_bad_1(x: A) {
fun testWithRange_bad_2(b: Boolean) { fun testWithRange_bad_2(b: Boolean) {
// bad // bad
when (b) { when (b) {
in b && b -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>b && b<!> -> {}
in b || b -> {} in <!CONFUSING_BRANCH_CONDITION_ERROR!>b || b<!> -> {}
} }
// ok // ok
when (b) { when (b) {
@@ -55,18 +55,18 @@ fun testWithSubject_ok(x: A, y: A?, any: Any, z: B) {
fun testWithSubject_bad_1(x: A) { fun testWithSubject_bad_1(x: A) {
// bad // bad
when (x) { when (x) {
x in x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x in x<!> -> {}
x !in x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x !in x<!> -> {}
x is String -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x is String<!> -> {}
x !is String -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x !is String<!> -> {}
x < x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x < x<!> -> {}
x > x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x > x<!> -> {}
x <= x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x <= x<!> -> {}
x >= x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x >= x<!> -> {}
x == x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x == x<!> -> {}
x != x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x != x<!> -> {}
x === x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x === x<!> -> {}
x !== x -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>x !== x<!> -> {}
} }
// ok // ok
when (x) { when (x) {
@@ -88,8 +88,8 @@ fun testWithSubject_bad_1(x: A) {
fun testWithSubject_bad_2(b: Boolean) { fun testWithSubject_bad_2(b: Boolean) {
// bad // bad
when (b) { when (b) {
b && b -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>b && b<!> -> {}
b || b -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>b || b<!> -> {}
} }
// ok // ok
when (b) { when (b) {
@@ -159,18 +159,18 @@ fun testWithRange_ok(x: A, y: A?, any: Any, z: B) {
fun testWithRange_bad_1(x: A) { fun testWithRange_bad_1(x: A) {
// bad // bad
when (x) { when (x) {
in x in x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x in x<!> -> {}
in x !in x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x !in x<!> -> {}
in x is String -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x is String<!> -> {}
in x !is String -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x !is String<!> -> {}
in x < x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x < x<!> -> {}
in x > x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x > x<!> -> {}
in x <= x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x <= x<!> -> {}
in x >= x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x >= x<!> -> {}
in x == x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x == x<!> -> {}
in x != x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x != x<!> -> {}
in x === x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x === x<!> -> {}
in x !== x -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>x !== x<!> -> {}
} }
// ok // ok
when (x) { when (x) {
@@ -192,8 +192,8 @@ fun testWithRange_bad_1(x: A) {
fun testWithRange_bad_2(b: Boolean) { fun testWithRange_bad_2(b: Boolean) {
// bad // bad
when (b) { when (b) {
in b && b -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>b && b<!> -> {}
in b || b -> {} in <!CONFUSING_BRANCH_CONDITION_WARNING!>b || b<!> -> {}
} }
// ok // ok
when (b) { when (b) {
@@ -29,7 +29,7 @@ fun case_3(value_1: Boolean?): Int = <!NO_ELSE_IN_WHEN!>when<!>(value_1) { }
// TESTCASE NUMBER: 4 // TESTCASE NUMBER: 4
fun case_4(value_1: Boolean?): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) { fun case_4(value_1: Boolean?): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) {
true && false && ((true || false)) || true && !!!false && !!!true -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false && !!!true<!> -> ""
true && false && ((true || false)) || true && !!!false -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false<!> -> ""
null -> "" null -> ""
} }
@@ -48,6 +48,6 @@ fun case_5(value_1: Boolean): String {
// TESTCASE NUMBER: 6 // TESTCASE NUMBER: 6
fun case_6(value_1: Boolean): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) { fun case_6(value_1: Boolean): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) {
true && false && ((true || false)) || true && !!!false && !!!true -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false && !!!true<!> -> ""
true && false && ((true || false)) || true && !!!false -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false<!> -> ""
} }
@@ -18,7 +18,7 @@ fun case_1(value_1: Boolean?): String = when (value_1) {
// TESTCASE NUMBER: 2 // TESTCASE NUMBER: 2
fun case_2(value_1: Boolean?): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) { fun case_2(value_1: Boolean?): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) {
true && false && ((true || false)) || true && !!!false && !!!true -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false && !!!true<!> -> ""
true && false && ((true || false)) || true && !!!false -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false<!> -> ""
null -> "" null -> ""
} }
@@ -17,6 +17,6 @@ fun case_1(value_1: Boolean): String = when (value_1) {
// TESTCASE NUMBER: 2 // TESTCASE NUMBER: 2
fun case_2(value_1: Boolean): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) { fun case_2(value_1: Boolean): String = <!NO_ELSE_IN_WHEN!>when<!> (value_1) {
true && false && ((true || false)) || true && !!!false && !!!true -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false && !!!true<!> -> ""
true && false && ((true || false)) || true && !!!false -> "" <!CONFUSING_BRANCH_CONDITION_WARNING!>true && false && ((true || false)) || true && !!!false<!> -> ""
} }
@@ -47,13 +47,13 @@ fun case_4(value_1: Int, value_2: String, value_3: String) {
fun case_5(value_1: Int, value_2: Int, value_3: Boolean?) { fun case_5(value_1: Int, value_2: Int, value_3: Boolean?) {
when (value_1) { when (value_1) {
1 -> when (value_3) { 1 -> when (value_3) {
value_2 > 1000 -> "1" <!CONFUSING_BRANCH_CONDITION_WARNING!>value_2 > 1000<!> -> "1"
value_2 > 100 -> "2" <!CONFUSING_BRANCH_CONDITION_WARNING!>value_2 > 100<!> -> "2"
else -> "3" else -> "3"
} }
2 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) { 2 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {
value_2 > 1000 -> "1" <!CONFUSING_BRANCH_CONDITION_WARNING!>value_2 > 1000<!> -> "1"
value_2 > 100 -> "2" <!CONFUSING_BRANCH_CONDITION_WARNING!>value_2 > 100<!> -> "2"
} }
3 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {} 3 -> <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_3) {}
4 -> when (value_3) { 4 -> when (value_3) {
@@ -72,8 +72,8 @@ fun case_5(value_1: Int, value_2: Int, value_3: Boolean?) {
// TESTCASE NUMBER: 6 // TESTCASE NUMBER: 6
fun case_6(value_1: Int, value_2: Int, value_3: Boolean?) = when (value_1) { fun case_6(value_1: Int, value_2: Int, value_3: Boolean?) = when (value_1) {
1 -> when (value_3) { 1 -> when (value_3) {
value_2 > 1000 -> 1 <!CONFUSING_BRANCH_CONDITION_WARNING!>value_2 > 1000<!> -> 1
value_2 > 100 -> 2 <!CONFUSING_BRANCH_CONDITION_WARNING!>value_2 > 100<!> -> 2
else -> 3 else -> 3
} }
else -> when (value_3) { else -> when (value_3) {
@@ -27,10 +27,10 @@ fun case_3(value_1: Boolean, value_2: Boolean, value_3: Long) {
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_1) { <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_1) {
value_2 -> {} value_2 -> {}
!value_2 -> {} !value_2 -> {}
getBoolean() && value_2 -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>getBoolean() && value_2<!> -> {}
getChar() != 'a' -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>getChar() != 'a'<!> -> {}
getList() === getAny() -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>getList() === getAny()<!> -> {}
value_3 <= 11 -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>value_3 <= 11<!> -> {}
} }
} }
@@ -19,8 +19,8 @@ fun case_2(value_1: Number, value_2: Int) {
// TESTCASE NUMBER: 3 // TESTCASE NUMBER: 3
fun case_3(value_1: Boolean, value_2: Boolean, value_3: Long) { fun case_3(value_1: Boolean, value_2: Boolean, value_3: Long) {
<!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_1) { <!NON_EXHAUSTIVE_WHEN_STATEMENT!>when<!> (value_1) {
value_2, !value_2, getBoolean() && value_2, getChar() != 'a' -> {} value_2, !value_2, <!CONFUSING_BRANCH_CONDITION_WARNING!>getBoolean() && value_2<!>, <!CONFUSING_BRANCH_CONDITION_WARNING!>getChar() != 'a'<!> -> {}
getList() === getAny(), value_3 <= 11 -> {} <!CONFUSING_BRANCH_CONDITION_WARNING!>getList() === getAny()<!>, <!CONFUSING_BRANCH_CONDITION_WARNING!>value_3 <= 11<!> -> {}
} }
} }