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 @CheckReturnValue to detect common mistake through static analysis #159

Open
jodzga opened this issue Feb 15, 2018 · 5 comments
Open

Comments

@jodzga
Copy link

jodzga commented Feb 15, 2018

A common mistake among new to ParSeq is to treat Task as if it's creation caused is execution e.g.:

Task<RelevanceItems> getRelevanceItemsTask = _relevanceBackendClient.get(keys)
  .map(relevanceItems -> {
    if (Sets.difference(userItems, relevanceItems).size() > 0) {
      // Doesn’t actually execute since this is a Task but isn’t connected to parent task
      _userItemsClient.update(userId, userItems.addAll(relevanceItems));
    }
    return _userItems;
  });

Using jsr305 @CheckReturnValue on methods that return Task would allow detecting this mistake through static analysis.

@linjer
Copy link

linjer commented Feb 15, 2018

This would be an excellent feature!

I might suggest considering jsr308 and Checker Framework over new jsr305 usage.

jsr305 is incompatible with Java 9 and has been inactive for a long time now. This has spurred a number of recent proposals to migrate off js305. One of the most popular options has been jsr308 and the Checker Framework.

See google/guava#2960 for discussion around Guava's recent migration. They have chosen to already migrate to the Checker Framework for nullability checks, and I believe they are still deciding on other annotations.

Currently, a lot of tooling support is not quite there, but I suspect with the upcoming Java 9 breakage and Guava's migration, we should see broader support follow very soon.

@skylarbpayne
Copy link

skylarbpayne commented Feb 15, 2018

As I'm looking at this more, I'm not sure that a change like this would catch a majority of the cases I've seen.

If we put @CheckReturnValue annotations on all core methods in ParSeq returning tasks, then we will catch cases like:

Task<RelevanceItems> getRelevanceItemsTask = _relevanceBackendClient.get(keys)
  .map(relevanceItems -> {
    if (Sets.difference(userItems, relevanceItems).size() > 0) {
      // Doesn’t actually execute since this is a Task but isn’t connected to parent task
      Task.callable(() -> doSomeStuff());
    }
    return _userItems;
  });

But unless _userItemsClient.update also has this annotation, we will not detect an issue with:

Task<RelevanceItems> getRelevanceItemsTask = _relevanceBackendClient.get(keys)
  .map(relevanceItems -> {
    if (Sets.difference(userItems, relevanceItems).size() > 0) {
      // Doesn’t actually execute since this is a Task but isn’t connected to parent task
      _userItemsClient.update(userId, userItems.addAll(relevanceItems));
    }
    return _userItems;
  });

Ideally, we'd want to have some type of static check to ensure that all results of type Task<T> are not ignored. At the moment, I'm not sure whether that's feasible, but I'd like to find better ideas to catch this case.

@jodzga
Copy link
Author

jodzga commented Feb 15, 2018

One possibility is to create a custom FindBugs rule. It should not be too hard: refactor rule that validates @CheckReturnValue annotation with a twist that it applies to all methods (annotation is not necessary) which return Task type.
This could be a tiny contrib project.

@skylarbpayne
Copy link

@linjer
Copy link

linjer commented Feb 16, 2018

If this turns out to be high effort, I want to note that findbugs community is moving towards the spotbugs project.

Some alternatives could include

  • Adding this as a feature in spotbugs instead
  • Use Google ErrorProne

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

3 participants