Skip to content

Commit f5539ef

Browse files
committed
SONARJAVA-1393 Fix continue in foreach statements
1 parent 2659b9d commit f5539ef

3 files changed

Lines changed: 62 additions & 9 deletions

File tree

java-squid/src/main/java/org/sonar/java/cfg/CFG.java

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -661,15 +661,16 @@ private void buildDoWhileStatement(DoWhileStatementTree doWhileStatementTree) {
661661
private void buildForEachStatement(ForEachStatement tree) {
662662
// TODO(npe) One solution is to create a forstatement node depending on type of expression (iterable or array) and build CFG from it.
663663
Block afterLoop = currentBlock;
664-
currentBlock = createBlock();
665-
Block loopback = currentBlock;
664+
Block statementBlock = createBlock();
665+
Block loopback = createBranch(tree, statementBlock, afterLoop);
666+
currentBlock = createBlock(loopback);
666667
addContinueTarget(loopback);
667668
breakTargets.addLast(afterLoop);
668669
build(tree.statement());
669670
breakTargets.removeLast();
670671
continueTargets.removeLast();
671-
currentBlock = createBranch(tree, currentBlock, afterLoop);
672-
loopback.addSuccessor(currentBlock);
672+
statementBlock.addSuccessor(currentBlock);
673+
currentBlock = loopback;
673674
build(tree.variable());
674675
build(tree.expression());
675676
currentBlock = createBlock(currentBlock);

java-squid/src/test/files/se/Reproducer.java

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,8 @@
11
package javax.annotation;
22
import javax.annotation.CheckForNull;
33
import java.lang.Object;
4+
import java.util.HashMap;
5+
import java.util.TreeSet;
46

57
@interface CheckForNull {}
68

@@ -59,6 +61,15 @@ private void foo(boolean b) {
5961

6062
}
6163
printState();
64+
}
6265

66+
public void continue_foreach(boolean a, boolean b, Map<String, String> map) {
67+
for (String prop : map.keySet()) {
68+
if (b) {
69+
continue;
70+
}
71+
String.format(" - %s=%s", prop, a ? "******" : "");
72+
}
6373
}
74+
6475
}

java-squid/src/test/java/org/sonar/java/cfg/CFGTest.java

Lines changed: 46 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -669,6 +669,47 @@ public void array_loop_with_continue() {
669669
cfgChecker.check(cfg);
670670
}
671671

672+
@Test
673+
public void foreach_loop_continue() {
674+
final CFG cfg = buildCFG("void fun(){ System.out.println('start'); for(String foo:list) {System.out.println(foo); if(foo.length()> 2) {continue;} System.out.println('');} System.out.println('end'); }");
675+
final CFGChecker cfgChecker = checker(
676+
block(
677+
element(Tree.Kind.CHAR_LITERAL, "'start'"),
678+
element(Tree.Kind.IDENTIFIER, "System"),
679+
element(Tree.Kind.MEMBER_SELECT),
680+
element(Tree.Kind.MEMBER_SELECT),
681+
element(Tree.Kind.METHOD_INVOCATION)).successors(2),
682+
block(
683+
element(Tree.Kind.IDENTIFIER, "foo"),
684+
element(Tree.Kind.IDENTIFIER, "System"),
685+
element(Tree.Kind.MEMBER_SELECT),
686+
element(Tree.Kind.MEMBER_SELECT),
687+
element(Kind.METHOD_INVOCATION),
688+
element(Tree.Kind.IDENTIFIER, "foo"),
689+
element(Tree.Kind.MEMBER_SELECT),
690+
element(Kind.METHOD_INVOCATION),
691+
element(Kind.INT_LITERAL, 2),
692+
element(Kind.GREATER_THAN)
693+
).terminator(Kind.IF_STATEMENT).successors(3, 4),
694+
terminator(Kind.CONTINUE_STATEMENT).successors(2),
695+
block(
696+
element(Tree.Kind.CHAR_LITERAL, "''"),
697+
element(Tree.Kind.IDENTIFIER, "System"),
698+
element(Tree.Kind.MEMBER_SELECT),
699+
element(Tree.Kind.MEMBER_SELECT),
700+
element(Tree.Kind.METHOD_INVOCATION)).successors(2),
701+
block(
702+
element(Tree.Kind.IDENTIFIER, "list"),
703+
element(Tree.Kind.VARIABLE, "foo")).terminator(Tree.Kind.FOR_EACH_STATEMENT).successors(1, 5),
704+
block(
705+
element(Tree.Kind.CHAR_LITERAL, "'end'"),
706+
element(Tree.Kind.IDENTIFIER, "System"),
707+
element(Tree.Kind.MEMBER_SELECT),
708+
element(Tree.Kind.MEMBER_SELECT),
709+
element(Tree.Kind.METHOD_INVOCATION)).successors(0));
710+
cfgChecker.check(cfg);
711+
}
712+
672713
@Test
673714
public void foreach_loop() {
674715
final CFG cfg = buildCFG("void fun(){ System.out.println(''); for(String foo:list) {System.out.println(foo);} System.out.println(''); }");
@@ -678,16 +719,16 @@ public void foreach_loop() {
678719
element(Tree.Kind.IDENTIFIER, "System"),
679720
element(Tree.Kind.MEMBER_SELECT),
680721
element(Tree.Kind.MEMBER_SELECT),
681-
element(Tree.Kind.METHOD_INVOCATION)).successors(3),
682-
block(
683-
element(Tree.Kind.IDENTIFIER, "list"),
684-
element(Tree.Kind.VARIABLE, "foo")).terminator(Tree.Kind.FOR_EACH_STATEMENT).successors(1, 2),
722+
element(Tree.Kind.METHOD_INVOCATION)).successors(2),
685723
block(
686724
element(Tree.Kind.IDENTIFIER, "foo"),
687725
element(Tree.Kind.IDENTIFIER, "System"),
688726
element(Tree.Kind.MEMBER_SELECT),
689727
element(Tree.Kind.MEMBER_SELECT),
690-
element(Tree.Kind.METHOD_INVOCATION)).successors(3),
728+
element(Tree.Kind.METHOD_INVOCATION)).successors(2),
729+
block(
730+
element(Tree.Kind.IDENTIFIER, "list"),
731+
element(Tree.Kind.VARIABLE, "foo")).terminator(Tree.Kind.FOR_EACH_STATEMENT).successors(1, 3),
691732
block(
692733
element(Tree.Kind.CHAR_LITERAL, "''"),
693734
element(Tree.Kind.IDENTIFIER, "System"),

0 commit comments

Comments
 (0)