[FIR] Implement BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY
This commit is contained in:
committed by
teamcityserver
parent
cbdd0f579a
commit
2333b1bcf6
+1
@@ -34,6 +34,7 @@ fun main(args: Array<String>) {
|
||||
alias<FirTryExpression>("TryExpressionChecker")
|
||||
alias<FirWhenExpression>("WhenExpressionChecker")
|
||||
alias<FirLoop>("LoopExpressionChecker")
|
||||
alias<FirLoopJump>("LoopJumpChecker")
|
||||
alias<FirBinaryLogicExpression>("LogicExpressionChecker")
|
||||
alias<FirReturnExpression>("ReturnExpressionChecker")
|
||||
alias<FirBlock>("BlockChecker")
|
||||
|
||||
+1
@@ -59,6 +59,7 @@ object DIAGNOSTICS_LIST : DiagnosticList("FirErrors") {
|
||||
val ASSIGNMENT_IN_EXPRESSION_CONTEXT by error<KtBinaryExpression>()
|
||||
val BREAK_OR_CONTINUE_OUTSIDE_A_LOOP by error<PsiElement>()
|
||||
val NOT_A_LOOP_LABEL by error<PsiElement>()
|
||||
val BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY by error<KtExpressionWithLabel>()
|
||||
val VARIABLE_EXPECTED by error<PsiElement>(PositioningStrategy.ASSIGNMENT_LHS)
|
||||
val DELEGATION_IN_INTERFACE by error<PsiElement>()
|
||||
val DELEGATION_NOT_TO_INTERFACE by error<PsiElement>()
|
||||
|
||||
+4
@@ -29,6 +29,8 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
get() = _whenExpressionCheckers
|
||||
override val loopExpressionCheckers: Set<FirLoopExpressionChecker>
|
||||
get() = _loopExpressionCheckers
|
||||
override val loopJumpCheckers: Set<FirLoopJumpChecker>
|
||||
get() = _loopJumpCheckers
|
||||
override val logicExpressionCheckers: Set<FirLogicExpressionChecker>
|
||||
get() = _logicExpressionCheckers
|
||||
override val returnExpressionCheckers: Set<FirReturnExpressionChecker>
|
||||
@@ -76,6 +78,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
private val _tryExpressionCheckers: MutableSet<FirTryExpressionChecker> = mutableSetOf()
|
||||
private val _whenExpressionCheckers: MutableSet<FirWhenExpressionChecker> = mutableSetOf()
|
||||
private val _loopExpressionCheckers: MutableSet<FirLoopExpressionChecker> = mutableSetOf()
|
||||
private val _loopJumpCheckers: MutableSet<FirLoopJumpChecker> = mutableSetOf()
|
||||
private val _logicExpressionCheckers: MutableSet<FirLogicExpressionChecker> = mutableSetOf()
|
||||
private val _returnExpressionCheckers: MutableSet<FirReturnExpressionChecker> = mutableSetOf()
|
||||
private val _blockCheckers: MutableSet<FirBlockChecker> = mutableSetOf()
|
||||
@@ -106,6 +109,7 @@ class ComposedExpressionCheckers : ExpressionCheckers() {
|
||||
_tryExpressionCheckers += checkers.tryExpressionCheckers
|
||||
_whenExpressionCheckers += checkers.whenExpressionCheckers
|
||||
_loopExpressionCheckers += checkers.loopExpressionCheckers
|
||||
_loopJumpCheckers += checkers.loopJumpCheckers
|
||||
_logicExpressionCheckers += checkers.logicExpressionCheckers
|
||||
_returnExpressionCheckers += checkers.returnExpressionCheckers
|
||||
_blockCheckers += checkers.blockCheckers
|
||||
|
||||
+2
@@ -25,6 +25,7 @@ abstract class ExpressionCheckers {
|
||||
open val tryExpressionCheckers: Set<FirTryExpressionChecker> = emptySet()
|
||||
open val whenExpressionCheckers: Set<FirWhenExpressionChecker> = emptySet()
|
||||
open val loopExpressionCheckers: Set<FirLoopExpressionChecker> = emptySet()
|
||||
open val loopJumpCheckers: Set<FirLoopJumpChecker> = emptySet()
|
||||
open val logicExpressionCheckers: Set<FirLogicExpressionChecker> = emptySet()
|
||||
open val returnExpressionCheckers: Set<FirReturnExpressionChecker> = emptySet()
|
||||
open val blockCheckers: Set<FirBlockChecker> = emptySet()
|
||||
@@ -53,6 +54,7 @@ abstract class ExpressionCheckers {
|
||||
@CheckersComponentInternal internal val allTryExpressionCheckers: Set<FirTryExpressionChecker> by lazy { tryExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allWhenExpressionCheckers: Set<FirWhenExpressionChecker> by lazy { whenExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allLoopExpressionCheckers: Set<FirLoopExpressionChecker> by lazy { loopExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allLoopJumpCheckers: Set<FirLoopJumpChecker> by lazy { loopJumpCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allLogicExpressionCheckers: Set<FirLogicExpressionChecker> by lazy { logicExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allReturnExpressionCheckers: Set<FirReturnExpressionChecker> by lazy { returnExpressionCheckers + basicExpressionCheckers }
|
||||
@CheckersComponentInternal internal val allBlockCheckers: Set<FirBlockChecker> by lazy { blockCheckers + basicExpressionCheckers }
|
||||
|
||||
+2
@@ -24,6 +24,7 @@ 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.FirLoopJump
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccess
|
||||
import org.jetbrains.kotlin.fir.expressions.FirQualifiedAccessExpression
|
||||
import org.jetbrains.kotlin.fir.expressions.FirResolvedQualifier
|
||||
@@ -46,6 +47,7 @@ typealias FirVariableAssignmentChecker = FirExpressionChecker<FirVariableAssignm
|
||||
typealias FirTryExpressionChecker = FirExpressionChecker<FirTryExpression>
|
||||
typealias FirWhenExpressionChecker = FirExpressionChecker<FirWhenExpression>
|
||||
typealias FirLoopExpressionChecker = FirExpressionChecker<FirLoop>
|
||||
typealias FirLoopJumpChecker = FirExpressionChecker<FirLoopJump>
|
||||
typealias FirLogicExpressionChecker = FirExpressionChecker<FirBinaryLogicExpression>
|
||||
typealias FirReturnExpressionChecker = FirExpressionChecker<FirReturnExpression>
|
||||
typealias FirBlockChecker = FirExpressionChecker<FirBlock>
|
||||
|
||||
@@ -51,6 +51,7 @@ 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
|
||||
@@ -97,6 +98,7 @@ object FirErrors {
|
||||
val ASSIGNMENT_IN_EXPRESSION_CONTEXT by error0<KtBinaryExpression>()
|
||||
val BREAK_OR_CONTINUE_OUTSIDE_A_LOOP by error0<PsiElement>()
|
||||
val NOT_A_LOOP_LABEL by error0<PsiElement>()
|
||||
val BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY by error0<KtExpressionWithLabel>()
|
||||
val VARIABLE_EXPECTED by error0<PsiElement>(SourceElementPositioningStrategies.ASSIGNMENT_LHS)
|
||||
val DELEGATION_IN_INTERFACE by error0<PsiElement>()
|
||||
val DELEGATION_NOT_TO_INTERFACE by error0<PsiElement>()
|
||||
|
||||
+1
-1
@@ -218,7 +218,7 @@ object FirReturnsImpliesAnalyzer : FirControlFlowChecker() {
|
||||
}
|
||||
|
||||
private val CheckerContext.containingProperty: FirProperty?
|
||||
get() = (containingDeclarations.asReversed().firstOrNull { it is FirProperty } as? FirProperty)
|
||||
get() = (containingDeclarations.lastOrNull { it is FirProperty } as? FirProperty)
|
||||
|
||||
private fun FirFunction.getParameterType(symbol: FirBasedSymbol<*>, context: CheckerContext): ConeKotlinType? {
|
||||
val typeRef = if (this.symbol == symbol) {
|
||||
|
||||
+6
-1
@@ -20,7 +20,7 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
get() = setOf(
|
||||
FirReservedUnderscoreExpressionChecker,
|
||||
FirExpressionAnnotationChecker,
|
||||
FirDeprecationChecker,
|
||||
FirDeprecationChecker
|
||||
)
|
||||
|
||||
override val qualifiedAccessCheckers: Set<FirQualifiedAccessChecker>
|
||||
@@ -76,6 +76,11 @@ object CommonExpressionCheckers : ExpressionCheckers() {
|
||||
FirLoopConditionChecker,
|
||||
)
|
||||
|
||||
override val loopJumpCheckers: Set<FirLoopJumpChecker>
|
||||
get() = setOf(
|
||||
FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker
|
||||
)
|
||||
|
||||
override val logicExpressionCheckers: Set<FirLogicExpressionChecker>
|
||||
get() = setOf(
|
||||
FirLogicExpressionTypeChecker,
|
||||
|
||||
+101
@@ -0,0 +1,101 @@
|
||||
/*
|
||||
* 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.FirElement
|
||||
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.declarations.*
|
||||
import org.jetbrains.kotlin.fir.expressions.*
|
||||
|
||||
object FirBreakOrContinueJumpsAcrossFunctionBoundaryChecker : FirLoopJumpChecker() {
|
||||
override fun check(expression: FirLoopJump, context: CheckerContext, reporter: DiagnosticReporter) {
|
||||
val errorPathElements = ArrayDeque<FirElement>()
|
||||
|
||||
fun findPathAndCheck(element: FirElement?): Boolean {
|
||||
fun findPathAndCheckWithAddingErrorElement(errorElement: FirElement, checkElement: FirElement?): Boolean {
|
||||
errorPathElements.addLast(errorElement)
|
||||
val result = findPathAndCheck(checkElement)
|
||||
errorPathElements.removeLast()
|
||||
return result
|
||||
}
|
||||
|
||||
if (element == null) {
|
||||
return false
|
||||
}
|
||||
|
||||
when (element) {
|
||||
expression -> {
|
||||
if (errorPathElements.any()) {
|
||||
reporter.reportOn(expression.source, FirErrors.BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY, context)
|
||||
}
|
||||
return true
|
||||
}
|
||||
is FirBlock -> {
|
||||
for (statement in element.statements) {
|
||||
if (findPathAndCheck(statement)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirWhenExpression -> {
|
||||
for (branch in element.branches) {
|
||||
if (findPathAndCheck(branch.result)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirVariable -> return findPathAndCheck(element.initializer)
|
||||
is FirWrappedExpression -> return findPathAndCheck(element.expression)
|
||||
is FirCall -> {
|
||||
for (argument in element.arguments) {
|
||||
if (findPathAndCheck(argument)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirClass -> {
|
||||
errorPathElements.addLast(element)
|
||||
for (declaration in element.declarations) {
|
||||
if (findPathAndCheck(declaration)) {
|
||||
errorPathElements.removeLast()
|
||||
return true
|
||||
}
|
||||
}
|
||||
errorPathElements.removeLast()
|
||||
}
|
||||
is FirFunction -> {
|
||||
if (findPathAndCheckWithAddingErrorElement(element, element.body)) {
|
||||
return true
|
||||
}
|
||||
|
||||
if (element is FirConstructor) {
|
||||
val argumentList = element.delegatedConstructor?.argumentList
|
||||
if (argumentList != null) {
|
||||
errorPathElements.addLast(element)
|
||||
for (argument in argumentList.arguments) {
|
||||
if (findPathAndCheck(argument)) {
|
||||
errorPathElements.removeLast()
|
||||
return true
|
||||
}
|
||||
}
|
||||
errorPathElements.removeLast()
|
||||
}
|
||||
}
|
||||
}
|
||||
is FirAnonymousInitializer -> return findPathAndCheckWithAddingErrorElement(element, element.body)
|
||||
is FirAnonymousObjectExpression -> return findPathAndCheckWithAddingErrorElement(element, element.anonymousObject)
|
||||
is FirAnonymousFunctionExpression -> return findPathAndCheckWithAddingErrorElement(element, element.anonymousFunction)
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
findPathAndCheck(expression.target.labeledElement.block)
|
||||
}
|
||||
}
|
||||
+8
@@ -117,6 +117,14 @@ class ExpressionCheckersDiagnosticComponent(
|
||||
checkers.allReturnExpressionCheckers.check(returnExpression, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitBreakExpression(breakExpression: FirBreakExpression, data: CheckerContext) {
|
||||
checkers.allLoopJumpCheckers.check(breakExpression, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitContinueExpression(continueExpression: FirContinueExpression, data: CheckerContext) {
|
||||
checkers.allLoopJumpCheckers.check(continueExpression, data, reporter)
|
||||
}
|
||||
|
||||
override fun visitBlock(block: FirBlock, data: CheckerContext) {
|
||||
checkers.allBlockCheckers.check(block, data, reporter)
|
||||
}
|
||||
|
||||
+2
@@ -67,6 +67,7 @@ import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.ASSIGN_OPERATOR_A
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BACKING_FIELD_IN_INTERFACE
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BOUNDS_NOT_ALLOWED_IF_BOUNDED_BY_TYPE_PARAMETER
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BOUND_ON_TYPE_ALIAS_PARAMETER_NOT_ALLOWED
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.BREAK_OR_CONTINUE_OUTSIDE_A_LOOP
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CALLABLE_REFERENCE_LHS_NOT_A_CLASS
|
||||
import org.jetbrains.kotlin.fir.analysis.diagnostics.FirErrors.CALLABLE_REFERENCE_TO_ANNOTATION_CONSTRUCTOR
|
||||
@@ -456,6 +457,7 @@ class FirDefaultErrorMessages {
|
||||
// map.put(EXPRESSION_REQUIRED, ...) // &
|
||||
map.put(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP, "'break' and 'continue' are only allowed inside a loop")
|
||||
map.put(NOT_A_LOOP_LABEL, "The label does not denote a loop") // *
|
||||
map.put(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY, "'break' or 'continue' jumps across a function or a class boundary")
|
||||
map.put(VARIABLE_EXPECTED, "Variable expected")
|
||||
map.put(DELEGATION_IN_INTERFACE, "Interfaces cannot use delegation")
|
||||
map.put(DELEGATION_NOT_TO_INTERFACE, "Only interfaces can be delegated to")
|
||||
|
||||
+13
-13
@@ -1,7 +1,7 @@
|
||||
fun test() {
|
||||
while (true) {
|
||||
fun local1() {
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -9,7 +9,7 @@ fun test() {
|
||||
fun test2() {
|
||||
while (true) {
|
||||
{
|
||||
continue
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -18,11 +18,11 @@ fun test3() {
|
||||
while (true) {
|
||||
class LocalClass {
|
||||
init {
|
||||
continue
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
||||
}
|
||||
|
||||
fun foo() {
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -32,7 +32,7 @@ fun test4() {
|
||||
while (true) {
|
||||
object: Any() {
|
||||
init {
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -42,10 +42,10 @@ fun test5() {
|
||||
while (true) {
|
||||
class LocalClass(val x: Int) {
|
||||
constructor() : this(42) {
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
constructor(y: Double) : this(y.toInt()) {
|
||||
continue
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -55,10 +55,10 @@ fun test6() {
|
||||
while (true) {
|
||||
class LocalClass(val x: Int) {
|
||||
init {
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
init {
|
||||
continue
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -68,10 +68,10 @@ fun test7() {
|
||||
while (true) {
|
||||
class LocalClass {
|
||||
val x: Int = if (true) {
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
else {
|
||||
continue
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -80,7 +80,7 @@ fun test7() {
|
||||
fun test8() {
|
||||
while (true) {
|
||||
class LocalClass(val x: Int) {
|
||||
constructor() : this(if (true) { 42 } else { break })
|
||||
constructor() : this(if (true) { 42 } else { <!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!> })
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-17
@@ -1,17 +0,0 @@
|
||||
fun call(f: () -> Unit) = f()
|
||||
|
||||
fun f1() {
|
||||
outer@ while (true) {
|
||||
call {
|
||||
break@outer
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun f2() {
|
||||
do {
|
||||
fun inner() {
|
||||
continue
|
||||
}
|
||||
} while (true)
|
||||
}
|
||||
+1
@@ -1,3 +1,4 @@
|
||||
// FIR_IDENTICAL
|
||||
fun call(f: () -> Unit) = f()
|
||||
|
||||
fun f1() {
|
||||
|
||||
Vendored
+1
-1
@@ -3,6 +3,6 @@ package b
|
||||
fun foo() {
|
||||
for (i in <!ITERATOR_MISSING, UNRESOLVED_REFERENCE!>collection<!>) {
|
||||
{
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
}<!SYNTAX!><!>
|
||||
|
||||
+4
-4
@@ -5,14 +5,14 @@
|
||||
fun case_1(value_1: Boolean) {
|
||||
while (value_1) {
|
||||
funWithExactlyOnceCallsInPlace {
|
||||
break
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
|
||||
}
|
||||
println("1")
|
||||
}
|
||||
|
||||
loop@ for (i in 0..10) {
|
||||
funWithExactlyOnceCallsInPlace {
|
||||
break@loop
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break@loop<!>
|
||||
}
|
||||
println("1")
|
||||
}
|
||||
@@ -22,14 +22,14 @@ fun case_1(value_1: Boolean) {
|
||||
fun case_2(value_1: Boolean) {
|
||||
for (i in 0..10) {
|
||||
funWithExactlyOnceCallsInPlace {
|
||||
continue
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
|
||||
}
|
||||
println("1")
|
||||
}
|
||||
|
||||
loop@ while (value_1) {
|
||||
funWithExactlyOnceCallsInPlace {
|
||||
continue@loop
|
||||
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue@loop<!>
|
||||
}
|
||||
println("1")
|
||||
}
|
||||
|
||||
+7
@@ -36,6 +36,7 @@ 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
|
||||
@@ -132,6 +133,12 @@ internal val KT_DIAGNOSTIC_CONVERTER = KtDiagnosticConverterBuilder.buildConvert
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY) { firDiagnostic ->
|
||||
BreakOrContinueJumpsAcrossFunctionBoundaryImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
token,
|
||||
)
|
||||
}
|
||||
add(FirErrors.VARIABLE_EXPECTED) { firDiagnostic ->
|
||||
VariableExpectedImpl(
|
||||
firDiagnostic as FirPsiDiagnostic,
|
||||
|
||||
+5
@@ -45,6 +45,7 @@ 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
|
||||
@@ -122,6 +123,10 @@ sealed class KtFirDiagnostic<PSI : PsiElement> : KtDiagnosticWithPsi<PSI> {
|
||||
override val diagnosticClass get() = NotALoopLabel::class
|
||||
}
|
||||
|
||||
abstract class BreakOrContinueJumpsAcrossFunctionBoundary : KtFirDiagnostic<KtExpressionWithLabel>() {
|
||||
override val diagnosticClass get() = BreakOrContinueJumpsAcrossFunctionBoundary::class
|
||||
}
|
||||
|
||||
abstract class VariableExpected : KtFirDiagnostic<PsiElement>() {
|
||||
override val diagnosticClass get() = VariableExpected::class
|
||||
}
|
||||
|
||||
+8
@@ -47,6 +47,7 @@ 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
|
||||
@@ -156,6 +157,13 @@ internal class NotALoopLabelImpl(
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class BreakOrContinueJumpsAcrossFunctionBoundaryImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
) : KtFirDiagnostic.BreakOrContinueJumpsAcrossFunctionBoundary(), KtAbstractFirDiagnostic<KtExpressionWithLabel> {
|
||||
override val firDiagnostic: FirPsiDiagnostic by weakRef(firDiagnostic)
|
||||
}
|
||||
|
||||
internal class VariableExpectedImpl(
|
||||
firDiagnostic: FirPsiDiagnostic,
|
||||
override val token: ValidityToken,
|
||||
|
||||
Reference in New Issue
Block a user