NullAway icon indicating copy to clipboard operation
NullAway copied to clipboard

@Contract("false -> !null") not honored

Open mhalbritter opened this issue 6 months ago • 5 comments

Hello!

I'd expected that code to compile:

String bar() {
    return foo(false);
}

@Contract("false -> !null")
@Nullable String foo(boolean returnNull) {
    if (returnNull) {
        return null;
    }
    return "foo";
}

Esssentially foo has a contract that if returnNull is false, the method never returns null.

Hoewever, when compiling this, NullAway errors:

error: [NullAway] returning @Nullable expression from method with @NonNull return type
        return foo(false);
        ^

(Wrongfully) changing the contract to

@Contract("_ -> !null")

and compilation works.

Maybe a case of partial support of @Contract annotations, as mentioned here?

mhalbritter avatar Jul 15 '25 11:07 mhalbritter

Reproducer: 1232.zip

mhalbritter avatar Jul 15 '25 11:07 mhalbritter

Thanks for the report. We have partial support for contracts and don't yet support detecting when true or false is passed as a literal argument. @mhalbritter is this showing up often in your code base?

msridhar avatar Jul 16 '25 03:07 msridhar

Can't say for sure, but I don't think so. I'm currently working on adding nullness annotations to our codebase, but it's far from done. So far, i've encountered the pattern two times.

mhalbritter avatar Jul 16 '25 07:07 mhalbritter

Thanks for the report. We have partial support for contracts and don't yet support detecting when true or false is passed as a literal argument. @mhalbritter is this showing up often in your code base?

In the Assert class in Spring Framework, we have several @Contract declarations that make use of boolean false in the contract clause.

Similarly, in the Assertions class in JUnit Jupiter, we have several @Contract declarations that make use of boolean true or false in the contract clause.

sbrannen avatar Jul 18 '25 14:07 sbrannen

@sbrannen do you have any examples with true or false in the antecedents and then null or !null in the consequent?

In any case, we can look into this one but it'll take a bit of work.

msridhar avatar Jul 23 '25 15:07 msridhar