Skip to content

Commit 36301b6

Browse files
BartLucienLucien Bart
andauthored
SONARJAVA-5219 S1319 Fix FP when type is used as function parameter (#5349)
Co-authored-by: Lucien Bart <[email protected]>
1 parent 504604f commit 36301b6

File tree

3 files changed

+86
-4
lines changed

3 files changed

+86
-4
lines changed

its/autoscan/src/test/resources/autoscan/diffs/diff_S1128.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3,4 +3,4 @@
33
"hasTruePositives": true,
44
"falseNegatives": 30,
55
"falsePositives": 0
6-
}
6+
}

java-checks-test-sources/default/src/main/java/checks/CollectionImplementationReferencedCheck.java

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
import java.util.HashMap;
44
import java.util.HashSet;
55
import java.util.LinkedList;
6+
import java.util.List;
67
import java.util.Map;
78
import java.util.Set;
89
import java.util.Stack;
@@ -11,9 +12,9 @@
1112
import java.util.Vector;
1213
import java.util.concurrent.ConcurrentHashMap;
1314
import java.util.concurrent.ConcurrentSkipListMap;
15+
import java.util.EnumSet;
1416

1517
class EmployeesTopLevel {
16-
1718
public EmployeesTopLevel(String s) { }
1819

1920
public HashSet<Employee> employees = new HashSet<>(); // Noncompliant {{The type of "employees" should be an interface such as "Set" rather than the implementation "HashSet".}} [[quickfixes=HashSet1]]
@@ -28,7 +29,6 @@ public EmployeesTopLevel(String s) { }
2829
// ^^^^^^^^^^
2930
// fix@LinkedList {{Replace "LinkedList" by "List"}}
3031
// edit@LinkedList [[sc=10;ec=20]] {{List}}
31-
// edit@LinkedList [[sl=5;sc=29;el=5;ec=29]] {{\nimport java.util.List;}}
3232

3333
private LinkedList<Employee> foo2() { return null; }
3434

@@ -49,7 +49,7 @@ public EmployeesTopLevel(String s) { }
4949
// ^^^^^^^^^^^^^^^^^
5050
// fix@ConcurrentHashMap {{Replace "ConcurrentHashMap" by "ConcurrentMap"}}
5151
// edit@ConcurrentHashMap [[sc=10;ec=27]] {{ConcurrentMap}}
52-
// edit@ConcurrentHashMap [[sl=12;sc=47;el=12;ec=47]] {{\nimport java.util.concurrent.ConcurrentMap;}}
52+
// edit@ConcurrentHashMap [[sl=13;sc=47;el=13;ec=47]] {{\nimport java.util.concurrent.ConcurrentMap;}}
5353

5454
public ConcurrentSkipListMap concurrentSkipListMap() { return null; } // Noncompliant {{The return type of this method should be an interface such as "ConcurrentMap" rather than the implementation "ConcurrentSkipListMap".}}
5555

@@ -153,7 +153,55 @@ public Integer foo14(LinkedList<Integer> list) { // Noncompliant
153153
return getList().poll();
154154
}
155155

156+
public void foo15(LinkedList<Integer> list){ // Compliant
157+
foo14(list);
158+
}
159+
160+
public void foo16(LinkedList<Integer> list){ // Compliant
161+
foo17(true, list);
162+
}
163+
164+
public void foo17(boolean bool, LinkedList<Integer> list){ // Noncompliant
165+
return;
166+
}
167+
168+
public void foo18(LinkedList<Integer> list){ // Noncompliant
169+
foo19(list);
170+
}
171+
172+
private void foo19(List<Integer> l){
173+
return;
174+
}
175+
156176
private LinkedList<Integer> getList() {
157177
return null;
158178
}
179+
180+
181+
public enum Fruit {
182+
APPLE,
183+
BANANA,
184+
ORANGE,
185+
PEAR;
186+
187+
// FP, EnumSet is used as argument in method
188+
public static final EnumSet<Fruit> FRUITS_FP = EnumSet.of(APPLE, ORANGE, PEAR); // Noncompliant
189+
190+
public static final EnumSet<Fruit> FRUITS = EnumSet.of(APPLE, ORANGE, PEAR); // Noncompliant
191+
192+
193+
public void useFruit(LinkedList<Integer> list1){ // Noncompliant
194+
EnumSet<Fruit> banana = EnumSet.complementOf(FRUITS_FP);
195+
FRUITS.contains(Fruit.APPLE);
196+
}
197+
198+
}
199+
200+
public void testEnum( EnumSet<Fruit> fruits){ // Compliant
201+
EnumSet<Fruit> banana = EnumSet.complementOf(fruits);
202+
EnumSet<Fruit> banana2 = EnumSet.complementOf(Fruit.FRUITS_FP);
203+
EnumSet<Fruit> notBanana = EnumSet.copyOf(fruits);
204+
}
205+
206+
159207
}

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

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,9 +30,12 @@
3030
import org.sonar.java.reporting.JavaTextEdit;
3131
import org.sonar.plugins.java.api.JavaFileScanner;
3232
import org.sonar.plugins.java.api.JavaFileScannerContext;
33+
import org.sonar.plugins.java.api.semantic.Type;
3334
import org.sonar.plugins.java.api.tree.BaseTreeVisitor;
35+
import org.sonar.plugins.java.api.tree.ExpressionTree;
3436
import org.sonar.plugins.java.api.tree.IdentifierTree;
3537
import org.sonar.plugins.java.api.tree.MemberSelectExpressionTree;
38+
import org.sonar.plugins.java.api.tree.MethodInvocationTree;
3639
import org.sonar.plugins.java.api.tree.MethodTree;
3740
import org.sonar.plugins.java.api.tree.Modifier;
3841
import org.sonar.plugins.java.api.tree.ModifiersTree;
@@ -361,5 +364,36 @@ public void visitMemberSelectExpression(MemberSelectExpressionTree tree) {
361364
excludedParameters.add(variableTree);
362365
}
363366
}
367+
368+
@Override
369+
public void visitMethodInvocation(MethodInvocationTree tree) {
370+
super.visitMethodInvocation(tree);
371+
372+
List<ExpressionTree> arguments = tree.arguments();
373+
var methodSymbol = tree.methodSymbol();
374+
if (methodSymbol.isUnknown()) {
375+
return;
376+
}
377+
var paramTypes = methodSymbol.parameterTypes();
378+
for (int i = 0; i < arguments.size(); i++) {
379+
processorArgument(arguments.get(i), paramTypes.get(i));
380+
}
381+
}
382+
383+
private void processorArgument(ExpressionTree argument, Type expectedType) {
384+
if (!(argument instanceof IdentifierTree)) {
385+
return;
386+
}
387+
388+
var variableName = ((IdentifierTree) argument).name();
389+
var variableTree = candidateParametersByName.get(variableName);
390+
if (variableTree == null) {
391+
return;
392+
}
393+
394+
if (expectedType.is(variableTree.type().symbolType().fullyQualifiedName())) {
395+
excludedParameters.add(variableTree);
396+
}
397+
}
364398
}
365399
}

0 commit comments

Comments
 (0)