typetools / typetools/checker-framework
@RequiresNonNull ignored when taking a method reference
Open
@smillst is already working on this.
Since Nov 4, 2019.
- Dominant language
- Java
- Stars
- 1.1k
- Forks
- 440
- Avg merge
- 1d 12h
- Merged PRs (30d)
- 134
Description
Annotating a method with @RequiresNonNull("myField") and then calling that from a lambda or Runnable without an in-line null check fails the checker (expected). But taking a method reference to the same method doesn't fail (which it probably should).
This means the method can be called in an invalid state (with myField == null), meaning the annotation loses a lot of its power.
Demonstration (the problematic line is the first call to ExecutorService#submit inside run()):
import java.util.concurrent.ExecutorService;
import java.util.concurrent.Executors;
import org.checkerframework.checker.nullness.qual.MonotonicNonNull;
import org.checkerframework.checker.nullness.qual.RequiresNonNull;
public class RequiresNonNullOnMethodReference {
@MonotonicNonNull private String monotonicField;
private void run() {
ExecutorService executorService = Executors.newSingleThreadExecutor();
// Method reference with outer and no null check
executorService.submit(this::myMethod); // Passes check (but should throw error)
if (monotonicField != null) {
executorService.submit(this::myMethod); // Passes check (not really expected, given the
// lambda & runnable equivalent below fail)
}
// Runnable with inner, outer and no null check
executorService.submit(() -> myMethod()); // Fails check (expected)
if (monotonicField != null) {
executorService.submit(() -> myMethod()); // Fails check (mostly expected)
}
executorService.submit(
() -> {
if (monotonicField != null) {
myMethod(); // Passes check (expected)
}
});
// Runnable with inner, outer and no null check
executorService.submit(
new Runnable() {
@Override
public void run() {
myMethod(); // Fails check (expected)
}
});
if (monotonicField != null) {
executorService.submit(
new Runnable() {
@Override
public void run() {
myMethod(); // Fails check (mostly expected)
}
});
}
executorService.submit(
new Runnable() {
@Override
public void run() {
if (monotonicField != null) {
myMethod(); // Passes check (expected)
}
}
});
executorService.shutdown();
}
@RequiresNonNull("monotonicField")
private void myMethod() {}
}
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
Assessment
This issue has not been assessed yet.