-
Notifications
You must be signed in to change notification settings - Fork 295
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 correct type-use annotation locations for nested types #1045
Enforce correct type-use annotation locations for nested types #1045
Conversation
Codecov ReportAttention: Patch coverage is
Additional details and impacted files@@ Coverage Diff @@
## master #1045 +/- ##
============================================
- Coverage 87.62% 87.61% -0.02%
- Complexity 2160 2183 +23
============================================
Files 85 85
Lines 7103 7161 +58
Branches 1386 1404 +18
============================================
+ Hits 6224 6274 +50
- Misses 450 453 +3
- Partials 429 434 +5 ☔ View full report in Codecov by Sentry. |
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 a great start! I think we are missing checking on various occurrences of annotated types, like method return types. We should be doing checking in all the places that this checker does it. Can we add that, and also tests?
if (hasNestedClass(state.getTypes(), symbol.type)) { | ||
errorMessage = | ||
new ErrorMessage( | ||
MessageTypes.NULLABLE_ON_WRONG_NESTED_CLASS_LEVEL, | ||
"Type-use nullability annotations should be applied on inner class"); |
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 can't understand this check and why it occurs here? I think the check should occur independent of whether the initializer assignment is valid. If we need to possibly report multiple error messages from this method, we can use the state.reportMatch
API to report the errors and then just always return Description.NO_MATCH
.
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.
Changed the logic here to adhere to the ErrorProne flow.
if (types == null || type == null) { | ||
return false; | ||
} |
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.
If these null checks are necessary the parameters should be @Nullable
. But I don't think they are needed?
61b0cdc
to
213bc44
Compare
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 really promising! I still need to check the tests more carefully, but here are some comments on the code
|| TYPE_USE_OR_TYPE_PARAMETER.containsAll(elementTypes)); | ||
} | ||
|
||
private void handleNullabilityOnNestedClass( |
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 method should probably be renamed and it needs Javadoc. For renaming, how about:
private void handleNullabilityOnNestedClass( | |
private void checkNullableAnnotationPositionInType( |
Tree typeTree, | ||
Tree errorReportingTree, | ||
VisitorState state) { | ||
if (!(typeTree instanceof JCTree.JCFieldAccess)) { |
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.
The public version of JCTree.JCFieldAccess
is com.sun.source.tree.MemberSelectTree
; can we just use that here?
@@ -1487,6 +1509,70 @@ public Description matchVariable(VariableTree tree, VisitorState state) { | |||
return Description.NO_MATCH; | |||
} | |||
|
|||
private static boolean isOnlyTypeAnnotation(Symbol anno) { |
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.
Rename?
private static boolean isOnlyTypeAnnotation(Symbol anno) { | |
private static boolean isTypeUseAnnotation(Symbol anno) { |
I think this will return true for annotations that are both type use and declaration.
return true; | ||
} | ||
ImmutableSet<ElementType> elementTypes = ImmutableSet.copyOf(target.value()); | ||
// Return true only if annotation is not type-use only |
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.
Maybe:
// Return true only if annotation is not type-use only | |
// Return true for any annotation that is not exclusively a type-use annotation |
@@ -340,6 +343,9 @@ private static boolean isDirectTypeUseAnnotation(Attribute.TypeCompound t, Confi | |||
// In JSpecify mode and without the LegacyAnnotationLocations flag, annotations on array | |||
// dimensions are *not* treated as applying to the top-level type, consistent with the JSpecify | |||
// spec. | |||
// Outside of JSpecify mode, annotations which are *not* on the inner type are not treated as |
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.
Do we mean "Outside of JSpecify mode", or independent of JSpecify mode? If it's true no matter what, we can just delete "Outside of JSpecify mode". Or maybe the part about outside JSpecify mode just relates to the use of the legacy annotations mode?
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.
That's correct. Since we had earlier blocked using JSpecify mode and Legacy annotations together, this probably is a bit confusing. I'll remove it for the sake of it brevity
if (!hasNestedClass(symbol.type)) { | ||
if (innerTypeCount > 0) { | ||
return true; | ||
} | ||
} | ||
return innerTypeCount == nestingDepth - 1; |
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.
need a comment explaining this logic
" // @Nullable does not apply to the inner type", | ||
" // BUG: Diagnostic contains: @NonNull field f2 not initialized", |
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.
Can we fix up indentation in all the tests for readability?
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.
couple more comments on the tests
" // BUG: Diagnostic contains: Type-use nullability annotations should be applied on inner class", | ||
" @Nullable A.B foo4 = null;", | ||
" // BUG: Diagnostic contains: assigning @Nullable expression to @NonNull field", | ||
" A.B.@Nullable C [][] foo5 = 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.
If we are handling multi-dim arrays can we add a test where the field is actually @Nullable
? I think you need to write A.B.C @Nullable [][]
" // BUG: Diagnostic contains: Type-use nullability annotations should be applied on inner class", | ||
" public @Nullable A.B method4() { return null; }", | ||
" public @Nullable A method5() { return null; }", | ||
" public @Nullable int method6() { return 0; }", |
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.
remove this one? eventually this should be an error (but not for this PR). @Nullable
makes no sense on a primitive type
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.
one question
* @param state The visitor state | ||
*/ | ||
private void checkNullableAnnotationPositionInType( | ||
List<? extends AnnotationTree> annotations, Tree type, Tree tree, VisitorState state) { |
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 don't understand why we need the separate tree
parameter. Why just not report errors directly on the type
tree? Won't that be better?
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
…into type-use-location-nested-class
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 great now, thanks a lot!
Enforce correct type-use annotation locations for nested types as per JSpecify norms. We enforce type-use annotations to be on the inner class and raise an error if they are not. For annotations that are both type use and declaration, we raise an error at an invalid location.
Current behavior
New behavior
For annotations which are both declaration and annotation and type-use, only
foo2
throws an error since the location isn't apt for either scenarios