@@ -12,7 +12,7 @@ use self::Destination::*;
1212
1313use syntax_pos:: { COMMAND_LINE_SP , DUMMY_SP , FileMap , Span , MultiSpan , CharPos } ;
1414
15- use { Level , CodeSuggestion , DiagnosticBuilder , CodeMapper } ;
15+ use { Level , CodeSuggestion , DiagnosticBuilder , SubDiagnostic , CodeMapper } ;
1616use RenderSpan :: * ;
1717use snippet:: { StyledString , Style , Annotation , Line } ;
1818use styled_buffer:: StyledBuffer ;
@@ -30,7 +30,10 @@ pub trait Emitter {
3030
3131impl Emitter for EmitterWriter {
3232 fn emit ( & mut self , db : & DiagnosticBuilder ) {
33- self . emit_messages_default ( db) ;
33+ let mut primary_span = db. span . clone ( ) ;
34+ let mut children = db. children . clone ( ) ;
35+ self . fix_multispans_in_std_macros ( & mut primary_span, & mut children) ;
36+ self . emit_messages_default ( & db. level , & db. message , & db. code , & primary_span, & children) ;
3437 }
3538}
3639
@@ -381,19 +384,100 @@ impl EmitterWriter {
381384 max
382385 }
383386
384- fn get_max_line_num ( & mut self , db : & DiagnosticBuilder ) -> usize {
387+ fn get_max_line_num ( & mut self , span : & MultiSpan , children : & Vec < SubDiagnostic > ) -> usize {
385388 let mut max = 0 ;
386389
387- let primary = self . get_multispan_max_line_num ( & db . span ) ;
390+ let primary = self . get_multispan_max_line_num ( span) ;
388391 max = if primary > max { primary } else { max } ;
389392
390- for sub in & db . children {
393+ for sub in children {
391394 let sub_result = self . get_multispan_max_line_num ( & sub. span ) ;
392395 max = if sub_result > max { primary } else { max } ;
393396 }
394397 max
395398 }
396399
400+ // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of
401+ // <*macros>. Since these locations are often difficult to read, we move these Spans from
402+ // <*macros> to their corresponding use site.
403+ fn fix_multispan_in_std_macros ( & mut self , span : & mut MultiSpan ) -> bool {
404+ let mut spans_updated = false ;
405+
406+ if let Some ( ref cm) = self . cm {
407+ let mut before_after: Vec < ( Span , Span ) > = vec ! [ ] ;
408+ let mut new_labels: Vec < ( Span , String ) > = vec ! [ ] ;
409+
410+ // First, find all the spans in <*macros> and point instead at their use site
411+ for sp in span. primary_spans ( ) {
412+ if ( * sp == COMMAND_LINE_SP ) || ( * sp == DUMMY_SP ) {
413+ continue ;
414+ }
415+ if cm. span_to_filename ( sp. clone ( ) ) . contains ( "macros>" ) {
416+ let v = cm. macro_backtrace ( sp. clone ( ) ) ;
417+ if let Some ( use_site) = v. last ( ) {
418+ before_after. push ( ( sp. clone ( ) , use_site. call_site . clone ( ) ) ) ;
419+ }
420+ }
421+ for trace in cm. macro_backtrace ( sp. clone ( ) ) . iter ( ) . rev ( ) {
422+ // Only show macro locations that are local
423+ // and display them like a span_note
424+ if let Some ( def_site) = trace. def_site_span {
425+ if ( def_site == COMMAND_LINE_SP ) || ( def_site == DUMMY_SP ) {
426+ continue ;
427+ }
428+ // Check to make sure we're not in any <*macros>
429+ if !cm. span_to_filename ( def_site) . contains ( "macros>" ) {
430+ new_labels. push ( ( trace. call_site ,
431+ "in this macro invocation" . to_string ( ) ) ) ;
432+ break ;
433+ }
434+ }
435+ }
436+ }
437+ for ( label_span, label_text) in new_labels {
438+ span. push_span_label ( label_span, label_text) ;
439+ }
440+ for sp_label in span. span_labels ( ) {
441+ if ( sp_label. span == COMMAND_LINE_SP ) || ( sp_label. span == DUMMY_SP ) {
442+ continue ;
443+ }
444+ if cm. span_to_filename ( sp_label. span . clone ( ) ) . contains ( "macros>" ) {
445+ let v = cm. macro_backtrace ( sp_label. span . clone ( ) ) ;
446+ if let Some ( use_site) = v. last ( ) {
447+ before_after. push ( ( sp_label. span . clone ( ) , use_site. call_site . clone ( ) ) ) ;
448+ }
449+ }
450+ }
451+ // After we have them, make sure we replace these 'bad' def sites with their use sites
452+ for ( before, after) in before_after {
453+ span. replace ( before, after) ;
454+ spans_updated = true ;
455+ }
456+ }
457+
458+ spans_updated
459+ }
460+
461+ // This does a small "fix" for multispans by looking to see if it can find any that
462+ // point directly at <*macros>. Since these are often difficult to read, this
463+ // will change the span to point at the use site.
464+ fn fix_multispans_in_std_macros ( & mut self ,
465+ span : & mut MultiSpan ,
466+ children : & mut Vec < SubDiagnostic > ) {
467+ let mut spans_updated = self . fix_multispan_in_std_macros ( span) ;
468+ for child in & mut children. iter_mut ( ) {
469+ spans_updated |= self . fix_multispan_in_std_macros ( & mut child. span ) ;
470+ }
471+ if spans_updated {
472+ children. push ( SubDiagnostic {
473+ level : Level :: Note ,
474+ message : "this error originates in a macro from the standard library" . to_string ( ) ,
475+ span : MultiSpan :: new ( ) ,
476+ render_span : None
477+ } ) ;
478+ }
479+ }
480+
397481 fn emit_message_default ( & mut self ,
398482 msp : & MultiSpan ,
399483 msg : & str ,
@@ -528,10 +612,6 @@ impl EmitterWriter {
528612 }
529613 }
530614
531- if let Some ( ref primary_span) = msp. primary_span ( ) . as_ref ( ) {
532- self . render_macro_backtrace_old_school ( primary_span, & mut buffer) ?;
533- }
534-
535615 // final step: take our styled buffer, render it, then output it
536616 emit_to_destination ( & buffer. render ( ) , level, & mut self . dst ) ?;
537617
@@ -578,26 +658,31 @@ impl EmitterWriter {
578658 }
579659 Ok ( ( ) )
580660 }
581- fn emit_messages_default ( & mut self , db : & DiagnosticBuilder ) {
582- let max_line_num = self . get_max_line_num ( db) ;
661+ fn emit_messages_default ( & mut self ,
662+ level : & Level ,
663+ message : & String ,
664+ code : & Option < String > ,
665+ span : & MultiSpan ,
666+ children : & Vec < SubDiagnostic > ) {
667+ let max_line_num = self . get_max_line_num ( span, children) ;
583668 let max_line_num_len = max_line_num. to_string ( ) . len ( ) ;
584669
585- match self . emit_message_default ( & db . span ,
586- & db . message ,
587- & db . code ,
588- & db . level ,
670+ match self . emit_message_default ( span,
671+ message,
672+ code,
673+ level,
589674 max_line_num_len,
590675 false ) {
591676 Ok ( ( ) ) => {
592- if !db . children . is_empty ( ) {
677+ if !children. is_empty ( ) {
593678 let mut buffer = StyledBuffer :: new ( ) ;
594679 draw_col_separator_no_space ( & mut buffer, 0 , max_line_num_len + 1 ) ;
595- match emit_to_destination ( & buffer. render ( ) , & db . level , & mut self . dst ) {
680+ match emit_to_destination ( & buffer. render ( ) , level, & mut self . dst ) {
596681 Ok ( ( ) ) => ( ) ,
597682 Err ( e) => panic ! ( "failed to emit error: {}" , e)
598683 }
599684 }
600- for child in & db . children {
685+ for child in children {
601686 match child. render_span {
602687 Some ( FullSpan ( ref msp) ) => {
603688 match self . emit_message_default ( msp,
@@ -640,29 +725,6 @@ impl EmitterWriter {
640725 _ => ( )
641726 }
642727 }
643- fn render_macro_backtrace_old_school ( & mut self ,
644- sp : & Span ,
645- buffer : & mut StyledBuffer ) -> io:: Result < ( ) > {
646- if let Some ( ref cm) = self . cm {
647- for trace in cm. macro_backtrace ( sp. clone ( ) ) {
648- let line_offset = buffer. num_lines ( ) ;
649-
650- let mut diag_string =
651- format ! ( "in this expansion of {}" , trace. macro_decl_name) ;
652- if let Some ( def_site_span) = trace. def_site_span {
653- diag_string. push_str (
654- & format ! ( " (defined in {})" ,
655- cm. span_to_filename( def_site_span) ) ) ;
656- }
657- let snippet = cm. span_to_string ( trace. call_site ) ;
658- buffer. append ( line_offset, & format ! ( "{} " , snippet) , Style :: NoStyle ) ;
659- buffer. append ( line_offset, "note" , Style :: Level ( Level :: Note ) ) ;
660- buffer. append ( line_offset, ": " , Style :: NoStyle ) ;
661- buffer. append ( line_offset, & diag_string, Style :: OldSchoolNoteText ) ;
662- }
663- }
664- Ok ( ( ) )
665- }
666728}
667729
668730fn draw_col_separator ( buffer : & mut StyledBuffer , line : usize , col : usize ) {
0 commit comments