-
Notifications
You must be signed in to change notification settings - Fork 854
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 type annotations #5
Comments
Will DI binding annotations like |
imho, they could be, but it seems awfully dodgy. |
If nothing else, changing binding annotations to type annotations seems unlikely/impossible since it would be an incompatible change to the JSR-330 spec. That said, I don't see any particular reason to think that type annotations would be especially likely to not have parameters. |
The proposed heuristics are generally reasonable. However, I am concerned about this one:
There are type annotations that take parameters; for instance, the Nullness Checker of the Checker Framework contains six of them ( When using the heuristics, I think google-java-format should examine as much code as possible -- at least the entire compilation unit or file, but preferably all the files that were passed to google-java-format. All the occurrences could vote on whether to treat the annotation as a declaration annotation or a type annotation. This will lead to correct results more often, and it will make the codebase more internally consistent. google-java-format can also look for a definition of the annotation definition in the files being formatted, which would give exact information. Here is an alternate approach that could make even fewer errors: tell google-java-format which annotations are type annotations. google-java-format could read a |
As a datapoint, this problem currently affects only 50 cases of This problem affects over 100 I work around the problem by running a wrapper around google-java-format: https://github.com/plume-lib/run-google-java-format. It contains a lst of annotations that should be treated as type annotations. That strategy is simple and has worked well for me. Perhaps google-java-format could adopt it. google-java-format's list could be fully-qualified annotation names, which would avoid any possibility of ambiguity. |
Thanks for raising this again. We still want to do something here, it's just been on the back burner. We still don't have a huge number of type annotations, so it's a relatively minor annoyance. (Perhaps that will be changing soon, though...) Having a hard-coded list of fully qualified names of type annotations seems like the least bad option to me. I'd like to try baking that list into the formatter instead of having a separate configuration file (like |
I agree with your design (having a list of fully-qualified names of type annotations) and that it's least bad. |
We have code like the following and GJF does not reformat the code to move the annotation immediately after the documentation block: /**
* Some docs
*/
public static @Nullable Foo getFoo(String s) { That is an instance of this issue correct? In our case it is |
Baking a list into GJF is definitely better than the current situation. However, it doesn't seem to accommodate the use case of users who define a new type annotations. A configuration file would permit the user to notify GJF about the new type annotation. If the list of type annotations is only baked-in, then the user will have poorly-formatted code until upgrading to a new release of GJF that knows about the new annotation. Do you have thoughts about that use case? |
@cushon A ping for your thoughts on handling new user-defined type annotations. Thanks! |
I understand the use-case of configuring new type annotations without having to update a hard-coded list and wait for a release. I also think avoiding configuration in the formatter has generally been a success. So I see a trade-off here. |
Yes, there is a tradeoff. The question is which design you support. There would be no point in someone contributing a fix if you would reject the design. Can you give some guidance regarding the design decision of the maintainers? Thanks. |
@cushon A ping for your decision about which design the maintainers prefer. Here is another option: rather than reading a configuration file with a hard-coded name, it could be passed as a command-line argument. google-java-format already respects over half a dozen command-line arguments that change its formatting, so one more does not seem like a violation of its current design principles. |
I'm wondering if we've exhausted the possibilities that don't require a configuration list. What are the worst effects if all we do is implement 1-4 from comment #1? (Perhaps whether to add #5 or not is a question of numbers, but we'd take our internal numbers with a grain of salt since we aren't high CF adopters.) item 3 seems like the key, so that even when people have to fix it it can stay fixed. |
I have finally made some time to investigate having the formatter recognize type annotations and format them differently, e.g. preferring @Deprecated
@Nullable Object foo() {} I don't see good options for avoiding the config file. We could preserve the existing formatting, but since the formatter has been adding line breaks for annotations all along that would reduce the benefit for code bases that are already using the formatter. The current implementation just hard codes a couple of well known type annotations. My straw person proposal for configuration is to add a system property that takes a path to a file name containing a list of fully qualified names of annotations. So for example, you could have
And then invoke the formatter with something like:
|
… list Given e.g. `@Deprecated @nullable Object foo() {}`, prefer this: ``` @deprecated @nullable Object foo() {} ``` instead of: ``` @deprecated @nullable Object foo() {} ``` The implementation is complicated by the fact that the AST doesn't store source position information for modifiers, and there's no requirement that declaration annotations, modifiers, and type annotations appear in any particular order in source. To work around this, we examine the token stream to figure out the ordering of the modifiers and annotations. #5 PiperOrigin-RevId: 392459885
… list Given e.g. `@Deprecated @nullable Object foo() {}`, prefer this: ``` @deprecated @nullable Object foo() {} ``` instead of: ``` @deprecated @nullable Object foo() {} ``` The implementation is complicated by the fact that the AST doesn't store source position information for modifiers, and there's no requirement that declaration annotations, modifiers, and type annotations appear in any particular order in source. To work around this, we examine the token stream to figure out the ordering of the modifiers and annotations. #5 PiperOrigin-RevId: 392459885
… list Given e.g. `@Deprecated @nullable Object foo() {}`, prefer this: ``` @deprecated @nullable Object foo() {} ``` instead of: ``` @deprecated @nullable Object foo() {} ``` The implementation is complicated by the fact that the AST doesn't store source position information for modifiers, and there's no requirement that declaration annotations, modifiers, and type annotations appear in any particular order in source. To work around this, we examine the token stream to figure out the ordering of the modifiers and annotations. #5 PiperOrigin-RevId: 392459885
… list Given e.g. `@Deprecated @nullable Object foo() {}`, prefer this: ``` @deprecated @nullable Object foo() {} ``` instead of: ``` @deprecated @nullable Object foo() {} ``` The implementation is complicated by the fact that the AST doesn't store source position information for modifiers, and there's no requirement that declaration annotations, modifiers, and type annotations appear in any particular order in source. To work around this, we examine the token stream to figure out the ordering of the modifiers and annotations. #5 PiperOrigin-RevId: 392459885
… list Given e.g. `@Deprecated @nullable Object foo() {}`, prefer this: ``` @deprecated @nullable Object foo() {} ``` instead of: ``` @deprecated @nullable Object foo() {} ``` The implementation is complicated by the fact that the AST doesn't store source position information for modifiers, and there's no requirement that declaration annotations, modifiers, and type annotations appear in any particular order in source. To work around this, we examine the token stream to figure out the ordering of the modifiers and annotations. #5 PiperOrigin-RevId: 392769609
… list Given e.g. `@Deprecated @nullable Object foo() {}`, prefer this: ``` @deprecated @nullable Object foo() {} ``` instead of: ``` @deprecated @nullable Object foo() {} ``` The implementation is complicated by the fact that the AST doesn't store source position information for modifiers, and there's no requirement that declaration annotations, modifiers, and type annotations appear in any particular order in source. To work around this, we examine the token stream to figure out the ordering of the modifiers and annotations. #5 Roll forward of 1a87579 without a use of a server-only Guava API. PiperOrigin-RevId: 392785887
… list Given e.g. `@Deprecated @nullable Object foo() {}`, prefer this: ``` @deprecated @nullable Object foo() {} ``` instead of: ``` @deprecated @nullable Object foo() {} ``` The implementation is complicated by the fact that the AST doesn't store source position information for modifiers, and there's no requirement that declaration annotations, modifiers, and type annotations appear in any particular order in source. To work around this, we examine the token stream to figure out the ordering of the modifiers and annotations. #5 Roll forward of 1a87579 without a use of a server-only Guava API. PiperOrigin-RevId: 392919024
@cushon Release 1.12.0 says "Format type annotation as part of the type, not part of the modifiers list", but it only handles two |
It isn't a priority right now, but I think we'd take a PR that added a system property that specified a file containing additional type annotation qualified names to consider in |
@cushon I think more explanation is needed why you think configuration file is the only option here. Are you worried about compatibility with current behaviour? Current behaviour is a bug and doesn't match the preferable style laid out in https://google.github.io/styleguide/javaguide.html . Also @mernst's proposal to add hardcoded list and a well put reasoning in #802 looks sound to me. |
We always want to format type annotations in-line:
This is tricky in contexts where type annotations could be mixed together with declaration annotations, such as field, method, and variable declarations. There's no syntactic information to we can use to distinguish between
@NullableType Object foo() {}
and@Deprecated Object foo() {}
, but we want to output the first annotation in-line, and the second vertically.Currently, we output ambiguous annotations as declaration annotations. This is fine for Java 7, and has the advantage of never incorrectly formatting a declaration annotation as a type annotation.
Here are some possible heuristics we could use to support this case for Java 8:
If the declaration isn't a void-returning method, and it has no regular modifiers, consider the existing formatting: type annotations are probably on the same line as the type, declaration annotations are probably vertical. (The risk here is that we'd preserve things like
@Override Object foo() {}
.)If the declaration is named
@Override
, it's probably a declaration annotation. This would offset the disadvantage of (3), but it could be confusing if@Override
behaves differently than other annotations.An annotation with parameters is unlikely to be a type annotation, and should probably be formatted vertically.
The text was updated successfully, but these errors were encountered: