@@ -17,6 +17,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
1717use rustc_middle:: mir:: interpret:: ConstValue ;
1818use rustc_middle:: ty:: subst:: { GenericArgKind , SubstsRef } ;
1919use rustc_middle:: ty:: { self , DefIdTree , TyCtxt } ;
20+ use rustc_session:: parse:: ParseSess ;
21+ use rustc_span:: source_map:: FilePathMapping ;
2022use rustc_span:: symbol:: { kw, sym, Symbol } ;
2123use std:: fmt:: Write as _;
2224use std:: mem;
@@ -486,20 +488,67 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
486488/// Render a sequence of macro arms in a format suitable for displaying to the user
487489/// as part of an item declaration.
488490pub ( super ) fn render_macro_arms < ' a > (
491+ tcx : TyCtxt < ' _ > ,
489492 matchers : impl Iterator < Item = & ' a TokenTree > ,
490493 arm_delim : & str ,
491494) -> String {
492495 let mut out = String :: new ( ) ;
493496 for matcher in matchers {
494- writeln ! ( out, " {} => {{ ... }}{}" , render_macro_matcher( matcher) , arm_delim) . unwrap ( ) ;
497+ writeln ! ( out, " {} => {{ ... }}{}" , render_macro_matcher( tcx, matcher) , arm_delim)
498+ . unwrap ( ) ;
495499 }
496500 out
497501}
498502
499503/// Render a macro matcher in a format suitable for displaying to the user
500504/// as part of an item declaration.
501- pub ( super ) fn render_macro_matcher ( matcher : & TokenTree ) -> String {
502- rustc_ast_pretty:: pprust:: tt_to_string ( matcher)
505+ pub ( super ) fn render_macro_matcher ( tcx : TyCtxt < ' _ > , matcher : & TokenTree ) -> String {
506+ if let Some ( snippet) = snippet_equal_to_token ( tcx, matcher) {
507+ snippet
508+ } else {
509+ rustc_ast_pretty:: pprust:: tt_to_string ( matcher)
510+ }
511+ }
512+
513+ /// Find the source snippet for this token's Span, reparse it, and return the
514+ /// snippet if the reparsed TokenTree matches the argument TokenTree.
515+ fn snippet_equal_to_token ( tcx : TyCtxt < ' _ > , matcher : & TokenTree ) -> Option < String > {
516+ // Find what rustc thinks is the source snippet.
517+ // This may not actually be anything meaningful if this matcher was itself
518+ // generated by a macro.
519+ let source_map = tcx. sess . source_map ( ) ;
520+ let span = matcher. span ( ) ;
521+ let snippet = source_map. span_to_snippet ( span) . ok ( ) ?;
522+
523+ // Create a Parser.
524+ let sess = ParseSess :: new ( FilePathMapping :: empty ( ) ) ;
525+ let file_name = source_map. span_to_filename ( span) ;
526+ let mut parser =
527+ match rustc_parse:: maybe_new_parser_from_source_str ( & sess, file_name, snippet. clone ( ) ) {
528+ Ok ( parser) => parser,
529+ Err ( diagnostics) => {
530+ for mut diagnostic in diagnostics {
531+ diagnostic. cancel ( ) ;
532+ }
533+ return None ;
534+ }
535+ } ;
536+
537+ // Reparse a single token tree.
538+ let mut reparsed_trees = match parser. parse_all_token_trees ( ) {
539+ Ok ( reparsed_trees) => reparsed_trees,
540+ Err ( mut diagnostic) => {
541+ diagnostic. cancel ( ) ;
542+ return None ;
543+ }
544+ } ;
545+ if reparsed_trees. len ( ) != 1 {
546+ return None ;
547+ }
548+ let reparsed_tree = reparsed_trees. pop ( ) . unwrap ( ) ;
549+
550+ // Compare against the original tree.
551+ if reparsed_tree. eq_unspanned ( matcher) { Some ( snippet) } else { None }
503552}
504553
505554pub ( super ) fn display_macro_source (
@@ -514,21 +563,21 @@ pub(super) fn display_macro_source(
514563 let matchers = tts. chunks ( 4 ) . map ( |arm| & arm[ 0 ] ) ;
515564
516565 if def. macro_rules {
517- format ! ( "macro_rules! {} {{\n {}}}" , name, render_macro_arms( matchers, ";" ) )
566+ format ! ( "macro_rules! {} {{\n {}}}" , name, render_macro_arms( cx . tcx , matchers, ";" ) )
518567 } else {
519568 if matchers. len ( ) <= 1 {
520569 format ! (
521570 "{}macro {}{} {{\n ...\n }}" ,
522571 vis. to_src_with_space( cx. tcx, def_id) ,
523572 name,
524- matchers. map( render_macro_matcher) . collect:: <String >( ) ,
573+ matchers. map( |matcher| render_macro_matcher( cx . tcx , matcher ) ) . collect:: <String >( ) ,
525574 )
526575 } else {
527576 format ! (
528577 "{}macro {} {{\n {}}}" ,
529578 vis. to_src_with_space( cx. tcx, def_id) ,
530579 name,
531- render_macro_arms( matchers, "," ) ,
580+ render_macro_arms( cx . tcx , matchers, "," ) ,
532581 )
533582 }
534583 }
0 commit comments