JSpecify mode: a `@Nullable` element of an array initializer is accepted where the component type excludes null (`new Object[] {null}`)
Maintainers usually reply within 1 day
Nobody has claimed this yet.
Assessment
- Difficulty
- 3/5
- Estimated time
- Half a day
- Newbie friendliness
- 58/100
Research direction
Start with the existing check in NullAway.matchAssignment for ArrayAccessTree targets, which is where the a[0] = n diagnostic on line 19 comes from, and compare it with how NewArrayTree initializers are handled today. Add a JSpecify test in nullaway/src/test/java/com/uber/nullaway/jspecify/ covering the new Object[] {null}, new Object[] {n} and Object[] a = {n} cases. Done when those three lines report a diagnostic, while new @Nullable Object[] {null} and @Nullable Object[] a = {n} remain accepted.
Written by the indexing model from the issue text.
Description
With JSpecify mode on, a @Nullable value written as an element of an array initializer is accepted where the array's component type excludes null: new Object[] {null}, new Object[] {n} and Object[] a = {n} with n declared @Nullable Object produce no diagnostic. The same value written as a[0] = n is reported as "Writing @Nullable expression into array with @NonNull contents".
Versions: NullAway master at bc2fee556 (0.14.3-SNAPSHOT) and the 0.14.2 release. Error Prone 2.50.0, JDK 21.0.9. Flags: -XepOpt:NullAway:JSpecifyMode=true -XDaddTypeAnnotationsToSymbol=true -XepOpt:NullAway:OnlyNullMarked=true.
Code sample. I ran it as a test in nullaway/src/test/java/com/uber/nullaway/jspecify/, with makeTestHelperWithArgs(JSpecifyJavacConfig.withJSpecifyModeArgs(Arrays.asList("-XepOpt:NullAway:OnlyNullMarked=true"))). Each // BUG marker sits on the line above the statement it expects a diagnostic on.
import org.jspecify.annotations.NullMarked;
import org.jspecify.annotations.Nullable;
@NullMarked
class Test {
static Object[] literal() {
// BUG: Diagnostic contains: Writing @Nullable expression into array
return new Object[] {null};
}
static Object[] nullable(@Nullable Object n) {
// BUG: Diagnostic contains: Writing @Nullable expression into array
return new Object[] {n};
}
static void shorthand(@Nullable Object n) {
// BUG: Diagnostic contains: Writing @Nullable expression into array
Object[] a = {n};
}
static void element(Object[] a, @Nullable Object n) {
// BUG: Diagnostic contains: Writing @Nullable expression into array
a[0] = n;
}
}
Expected: a diagnostic on each initializer element that may be null, on lines 7, 11 and 15, as there is one on line 19 today:
Writing @Nullable expression into array with @NonNull contents.
The grounding is NullAway's own check for line 19: in @NullMarked code Object[] has a non-null component type, and an initializer element is written into that component exactly as a[0] = n is. Reusing the line 19 message is one possible shape; the requirement is the report. An initializer whose type admits null elements, new @Nullable Object[] {null} or @Nullable Object[] a = {n}, stays accepted.
Actual: only line 19 is reported, on master and on 0.14.2. The test fails with:
Did not see an error on line 7 matching Writing @Nullable expression into array. All errors:
/Test.java:19: warning: [NullAway] Writing @Nullable expression into array with @NonNull contents.
a[0] = n;
^
(see http://t.uber.com/nullaway )
Analysis, a guess; the report stands without it. The check for line 19 lives in NullAway.matchAssignment, under tree.getVariable() instanceof ArrayAccessTree, and compares mayBeNullExpr of the right-hand side against isArrayElementNullable of the array's type. NullAway implements no NewArrayTreeMatcher, so the elements of NewArrayTree.getInitializers() never reach a comparable check; the same two predicates applied to each initializer, with the component nullability taken from the NewArrayTree's type (or from the declared type for the {n} shorthand), would report lines 7, 11 and 15.
Related: the same gap hides a type-variable value with a nullable bound written into such an array, which is also a case of the documented "checking of generic class implementations" limitation (wiki, JSpecify Support); the CastToNonNullMethod side of that is #1961.
Assisted-by: Claude Code (claude-opus-5-5)
- Dominant language
- Java
- Stars
- 4.1k
- Forks
- 379
- Avg merge
- 1d 2h
- Merged PRs (30d)
- 106
Getting set up
- No Dockerfile or Docker Compose file
- Has a pull request template
- Read the contributing 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.
More from uber/NullAway
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
uber/NullAway#2145 · 1 reaction ·
Maintainers usually reply within 1 day
-
Difficulty 1/5 1-3 hours Newbie friendliness 85/100
uber/NullAway#2058 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 76/100
uber/NullAway#1899 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 5/5 Over a week Newbie friendliness 15/100
uber/NullAway#2160 · 1 comment ·
Maintainers usually reply within 1 day
-
Difficulty 3/5 1-2 days Newbie friendliness 62/100
Maintainers usually reply within 1 day
Similar issues
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100
johanhaleby/occurrent#1505 ·
Maintainers usually reply within 1 day
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
FasterXML/jackson-databind#6443 ·
Maintainers usually reply within 1 day
-
Difficulty 2/5 1-3 hours Newbie friendliness 80/100
finos/fluxnova-bpm-platform#387 ·
Maintainers usually reply within 4 days
-
Difficulty 1/5 Under an hour Newbie friendliness 88/100