Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix inconsistent treatment of generated code with restrictive annotations #618

Merged

Conversation

lazaroclapp
Copy link
Collaborator

Without this change, we have a bug whenever the following flags are
used together:

-XepOpt:NullAway:TreatGeneratedAsUnannotated=true
-XepOpt:NullAway:AcknowledgeRestrictiveAnnotations=true

and a method inside @Generated code is explicitly marked as having a
@Nullable return.

In this case, the RestrictiveAnnotationHandler would treat the method
as definitely @NonNull when handling the onOverrideMayBeNullExpr extension
point, but as @Nullable for the purposes of onDataflowVisitMethodInvocation.

This is inconsistent on its own, but it produces even more undesirable behavior
if a castToNonNull method is configured (whether through library models or
-XepOpt:NullAway:CastToNonNullMethod).

If foo is such a @Generated+@Nullable method, then, in the above
configuration:

Object o = castToNonNull(foo());
o.toString();

Produces an error, claiming that a known @NonNull value is being passed to
the cast.

Yet the following code:

Object o = foo();
o.toString();

Causes NullAway to complain about a @Nullable dereference (due to dataflow
concluding o is @Nullable).

To fix this, we need to make sure that the behavior of AcknowledgeRestrictiveAnnotations
is consistent.

One option is to not care about @Generated vs non-generated code, or
about TreatGeneratedAsUnannotated, and always use restrictive annotations
if available. Unfortunatelly, this is a change that will increase the number of
errors from NullAway on existing codebases (internally, we use
TreatGeneratedAsUnannotated explicitly as a way to relax our checks around
thrift generated code which does have @Nullable annotations). Thus, the one
remaining answer seems to be that, in this configuration, generated code should
be treated optimistically for both onOverrideMayBeNullExpr and dataflow.

…andler

Without this change, we have a bug whenever the following flags were
used together:

```
-XepOpt:NullAway:TreatGeneratedAsUnannotated=true
-XepOpt:NullAway:AcknowledgeRestrictiveAnnotations=true
```

and a method inside `@Generated` code is explicitly marked as having a
`@Nullable` return.

In this case, the `RestrictiveAnnotationHandler` would treat the method
as definitely `@NonNull` when handling the `onOverrideMayBeNullExpr` extension
point, but as `@Nullable` for the purposes of `onDataflowVisitMethodInvocation`.

This is inconsistent on its own, but it produces even more undesirable behavior
if a `castToNonNull` method is configured (whether through library models or
`-XepOpt:NullAway:CastToNonNullMethod`).

If `foo` is such a `@Generated`+`@Nullable` method, then, in the above
configuration:

```
Object o = castToNonNull(foo());
o.toString();
```

Produces an error, claiming that a known `@NonNull` value is being passed to
the cast.

Yet the following code:
```
Object o = foo();
o.toString();
```

Causes NullAway to complain about a `@Nullable` dereference (due to dataflow
concluding `o` is `@Nullable`).

To fix this, we need to make sure that the behavior of `AcknowledgeRestrictiveAnnotations`
is consistent.

One option is to not care about `@Generated` vs non-generated code, or
about `TreatGeneratedAsUnannotated`, and always use restrictive annotations
if available. Unfortunatelly, this is a change that will increase the number of
errors from NullAway on existing codebases (internally, we use
`TreatGeneratedAsUnannotated` explicitly as a way to relax our checks around
thrift generated code which does have `@Nullable` annotations). Thus, the one
remaining answer seems to be that, in this configuration, generated code should
be treated optimistically for both `onOverrideMayBeNullExpr` and dataflow.
@coveralls
Copy link

Pull Request Test Coverage Report for Build #887

  • 0 of 0 changed or added relevant lines in 0 files are covered.
  • 2 unchanged lines in 1 file lost coverage.
  • Overall coverage decreased (-0.01%) to 92.552%

Files with Coverage Reduction New Missed Lines %
../nullaway/src/main/java/com/uber/nullaway/dataflow/AccessPath.java 2 95.74%
Totals Coverage Status
Change from base Build #886: -0.01%
Covered Lines: 4859
Relevant Lines: 5250

💛 - Coveralls

Copy link
Collaborator

@msridhar msridhar left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nice find! This must have been tricky to track down

@lazaroclapp lazaroclapp merged commit 2c98f2b into master Jul 8, 2022
@lazaroclapp lazaroclapp deleted the lazaro_fix_restrictive_annotations_inconsistency branch July 8, 2022 17:28
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.

None yet

3 participants