@@ -16,6 +16,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
16
16
use rustc_middle:: mir:: interpret:: ConstValue ;
17
17
use rustc_middle:: ty:: subst:: { GenericArgKind , SubstsRef } ;
18
18
use rustc_middle:: ty:: { self , DefIdTree , TyCtxt } ;
19
+ use rustc_session:: parse:: ParseSess ;
20
+ use rustc_span:: source_map:: FilePathMapping ;
19
21
use rustc_span:: symbol:: { kw, sym, Symbol } ;
20
22
use std:: fmt:: Write as _;
21
23
use std:: mem;
@@ -484,20 +486,67 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
484
486
/// Render a sequence of macro arms in a format suitable for displaying to the user
485
487
/// as part of an item declaration.
486
488
pub ( super ) fn render_macro_arms < ' a > (
489
+ cx : & DocContext < ' _ > ,
487
490
matchers : impl Iterator < Item = & ' a TokenTree > ,
488
491
arm_delim : & str ,
489
492
) -> String {
490
493
let mut out = String :: new ( ) ;
491
494
for matcher in matchers {
492
- writeln ! ( out, " {} => {{ ... }}{}" , render_macro_matcher( matcher) , arm_delim) . unwrap ( ) ;
495
+ writeln ! ( out, " {} => {{ ... }}{}" , render_macro_matcher( cx, matcher) , arm_delim)
496
+ . unwrap ( ) ;
493
497
}
494
498
out
495
499
}
496
500
497
501
/// Render a macro matcher in a format suitable for displaying to the user
498
502
/// as part of an item declaration.
499
- pub ( super ) fn render_macro_matcher ( matcher : & TokenTree ) -> String {
500
- rustc_ast_pretty:: pprust:: tt_to_string ( matcher)
503
+ pub ( super ) fn render_macro_matcher ( cx : & DocContext < ' _ > , matcher : & TokenTree ) -> String {
504
+ if let Some ( snippet) = snippet_equal_to_token ( cx, matcher) {
505
+ snippet
506
+ } else {
507
+ rustc_ast_pretty:: pprust:: tt_to_string ( matcher)
508
+ }
509
+ }
510
+
511
+ /// Find the source snippet for this token's Span, reparse it, and return the
512
+ /// snippet if the reparsed TokenTree matches the argument TokenTree.
513
+ fn snippet_equal_to_token ( cx : & DocContext < ' _ > , matcher : & TokenTree ) -> Option < String > {
514
+ // Find what rustc thinks is the source snippet.
515
+ // This may not actually be anything meaningful if this matcher was itself
516
+ // generated by a macro.
517
+ let source_map = cx. sess ( ) . source_map ( ) ;
518
+ let span = matcher. span ( ) ;
519
+ let snippet = source_map. span_to_snippet ( span) . ok ( ) ?;
520
+
521
+ // Create a Parser.
522
+ let sess = ParseSess :: new ( FilePathMapping :: empty ( ) ) ;
523
+ let file_name = source_map. span_to_filename ( span) ;
524
+ let mut parser =
525
+ match rustc_parse:: maybe_new_parser_from_source_str ( & sess, file_name, snippet. clone ( ) ) {
526
+ Ok ( parser) => parser,
527
+ Err ( diagnostics) => {
528
+ for mut diagnostic in diagnostics {
529
+ diagnostic. cancel ( ) ;
530
+ }
531
+ return None ;
532
+ }
533
+ } ;
534
+
535
+ // Reparse a single token tree.
536
+ let mut reparsed_trees = match parser. parse_all_token_trees ( ) {
537
+ Ok ( reparsed_trees) => reparsed_trees,
538
+ Err ( mut diagnostic) => {
539
+ diagnostic. cancel ( ) ;
540
+ return None ;
541
+ }
542
+ } ;
543
+ if reparsed_trees. len ( ) != 1 {
544
+ return None ;
545
+ }
546
+ let reparsed_tree = reparsed_trees. pop ( ) . unwrap ( ) ;
547
+
548
+ // Compare against the original tree.
549
+ if reparsed_tree. eq_unspanned ( matcher) { Some ( snippet) } else { None }
501
550
}
502
551
503
552
pub ( super ) fn display_macro_source (
@@ -512,21 +561,21 @@ pub(super) fn display_macro_source(
512
561
let matchers = tts. chunks ( 4 ) . map ( |arm| & arm[ 0 ] ) ;
513
562
514
563
if def. macro_rules {
515
- format ! ( "macro_rules! {} {{\n {}}}" , name, render_macro_arms( matchers, ";" ) )
564
+ format ! ( "macro_rules! {} {{\n {}}}" , name, render_macro_arms( cx , matchers, ";" ) )
516
565
} else {
517
566
if matchers. len ( ) <= 1 {
518
567
format ! (
519
568
"{}macro {}{} {{\n ...\n }}" ,
520
569
vis. to_src_with_space( cx. tcx, def_id) ,
521
570
name,
522
- matchers. map( render_macro_matcher) . collect:: <String >( ) ,
571
+ matchers. map( |matcher| render_macro_matcher( cx , matcher ) ) . collect:: <String >( ) ,
523
572
)
524
573
} else {
525
574
format ! (
526
575
"{}macro {} {{\n {}}}" ,
527
576
vis. to_src_with_space( cx. tcx, def_id) ,
528
577
name,
529
- render_macro_arms( matchers, "," ) ,
578
+ render_macro_arms( cx , matchers, "," ) ,
530
579
)
531
580
}
532
581
}
0 commit comments