-
Notifications
You must be signed in to change notification settings - Fork 300
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
Handle assertThat(...).isNotNull() statements #304
Conversation
navahgar
commented
Apr 19, 2019
- This adds handling of some nullness assertions to NullAway. Specifically, this adds support for "assertThat(...).isNotNull()" statements.
- Issue Feature request: Recognize common "assertThat(...).isNotNull()" statements #301
- This change also includes unit tests for this functionality.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
A few comments, particularly around that Name
initialization we are trying to do and about putting this handler behind a Config flag. The rest are just nits, I think. Really nice overall! :)
nullaway/src/main/java/com/uber/nullaway/handlers/Handlers.java
Outdated
Show resolved
Hide resolved
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
private boolean areMethodNamesInitialized() { | ||
return isNotNull != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Actually, upon reflection, this whole thing is not thread safe, since this could execute concurrent with initializeMethodNames
and return true
when say isNotNullOwner
and the rest are still uninitialized. So the other method being synchronized
is mostly pointless.
My thoughts:
- I remain unsure whether the same BugChecker instance, and therefore this class, will be called in parallel, we could just leave both methods unprotected and the then fix it if it turns out it can. (cc: @msridhar , do you know the answer here? )
- We could conservatively move this check to
initializeMethodNames
and just have that method return early ifisNotNull
is already set, then callinitializeMethodNames
unconditionally fromonDataflowVisitMethodInvocation
- We could use
toString()
to match the methods, measure the overhead and leave it at that if it's not high. Early optimization being the root of all evil and all that :)
What do you think?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concurrency is only an issue with static fields, which we should avoid unless they are immutable values. There should be a single BugChecker instance per javac instance and it should not be getting called from multiple threads.
Since the only static fields here are final Strings we should be fine. But the synchronized
on the private method is unnecessary.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thanks for the clarification. Removed synchronized
on the method.
return matchesMethod(methodSymbol, assertThat, assertThatOwner); | ||
} | ||
|
||
private boolean matchesMethod( |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
👍
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good overall! I approve once @lazaroclapp's comments are addressed
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
} | ||
|
||
private boolean areMethodNamesInitialized() { | ||
return isNotNull != null; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Concurrency is only an issue with static fields, which we should avoid unless they are immutable values. There should be a single BugChecker instance per javac instance and it should not be getting called from multiple threads.
Since the only static fields here are final Strings we should be fine. But the synchronized
on the private method is unnecessary.
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
nullaway/src/main/java/com/uber/nullaway/handlers/Handlers.java
Outdated
Show resolved
Hide resolved
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
nullaway/src/main/java/com/uber/nullaway/handlers/AssertionHandler.java
Outdated
Show resolved
Hide resolved
"}") | ||
.doTest(); | ||
} | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
After adding the flag, do add a positive test that returns an error on the same code with the flag turned off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Added a test with flag turned off.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Looks good to me if tests pass!
Happy to land this and then add the JUnit API support before perf testing it internally, particularly since it's off by default.
🎉