Merge pull request #388 from dezgeg/fix-jump-across-function-boundary

KT-4334: Disallow break or continue across a function boundary
This commit is contained in:
Svetlana Isakova
2014-02-26 13:28:36 +03:00
7 changed files with 42 additions and 1 deletions
@@ -636,6 +636,7 @@ public class JetControlFlowProcessor {
public void visitBreakExpressionVoid(@NotNull JetBreakExpression expression, CFPContext context) {
JetElement loop = getCorrespondingLoop(expression);
if (loop != null) {
checkJumpDoesNotCrossFunctionBoundary(expression, loop);
builder.jump(builder.getExitPoint(loop));
}
}
@@ -644,6 +645,7 @@ public class JetControlFlowProcessor {
public void visitContinueExpressionVoid(@NotNull JetContinueExpression expression, CFPContext context) {
JetElement loop = getCorrespondingLoop(expression);
if (loop != null) {
checkJumpDoesNotCrossFunctionBoundary(expression, loop);
builder.jump(builder.getEntryPoint(loop));
}
}
@@ -672,6 +674,16 @@ public class JetControlFlowProcessor {
return loop;
}
private void checkJumpDoesNotCrossFunctionBoundary(@NotNull JetLabelQualifiedExpression jumpExpression, @NotNull JetElement jumpTarget) {
BindingContext bindingContext = trace.getBindingContext();
FunctionDescriptor labelExprEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpExpression);
FunctionDescriptor labelTargetEnclosingFunc = BindingContextUtils.getEnclosingFunctionDescriptor(bindingContext, jumpTarget);
if (labelExprEnclosingFunc != labelTargetEnclosingFunc) {
trace.report(BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY.on(jumpExpression));
}
}
@Override
public void visitReturnExpressionVoid(@NotNull JetReturnExpression expression, CFPContext context) {
JetExpression returnedExpression = expression.getReturnedExpression();
@@ -431,6 +431,7 @@ public interface Errors {
DiagnosticFactory0<JetSimpleNameExpression> AMBIGUOUS_LABEL = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetLabelQualifiedExpression> BREAK_OR_CONTINUE_OUTSIDE_A_LOOP = DiagnosticFactory0.create(ERROR);
DiagnosticFactory0<JetLabelQualifiedExpression> BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY = DiagnosticFactory0.create(ERROR);
DiagnosticFactory1<JetLabelQualifiedExpression, String> NOT_A_LOOP_LABEL = DiagnosticFactory1.create(ERROR);
DiagnosticFactory1<JetReturnExpression, String> NOT_A_RETURN_LABEL = DiagnosticFactory1.create(ERROR);
@@ -327,6 +327,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_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", TO_STRING);
MAP.put(NOT_A_RETURN_LABEL, "The label ''{0}'' does not reference to a context from which we can return", TO_STRING);
@@ -236,6 +236,11 @@ public class BindingContextUtils {
return descriptor;
}
public static FunctionDescriptor getEnclosingFunctionDescriptor(@NotNull BindingContext context, @NotNull JetElement element) {
JetFunction function = PsiTreeUtil.getParentOfType(element, JetFunction.class);
return (FunctionDescriptor)context.get(DECLARATION_TO_DESCRIPTOR, function);
}
public static void reportAmbiguousLabel(
@NotNull BindingTrace trace,
@NotNull JetSimpleNameExpression targetLabel,
@@ -0,0 +1,17 @@
fun call(f: () -> Unit) = f()
fun f1() {
@outer while (true) {
call {
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break@outer<!>
}
}
}
fun f2() {
do {
fun inner() {
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>continue<!>
}
} while (true)
}
@@ -3,6 +3,6 @@ package b
fun foo() {
for (i in <!UNRESOLVED_REFERENCE!>collection<!>) {
<!UNUSED_FUNCTION_LITERAL!>{
break
<!BREAK_OR_CONTINUE_JUMPS_ACROSS_FUNCTION_BOUNDARY!>break<!>
}<!>
}<!SYNTAX!><!>
@@ -1745,6 +1745,11 @@ public class JetDiagnosticsTestGenerated extends AbstractJetDiagnosticsTest {
doTest("compiler/testData/diagnostics/tests/controlStructures/ForbidStatementAsDirectFunctionBody.kt");
}
@TestMetadata("jumpAcrossFunctionBoundary.kt")
public void testJumpAcrossFunctionBoundary() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlStructures/jumpAcrossFunctionBoundary.kt");
}
@TestMetadata("kt1075.kt")
public void testKt1075() throws Exception {
doTest("compiler/testData/diagnostics/tests/controlStructures/kt1075.kt");