From 252c4118ebbc85798f3b0f7fa7f2add6a572e61c Mon Sep 17 00:00:00 2001 From: Dmitry Jemerov Date: Mon, 30 Mar 2015 20:44:31 +0200 Subject: [PATCH] report 'break' and 'continue' inside 'when' as errors (even if 'when' is nested in a loop) --- .../kotlin/cfg/JetControlFlowProcessor.java | 6 ++ .../jetbrains/kotlin/diagnostics/Errors.java | 1 + .../rendering/DefaultErrorMessages.java | 1 + .../diagnostics/tests/BreakContinue.kt | 2 +- .../diagnostics/tests/BreakContinue.txt | 2 +- .../diagnostics/tests/BreakContinueInWhen.kt | 55 +++++++++++++++++++ .../diagnostics/tests/BreakContinueInWhen.txt | 6 ++ .../checkers/JetDiagnosticsTestGenerated.java | 6 ++ 8 files changed, 77 insertions(+), 2 deletions(-) create mode 100644 compiler/testData/diagnostics/tests/BreakContinueInWhen.kt create mode 100644 compiler/testData/diagnostics/tests/BreakContinueInWhen.txt diff --git a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java index d2f488d57d3..445610f6be3 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/cfg/JetControlFlowProcessor.java @@ -977,6 +977,12 @@ public class JetControlFlowProcessor { loop = builder.getCurrentLoop(); if (loop == null) { trace.report(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP.on(expression)); + } else { + JetWhenExpression whenExpression = PsiTreeUtil.getParentOfType(expression, JetWhenExpression.class, true, + JetLoopExpression.class); + if (whenExpression != null) { + trace.report(BREAK_OR_CONTINUE_IN_WHEN.on(expression)); + } } } if (loop != null && loop.getBody() != null diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java index e649e07ed70..34795f1b54d 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/Errors.java @@ -500,6 +500,7 @@ public interface Errors { DiagnosticFactory0 AMBIGUOUS_LABEL = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = DiagnosticFactory0.create(ERROR); + DiagnosticFactory0 BREAK_OR_CONTINUE_IN_WHEN = DiagnosticFactory0.create(ERROR); DiagnosticFactory0 BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY = DiagnosticFactory0.create(ERROR); DiagnosticFactory1 NOT_A_LOOP_LABEL = DiagnosticFactory1.create(ERROR); DiagnosticFactory1 NOT_A_RETURN_LABEL = DiagnosticFactory1.create(ERROR); diff --git a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java index 04add4c66b0..0c6f6649292 100644 --- a/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java +++ b/compiler/frontend/src/org/jetbrains/kotlin/diagnostics/rendering/DefaultErrorMessages.java @@ -407,6 +407,7 @@ public class DefaultErrorMessages { MAP.put(NO_TAIL_CALLS_FOUND, "A function is marked as tail-recursive but no tail calls are found"); MAP.put(VALUE_PARAMETER_WITH_NO_TYPE_ANNOTATION, "A type annotation is required on a value parameter"); MAP.put(BREAK_OR_CONTINUE_OUTSIDE_A_LOOP, "'break' and 'continue' are only allowed inside a loop"); + MAP.put(BREAK_OR_CONTINUE_IN_WHEN, "'break' and 'continue' are not allowed in 'when' statements. Consider using labels to continue/break from the outer loop"); MAP.put(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY, "'break' or 'continue' jumps across a function boundary"); MAP.put(NOT_A_LOOP_LABEL, "The label ''{0}'' does not denote a loop", STRING); MAP.put(NOT_A_RETURN_LABEL, "The label ''{0}'' does not reference to a context from which we can return", STRING); diff --git a/compiler/testData/diagnostics/tests/BreakContinue.kt b/compiler/testData/diagnostics/tests/BreakContinue.kt index fd000c2c7b3..c4dd5a0e2ca 100644 --- a/compiler/testData/diagnostics/tests/BreakContinue.kt +++ b/compiler/testData/diagnostics/tests/BreakContinue.kt @@ -82,4 +82,4 @@ class C { } a.compareTo("2") } -} \ No newline at end of file +} diff --git a/compiler/testData/diagnostics/tests/BreakContinue.txt b/compiler/testData/diagnostics/tests/BreakContinue.txt index a9424ef1f0e..b91551ece9a 100644 --- a/compiler/testData/diagnostics/tests/BreakContinue.txt +++ b/compiler/testData/diagnostics/tests/BreakContinue.txt @@ -1,4 +1,4 @@ -package +package internal final class C { public constructor C() diff --git a/compiler/testData/diagnostics/tests/BreakContinueInWhen.kt b/compiler/testData/diagnostics/tests/BreakContinueInWhen.kt new file mode 100644 index 00000000000..5fac2451d9a --- /dev/null +++ b/compiler/testData/diagnostics/tests/BreakContinueInWhen.kt @@ -0,0 +1,55 @@ +fun breakContinueInWhen(i: Int) { + for (y in 0..10) { + when(i) { + 0 -> continue + 1 -> break + 2 -> { + for(z in 0..10) { + break + } + for(w in 0..10) { + continue + } + } + } + } +} + + +fun breakContinueInWhenWithWhile(i: Int, j: Int) { + while (i > 0) { + when (i) { + 0 -> continue + 1 -> break + 2 -> { + while (j > 0) { + break + } + } + } + } +} + +fun breakContinueInWhenWithDoWhile(i: Int, j: Int) { + do { + when (i) { + 0 -> continue + 1 -> break + 2 -> { + do { + if (j == 5) break + if (j == 10) continue + } while (j > 0) + } + } + } while (i > 0) +} + +fun labeledBreakContinue(i: Int) { + @outer for (y in 0..10) { + when (i) { + 0 -> continue@outer + 1 -> break@outer + } + } +} diff --git a/compiler/testData/diagnostics/tests/BreakContinueInWhen.txt b/compiler/testData/diagnostics/tests/BreakContinueInWhen.txt new file mode 100644 index 00000000000..b29df873554 --- /dev/null +++ b/compiler/testData/diagnostics/tests/BreakContinueInWhen.txt @@ -0,0 +1,6 @@ +package + +internal fun breakContinueInWhen(/*0*/ i: kotlin.Int): kotlin.Unit +internal fun breakContinueInWhenWithDoWhile(/*0*/ i: kotlin.Int, /*1*/ j: kotlin.Int): kotlin.Unit +internal fun breakContinueInWhenWithWhile(/*0*/ i: kotlin.Int, /*1*/ j: kotlin.Int): kotlin.Unit +internal fun labeledBreakContinue(/*0*/ i: kotlin.Int): kotlin.Unit diff --git a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java index ffb65f42f40..b8fac9bdeea 100644 --- a/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/checkers/JetDiagnosticsTestGenerated.java @@ -180,6 +180,12 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest { doTest(fileName); } + @TestMetadata("BreakContinueInWhen.kt") + public void testBreakContinueInWhen() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/BreakContinueInWhen.kt"); + doTest(fileName); + } + @TestMetadata("Builders.kt") public void testBuilders() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/diagnostics/tests/Builders.kt");