mirror of https://github.com/rust-lang/rust.git
rustdoc: Preserve rendering of macro_rules matchers when possible
This commit is contained in:
parent
f8abed9ed4
commit
336c85a053
|
@ -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;
|
||||
|
@ -484,21 +486,68 @@ 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>(
|
||||
cx: &DocContext<'_>,
|
||||
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(cx, 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 {
|
||||
pub(super) fn render_macro_matcher(cx: &DocContext<'_>, matcher: &TokenTree) -> String {
|
||||
if let Some(snippet) = snippet_equal_to_token(cx, 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(cx: &DocContext<'_>, 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.
|
||||
let source_map = cx.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());
|
||||
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(
|
||||
cx: &mut DocContext<'_>,
|
||||
|
@ -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, 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, 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, matchers, ","),
|
||||
)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue