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

Add more Optional methods to ReturnValueIgnored #2282

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
Original file line number Diff line number Diff line change
Expand Up @@ -204,8 +204,16 @@ private static boolean functionalMethod(ExpressionTree tree, VisitorState state)
private static final Matcher<ExpressionTree> OPTIONAL_METHODS =
anyOf(
staticMethod().onClass("java.util.Optional"),
instanceMethod().onExactClass("java.util.Optional").named("filter"),
pkoenig10 marked this conversation as resolved.
Show resolved Hide resolved
instanceMethod().onExactClass("java.util.Optional").named("flatMap"),
instanceMethod().onExactClass("java.util.Optional").named("get"),
instanceMethod().onExactClass("java.util.Optional").named("isEmpty"),
instanceMethod().onExactClass("java.util.Optional").named("isPresent"),
instanceMethod().onExactClass("java.util.Optional").named("isEmpty"));
instanceMethod().onExactClass("java.util.Optional").named("map"),
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

FYI we have a separate check just for this one, with a fix that migrates to ifPresent: https://github.com/google/error-prone/blob/master/core/src/main/java/com/google/errorprone/bugpatterns/OptionalMapUnusedValue.java. We were planning to add map here after that cleanup was done.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Do you want me to remove map from here for now?

instanceMethod().onExactClass("java.util.Optional").named("or"),
instanceMethod().onExactClass("java.util.Optional").named("orElse"),
instanceMethod().onExactClass("java.util.Optional").named("orElseGet"),
instanceMethod().onExactClass("java.util.Optional").named("orElseThrow"));
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Calling orElseThrow to assert an Optional is present and then discarding the return result appears to be more common than the other examples here. I'm not really defending that as a pattern, just saying that making this one an error maybe not be lower priority for us. I'm curious if you've run into examples of that?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Occasionally, but rarely.

Copy link
Contributor Author

@pkoenig10 pkoenig10 Apr 13, 2021

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As a reference, SonarLint requires that return values are used for all Optional methods that return non-void values.
https://github.com/SonarSource/sonar-java/blob/d59d157c852ac924f3029ddb8c0aa366501f9fda/java-checks/src/main/java/org/sonar/java/checks/IgnoredReturnValueCheck.java#L68

Maybe we should do the same here?


/**
* The return values of {@link java.util.concurrent.TimeUnit} methods should always be checked.
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -17,10 +17,13 @@
package com.google.errorprone.bugpatterns;

import com.google.errorprone.CompilationTestHelper;
import com.google.errorprone.util.RuntimeVersion;
import org.junit.Test;
import org.junit.runner.RunWith;
import org.junit.runners.JUnit4;

import static org.junit.Assume.assumeTrue;

/** @author alexeagle@google.com (Alex Eagle) */
@RunWith(JUnit4.class)
public class ReturnValueIgnoredTest {
Expand Down Expand Up @@ -169,9 +172,72 @@ public void optionalInstanceMethods() {
" void optional() {",
" Optional<Integer> optional = Optional.of(42);",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.isPresent();",
" optional.filter(v -> v > 40);",
" optional.map(v -> Integer.toString(v));",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.flatMap(v -> Optional.of(v + 1));",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.get();",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.isPresent();",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.map(v -> v + 1);",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.orElse(40);",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.orElseGet(() -> 40);",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.orElseThrow(() -> new RuntimeException());",
" }",
"}")
.doTest();
}

@Test
public void optionalInstanceMethods_jdk9() {
assumeTrue(RuntimeVersion.isAtLeast9());
compilationHelper
.addSourceLines(
"Test.java",
"import java.util.Optional;",
"class Test {",
" void optional() {",
" Optional<Integer> optional = Optional.of(42);",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.or(() -> Optional.empty());",
" }",
"}")
.doTest();
}

@Test
public void optionalInstanceMethods_jdk10() {
assumeTrue(RuntimeVersion.isAtLeast10());
compilationHelper
.addSourceLines(
"Test.java",
"import java.util.Optional;",
"class Test {",
" void optional() {",
" Optional<Integer> optional = Optional.of(42);",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.orElseThrow();",
" }",
"}")
.doTest();
}

@Test
public void optionalInstanceMethods_jdk11() {
assumeTrue(RuntimeVersion.isAtLeast11());
compilationHelper
.addSourceLines(
"Test.java",
"import java.util.Optional;",
"class Test {",
" void optional() {",
" Optional<Integer> optional = Optional.of(42);",
" // BUG: Diagnostic contains: ReturnValueIgnored",
" optional.isEmpty();",
" }",
"}")
.doTest();
Expand Down