Groovy: control flow: nested switches & for-s fix & tests

This commit is contained in:
Daniil Ovchinnikov
2014-10-16 11:33:47 +04:00
parent b3b56ab618
commit e0e453487f
10 changed files with 230 additions and 18 deletions
@@ -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<Pair<InstructionImpl, GroovyPsiElement>> target = collectCorrespondingPendingEdges(element);
for (Pair<InstructionImpl, GroovyPsiElement> pair : target) {
addEdge(pair.getFirst(), instruction);
checkPending(element, instruction);
}
private void checkPending(@Nullable PsiElement currentScope, @NotNull InstructionImpl targetInstruction) {
final List<Pair<InstructionImpl, GroovyPsiElement>> pendingEdges = collectCorrespondingPendingEdges(currentScope);
for (Pair<InstructionImpl, GroovyPsiElement> pair : pendingEdges) {
addEdge(pair.getFirst(), targetInstruction);
}
}
@@ -1224,9 +1238,7 @@ public class ControlFlowBuilder extends GroovyRecursiveElementVisitor {
@Nullable
private InstructionImpl findInstruction(PsiElement element) {
final Iterator<InstructionImpl> 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;
@@ -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(); }
@@ -146,9 +146,7 @@ def switchTest() {
''')
}
@SuppressWarnings("GroovyUnusedDeclaration")
void ignoreTestSwitchDeep() {
void testDeepSwitch() {
testHighlighting('''
def deepSwitchTest() {
def <warning descr="Variable 'sw' can be final">sw</warning>
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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
@@ -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