Skip to content

Commit 7dbbe02

Browse files
committed
SONARJAVA-1217 Refine raised issues
When the iterable is an identifier raise an issue only if its owner is a method to skip fields. When the iterable is not an identifier raise issues only for consecutives foreachs.
1 parent eccae94 commit 7dbbe02

3 files changed

Lines changed: 30 additions & 30 deletions

File tree

its/ruling/src/test/resources/expected/squid-S3047.json

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,15 +5,6 @@
55
'project:java/awt/Window.java':[
66
1614,
77
],
8-
'project:java/lang/ApplicationShutdownHooks.java':[
9-
104,
10-
],
11-
'project:java/lang/ProcessEnvironment.java':[
12-
279,
13-
],
14-
'project:javax/swing/colorchooser/ColorPanel.java':[
15-
96,
16-
],
178
'project:javax/swing/plaf/synth/SynthDesktopPaneUI.java':[
189
219,
1910
],

java-checks/src/main/java/org/sonar/java/checks/LoopsOnSameSetCheck.java

Lines changed: 18 additions & 18 deletions
Original file line numberDiff line numberDiff line change
@@ -37,11 +37,10 @@
3737
import org.sonar.squidbridge.annotations.SqaleConstantRemediation;
3838
import org.sonar.squidbridge.annotations.SqaleSubCharacteristic;
3939

40+
import javax.annotation.Nullable;
4041
import java.util.HashMap;
41-
import java.util.HashSet;
4242
import java.util.List;
4343
import java.util.Map;
44-
import java.util.Set;
4544

4645
@Rule(
4746
key = "S3047",
@@ -61,41 +60,42 @@ public List<Tree.Kind> nodesToVisit() {
6160
@Override
6261
public void visitNode(Tree tree) {
6362
Map<Symbol, Integer> forEachSymbols = new HashMap<>();
64-
Set<Tree> forEachIterables = new HashSet<>();
63+
Tree previousForeachIterable = null;
6564
for (Tree item : ((BlockTree) tree).body()) {
6665
if (item.is(Tree.Kind.FOR_EACH_STATEMENT)) {
67-
checkForEach(forEachSymbols, forEachIterables, (ForEachStatement) item);
66+
ForEachStatement forEachStatement = (ForEachStatement) item;
67+
checkForEach(forEachSymbols, previousForeachIterable, forEachStatement);
68+
previousForeachIterable = forEachStatement.expression();
6869
} else {
70+
previousForeachIterable = null;
6971
item.accept(new InvalidatorVisitor(forEachSymbols));
7072
}
7173
}
7274
}
7375

74-
private void checkForEach(Map<Symbol, Integer> forEachSymbols, Set<Tree> forEachIterables, ForEachStatement item) {
76+
private void checkForEach(Map<Symbol, Integer> forEachSymbols, @Nullable Tree previousIterable, ForEachStatement item) {
7577
ExpressionTree expressionTree = ExpressionsHelper.skipParentheses(item.expression());
7678
if (expressionTree.is(Tree.Kind.IDENTIFIER)) {
7779
checkForEachIdentifier(forEachSymbols, (IdentifierTree) expressionTree);
78-
} else {
79-
checkForEachExpression(forEachIterables, expressionTree);
80+
} else if (previousIterable != null) {
81+
checkForEachExpression(previousIterable, expressionTree);
8082
}
8183
}
8284

83-
private void checkForEachExpression(Set<Tree> forEachIterables, ExpressionTree expressionTree) {
84-
for (Tree subTree : forEachIterables) {
85-
if (SyntacticEquivalence.areEquivalent(expressionTree, subTree)) {
86-
addIssue(expressionTree, FirstSyntaxTokenFinder.firstSyntaxToken(subTree).line());
87-
return;
88-
}
85+
private void checkForEachExpression(Tree forEachIterable, ExpressionTree expressionTree) {
86+
if (SyntacticEquivalence.areEquivalent(expressionTree, forEachIterable)) {
87+
addIssue(expressionTree, FirstSyntaxTokenFinder.firstSyntaxToken(forEachIterable).line());
8988
}
90-
forEachIterables.add(expressionTree);
9189
}
9290

9391
private void checkForEachIdentifier(Map<Symbol, Integer> forEachSymbols, IdentifierTree node) {
9492
Symbol symbol = node.symbol();
95-
if (forEachSymbols.containsKey(symbol)) {
96-
addIssue(node, forEachSymbols.get(symbol));
97-
} else {
98-
forEachSymbols.put(symbol, ((JavaTree) node).getLine());
93+
if (symbol.owner().isMethodSymbol()) {
94+
if (forEachSymbols.containsKey(symbol)) {
95+
addIssue(node, forEachSymbols.get(symbol));
96+
} else {
97+
forEachSymbols.put(symbol, ((JavaTree) node).getLine());
98+
}
9999
}
100100
}
101101

java-checks/src/test/files/checks/LoopsOnSameSetCheck.java

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,17 +7,22 @@ private List<String> getList() {
77
return null;
88
}
99

10+
private List<String> globalStrings;
11+
1012
public void doSomethingToAList(List<String> strings, List<String> strings2) {
1113
for (String str : strings);
12-
for (String str : strings); // Noncompliant {{Combine this loop with the one that starts on line 11.}}
14+
foo();
15+
for (String str : strings); // Noncompliant {{Combine this loop with the one that starts on line 13.}}
1316
strings = null;
1417
for (String str : strings); // strings get reassigned
1518
for (String str : getList());
16-
for (String str : getList()); // Noncompliant {{Combine this loop with the one that starts on line 15.}}
19+
for (String str : getList()); // Noncompliant {{Combine this loop with the one that starts on line 18.}}
20+
foo();
21+
for (String str : getList()); // no issue if something in between for loops
1722
for (String str : foo());
1823
List<String> list = null;
1924
for (String str : list);
20-
for (String str : list); // Noncompliant {{Combine this loop with the one that starts on line 19.}}
25+
for (String str : list); // Noncompliant {{Combine this loop with the one that starts on line 24.}}
2126
if (list.size() > 10) {
2227
list.remove(0);
2328
}
@@ -35,5 +40,9 @@ void foo() {
3540
}
3641
}
3742
};
43+
for (String str : globalStrings);
44+
modifyGlobalStrings();
45+
// no issues for fields
46+
for (String str : globalStrings);
3847
}
3948
}

0 commit comments

Comments
 (0)