diff --git a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java index 79101b641319..dee7bfd88eb6 100644 --- a/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java +++ b/plugins/groovy/groovy-psi/src/org/jetbrains/plugins/groovy/lang/psi/controlFlow/impl/ControlFlowBuilder.java @@ -252,22 +252,29 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { @Override public void visitBreakStatement(GrBreakStatement breakStatement) { super.visitBreakStatement(breakStatement); - final GrStatement target = breakStatement.findTargetStatement(); - if (target != null && myHead != null) { - addPendingEdge(target, myHead); + GrStatement target = breakStatement.resolveLabel(); + if (target == null) target = breakStatement.findTargetStatement(); + if (target != null) { + if (myHead != null) { + addPendingEdge(target, myHead); + } + readdPendingEdge(target); } - interruptFlow(); } @Override public void visitContinueStatement(GrContinueStatement continueStatement) { super.visitContinueStatement(continueStatement); - final GrStatement target = continueStatement.findTargetStatement(); - if (target != null && myHead != null) { + GrStatement target = continueStatement.resolveLabel(); + if (target == null) target = continueStatement.findTargetStatement(); + if (target != null) { final InstructionImpl instruction = findInstruction(target); if (instruction != null) { - addEdge(myHead, instruction); + if (myHead != null) { + addEdge(myHead, instruction); + } + checkPending(continueStatement, instruction); } } interruptFlow(); @@ -761,17 +768,20 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { } private void addForLoopBreakingEdge(GrForStatement forStatement, @Nullable GrForClause clause) { + final GroovyPsiElement target = forStatement.getParent() instanceof GrLabeledStatement + ? (GroovyPsiElement)forStatement.getParent() + : forStatement; if (clause instanceof GrTraditionalForClause) { final GrExpression condition = ((GrTraditionalForClause)clause).getCondition(); if (condition != null) { condition.accept(this); if (!alwaysTrue(condition)) { - addPendingEdge(forStatement, myHead); //break cycle + addPendingEdge(target, myHead); //break cycle } } } else { - addPendingEdge(forStatement, myHead); //break cycle + addPendingEdge(target, myHead); //break cycle } } @@ -813,9 +823,13 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { private void checkPending(@NotNull InstructionImpl instruction) { final PsiElement element = instruction.getElement(); - List> target = collectCorrespondingPendingEdges(element); - for (Pair pair : target) { - addEdge(pair.getFirst(), instruction); + checkPending(element, instruction); + } + + private void checkPending(@Nullable PsiElement currentScope, @NotNull InstructionImpl targetInstruction) { + final List> pendingEdges = collectCorrespondingPendingEdges(currentScope); + for (Pair pair : pendingEdges) { + addEdge(pair.getFirst(), targetInstruction); } } @@ -1224,9 +1238,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor { @Nullable private InstructionImpl findInstruction(PsiElement element) { - final Iterator iterator = myProcessingStack.descendingIterator(); - while (iterator.hasNext()) { - final InstructionImpl instruction = iterator.next(); + for (final InstructionImpl instruction : myInstructions) { if (element.equals(instruction.getElement())) return instruction; } return null; diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy index 859b81a0cebb..986438763e2d 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/controlFlow/ControlFlowTest.groovy @@ -47,6 +47,13 @@ public class ControlFlowTest extends LightCodeInsightFixtureTestCase { public void testSwitch3() { doTest(); } public void testSwitch4() { doTest(); } public void testSwitch5() { doTest(); } + public void testNestedSwitch1() { doTest() }; + public void testNestedSwitch2() { doTest() }; + public void testNestedSwitch3() { doTest() }; + public void testNestedSwitch4() { doTest() }; + public void testSwitchWithinFor() {doTest() }; + public void testSwitchWithinLabeledFor() { doTest() }; + public void testForWithinSwitchWithinFor() { doTest() }; public void testThrow1() { doTest(); } public void testThrowInCatch() { doTest(); } public void testTry1() { doTest(); } diff --git a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyVariableCanBeFinalTest.groovy b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyVariableCanBeFinalTest.groovy index 1b99ccd32fd4..302bbb2cb361 100644 --- a/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyVariableCanBeFinalTest.groovy +++ b/plugins/groovy/test/org/jetbrains/plugins/groovy/lang/highlighting/GroovyVariableCanBeFinalTest.groovy @@ -146,9 +146,7 @@ def switchTest() { ''') } - - @SuppressWarnings("GroovyUnusedDeclaration") - void ignoreTestSwitchDeep() { + void testDeepSwitch() { testHighlighting(''' def deepSwitchTest() { def sw diff --git a/plugins/groovy/testdata/groovy/controlFlow/forWithinSwitchWithinFor.test b/plugins/groovy/testdata/groovy/controlFlow/forWithinSwitchWithinFor.test new file mode 100644 index 000000000000..e3c35d48eee3 --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/forWithinSwitchWithinFor.test @@ -0,0 +1,55 @@ +outer: +for (def a : array) { + sw: + switch (a) { + case b: break outer; + case c: + inner: + for (def aaa : array) { + if (d) { + continue outer + } else if (e) { + continue inner + } else if (f) { + break sw; + } + }; + break sw; + case g: println(); + }; + if (h) { + continue inner + } +} +----- +0(1) element: null +1(2) element: Labeled statement +2(3) READ array +3(4,30) element: For statement +4(5) WRITE a +5(6) element: Block statement +6(7) element: Labeled statement +7(8) READ a +8(9,10,25,30) element: Switch statement +9(30) READ b +10(11) READ c +11(12) element: Labeled statement +12(13) READ array +13(14,27) element: For statement +14(15) WRITE aaa +15(16) element: Block statement +16(17) element: IF statement +17(1,18) READ d +18(19) element: IF statement +19(11,20) READ e +20(21) element: IF statement +21(22,27) READ f +22(23) End element: IF statement +23(24) End element: IF statement +24(13) End element: IF statement +25(26) READ g +26(27) READ println +27(28) element: IF statement +28(11,29) READ h +29(3) End element: IF statement +30() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch1.test b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch1.test new file mode 100644 index 000000000000..d2c07f5b089f --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch1.test @@ -0,0 +1,20 @@ +switch (a) { + case b: break + case c: switch (d) { + case e: break + case f: break + default: break + }; break + default: break +} +----- +0(1) element: null +1(2) READ a +2(3,4,9) element: Switch statement +3(9) READ b +4(5) READ c +5(6) READ d +6(7,8,9) element: Switch statement +7(9) READ e +8(9) READ f +9() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch2.test b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch2.test new file mode 100644 index 000000000000..dfe15dcca289 --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch2.test @@ -0,0 +1,22 @@ +switch (a) { + case b: break + case c: switch (d) { + case e: break + case f: break + default: break + } + case g: break + default: break +} +----- +0(1) element: null +1(2) READ a +2(3,4,9,10) element: Switch statement +3(10) READ b +4(5) READ c +5(6) READ d +6(7,8,9) element: Switch statement +7(9) READ e +8(9) READ f +9(10) READ g +10() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch3.test b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch3.test new file mode 100644 index 000000000000..1b0ff60f1c3c --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch3.test @@ -0,0 +1,26 @@ +switch (a) { + case b: break + case c: switch (d) { + case e: break + case f: println 1 + case g: break + default: break + }; break + case h: break + default: break +} +----- +0(1) element: null +1(2) READ a +2(3,4,12,13) element: Switch statement +3(13) READ b +4(5) READ c +5(6) READ d +6(7,8,11,13) element: Switch statement +7(13) READ e +8(9) READ f +9(10) READ println +10(11) element: Call expression MAYBE_RETURN +11(13) READ g +12(13) READ h +13() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch4.test b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch4.test new file mode 100644 index 000000000000..d290b0fc7af0 --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/nestedSwitch4.test @@ -0,0 +1,26 @@ +switch (a) { + case b: break + case c: switch (d) { + case e: break + case f: println 1 + case g: break + default: break + } + case h: break + default: break +} +----- +0(1) element: null +1(2) READ a +2(3,4,12,13) element: Switch statement +3(13) READ b +4(5) READ c +5(6) READ d +6(7,8,11,12) element: Switch statement +7(12) READ e +8(9) READ f +9(10) READ println +10(11) element: Call expression MAYBE_RETURN +11(12) READ g +12(13) READ h +13() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/switchWithinFor.test b/plugins/groovy/testdata/groovy/controlFlow/switchWithinFor.test new file mode 100644 index 000000000000..fa43b743e30c --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/switchWithinFor.test @@ -0,0 +1,22 @@ +for (def i in arr) { + switch (i) { + case a: break + case b: break + default: i; break + } + continue + println() +} +----- +0(1) element: null +1(2) READ arr +2(3,11) element: For statement +3(4) WRITE i +4(5) element: Block statement +5(6) READ i +6(7,8,9) element: Switch statement +7(2) READ a +8(2) READ b +9(2) READ i +10(2) READ println +11() element: null \ No newline at end of file diff --git a/plugins/groovy/testdata/groovy/controlFlow/switchWithinLabeledFor.test b/plugins/groovy/testdata/groovy/controlFlow/switchWithinLabeledFor.test new file mode 100644 index 000000000000..dc295c3007a0 --- /dev/null +++ b/plugins/groovy/testdata/groovy/controlFlow/switchWithinLabeledFor.test @@ -0,0 +1,24 @@ +outer: +for (def i in arr) { + switch (i) { + case a: break + case b: break + default: i; break + } + continue outer + println() +} +----- +0(1) element: null +1(2) element: Labeled statement +2(3) READ arr +3(4,12) element: For statement +4(5) WRITE i +5(6) element: Block statement +6(7) READ i +7(8,9,10) element: Switch statement +8(1) READ a +9(1) READ b +10(1) READ i +11(3) READ println +12() element: null \ No newline at end of file