Incorrect assignment assumption in try-with-resources
Answered
Hi team
The following code incorrectly raises a "Value '' is allways 'null'" warning:
Thing thing = null;
try (Resource autoCloseable = new Resource()) { // May throw a ClosingException **ONLY** when closed
thing = buildAThing(autoCloseable); // This throws nothing
return thing;
} catch (ClosingException e) {
return thing; // Warning: 'thing' is always 'null'
}
In this struct (typical case of ignoring closing exceptions), the code block inside try-with-resources never will throw an (checked) exception, and hence, assignment to 'thing' will always occur, and the warning is then false.
Please sign in to leave a comment.
Could you please provide full project example for investigation?
A single-file project does for the warning to rise.
Here, there is no way 'size' is not assigned: 'Stream.of' rises no exception, so can't fail. Same for 'Stream.count'. So 'size' will allways be assigned.
There are two paths this code may follow:
1.- Happy path:
2.- Unhappy path:
As you can see, in both paths `size` is always set (step 3), an hence the warning in step 6 is misleading.
Probably related, if we skip initializing 'size', replacing
Long size = null;
by
Long size;
then 'javac' raises error:
$ javac src/bugcheck.javasrc\bugcheck.java:10: error: variable size might not have been initialized
return size;
^
1 error
despite the same reasoning can be used to confirm 'size' will surely be initialized.
Sorry, I realized the previous example may be misleading.
In the example, 'Exception' may also be thrown by the resource definition ('Stream autoCloseable = ...'). In this case, 'size' could not be initialized, and hence the warning is right.
But the issue is still present even if we are only catching an exception that can only be thrown while closing resources:
public class bugcheck {
private static class MyAutoCloseable implements AutoCloseable {
@Override public void close() throws MyClosingException {}
Long count() { return 0L; }
private class MyClosingException extends Exception {}
}
private static Object nullCheck() {
Long size = null;
try (MyAutoCloseable autoCloseable = new MyAutoCloseable()) {
size = autoCloseable.count();
return size;
} catch (MyAutoCloseable.MyClosingException e) { // Only can be thrown when closing
return size;
}
}
}
Thanks for the example! I reported an issue on YouTrack: https://youtrack.jetbrains.com/issue/IDEA-181860
Please start following it to receive automatic notifications from YouTrack when the issue is updated.
See https://intellij-support.jetbrains.com/hc/en-us/articles/207241135-How-to-follow-YouTrack-issues-and-receive-notifications if you are not familiar with YouTrack.