mirror of
https://github.com/rust-lang/rust.git
synced 2026-05-31 13:40:15 +03:00
Correctly generate bang macro declaration in docs for attr/derive kinds
This commit is contained in:
@@ -585,38 +585,68 @@ pub(crate) fn has_doc_flag<F: Fn(&DocAttribute) -> bool>(
|
||||
|
||||
/// Render a sequence of macro arms in a format suitable for displaying to the user
|
||||
/// as part of an item declaration.
|
||||
fn render_macro_arms<'a>(
|
||||
fn render_macro_arms(
|
||||
tcx: TyCtxt<'_>,
|
||||
matchers: impl Iterator<Item = &'a TokenTree>,
|
||||
tokens: &rustc_ast::tokenstream::TokenStream,
|
||||
arm_delim: &str,
|
||||
) -> String {
|
||||
let mut tokens = tokens.iter();
|
||||
let mut out = String::new();
|
||||
for matcher in matchers {
|
||||
while let Some(mut token) = tokens.next() {
|
||||
// If this an attr/derive rule, it looks like `attr() () => {}`, so the token needs to be
|
||||
// handled at the same time as the actual matcher.
|
||||
//
|
||||
// Without that, we would end up with `attr()` on one line and the matcher `()` on another.
|
||||
let pre = if matches!(token, TokenTree::Token(..)) {
|
||||
let pre = format!("{}() ", render_macro_matcher(tcx, token));
|
||||
// Skipping the always empty `()` following the attr/derive ident.
|
||||
tokens.next();
|
||||
let Some(next) = tokens.next() else {
|
||||
return out;
|
||||
};
|
||||
token = next;
|
||||
pre
|
||||
} else {
|
||||
String::new()
|
||||
};
|
||||
writeln!(
|
||||
out,
|
||||
" {matcher} => {{ ... }}{arm_delim}",
|
||||
matcher = render_macro_matcher(tcx, matcher),
|
||||
" {pre}{matcher} => {{ ... }}{arm_delim}",
|
||||
matcher = render_macro_matcher(tcx, token),
|
||||
)
|
||||
.unwrap();
|
||||
// We skip the `=>`, macro "body" and the delimiter closing that "body" since we don't
|
||||
// render them.
|
||||
tokens.next();
|
||||
tokens.next();
|
||||
tokens.next();
|
||||
}
|
||||
out
|
||||
}
|
||||
|
||||
pub(super) fn display_macro_source(tcx: TyCtxt<'_>, name: Symbol, def: &ast::MacroDef) -> String {
|
||||
// Extract the spans of all matchers. They represent the "interface" of the macro.
|
||||
let matchers = def.body.tokens.chunks(4).map(|arm| &arm[0]);
|
||||
|
||||
if def.macro_rules {
|
||||
format!("macro_rules! {name} {{\n{arms}}}", arms = render_macro_arms(tcx, matchers, ";"))
|
||||
format!(
|
||||
"macro_rules! {name} {{\n{arms}}}",
|
||||
arms = render_macro_arms(tcx, &def.body.tokens, ";")
|
||||
)
|
||||
} else {
|
||||
if matchers.len() <= 1 {
|
||||
if def.body.tokens.len() <= 4 {
|
||||
format!(
|
||||
"macro {name}{matchers} {{\n ...\n}}",
|
||||
matchers =
|
||||
matchers.map(|matcher| render_macro_matcher(tcx, matcher)).collect::<String>(),
|
||||
matchers = def
|
||||
.body
|
||||
.tokens
|
||||
.get(0)
|
||||
.map(|matcher| render_macro_matcher(tcx, matcher))
|
||||
.unwrap_or_default(),
|
||||
)
|
||||
} else {
|
||||
format!("macro {name} {{\n{arms}}}", arms = render_macro_arms(tcx, matchers, ","))
|
||||
format!(
|
||||
"macro {name} {{\n{arms}}}",
|
||||
arms = render_macro_arms(tcx, &def.body.tokens, ",")
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -7,7 +7,7 @@ assert-text: ("#rustdoc-modnav .block.macro .current", "b")
|
||||
|
||||
define-function: (
|
||||
"check_macro",
|
||||
[name, info],
|
||||
[name, info, kind],
|
||||
block {
|
||||
// It should be present twice in the sidebar.
|
||||
assert-count: ("#rustdoc-modnav a[href='macro." + |name| + ".html']", 2)
|
||||
@@ -24,11 +24,16 @@ define-function: (
|
||||
assert-count: ("#rustdoc-modnav .current", 2)
|
||||
// We check it has the expected information.
|
||||
assert-text: ("h3.macro-info", "ⓘ This is " + |info| + "/function macro")
|
||||
// We check how the item declaration looks like.
|
||||
assert-text: (".item-decl", "macro_rules! " + |name| + " {
|
||||
" + |kind| + "() () => { ... };
|
||||
() => { ... };
|
||||
}")
|
||||
}
|
||||
)
|
||||
|
||||
call-function: ("check_macro", {"name": "attr_macro", "info": "an attribute"})
|
||||
call-function: ("check_macro", {"name": "derive_macro", "info": "a derive"})
|
||||
call-function: ("check_macro", {"name": "attr_macro", "info": "an attribute", "kind": "attr"})
|
||||
call-function: ("check_macro", {"name": "derive_macro", "info": "a derive", "kind": "derive"})
|
||||
|
||||
define-function: (
|
||||
"crate_page",
|
||||
@@ -74,3 +79,13 @@ define-function: (
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/all.html"
|
||||
call-function: ("all_items_page", {"name": "attr_macro", "section_id": "attribute-macros"})
|
||||
call-function: ("all_items_page", {"name": "derive_macro", "section_id": "derives"})
|
||||
|
||||
// We now check a macro with all 3 different kinds.
|
||||
go-to: "file://" + |DOC_PATH| + "/test_docs/macro.one_for_all_macro.html"
|
||||
assert-text: (".item-decl", "macro_rules! one_for_all_macro {
|
||||
attr() () => { ... };
|
||||
derive() () => { ... };
|
||||
() => { ... };
|
||||
}")
|
||||
// We check it has the expected information.
|
||||
assert-text: ("h3.macro-info", "ⓘ This is an attribute/derive/function macro")
|
||||
|
||||
Reference in New Issue
Block a user