-
Notifications
You must be signed in to change notification settings - Fork 299
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
Enforce Strict Interpretation Of Type Use Annotation Locations Outside of JSpecify mode #1010
Conversation
Looks promising! But I don't see any checks in the code as to whether the relevant annotation is type use or declaration. Is that not needed? |
Codecov ReportAll modified and coverable lines are covered by tests ✅
Additional details and impacted files@@ Coverage Diff @@
## master #1010 +/- ##
============================================
- Coverage 86.00% 86.00% -0.01%
- Complexity 2087 2091 +4
============================================
Files 83 83
Lines 6903 6908 +5
Branches 1330 1331 +1
============================================
+ Hits 5937 5941 +4
Misses 551 551
- Partials 415 416 +1 ☔ View full report in Codecov by Sentry. |
Thanks for this @armughan11! Related to #708 (comment), I wanted to document the test scenarios we want to go through here.
I wrote down what I expect the nullability behavior to be in each case. For those cases with ❓ I think we should just preserve current behavior but I'm not 100% sure what that is. @armughan11 could you go through this table and make sure we have coverage of these cases? |
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.
Looking great! I have a few comments.
Also, I think we are missing some tests of the nullability of array elements in JSpecify mode. E.g., we need to test if we have a "both" annotation for the top level array reference (Object @Nullable []
), the array elements should not be treated as @Nullable
.
.doTest(); | ||
} | ||
|
||
private CompilationTestHelper makeHelper() { |
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.
private CompilationTestHelper makeHelper() { | |
private CompilationTestHelper makeLegacyModeHelper() { |
.addSourceLines( | ||
"Test.java", | ||
"package com.uber;", | ||
"import org.checkerframework.checker.nullness.qual.Nullable;", |
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.
Let's use the JSpecify @Nullable
when testing pure type use annotations
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.
Fixed
" @Nullable Object [][] foo4 = null;", | ||
" // ok according to spec", | ||
" Object @Nullable [][] foo5 = null;", | ||
" // NOT ok; @Nullable applies to first array dimension not the elements or the array ref", |
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.
What does "NOT ok" mean? I think in legacy mode we're just trying to preserve NullAway's legacy behavior? "NOT ok" makes it sound like we should report an error
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.
Fixed
.addSourceLines( | ||
"Test.java", | ||
"package com.uber;", | ||
"import org.checkerframework.checker.nullness.qual.Nullable;", |
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.
use jspecify annotation
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.
Fixed
" Object @Nullable[] foo2 = null;", | ||
" // ok, but @Nullable is not applied on top-level of array ", | ||
" @Nullable Object @Nullable [] foo3 = null;", | ||
" // ok only for backwards compat", |
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.
delete this line?
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.
Fixed
.addSourceLines( | ||
"Test.java", | ||
"package com.uber;", | ||
"import org.jetbrains.annotations.Nullable;", |
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.
I saw somewhere that the targets for JetBrains annotations have changed across releases. Maybe we should just declare our own annotation com.uber.Nullable
in the test that targets all the locations, to avoid issues?
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.
Here is a code snippet for adding our own "both" annotation to a test:
.addSourceLines(
"Nullable.java",
"package com.uber;",
"import java.lang.annotation.ElementType;",
"import java.lang.annotation.Target;",
"@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})",
"public @interface Nullable {}")
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.
Fixed, thanks for the snippet!
@@ -608,6 +608,25 @@ public void mismatchedIndexUse() { | |||
.doTest(); | |||
} | |||
|
|||
@Test | |||
public void typeUseAndDeclarationLegacyAnnotationOnArray() { |
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.
This is not testing legacy mode. In fact, is there a way for us to fail if the config says that both JSpecify mode and legacy mode are enabled? That shouldn't be allowed.
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.
Our JSpecify tests run fine when both are enabled. Do we still want to restrict this?
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.
@armughan11 I think yes, since it's just invalid, and probably the user made a mistake.
@ben-manes FYI this change may impact Caffeine. I think Caffeine uses Checker Framework annotations (which are type use) and might put them in the "wrong" place for declaring that array references are |
I'd be happy to make any updates and its an internal only change. I only see one case where an array is annotated /** Table of buffers. When non-null, size is a power of 2. */
volatile Buffer<E> @Nullable[] table; The array or its elements may be null, and the array is resized as needed. If that now prefers to be double annotated that's fine. I think the array elements being null was assumed by NullAway so I only had to specify that the array reference was, which is the correct syntax? |
That annotation looks correct and should work fine. Maybe I was thinking of an old version. I'll try to run a snapshot version of NullAway with this change on Caffeine and see if there are any unexpected errors. |
I've temporarily converted this PR to a draft. #1015, #1020, and #1021 should land before this one, and then we should cut a bug-fix release, and then we can land this. @armughan11 you can continue to work on the review comments and I will re-review |
8e94fd2
to
4b6187f
Compare
Co-authored-by: Manu Sridharan <[email protected]>
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.
Almost set! Just a couple of minor things.
Also can you confirm we have good coverage of whether array elements are treated as @Nullable
according to the table? I realize some of these tests may have existed already and are not part of this PR.
"import java.lang.annotation.ElementType;", | ||
"import java.lang.annotation.Target;", | ||
"@Target({ElementType.METHOD, ElementType.FIELD, ElementType.PARAMETER, ElementType.LOCAL_VARIABLE, ElementType.TYPE_USE})", | ||
"public @interface Nullable {}", |
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.
Let's use two test source files for clean-ness. Rough suggestion:
"public @interface Nullable {}", | |
"public @interface Nullable {}") | |
.addSourceLines("Test.java", | |
"package com.uber;", |
Please make the change in other places as well.
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.
Fixed
@msridhar For the three cases where we expect For annotations which are both in JSpecify mode, i have added that test as part of the latest commit. |
@ben-manes I confirmed there are no new errors due to this change on the master branch of Caffeine. |
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 great contribution!
Currently, outside of JSpecify, both top-level and element annotations are treated the same, i.e., considered as top-level annotations. This changes the default behavior by ignoring annotations on elements and adds a flag to revert back to legacy behavior.
Example:
Current Behavior:
Both assignments are fine
New Behavior:
The first assignment raises an error since annotations on elements are ignored altogether and NOT treated as top-level annotations. Fixes #1007