Skip to content

Add @Nullable to more parameters. - #176

Merged
cpovirk merged 1 commit into
mainfrom
mostlyparam
Oct 13, 2026
Merged

cpovirk merged 1 commit into
mainfrom
mostlyparam

Conversation

@cpovirk

@cpovirk cpovirk commented Oct 13, 2026

Copy link
Copy Markdown
Collaborator

This is almost all from https://errorprone.info/bugpattern/ParameterMissingNullable but in its more aggressive mode, the one that looks for someParam == null in the implementation of a method and assumes that that makes the parameter nullable unless it's clearly doing something like throw new NullPointerException().

But I made two manual additions and many manual reverts.

Additions:

I covered another overload of Signature.ClassTypeSign.of beyond the one identified by the static checking.

I annotated the return type of Identity.getScope() as @Nullable to match the newly annotated constructor parameter. (Notice also that that field is left null by the other constructors.)

Reverts:

In InetAddress and Inet6Address, I reverted because the code goes on to throw UnknownHostException.

In URLConnection, I wasn't sure how seriously to take the seemingly nullable url constructor parameter, to say nothing of the protected url field or the public getURL method.

In URLStreamHandler.openConnection, I think maybe the checking got confused by ||?

In URLStreamHandler.setURL, I wasn't sure how seriously to take the seemingly nullable file and especially host parameter, and the method is deprecated, anyway. (It has an undeprecated overload that I didn't get into.)

BasicPermission.implies allows null, but it's an undocumented behavior of a deprecated method that overrides an inherited method, so I backed away.

Date has handling for null but only to fall through to throw IAE.

HashMap and CompletableFuture show that ParameterMissingNullable wants to turn V into @Nullable V in its aggressive mode, even when it shouldn't.

Hashtable.merge doesn't exactly show the same, and I think that method should probably throw for a null value, per the contract of Map.merge, as implemented in HashMap and tested in Guava.

I didn't feel like figuring out Cipher.init and its overload.

I was grossed out enough by the fact that Mac.update(null, ...) works for byte array (but not ByteBuffer!) that I didn't touch it. (I was also grossed out by how CipherInputStream.read(null, off, len) doesn't throw NPE, but I begrudgingly added @Nullable anyway.)

In ChoiceCallback and ConfirmationCallback, I didn't feel like I had a good enough handle on null choices to add @Nullable there.

X500Principal.getName checks for null but falls through to throw IAE.

I added @Nullable to the parameter of RuleBasedCollator.getCollationKey, matching my previous work on the return type. It would have made sense to continue on to Collator itself, but the null "support" here seems questionable: RulesBasedComparator itself throws if getCollationKey returns null, and proper null annotation in Collator would involve @Nullable on parameters of both compare overloads and in its implemented interface (producing Comparator<@Nullable Object>). getCollationKey might be a case for @PolyNull, but there is more going on there. (Collator probably "should have" been made a generic type.)

This is almost all from https://errorprone.info/bugpattern/ParameterMissingNullable but in its more aggressive mode, the one that [looks for `someParam == null` in the implementation of a method](https://github.com/google/error-prone/blob/9360a0a9423f0e4be68f3683dcfa080460ed0827/core/src/main/java/com/google/errorprone/bugpatterns/nullness/ParameterMissingNullable.java#L83) and assumes that that makes the parameter nullable unless it's clearly doing something like `throw new NullPointerException()`.

But I made two manual additions and many manual reverts.

Additions:

I covered another overload of `Signature.ClassTypeSign.of` beyond the one identified by the static checking.

I annotated the _return type_ of `Identity.getScope()` as `@Nullable` to match the newly annotated constructor parameter. (Notice also that that field is left null by the other constructors.)

Reverts:

In `InetAddress` and `Inet6Address`, I reverted because the code goes on to throw `UnknownHostException`.

In `URLConnection`, I wasn't sure how seriously to take the seemingly nullable `url` constructor parameter, to say nothing of the `protected` `url` field or the public `getURL` method.

In `URLStreamHandler.openConnection`, I think maybe the checking got confused by `||?`

In `URLStreamHandler.setURL`, I wasn't sure how seriously to take the seemingly nullable `file` and especially `host` parameter, and the method is deprecated, anyway. (It has an undeprecated overload that I didn't get into.)

`BasicPermission.implies` allows `null`, but it's an undocumented behavior of a deprecated method that overrides an inherited method, so I backed away.

`Date` has handling for `null` but only to fall through to throw IAE.

`HashMap` and `CompletableFuture` show that ParameterMissingNullable wants to turn `V` into `@Nullable V` in its aggressive mode, even when it shouldn't.

`Hashtable.merge` doesn't exactly show the same, and I think that method should probably throw for a null `value`, per [the contract of `Map.merge`](https://docs.oracle.com/en/java/javase/27/docs/api/java.base/java/util/Map.html#merge(K,V,java.util.function.BiFunction)), as [implemented in `HashMap`](https://github.com/openjdk/jdk/blob/a5afd6e6bf1be7c2c6b166b70e5e704e692b9854/src/java.base/share/classes/java/util/HashMap.java#L1388) and [tested in Guava](https://github.com/google/guava/blob/6b3a8d7498a7fde122967ba37a023ba3dcb47792/guava-testlib/src/com/google/common/collect/testing/testers/MapMergeTester.java#L150).

I didn't feel like figuring out `Cipher.init` and its overload.

I was grossed out enough by the fact that `Mac.update(null, ...)` works for byte array (but not `ByteBuffer`!) that I didn't touch it. (I was also grossed out by how `CipherInputStream.read(null, off, len)` doesn't throw NPE, but I begrudgingly added `@Nullable` anyway.)

In `ChoiceCallback` and `ConfirmationCallback`, I didn't feel like I had a good enough handle on null `choices` to add `@Nullable` there.

`X500Principal.getName` checks for `null` but falls through to throw IAE.

I added `@Nullable` to the parameter of `RuleBasedCollator.getCollationKey`, matching my previous work on the return type. It would have made sense to continue on to `Collator` itself, but the null "support" here seems questionable: `RulesBasedComparator` itself throws if `getCollationKey` returns null, and proper null annotation in `Collator` would involve `@Nullable` on parameters of both `compare` overloads and in its implemented interface (producing `Comparator<@nullable Object>`). `getCollationKey` might be a case for [`@PolyNull`](jspecify/jspecify#79), but there is more going on there. (`Collator` probably "should have" been made a generic type.)
@cpovirk
cpovirk merged commit c91bc3a into main Oct 13, 2026
30 checks passed
@cpovirk
cpovirk deleted the mostlyparam branch October 13, 2026 22:48
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

Successfully merging this pull request may close these issues.

2 participants