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

refactor: streamline mayBeNullExpr flow #753

Merged
merged 2 commits into from Apr 4, 2023

Conversation

XN137
Copy link
Contributor

@XN137 XN137 commented Mar 31, 2023

the uniform flow is now:
- return early for obvious expression types
- determine initial exprMayBeNull through simple checks
- apply handler overrides in single place
- finally run dataflow if exprMayBeNull is true in single place

idea from discussion on other PR

open questions:

a) why are no tests failing when we return early from the switch for some expressions?
(this is giving performance benefits because we are not redundantly calling the handler chain or dataflow analysis)

-> no handler ever overrides those expression types and dataflow analysis does not matter for them?

b) why are no tests failing because we change the order of "dataflow" and "handler overrides" in some methods, even though they state the order difference is intentional and important there

-> order should be uniform with dataflow running last

@XN137 XN137 force-pushed the refactor-streamline-mayBeNullExpr branch from 9cb0c44 to 8618248 Compare March 31, 2023 09:07
@XN137 XN137 changed the title Refactor streamline may be null expr refactor: streamline mayBeNullExpr flow Mar 31, 2023
@msridhar
Copy link
Collaborator

Thanks for looking into this! Re: a) I put up a commit that shows the problem:

msridhar@69cea80

There, I changed the order of dataflow and handlers for method calls, and you can see that several tests fail. This is because we rely on dataflow to "override" results from the handler, e.g., in the case of a null check of a call to Optional.get(). Interestingly, in reading the code I ran into this:

msridhar@69cea80#diff-f5f114bb393be97fed48630313d15457ba3cbd039ad291304bbbb71245cf6c2aR146

Oddly, LibraryModelsHandler is running dataflow! Under the structure I proposed here this should not be necessary.

In general, I prefer a refactor like what is in the draft here to #748. Now that we've dug into this and I've swapped things in, I'd rather do things right and make the invariants and expectations clear if we're going to do a refactor.

@XN137
Copy link
Contributor Author

XN137 commented Mar 31, 2023

i was aware that LibraryModelsHandler is calling dataflow and also found it odd, i was assuming you guys would argue its there for good reasons (even though no test is failing without)

see my suggestion around this in #754

as for the "order problem" compare current master here versus there

if we always want dataflow to run after handler overrides, then yeah we can streamline as suggested in this PR

@XN137 XN137 force-pushed the refactor-streamline-mayBeNullExpr branch 2 times, most recently from 05cc788 to f34cd53 Compare April 1, 2023 07:43
break;
default:
// match switch expressions by comparing strings, so the code compiles on JDK versions < 12
if (expr.getKind().name().equals("SWITCH_EXPRESSION")) {
exprMayBeNull = nullnessFromDataflow(state, expr);
exprMayBeNull = true;
Copy link
Contributor Author

Choose a reason for hiding this comment

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

note that here and above, we used to first run dataflow and only then called the handler overrides

while now we would be doing it the other way round.
running dataflow last seems like the most uniform way?
also there are no tests failing so maybe the old order did not matter?

Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, agreed, running dataflow last uniformly is what we want.

Copy link
Collaborator

Choose a reason for hiding this comment

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

We do, under some circumstances, want handlers to override the results from the dataflow analysis, but I think this should in all cases be done by using one of the handler methods that run as part of the dataflow analysis itself, not the AST-node taking methods... (Edit: to clarify, I am agreeing with the uniform ordering here)

the uniform flow is now:
- return early for obvious expression types
- determine initial exprMayBeNull through simple checks
- apply handler overrides in single place
- finally run dataflow if exprMayBeNull is true in single place
@XN137 XN137 force-pushed the refactor-streamline-mayBeNullExpr branch from f34cd53 to 3127f16 Compare April 1, 2023 07:52
} else {
throw new RuntimeException(
"whoops, better handle " + expr.getKind() + " " + state.getSourceForNode(expr));
}
}
exprMayBeNull = handler.onOverrideMayBeNullExpr(this, expr, exprSymbol, state, exprMayBeNull);
return exprMayBeNull;
return exprMayBeNull && nullnessFromDataflow(state, expr);
Copy link
Contributor Author

Choose a reason for hiding this comment

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

together with the LibraryModelsHandler refactoring, this would be the only place where nullnessFromDataflow would be getting called still

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.

Overall this change looks really good to me! Modulo my relatively minor comment, I think we can shift this off of draft mode and land it (though @lazaroclapp you may want to look)

// Check handler.onOverrideMayBeNullExpr before dataflow.
exprMayBeNull = handler.onOverrideMayBeNullExpr(this, expr, exprSymbol, state, true);
return exprMayBeNull ? nullnessFromDataflow(state, expr) : false;
exprMayBeNull = true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Add a comment here saying we rely on inference / dataflow analysis for local variables

Copy link
Contributor Author

Choose a reason for hiding this comment

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

done, please check if it is as you had mind.

also i tried putting answers to the questions in the PR description, wdyt?

Copy link
Collaborator

Choose a reason for hiding this comment

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

LGTM. Will take another look later in the day and then likely land this

break;
default:
// match switch expressions by comparing strings, so the code compiles on JDK versions < 12
if (expr.getKind().name().equals("SWITCH_EXPRESSION")) {
exprMayBeNull = nullnessFromDataflow(state, expr);
exprMayBeNull = true;
Copy link
Collaborator

Choose a reason for hiding this comment

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

Yes, agreed, running dataflow last uniformly is what we want.

@XN137 XN137 marked this pull request as ready for review April 4, 2023 15:26
Copy link
Collaborator

@lazaroclapp lazaroclapp left a comment

Choose a reason for hiding this comment

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

Makes sense to me and thanks for the clean up! Once this and the LibraryModelsHandler change both land, I'd vote we do some internal sanity testing and also some performance testing. I think we cache dataflow results, so probably we won't see a difference from the reduced number of calls to it, but might be worth double-checking! Either way, the logic is clearer, I feel!

@msridhar msridhar merged commit 67c357e into uber:master Apr 4, 2023
7 checks passed
@XN137 XN137 deleted the refactor-streamline-mayBeNullExpr branch April 4, 2023 17:33
msridhar added a commit to msridhar/NullAway that referenced this pull request Jul 18, 2023
msridhar added a commit to msridhar/NullAway that referenced this pull request Jul 18, 2023
msridhar added a commit to msridhar/NullAway that referenced this pull request Jul 19, 2023
msridhar added a commit to msridhar/NullAway that referenced this pull request Jul 19, 2023
msridhar added a commit to msridhar/NullAway that referenced this pull request Jul 19, 2023
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