Skip to content
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

rustdoc: Preserve rendering of macro_rules matchers when possible #92334

Merged
merged 3 commits into from Jan 14, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
61 changes: 55 additions & 6 deletions src/librustdoc/clean/utils.rs
Expand Up @@ -16,6 +16,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
use rustc_middle::mir::interpret::ConstValue;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef};
use rustc_middle::ty::{self, DefIdTree, TyCtxt};
use rustc_session::parse::ParseSess;
use rustc_span::source_map::FilePathMapping;
use rustc_span::symbol::{kw, sym, Symbol};
use std::fmt::Write as _;
use std::mem;
Expand Down Expand Up @@ -484,20 +486,67 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
/// Render a sequence of macro arms in a format suitable for displaying to the user
/// as part of an item declaration.
pub(super) fn render_macro_arms<'a>(
tcx: TyCtxt<'_>,
matchers: impl Iterator<Item = &'a TokenTree>,
arm_delim: &str,
) -> String {
let mut out = String::new();
for matcher in matchers {
writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(matcher), arm_delim).unwrap();
writeln!(out, " {} => {{ ... }}{}", render_macro_matcher(tcx, matcher), arm_delim)
.unwrap();
}
out
}

/// Render a macro matcher in a format suitable for displaying to the user
/// as part of an item declaration.
pub(super) fn render_macro_matcher(matcher: &TokenTree) -> String {
rustc_ast_pretty::pprust::tt_to_string(matcher)
pub(super) fn render_macro_matcher(tcx: TyCtxt<'_>, matcher: &TokenTree) -> String {
if let Some(snippet) = snippet_equal_to_token(tcx, matcher) {
snippet
} else {
rustc_ast_pretty::pprust::tt_to_string(matcher)
}
}

/// Find the source snippet for this token's Span, reparse it, and return the
/// snippet if the reparsed TokenTree matches the argument TokenTree.
fn snippet_equal_to_token(tcx: TyCtxt<'_>, matcher: &TokenTree) -> Option<String> {
// Find what rustc thinks is the source snippet.
// This may not actually be anything meaningful if this matcher was itself
// generated by a macro.
camelid marked this conversation as resolved.
Show resolved Hide resolved
let source_map = tcx.sess.source_map();
let span = matcher.span();
let snippet = source_map.span_to_snippet(span).ok()?;

// Create a Parser.
let sess = ParseSess::new(FilePathMapping::empty());
camelid marked this conversation as resolved.
Show resolved Hide resolved
let file_name = source_map.span_to_filename(span);
let mut parser =
match rustc_parse::maybe_new_parser_from_source_str(&sess, file_name, snippet.clone()) {
Ok(parser) => parser,
Err(diagnostics) => {
for mut diagnostic in diagnostics {
diagnostic.cancel();
}
return None;
}
};

// Reparse a single token tree.
let mut reparsed_trees = match parser.parse_all_token_trees() {
Ok(reparsed_trees) => reparsed_trees,
Err(mut diagnostic) => {
diagnostic.cancel();
return None;
}
};
if reparsed_trees.len() != 1 {
return None;
}
let reparsed_tree = reparsed_trees.pop().unwrap();

// Compare against the original tree.
if reparsed_tree.eq_unspanned(matcher) { Some(snippet) } else { None }
}

pub(super) fn display_macro_source(
Expand All @@ -512,21 +561,21 @@ pub(super) fn display_macro_source(
let matchers = tts.chunks(4).map(|arm| &arm[0]);

if def.macro_rules {
format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(matchers, ";"))
format!("macro_rules! {} {{\n{}}}", name, render_macro_arms(cx.tcx, matchers, ";"))
} else {
if matchers.len() <= 1 {
format!(
"{}macro {}{} {{\n ...\n}}",
vis.to_src_with_space(cx.tcx, def_id),
name,
matchers.map(render_macro_matcher).collect::<String>(),
matchers.map(|matcher| render_macro_matcher(cx.tcx, matcher)).collect::<String>(),
)
} else {
format!(
"{}macro {} {{\n{}}}",
vis.to_src_with_space(cx.tcx, def_id),
name,
render_macro_arms(matchers, ","),
render_macro_arms(cx.tcx, matchers, ","),
)
}
}
Expand Down
12 changes: 6 additions & 6 deletions src/test/rustdoc/decl_macro.rs
Expand Up @@ -9,7 +9,7 @@ pub macro my_macro() {

}

// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok : tt) *) {'
// @has decl_macro/macro.my_macro_2.html //pre 'pub macro my_macro_2($($tok:tt)*) {'
// @has - //pre '...'
// @has - //pre '}'
pub macro my_macro_2($($tok:tt)*) {
Expand All @@ -18,8 +18,8 @@ pub macro my_macro_2($($tok:tt)*) {

// @has decl_macro/macro.my_macro_multi.html //pre 'pub macro my_macro_multi {'
// @has - //pre '(_) => { ... },'
// @has - //pre '($foo : ident.$bar : expr) => { ... },'
// @has - //pre '($($foo : literal), +) => { ... },'
// @has - //pre '($foo:ident . $bar:expr) => { ... },'
// @has - //pre '($($foo:literal),+) => { ... },'
// @has - //pre '}'
pub macro my_macro_multi {
(_) => {
Expand All @@ -33,7 +33,7 @@ pub macro my_macro_multi {
}
}

// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo : expr) {'
// @has decl_macro/macro.by_example_single.html //pre 'pub macro by_example_single($foo:expr) {'
// @has - //pre '...'
// @has - //pre '}'
pub macro by_example_single {
Expand All @@ -42,12 +42,12 @@ pub macro by_example_single {

mod a {
mod b {
// @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo : expr) {'
// @has decl_macro/a/b/macro.by_example_vis.html //pre 'pub(super) macro by_example_vis($foo:expr) {'
pub(in super) macro by_example_vis {
($foo:expr) => {}
}
mod c {
// @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo : expr) {'
// @has decl_macro/a/b/c/macro.by_example_vis_named.html //pre 'pub(in a) macro by_example_vis_named($foo:expr) {'
pub(in a) macro by_example_vis_named {
($foo:expr) => {}
}
Expand Down
14 changes: 14 additions & 0 deletions src/test/rustdoc/macro-generated-macro.rs
@@ -0,0 +1,14 @@
macro_rules! outer {
($($matcher:tt)*) => {
#[macro_export]
macro_rules! inner {
(<= $($matcher)* =>) => {};
}
}
}

// @has macro_generated_macro/macro.inner.html //pre 'macro_rules! inner {'
// @has - //pre '(<= type $($i : ident) :: * + $e : expr =>) => { ... };'
outer!(type $($i:ident)::* + $e:expr);

inner!(<= type foo::bar + x.sort() =>);
8 changes: 4 additions & 4 deletions src/test/rustdoc/macros.rs
@@ -1,7 +1,7 @@
// @has macros/macro.my_macro.html //pre 'macro_rules! my_macro {'
// @has - //pre '() => { ... };'
// @has - //pre '($a : tt) => { ... };'
// @has - //pre '($e : expr) => { ... };'
// @has - //pre '($a:tt) => { ... };'
// @has - //pre '($e:expr) => { ... };'
#[macro_export]
macro_rules! my_macro {
() => [];
Expand All @@ -12,8 +12,8 @@ macro_rules! my_macro {
// Check that exported macro defined in a module are shown at crate root.
// @has macros/macro.my_sub_macro.html //pre 'macro_rules! my_sub_macro {'
// @has - //pre '() => { ... };'
// @has - //pre '($a : tt) => { ... };'
// @has - //pre '($e : expr) => { ... };'
// @has - //pre '($a:tt) => { ... };'
// @has - //pre '($e:expr) => { ... };'
mod sub {
#[macro_export]
macro_rules! my_sub_macro {
Expand Down
8 changes: 4 additions & 4 deletions src/test/rustdoc/reexports-priv.rs
Expand Up @@ -5,7 +5,7 @@

extern crate reexports;

// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
// @!has 'foo/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
Expand Down Expand Up @@ -61,11 +61,11 @@ use reexports::UnionLocal;

pub mod outer {
pub mod inner {
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
// @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place : expr) {'
// @has 'foo/outer/inner/macro.addr_of_crate.html' '//*[@class="docblock item-decl"]' 'pub(crate) macro addr_of_crate($place:expr) {'
pub(crate) use reexports::addr_of_crate;
// @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place : expr) {'
// @has 'foo/outer/inner/macro.addr_of_super.html' '//*[@class="docblock item-decl"]' 'pub(in outer) macro addr_of_super($place:expr) {'
pub(super) use reexports::addr_of_super;
// @!has 'foo/outer/inner/macro.addr_of_self.html'
pub(self) use reexports::addr_of_self;
Expand Down
4 changes: 2 additions & 2 deletions src/test/rustdoc/reexports.rs
Expand Up @@ -4,7 +4,7 @@

extern crate reexports;

// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
// @has 'foo/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
// @!has 'foo/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
Expand Down Expand Up @@ -60,7 +60,7 @@ use reexports::UnionLocal;

pub mod outer {
pub mod inner {
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place : expr) {'
// @has 'foo/outer/inner/macro.addr_of.html' '//*[@class="docblock item-decl"]' 'pub macro addr_of($place:expr) {'
pub use reexports::addr_of;
// @!has 'foo/outer/inner/macro.addr_of_crate.html'
pub(crate) use reexports::addr_of_crate;
Expand Down