Open mernst opened 5 years ago
This behavior isn't great, I agree.
The reason for it is that @LengthOf
isn't actually claimed by any checker, so there is no AnnotatedTypeFactory
to query the return type of the method. @LengthOf
is an alias for @LTEqLengthOf
, but there's no way to differentiate the two from an annotated type factory's perspective.
One alternative would be looking at the annotation the user actually wrote (a la the Value Checker with @Positive
annotations), but that's restricted to where source code is available (meaning not the JDK, so we'd still need to special-case String#length()
).
An alternative to your proposal is to make @LengthOf
only a declaration annotation. We could then infer the @NonNegative @LtEqLengthOf
annotations in their appropriate type factories. The resulting bytecode would then have both LenghtOf
(as a declaration annotation) and standard lower/upper bound annotations.
Would that address your concern?
@LengthOf
expresses a fact about an expression's value. Therefore, it should be a type annotation. Also, for maximal expressiveness and least surprise, it should be permitted to be written on any type, and not just on method return types.
I think a better solution is to make @LengthOf
only a type annotation, rather than making it only a method annotation.
If @LengthOf
is a type annotation, it needs to be available to checkers. Presumably, this means it needs to exist in an existing hierarchy or a new one.
What implementation difficulties does that present?
@LengthOf
doesn't fit into any of the Index Checker's existing type systems, because it is a "two-sided" annotation - it contains information about both the lowerbound and the upperbound. It's therefore most natural to represent it as an alias for @NonNegative @LtEqLengthOf
, which is what is done now.
As we both mentioned above, however, this prevents the SameLen Checker from finding this annotation in particular, because:
@LengthOf
@LengthOf
won't appear in pre-compiled bytecode because the LBC/UBC will replace it with their own annotationsIt sounds like you might be suggesting that @LengthOf
should be handled by its own type system. I do not think this is wise, because:
I also disagree with your characterization of @LengthOf
as definitely a fact about an expression's value. We've talked before about a @SizeMethod
or @LengthMethod
annotation to represent the method that returns the size of a collection when the collection is user defined, and I've always thought of @LengthOf
as a prototype implementation of that. Such an annotation is more naturally a declaration annotation, since its expressing a fact about the method (that this is the canonical method to call to get the length of the sequence).
I agree that the name @LengthOf
for a declaration annotation is confusing. What if we changed the name to @LengthMethod
, and then otherwise implemented what I suggested? (that is, make it a declaration annotation that creates a requirement that the return type is @IndexOrHigh
? That check could even be syntactic, and we could require users to write the annotations - I think I would prefer that design)
As currently specified, @LengthOf
is a type annotation and not a method annotation.
Changing its name, semantics, and target locations (as you propose) would be better than the current situation, and would address the known use cases. So, I could support that change. Thanks for the suggestion.
It is surprising that the type annotation LengthOf is meta-annotated as
Here is an excerpt from commit 71379bb7de:
We have a FAQ that says not to make an annotation applicable to both type uses and declarations.
The
METHOD
target has surprising results. For example, it means that when a source has only one occurrence of@LengthOf
, its corresponding .class file has two occurrences. A recent bug report says that this behavior is confusing.I propose that we clean up the code (and help Shubham, who reported the issue I mentioned above) by doing 2 things:
METHOD
fromLengthOf
's@Target
meta-annotation.String.length
inisLengthOfMethodInvocation
.Both items require changes to
isLengthOfMethodInvocation
.Regarding item 1:
In
isLengthOfMethodInvocation
this line should look for a type, not a declaration, annotation:Regarding item 2:
Remove the first clause from the implementation of
isLengthOfMethodInvocation
: