Skip to content

Commit 445b488

Browse files
committed
SONARJAVA-1401 Correction of CFG for conditional OR/AND
1 parent 6e95154 commit 445b488

3 files changed

Lines changed: 39 additions & 22 deletions

File tree

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

Lines changed: 13 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -149,17 +149,6 @@ public Block falseBlock() {
149149
return falseBlock;
150150
}
151151

152-
Block branchingBlock() {
153-
if (elements.isEmpty() && terminator != null) {
154-
if (terminator.is(Tree.Kind.CONDITIONAL_AND)) {
155-
return falseBlock;
156-
} else if (terminator.is(Tree.Kind.CONDITIONAL_OR)) {
157-
return trueBlock;
158-
}
159-
}
160-
return this;
161-
}
162-
163152
void addSuccessor(Block successor) {
164153
successors.add(successor);
165154
}
@@ -529,26 +518,30 @@ private void buildMemberSelect(MemberSelectExpressionTree mse) {
529518
}
530519

531520
private void buildConditionalAnd(BinaryExpressionTree tree) {
532-
// If the current block is itself a conditional expression, the false block should branch to the false block of it
533-
final Block falseBlock = currentBlock;
534-
// process RHS
521+
Block falseBlock = currentBlock;
535522
currentBlock = createBlock(falseBlock);
523+
// process RHS
536524
build(tree.rightOperand());
537-
final Block trueBlock = currentBlock;
538525
// process LHS
539-
currentBlock = createBranch(tree, trueBlock, falseBlock.branchingBlock());
540-
build(tree.leftOperand());
526+
buildConditionalBinaryLHS(tree, currentBlock, falseBlock);
541527
}
542528

543529
private void buildConditionalOr(BinaryExpressionTree tree) {
544-
// process RHS
545530
Block trueBlock = currentBlock;
546531
currentBlock = createBlock(trueBlock);
532+
// process RHS
547533
build(tree.rightOperand());
548-
Block falseBlock = currentBlock;
549534
// process LHS
550-
currentBlock = createBranch(tree, trueBlock.branchingBlock(), falseBlock);
535+
buildConditionalBinaryLHS(tree, trueBlock, currentBlock);
536+
}
537+
538+
private void buildConditionalBinaryLHS(BinaryExpressionTree tree, Block trueBlock, Block falseBlock) {
539+
currentBlock = createBlock();
540+
Block toComplete = currentBlock;
551541
build(tree.leftOperand());
542+
toComplete.terminator = tree;
543+
toComplete.addFalseSuccessor(falseBlock);
544+
toComplete.addTrueSuccessor(trueBlock);
552545
}
553546

554547
private void buildLabeledStatement(LabeledStatementTree labeledStatement) {

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -83,4 +83,8 @@ private void increment(int index, int index2) {
8383
}
8484
}
8585

86+
private boolean sizesDontMatch(boolean bool, boolean a, boolean b) {
87+
return (!bool && a) || (bool && b);
88+
}
89+
8690
}

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

Lines changed: 22 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -256,6 +256,7 @@ public ElementChecker(final Tree.Kind kind) {
256256
case PLUS_ASSIGNMENT:
257257
case ASSIGNMENT:
258258
case ARRAY_ACCESS_EXPRESSION:
259+
case LOGICAL_COMPLEMENT:
259260
case PLUS:
260261
break;
261262
default:
@@ -1141,7 +1142,7 @@ public void returnCascadedAnd() throws Exception {
11411142
final CFG cfg = buildCFG(
11421143
"void andAll(boolean a, boolean b, boolean c) { return a && b && c;}");
11431144
final CFGChecker cfgChecker = checker(
1144-
block(element(Kind.IDENTIFIER, "a")).terminator(Kind.CONDITIONAL_AND).ifTrue(4).ifFalse(1),
1145+
block(element(Kind.IDENTIFIER, "a")).terminator(Kind.CONDITIONAL_AND).ifTrue(4).ifFalse(3),
11451146
block(element(Kind.IDENTIFIER, "b")).successors(3),
11461147
terminator(Kind.CONDITIONAL_AND).ifTrue(2).ifFalse(1),
11471148
block(element(Kind.IDENTIFIER, "c")).successors(1),
@@ -1154,14 +1155,33 @@ public void returnCascadedOr() throws Exception {
11541155
final CFG cfg = buildCFG(
11551156
"void orAll(boolean a, boolean b, boolean c) { return a || b || c;}");
11561157
final CFGChecker cfgChecker = checker(
1157-
block(element(Kind.IDENTIFIER, "a")).terminator(Kind.CONDITIONAL_OR).ifTrue(1).ifFalse(4),
1158+
block(element(Kind.IDENTIFIER, "a")).terminator(Kind.CONDITIONAL_OR).ifTrue(3).ifFalse(4),
11581159
block(element(Kind.IDENTIFIER, "b")).successors(3),
11591160
terminator(Kind.CONDITIONAL_OR).ifTrue(1).ifFalse(2),
11601161
block(element(Kind.IDENTIFIER, "c")).successors(1),
11611162
terminator(Kind.RETURN_STATEMENT).successors(0));
11621163
cfgChecker.check(cfg);
11631164
}
11641165

1166+
@Test
1167+
public void complex_boolean_expression() throws Exception {
1168+
final CFG cfg = buildCFG(" private boolean fun(boolean bool, boolean a, boolean b) {\n" +
1169+
" return (!bool && a) || (bool && b);\n" +
1170+
" }");
1171+
final CFGChecker cfgChecker = checker(
1172+
block(
1173+
element(Kind.IDENTIFIER, "bool"),
1174+
element(Kind.LOGICAL_COMPLEMENT)
1175+
).terminator(Kind.CONDITIONAL_AND).ifTrue(5).ifFalse(4),
1176+
block(element(Kind.IDENTIFIER, "a")).successors(4),
1177+
terminator(Kind.CONDITIONAL_OR).ifTrue(1).ifFalse(3),
1178+
block(element(Kind.IDENTIFIER, "bool")).terminator(Kind.CONDITIONAL_AND).ifTrue(2).ifFalse(1),
1179+
block(element(Kind.IDENTIFIER, "b")).successors(1),
1180+
terminator(Kind.RETURN_STATEMENT).successors(0));
1181+
cfgChecker.check(cfg);
1182+
1183+
}
1184+
11651185
@Test
11661186
public void method_reference() throws Exception {
11671187
final CFG cfg = buildCFG("void fun() { foo(Object::toString); }");

0 commit comments

Comments
 (0)