@@ -17,6 +17,8 @@ use rustc_hir::def_id::{DefId, LOCAL_CRATE};
17
17
use rustc_middle:: mir:: interpret:: ConstValue ;
18
18
use rustc_middle:: ty:: subst:: { GenericArgKind , SubstsRef } ;
19
19
use rustc_middle:: ty:: { self , DefIdTree , TyCtxt } ;
20
+ use rustc_session:: parse:: ParseSess ;
21
+ use rustc_span:: source_map:: FilePathMapping ;
20
22
use rustc_span:: symbol:: { kw, sym, Symbol } ;
21
23
use std:: fmt:: Write as _;
22
24
use std:: mem;
@@ -486,20 +488,67 @@ crate const DOC_RUST_LANG_ORG_CHANNEL: &str = env!("DOC_RUST_LANG_ORG_CHANNEL");
486
488
/// Render a sequence of macro arms in a format suitable for displaying to the user
487
489
/// as part of an item declaration.
488
490
pub ( super ) fn render_macro_arms < ' a > (
491
+ tcx : TyCtxt < ' _ > ,
489
492
matchers : impl Iterator < Item = & ' a TokenTree > ,
490
493
arm_delim : & str ,
491
494
) -> String {
492
495
let mut out = String :: new ( ) ;
493
496
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 ( ) ;
495
499
}
496
500
out
497
501
}
498
502
499
503
/// Render a macro matcher in a format suitable for displaying to the user
500
504
/// 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 }
503
552
}
504
553
505
554
pub ( super ) fn display_macro_source (
@@ -514,21 +563,21 @@ pub(super) fn display_macro_source(
514
563
let matchers = tts. chunks ( 4 ) . map ( |arm| & arm[ 0 ] ) ;
515
564
516
565
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, ";" ) )
518
567
} else {
519
568
if matchers. len ( ) <= 1 {
520
569
format ! (
521
570
"{}macro {}{} {{\n ...\n }}" ,
522
571
vis. to_src_with_space( cx. tcx, def_id) ,
523
572
name,
524
- matchers. map( render_macro_matcher) . collect:: <String >( ) ,
573
+ matchers. map( |matcher| render_macro_matcher( cx . tcx , matcher ) ) . collect:: <String >( ) ,
525
574
)
526
575
} else {
527
576
format ! (
528
577
"{}macro {} {{\n {}}}" ,
529
578
vis. to_src_with_space( cx. tcx, def_id) ,
530
579
name,
531
- render_macro_arms( matchers, "," ) ,
580
+ render_macro_arms( cx . tcx , matchers, "," ) ,
532
581
)
533
582
}
534
583
}
0 commit comments