Open peter-lyons-kehl opened 1 year ago
This is a really unfortunate consequence of #12603. We do show rustdoc of proc macros, but we fail to expand your internal macros to generate the attribute macros in the first place.
The problem is that your internal macro prefixed_lint!
takes a path, which rustc would wrap in an opaque AST fragment upon macro expansion (see the Rust reference for details), but rust-analyzer does not (yes, it's a bug). So while your proc macros in allow_internal
receive paths wrapped in TokenTree::Group
when they're run by rustc, they receive plain paths when they're run by rust-analyzer.
One thing you can do to workaround this is to have prefixed_lint!
and other helper macros take paths as tt fragment type, because rustc special-cases it and wouldn't wrap it in the said opaque fragment. This requires changing other internal proc macros like generate_allow_attribute_macro_definition_prefixed
but should work properly with both rustc and rust-analyzer.
I hate to suggest a workaround instead of fixing the bug, but we've been failing to figure out how to resolve it properly, so this should be the quickest way to make your crate work in rust-analyzer. Sorry for the inconvenience.
Hi Ryo,
Thank you so mach for deep insight. Workarounds are fine.
Only for reference, or for anyone curious or with a similar problem: Unfortunately, and to my surprise, paths (or some paths, at least: like clippy::alloc_instead_of_core
, and any clippy::
or rustdoc::
valid lint paths) cannot be matched by tt
macro variables. (As https://veykril.github.io/tlborm/decl-macros/minutiae/fragment-specifiers.html#tt says, tt
"can match nearly anything" - but it doesn't say what correct/paired tokens tt
can't match).
That's with 1.71.0-nightly (e9e1bbc7a 2023-05-17)
, and even if the macro by example takes only one parameter (while in my crate I need two parameters, or more). Example is at https://github.com/peter-kehl/macro_rules_path_as_tt:
❯ cargo check
Checking macro_rules_path_as_tt v0.1.0 (/share/pkehl/GIT/macro_rules_path_as_tt)
error: no rules expected the token `::`
--> src/lib.rs:12:41
|
1 | macro_rules! prefixed_lint_versioned {
| ------------------------------------ when calling this macro
...
12 | prefixed_lint_versioned!(1.2, clippy::alloc_instead_of_core);
| ^^ no rules expected this token in macro call
|
note: while trying to match meta-variable `$lint_path:tt`
--> src/lib.rs:2:23
|
2 | ($major_minor:tt, $lint_path:tt) => {
| ^^^^^^^^^^^^^
error: no rules expected the token `::`
--> src/lib.rs:14:30
|
6 | macro_rules! consume_path_only {
| ------------------------------ when calling this macro
...
14 | consume_path_only!(clippy::alloc_instead_of_core);
| ^^ no rules expected this token in macro call
|
note: while trying to match meta-variable `$lint_path:tt`
--> src/lib.rs:7:6
|
7 | ($lint_path:tt) => {
Update: The above is even more strange, because I do have $lint_path:tt
working with macro_rules
. It's at
generate_allow_attribute_macro_definition_internal_with_given_docs
https://github.com/coop-rs/allow/tree/35c47bc7fcd223e6e853ac156585839ce34a80c4/allow_prefixed/src/lib.rs#L60 and generate_allow_attribute_macro_definition_internal
https://github.com/coop-rs/allow/tree/35c47bc7fcd223e6e853ac156585839ce34a80c4/allow_prefixed/src/lib.rs#L114.Anyway, I am exploring a different workaround: Since all prefixed lints have only one path level (either rustdoc::
or clippy::
prefix), I'll take the prefix and the lint name as two separate tt
parameters, and I'll join them together into a tt
(either with paste
crate or manually). I'll post here.
Another surprise: If a macro (by example) accepts a path
fragment (like $lint_path:path
), then such a macro CAN invoke another macro (by example) passing that meta variable, even if that other macro accepts it as tt
(like $lint_path:tt
):
macro_rules! consume_path_only_as_path_then_pass_down_as_tt {
($lint_path:path) => {
consume_tt_only!($lint_path);
};
}
macro_rules! consume_tt_only {
($lint_path:tt) => {};
}
pub fn test_macro() {
// ...
// the following does compile!
consume_path_only_as_path_then_pass_down_as_tt!(clippy::alloc_instead_of_core);
}
(Updated https://github.com/peter-kehl/macro_rules_path_as_tt.)
Thank you. I confirm that using tt
all the way from the top level macro_rules!
is a good enough workaround. I'm lucky - I have a small number of macro_rules! combinations/"paths" to handle. Otherwise this would not be feasible.
(Then my only problem was that rust-analyzer
doesn't show rustdoc coming from stringify!
in #[doc = stringify!()]
- #8092. I've worked around by generating that from (another) proc macro, from another crate, of course - luckily I already had to use two levels of proc_macro crates.)
Feel free to close this issue (since it can be worked around), or keep open, as you see fit.
Thank you for
rust-analyzer
.use ... as ...;
under an alias.Example: Attribute macros aliased on purpose from https://docs.rs/allow_prefixed/latest/allow_prefixed (or from https://docs.rs/allow_prefixed/latest/allow):
Crrent
rust-analyzer
versionv0.3.1506
in current VS Code:Thank you in advance.