Skip to content

Commit d15d1ce

Browse files
authored
Merge pull request #103 from max-208/69-java
[Challenge-25][GCI69][S.T.E.P] Enumeration false positive
2 parents 1dead4d + 13290e8 commit d15d1ce

File tree

5 files changed

+99
-18
lines changed

5 files changed

+99
-18
lines changed

CHANGELOG.md

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
1010
### Added
1111

1212
### Changed
13+
14+
- [#103](https://github.com/green-code-initiative/creedengo-java/pull/103) GCI69 Java : calls to hasMoreElements() and nextElement() methods from java.util.Enumeration interface aren't flagged anymore when called in a for loop
1315
- [#110](https://github.com/green-code-initiative/creedengo-java/pull/110) GCI82 - remove false positives with reassignment using this and with passing a variable to a function it can be reassigned in
1416
- compatibility updates for SonarQube 25.5.0
1517
- upgrade libraries versions

src/it/java/org/greencodeinitiative/creedengo/java/integration/tests/GCIRulesIT.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -451,8 +451,8 @@ void testGCI69() {
451451
String filePath = "src/main/java/org/greencodeinitiative/creedengo/java/checks/NoFunctionCallWhenDeclaringForLoop.java";
452452
String ruleId = "creedengo-java:GCI69";
453453
String ruleMsg = "Do not call a function when declaring a for-type loop";
454-
int[] startLines = new int[]{58, 66, 74, 101};
455-
int[] endLines = new int[]{58, 66, 74, 101};
454+
int[] startLines = new int[]{62, 70, 78, 106, 127};
455+
int[] endLines = new int[]{62, 70, 78, 106, 127};
456456

457457
checkIssuesForFile(filePath, ruleId, ruleMsg, startLines, endLines);
458458
}

src/it/test-projects/creedengo-java-plugin-test-project/src/main/java/org/greencodeinitiative/creedengo/java/checks/NoFunctionCallWhenDeclaringForLoop.java

Lines changed: 39 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import java.util.List;
2020
import java.util.ListIterator;
2121
import java.util.Arrays;
22+
import java.util.Enumeration;
23+
import java.util.Collections;
24+
25+
2226
class NoFunctionCallWhenDeclaringForLoop {
2327

2428
public int getMyValue() {
@@ -94,26 +98,56 @@ public void test7() {
9498
}
9599

96100
// iterator called in an indirect way is allowed
97-
for (final OtherClassWithIterator otherClass = new OtherClassWithIterator(joursSemaine.iterator()); otherClass.iterator.hasNext(); jour = otherClass.iterator.next()) {
101+
for (final OtherClassWrapper otherClass = new OtherClassWrapper(joursSemaine.iterator()); otherClass.iterator.hasNext(); jour = otherClass.iterator.next()) {
98102
System.out.println(jour);
99103
}
104+
100105
// but using a method that returns an iterator causes an issue
101-
for (final OtherClassWithIterator otherClass = new OtherClassWithIterator(joursSemaine.iterator()); otherClass.getIterator().hasNext(); jour = otherClass.getIterator().next()) { // Noncompliant {{Do not call a function when declaring a for-type loop}}
106+
for (final OtherClassWrapper otherClass = new OtherClassWrapper(joursSemaine.iterator()); otherClass.getIterator().hasNext(); jour = otherClass.getIterator().next()) { // Noncompliant {{Do not call a function when declaring a for-type loop}}
107+
System.out.println(jour);
108+
}
109+
110+
}
111+
112+
// compliant, enumeration is allowed
113+
public void test8() {
114+
final List<String> joursSemaine = Arrays.asList("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche");
115+
116+
String jour = null;
117+
for (final Enumeration<String> enumeration = Collections.enumeration(joursSemaine); enumeration.hasMoreElements(); jour = enumeration.nextElement()) {
118+
System.out.println(jour);
119+
}
120+
121+
// enumeration called in an indirect way is allowed
122+
for(final OtherClassWrapper otherClass = new OtherClassWrapper(Collections.enumeration(joursSemaine)); otherClass.enumeration.hasMoreElements(); jour = otherClass.enumeration.nextElement()) {
123+
System.out.println(jour);
124+
}
125+
126+
// but using a method that returns an enumeration causes an issue
127+
for(final OtherClassWrapper otherClass = new OtherClassWrapper(Collections.enumeration(joursSemaine)); otherClass.getEnumeration().hasMoreElements(); jour = otherClass.getEnumeration().nextElement()) { // Noncompliant {{Do not call a function when declaring a for-type loop}}
102128
System.out.println(jour);
103129
}
104130

105131
}
106132

107133
}
108134

109-
class OtherClassWithIterator {
110-
public final Iterator<String> iterator;
135+
class OtherClassWrapper {
136+
public Iterator<String> iterator = null;
137+
public Enumeration<String> enumeration = null;
111138

112-
public OtherClassWithIterator(Iterator<String> iterator){
139+
public OtherClassWrapper(Iterator<String> iterator){
113140
this.iterator = iterator;
114141
}
142+
public OtherClassWrapper(Enumeration<String> enumeration){
143+
this.enumeration = enumeration;
144+
}
115145

116146
public Iterator<String> getIterator(){
117147
return iterator;
118148
}
149+
150+
public Enumeration<String> getEnumeration(){
151+
return enumeration;
152+
}
119153
}

src/main/java/org/greencodeinitiative/creedengo/java/checks/NoFunctionCallWhenDeclaringForLoop.java

Lines changed: 18 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@
2626

2727
import org.sonar.check.Rule;
2828
import org.sonar.plugins.java.api.IssuableSubscriptionVisitor;
29+
import org.sonar.plugins.java.api.semantic.MethodMatchers;
2930
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
3031
import org.sonar.plugins.java.api.tree.ClassTree;
3132
import org.sonar.plugins.java.api.tree.CompilationUnitTree;
@@ -44,6 +45,20 @@ public class NoFunctionCallWhenDeclaringForLoop extends IssuableSubscriptionVisi
4445

4546
protected static final String MESSAGERULE = "Do not call a function when declaring a for-type loop";
4647

48+
private static final String ITERATOR = "java.util.Iterator";
49+
private static final MethodMatchers ITERATOR_METHODS = MethodMatchers.create()
50+
.ofSubTypes(ITERATOR)
51+
.names("hasNext", "next")
52+
.withAnyParameters()
53+
.build();
54+
private static final String ENUMERATION = "java.util.Enumeration";
55+
private static final MethodMatchers ENUMERATION_METHODS = MethodMatchers.create()
56+
.ofSubTypes(ENUMERATION)
57+
.names("hasMoreElements", "nextElement")
58+
.withAnyParameters()
59+
.build();
60+
61+
4762
private static final Map<String, Collection<Integer>> linesWithIssuesByClass = new HashMap<>();
4863

4964
@Override
@@ -68,19 +83,15 @@ private class MethodInvocationInForStatementVisitor extends BaseTreeVisitor {
6883

6984
@Override
7085
public void visitMethodInvocation(MethodInvocationTree tree) {
71-
if (!lineAlreadyHasThisIssue(tree) && !isIteratorMethod(tree)) {
86+
if (!lineAlreadyHasThisIssue(tree) && !isMethodAllowed(tree)) {
7287
report(tree);
7388
return;
7489
}
7590
super.visitMethodInvocation(tree);
7691
}
7792

78-
private boolean isIteratorMethod(MethodInvocationTree tree) {
79-
boolean isIterator = tree.methodSymbol().owner().type().isSubtypeOf("java.util.Iterator");
80-
String methodName = tree.methodSelect().lastToken().text();
81-
boolean isMethodNext = methodName.equals("next");
82-
boolean isMethodHasNext = methodName.equals("hasNext");
83-
return isIterator && (isMethodNext || isMethodHasNext);
93+
private boolean isMethodAllowed(MethodInvocationTree tree) {
94+
return ITERATOR_METHODS.matches(tree) || ENUMERATION_METHODS.matches(tree);
8495
}
8596

8697
private boolean lineAlreadyHasThisIssue(Tree tree) {

src/test/files/NoFunctionCallWhenDeclaringForLoop.java

Lines changed: 38 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,10 @@
1919
import java.util.List;
2020
import java.util.ListIterator;
2121
import java.util.Arrays;
22+
import java.util.Enumeration;
23+
import java.util.Collections;
24+
25+
2226
class NoFunctionCallWhenDeclaringForLoop {
2327

2428
public int getMyValue() {
@@ -94,26 +98,56 @@ public void test7() {
9498
}
9599

96100
// iterator called in an indirect way is allowed
97-
for (final OtherClassWithIterator otherClass = new OtherClassWithIterator(joursSemaine.iterator()); otherClass.iterator.hasNext(); jour = otherClass.iterator.next()) {
101+
for (final OtherClassWrapper otherClass = new OtherClassWrapper(joursSemaine.iterator()); otherClass.iterator.hasNext(); jour = otherClass.iterator.next()) {
98102
System.out.println(jour);
99103
}
104+
100105
// but using a method that returns an iterator causes an issue
101-
for (final OtherClassWithIterator otherClass = new OtherClassWithIterator(joursSemaine.iterator()); otherClass.getIterator().hasNext(); jour = otherClass.getIterator().next()) { // Noncompliant {{Do not call a function when declaring a for-type loop}}
106+
for (final OtherClassWrapper otherClass = new OtherClassWrapper(joursSemaine.iterator()); otherClass.getIterator().hasNext(); jour = otherClass.getIterator().next()) { // Noncompliant {{Do not call a function when declaring a for-type loop}}
107+
System.out.println(jour);
108+
}
109+
110+
}
111+
112+
// compliant, enumeration is allowed
113+
public void test8() {
114+
final List<String> joursSemaine = Arrays.asList("Lundi", "Mardi", "Mercredi", "Jeudi", "Vendredi", "Samedi", "Dimanche");
115+
116+
String jour = null;
117+
for (final Enumeration<String> enumeration = Collections.enumeration(joursSemaine); enumeration.hasMoreElements(); jour = enumeration.nextElement()) {
118+
System.out.println(jour);
119+
}
120+
121+
// enumeration called in an indirect way is allowed
122+
for(final OtherClassWrapper otherClass = new OtherClassWrapper(Collections.enumeration(joursSemaine)); otherClass.enumeration.hasMoreElements(); jour = otherClass.enumeration.nextElement()) {
123+
System.out.println(jour);
124+
}
125+
126+
// but using a method that returns an enumeration causes an issue
127+
for(final OtherClassWrapper otherClass = new OtherClassWrapper(Collections.enumeration(joursSemaine)); otherClass.getEnumeration().hasMoreElements(); jour = otherClass.getEnumeration().nextElement()) { // Noncompliant {{Do not call a function when declaring a for-type loop}}
102128
System.out.println(jour);
103129
}
104130

105131
}
106132

107133
}
108134

109-
class OtherClassWithIterator {
135+
class OtherClassWrapper {
110136
public final Iterator<String> iterator;
137+
public final Enumeration<String> enumeration;
111138

112-
public OtherClassWithIterator(Iterator<String> iterator){
139+
public OtherClassWrapper(Iterator<String> iterator){
113140
this.iterator = iterator;
114141
}
142+
public OtherClassWrapper(Enumeration<String> enumeration){
143+
this.enumeration = enumeration;
144+
}
115145

116146
public Iterator<String> getIterator(){
117147
return iterator;
118148
}
149+
150+
public Enumeration<String> getEnumeration(){
151+
return enumeration;
152+
}
119153
}

0 commit comments

Comments
 (0)