mirror of
https://gitflic.ru/project/openide/openide.git
synced 2026-09-18 09:34:34 +07:00
Groovy: control flow: nested switches & for-s fix & tests
This commit is contained in:
+27
-15
@@ -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;
|
||||
|
||||
+7
@@ -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(); }
|
||||
|
||||
+1
-3
@@ -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
|
||||
Reference in New Issue
Block a user