Skip to content

Commit

Permalink
SuspiciousListRemove: control flow with "return" is compliant (#4613)
Browse files Browse the repository at this point in the history
Leaving a loop with `return` is the same as leaving the loop
with `break`.

Co-authored-by: Julian Ladisch <[email protected]>
  • Loading branch information
erwan-serandour and julianladisch authored Dec 13, 2023
1 parent 3ec821f commit f1d1661
Show file tree
Hide file tree
Showing 2 changed files with 40 additions and 4 deletions.
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
package checks;

import java.util.ArrayList;
import java.util.List;

public class SuspiciousListRemove {
Expand Down Expand Up @@ -66,6 +67,34 @@ void controlFlow2(List<String> list) {
}
}

void controlFlowReturn(List<String> list) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).isEmpty()) {
list.remove(i); // Compliant because control flow with "return"
return;
}
}
}

String controlFlowReturn2(List<String> list) {
for (int i = 0; i < list.size(); i++) {
if (list.get(i).isEmpty()) {
return list.remove(i); // Compliant because control flow with "return"
}
}
return null;
}

List<String> controlFlowReturn3(List<String> list) {
List<String> deleted = new ArrayList<>();
for (int i = 0; i < list.size(); i++) {
if (list.get(i).isEmpty()) {
deleted.add(list.remove(i)); // Noncompliant
}
}
return deleted; // "return" is outside the loop
}

void coverage1(List<String> list, int from) {
for (this.x = from; this.x < list.size(); this.x++)
list.remove(this.x); // Consider only local vars
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@
import org.sonar.plugins.java.api.tree.ForStatementTree;
import org.sonar.plugins.java.api.tree.IdentifierTree;
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
import org.sonar.plugins.java.api.tree.ReturnStatementTree;
import org.sonar.plugins.java.api.tree.StatementTree;
import org.sonar.plugins.java.api.tree.Tree;
import org.sonar.plugins.java.api.tree.UnaryExpressionTree;
Expand Down Expand Up @@ -97,7 +98,7 @@ private static boolean isIncrementingLoop(ForStatementTree forStatementTree, Sym
private static class LoopBodyVisitor extends BaseTreeVisitor {
private final Symbol counter;
private MethodInvocationTree listRemove;
private boolean hasBreakOrContinue;
private boolean hasBreakOrContinueOrReturn;
private boolean isCounterAssigned;

public LoopBodyVisitor(Symbol counter) {
Expand All @@ -114,16 +115,22 @@ public void visitMethodInvocation(MethodInvocationTree tree) {

@Override
public void visitBreakStatement(BreakStatementTree tree) {
hasBreakOrContinue = true;
hasBreakOrContinueOrReturn = true;
super.visitBreakStatement(tree);
}

@Override
public void visitContinueStatement(ContinueStatementTree tree) {
hasBreakOrContinue = true;
hasBreakOrContinueOrReturn = true;
super.visitContinueStatement(tree);
}

@Override
public void visitReturnStatement(ReturnStatementTree tree) {
hasBreakOrContinueOrReturn = true;
super.visitReturnStatement(tree);
}

@Override
public void visitAssignmentExpression(AssignmentExpressionTree tree) {
if (tree.variable().is(Tree.Kind.IDENTIFIER)) {
Expand All @@ -141,7 +148,7 @@ public void visitUnaryExpression(UnaryExpressionTree tree) {
}

boolean hasIssue() {
return listRemove != null && !hasBreakOrContinue && !isCounterAssigned;
return listRemove != null && !hasBreakOrContinueOrReturn && !isCounterAssigned;
}
}

Expand Down

0 comments on commit f1d1661

Please sign in to comment.