[java] ReturnEmptyCollectionRatherThanNull - fix false positive for

lambdas

Fixes #3721
This commit is contained in:
Andreas Dangel 2022-01-10 18:21:20 +01:00
parent 7173f65a87
commit ff2dfedf3c
No known key found for this signature in database
GPG Key ID: 93450DF2DF9A3FA3
3 changed files with 57 additions and 4 deletions

View File

@ -27,6 +27,7 @@ This is a {{ site.pmd.release_type }} release.
* [#3468](https://github.com/pmd/pmd/issues/3468): \[java] UnusedPrivateMethod false positive when outer class calls private static method on inner class
* java-errorprone
* [#3686](https://github.com/pmd/pmd/issues/3686): \[java] ReturnEmptyCollectionRatherThanNull - false negative with conditioned returns
* [#3721](https://github.com/pmd/pmd/issues/3721): \[java] ReturnEmptyCollectionRatherThanNull - false positive with stream and lambda
* java-performance
* [#3492](https://github.com/pmd/pmd/issues/3492): \[java] UselessStringValueOf: False positive when there is no initial String to append to

View File

@ -2923,14 +2923,15 @@ See Effective Java, 3rd Edition, Item 54: Return empty collections or arrays ins
<property name="xpath">
<value>
<![CDATA[
//MethodDeclaration
[
//ReturnStatement/Expression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral
[ancestor::MethodDeclaration[1]
[
(./ResultType/Type[pmd-java:typeIs('java.util.Collection')
or pmd-java:typeIs('java.util.Map')
or @ArrayType=true()])
]
]
//ReturnStatement/Expression/PrimaryExpression/PrimaryPrefix/Literal/NullLiteral
[not(./ancestor::StatementExpression)]
[not(./ancestor::LambdaExpression)]
]]>
</value>
</property>

View File

@ -174,4 +174,55 @@ public class Foo {
}
]]></code>
</test-code>
<test-code>
<description>[java] ReturnEmptyCollectionRatherThanNull - false positive with stream and lambda #3721</description>
<expected-problems>1</expected-problems>
<expected-linenumbers>37</expected-linenumbers>
<code><![CDATA[
import java.util.*;
import java.util.concurrent.Callable;
public class Foo {
private Map<Path, List<String>> joinFutures(Map<String, List<Future<String>>> map) {
Map<String, List<String>> joined = new HashMap<>();
for (String p : map.keySet()) {
List<String> evaluatedResult = map.get(p).stream()
.map(f -> {
try {
return f.get();
} catch (InterruptedException | ExecutionException e) {
e.printStackTrace();
return null; // <----- false positive here
}
})
.filter(Objects::nonNull)
.sorted(Comparator.naturalOrder())
.collect(Collectors.toList());
if (!evaluatedResult.isEmpty()) {
joined.put(p, evaluatedResult);
}
}
// checking basic lambdas and anonymous classes as well
Callable<Object> c = a -> { return null; }; // <----- false positive here
Callable<Object> c2 = new Callable<Object>() {
public Object call() {
return null; // <----- false positive here
}
};
Callable<List<String>> c3 = new Callable<List<String>>() {
public List<String> call() {
return null;
}
};
return joined;
}
}
]]></code>
</test-code>
</test-data>