]> git.lizzy.rs Git - rust.git/commitdiff
rustdoc: Preserve rendering of macro_rules matchers when possible
authorDavid Tolnay <dtolnay@gmail.com>
Mon, 27 Dec 2021 21:44:14 +0000 (13:44 -0800)
committerDavid Tolnay <dtolnay@gmail.com>
Mon, 27 Dec 2021 22:20:18 +0000 (14:20 -0800)
src/librustdoc/clean/utils.rs
src/test/rustdoc/decl_macro.rs
src/test/rustdoc/macros.rs
src/test/rustdoc/reexports-priv.rs
src/test/rustdoc/reexports.rs

index 7d5e2e36bd1903a20afa7c370dc2c83972212581..5fe7dd6c2bc837a45f5c033a0c517dca876babf3 100644 (file)
@@ -16,6 +16,8 @@
 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,20 +486,67 @@ fn print_const_with_custom_print_scalar(tcx: TyCtxt<'_>, ct: &'tcx ty::Const<'tc
 /// 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 {
-    rustc_ast_pretty::pprust::tt_to_string(matcher)
+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(
@@ -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, ","),
             )
         }
     }
index fe19dadbe0243113ffde82585b78e34123115ef8..94ade31b5e5f4ce4f12bc5c5a830dc0d7cd400da 100644 (file)
@@ -9,7 +9,7 @@
 
 }
 
-// @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)*) {
@@ -18,8 +18,8 @@
 
 // @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 {
     (_) => {
@@ -33,7 +33,7 @@
     }
 }
 
-// @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 {
 
 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) => {}
             }
index 1cd454720e7d14250bc3fc07cb0e0be25f4dbcc9..ae0cf7a14789d78103c6cb4585ea36ab650153f7 100644 (file)
@@ -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 {
     () => [];
@@ -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 {
index 95f741807494cf8e8ba7b780ab2fb7d0783ecbd4..aea9b9f2b395dc1b85b63f0c891026607df629db 100644 (file)
@@ -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;
 
 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;
index 3b315308470356e4eae661fd59da051143927ad3..7abcbfb618122194125511eab7812079367b65e8 100644 (file)
@@ -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;
@@ -60,7 +60,7 @@
 
 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;