-
Notifications
You must be signed in to change notification settings - Fork 289
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
When using a property initializer in a primary constructor, the annotations don't have the correct use-site target #1760
Comments
It doesn't look though that the use-site target got lost in these examples, as it has never been specified explicitly? I don't think that's a correct expectation.
Not unless these use-site targets were set explicitly, the default is no use-site targets. And to answer the questions:
I'd say the user should be responsible for making sure there are no clashes, the library simply merges the annotations from the property and the parameter.
That's user error, I don't think the library should be correcting that error, as the library doesn't know what the user's real intent was. Also, please note that it's perfectly possible to generate incorrect, uncompilable code with KotlinPoet. KotlinPoet very deliberately doesn't act as a Kotlin compiler (even though it packages some basic correctness checks), this is not its purpose.
But this is not how Kotlin models these concepts. Primary constructor syntax allows you to simultaneously declare a property and a parameter with the same name, but they're still two different things, which KotlinPoet reflects. All in all, it's not really clear what the issue here is. Is the ask to have the library auto-generate use-site targets based on which specs the annotations are attached to? Or is the ask to have more complex rules around merging annotations from properties and parameters? |
I'm gonna close this issue as it's been inactive for over two weeks and it's not clear what the request is, but please feel free to reopen and clarify your expectations. Thank you! |
I missed the notification. All I'm saying is: if I annotate a property, it has a default use-site target of You wrote:
So I guess we're on the same page so far? Then, when I build a constructor where the property and parameter are merged, and KotlinPoet omits the use-site target, then the annotation which was originally meant for the parameter, it also gets copied to the property, or vice versa. What KotlinPoet does: if there was no use-site target on the originally built elements, then there's no use-site target on the final code output either. That is reasonable as well. The issue is that the lack of a use-site target has different meanings, because different contexts have different defaults. From that point of view, omitting the use-site target means adding a use-site target to an element where it was not specified. |
Got it, I see what you're saying, thanks for clarifying! I think it would make sense to generate use-site targets to preserve behaviour. |
Sample code
Expected behavior
If you run the above, the following is printed, which correctly shows that prop1 is annotated as a field but not as a constructor parameter, while prop2 is the opposite:
Unexpected behavior
If you uncomment the two lines in the original code to get the collapsed parameter+property syntax, both prop1 and prop2 have the same annotation, so as part of the collapsing process, the use-site target is lost:
Additional info
To match the built type fully, we would expect prop1 to have
@get:Suppress
and prop2 to have@param:Suppress
. Not having a use-site target is not too wrong, it just includes more scopes than necessary, while fixing this issue would remove some scopes. It raises some interesting questions though, like what if the user specifies a use-site target on the AnnotationSpec itself, who should win, what if they specify an incorrect use-site target (e.g. annotate the ParameterSpec as UseSiteTarget.FIELD which is wrong), what if someone likes the current behavior and only want to annotate either the PropertySpec or the ParameterSpec but not both, etc. I think most of these problems stem from the fact that the user is expected to build two elements which are generated as one, so of course some coercion will have to take place. If I could build a primary constructor with only PropertySpec's but not ParameterSpec's, it would be easier to figure out what the user really wanted, and the builder code would be less repetitive as well.The text was updated successfully, but these errors were encountered: