-
Notifications
You must be signed in to change notification settings - Fork 891
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
rustfmt does not understand cfg_attr used to start a rustdoc example/test #5420
Comments
Thank you for expanding with these details. Yes, fundamentally the problem is that you're trying to have rustfmt format something that doesn't actually exist at the phase rustfmt operates within. rustfmt works with the absolute earliest stages of the compiler's processing, fully before any and all macros expansion and semantic processing of attributes, features, etc. All rustfmt sees is the AST representation of a sequence of attributes, and the comment text exactly as authored in the input source file. As such, rustfmt will never be able to see and process your comment fully correctly (it recognizes certain code block languages and acts differently accordingly. There's probably some additional things at play which we can try to dig into, but want to stress that there's likely a relatively low ceiling of what can be done and that you may want to consider skipping formatting or perhaps refactoring things a bit (albeit at the expense of likely having to duplicate comment text) |
I think your thought process is correct here. I'm also inclined to believe that we're treating the first occurrence of ``` as an opening code fence. As @calebcartwright pointed out rustfmt operates on the AST pre-expansion. The relevant code is in Lines 382 to 501 in b3d4fb4
What's happening is (based on your first snippet):
The code fence issue not being wrapped to the next line when |
Thanks both for taking the time to dig into this. #5244 makes it much easier to deduce what is happening here as that had me confused.
A heuristic could be used to naively transform The cost of doing that would be negligible (only if such an attribute were encountered) but the real question would be how well it would handle the majority of cases using such a construct and how other cases might break differently with such a |
Just to clarify The docs for
|
I edited my previous comment just as you were posting yours. Thanks for explaining what I had missed. I was using astexplorer.net (which uses (I also realize that my suggested heuristic above was strictly one-way and didn't provide for how rustfmt would need to be modified to be able to emit rustdoc back in the same form it ingested it.) |
Would the advice from this Stack Overflow be an acceptable workaround for your issue? Something like this: //! ```
//! use size::Size;
//!
//! // This is a short comment. It causes no problems.
//! let s1 = Size::from_mib(13) / 2;
//! # #![cfg_attr(feature = "std")]
//! assert_eq!(s1, Size::from_mib(6.5_f32));
//!
//! // This is a contrived long comment line within what should be detected as a rustdoc section. With `wrap_comments = true`, this comment is mangled.
//! let s3 = Size::from_mib(12) - Size::from_mib(14.2_f64);
//! # #![cfg_attr(feature = "std")]
//! assert_eq!(s3, Size::from_kib(-2252.8));
//! ```
//!
//! I think `rustfmt` treats everything here as code and doesn't touch it via either of `wrap_comments` or `max_width`, although one or the other should?
//! My guess is that the closing ``` above are treated as opening ``` because the original ``` via
//! the cfg_attr macro isn't recognized. If not, then I think the easiest way to deal with this limitation right now is to slap a |
That's an option, although semantically it would be incorrect as the entire block is no longer valid. (In this case, without the I tried to use e.g. #![rustfmt::skip]
//! This is a module-level documentation with an accompanying test My naive reading would be that the #[rustfmt::skip]
//! This is a module-level documentation with an accompanying test wasn't valid because attributes don't apply to attributes but rather the first non-attribute thing after them. A |
Looks like there's an open issue for rustdoc to implement a feature like this rust-lang/rust#93083. For now, maybe you could try wrapping all the code that needs to be conditinally compiled in a block that will be hidden as suggested in the issue:
|
That's a much cleaner suggestion, thanks! Note that tests will still report "run" instead of "skipped" when using an unmatching feature with this approach vs the original way outlined in the issue. Would there be interest in implementing |
Sorry, but no, absolutely zero. Naturally we don't want to spend cycles to introduce rustfmt features that would be a relatively short term workaround for something that should (and ostensibly will) be addressed upstream. Regardless, there's myriad reasons both technical/internal and user facing as to why we wouldn't want to pursue an attribute-driven strategy. Thanks again bringing this to our attention and elevating from Discord with relevant details, though I'm going to close as it seems there's sufficient workarounds available already and no lasting/strategic action on our end that would make sense to pursue at this time. We can revisit down the road if there's no upstream movement, but we'd almost certainly need to go down the config route instead of attributes. |
@calebcartwright Thanks for the info and no hard feelings on my end. I do have but one follow-up however, evoked by your saying
I want to clarify that the example attribute (
which isn't actually possible, because you can't apply an attribute to the attribute, so the entire module would have been skipped from formatting in this case. To the best of my knowledge, In all cases, I agree that if there's some solution forthcoming from the rust side of things that it would obviate the need for any of this and be preferred to any workarounds we would deploy in rustfmt itself or the codebase being formatted. 👍 |
Thanks, but I'm aware 😉 I think you may have misinterpreted a few of my points, or perhaps I didn't include adequate detail to fully explain them, but either way it's moot at this point. The notion of dynamic formatting driven via outer attributes isn't new. There's been plenty of prior discussion, and suffice to say it's not happening. |
With
wrap_comments = true
, rustfmt mangles source code (in different ways) within a test/example in rustdoc if#![cfg_attr]
is used to enable the start of a code block:Sample input:
The result after a format run:
As you can see,
std
feature, the section should be recognized as code, just that it will either be ignored or executed by the test harness//
so it will be treated as code (and fail).wrap_comments
ormax_width
despite being in violation of both. As I mention, I think it's because the closing ``` is treated as opening one instead (because the actual opening one is not seen)But I'm not sure that's actually the explanation because with a different input, rustfmt mangles the closing ``` as well (for some reason it doesn't happen with the example above):
input:
formatted output:
Notice how here the text after the closing ``` is still not reformatted but the closing ``` was treated as text and merged with the (incorrectly) wrapped contents of the previous line. So it might be more complicated than that.
The text was updated successfully, but these errors were encountered: