Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

NonComparableStreamSort validates direct types #1070

Merged
merged 2 commits into from
Dec 10, 2019
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@
import com.google.errorprone.util.ASTHelpers;
import com.sun.source.tree.ExpressionTree;
import com.sun.source.tree.MethodInvocationTree;
import com.sun.tools.javac.code.Symbol;
import com.sun.tools.javac.code.Type;
import java.util.stream.Stream;

Expand All @@ -36,7 +37,7 @@
name = "NonComparableStreamSort",
link = "https://github.com/palantir/gradle-baseline#baseline-error-prone-checks",
linkType = BugPattern.LinkType.CUSTOM,
severity = SeverityLevel.ERROR,
severity = SeverityLevel.WARNING,
summary = "Stream.sorted() should only be called on streams of Comparable types.")
public final class NonComparableStreamSort extends BugChecker implements BugChecker.MethodInvocationTreeMatcher {
private static final long serialVersionUID = 1L;
Expand All @@ -53,11 +54,19 @@ public Description matchMethodInvocation(MethodInvocationTree tree, VisitorState
return Description.NO_MATCH;
}
Type returnType = ASTHelpers.getReturnType(tree);
if (returnType == null || returnType.getTypeArguments().size() != 1) {
if (returnType == null) {
return Description.NO_MATCH;
}
Type streamParameterType = Iterables.getOnlyElement(returnType.getTypeArguments());
if (ASTHelpers.isCastable(streamParameterType, state.getTypeFromString(Comparable.class.getName()), state)) {
Symbol streamSymbol = state.getSymbolFromString(Stream.class.getName());
if (streamSymbol == null) {
return Description.NO_MATCH;
}
Type streamType = state.getTypes().asSuper(returnType, streamSymbol);
if (streamType.getTypeArguments().size() != 1) {
return Description.NO_MATCH;
}
Type streamParameterType = Iterables.getOnlyElement(streamType.getTypeArguments());
if (ASTHelpers.isSubtype(streamParameterType, state.getTypeFromString(Comparable.class.getName()), state)) {
return Description.NO_MATCH;
}
return buildDescription(tree)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,7 +41,7 @@ public void should_fail_on_non_comparable_stream() {
"class Test {",
" public static final void main(String[] args) {",
" List<Object> list = new ArrayList<>();",
" // BUG: Stream.sorted() should only be called on streams of Comparable types.",
" // BUG: Diagnostic contains: Stream.sorted() should only be called on streams of Comparable",
" list.stream().sorted();",
" }",
"}"
Expand All @@ -62,4 +62,21 @@ public void should_on_comparable_stream() {
"}"
).doTest();
}

@Test
public void should_fail_without_direct_types() {
compilationHelper.addSourceLines(
"Test.java",
"import java.util.List;",
"import java.util.ArrayList;",
"class Test {",
" public static final void main(String[] args) {",
" List<Iface> list = new ArrayList<>();",
" // BUG: Diagnostic contains: Stream.sorted() should only be called on streams of Comparable",
" list.stream().sorted();",
" }",
" interface Iface {}",
"}"
).doTest();
}
}
13 changes: 13 additions & 0 deletions changelog/@unreleased/pr-1070.v2.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
type: improvement
improvement:
description: |-
Improve `NonComparableStreamSort` to validate that stream types implement comparable, as opposed to validating that casting to comparable does not cause a compiler error.

This commit reduces the severity to WARNING because it's
possible that the check will flag code that happens to work
today, but we strongly recommend against sorting streams of
a type that is not directly comparable without a custom
comparator because it is likely to break later due to lack
of enforcement by the type system.
links:
- https://github.com/palantir/gradle-baseline/pull/1070