From 159d249705659ecb2ef41623105cab1c9f95b802 Mon Sep 17 00:00:00 2001 From: Philipp Hansch Date: Thu, 5 Sep 2019 21:31:12 +0200 Subject: [PATCH] annotate-snippet emitter: Deal with multispans from macros, too This moves the two methods from the `EmitterWriter` impl to trait default methods in the `Emitter` trait so that they can be re-used by the `AnnotateSnippetEmitterWriter`. Closes #61810 --- .../annotate_snippet_emitter_writer.rs | 12 +- src/librustc_errors/emitter.rs | 251 +++++++++--------- 2 files changed, 137 insertions(+), 126 deletions(-) diff --git a/src/librustc_errors/annotate_snippet_emitter_writer.rs b/src/librustc_errors/annotate_snippet_emitter_writer.rs index 3bed5d81dc514..60ee7507223e9 100644 --- a/src/librustc_errors/annotate_snippet_emitter_writer.rs +++ b/src/librustc_errors/annotate_snippet_emitter_writer.rs @@ -30,10 +30,14 @@ pub struct AnnotateSnippetEmitterWriter { impl Emitter for AnnotateSnippetEmitterWriter { /// The entry point for the diagnostics generation fn emit_diagnostic(&mut self, db: &DiagnosticBuilder<'_>) { - let children = db.children.clone(); - let (primary_span, suggestions) = self.primary_span_formatted(&db); - - // FIXME(#59346): Add `fix_multispans_in_std_macros` function from emitter.rs + let mut children = db.children.clone(); + let (mut primary_span, suggestions) = self.primary_span_formatted(&db); + + self.fix_multispans_in_std_macros(&self.source_map, + &mut primary_span, + &mut children, + &db.level, + db.handler.flags.external_macro_backtrace); self.emit_messages_default(&db.level, db.message(), diff --git a/src/librustc_errors/emitter.rs b/src/librustc_errors/emitter.rs index a298f9958f2d1..0ce69eecc6b1e 100644 --- a/src/librustc_errors/emitter.rs +++ b/src/librustc_errors/emitter.rs @@ -247,6 +247,133 @@ pub trait Emitter { (primary_span, &db.suggestions) } } + + // This does a small "fix" for multispans by looking to see if it can find any that + // point directly at <*macros>. Since these are often difficult to read, this + // will change the span to point at the use site. + fn fix_multispans_in_std_macros(&self, + source_map: &Option>, + span: &mut MultiSpan, + children: &mut Vec, + level: &Level, + backtrace: bool) { + let mut spans_updated = self.fix_multispan_in_std_macros(source_map, span, backtrace); + for child in children.iter_mut() { + spans_updated |= self.fix_multispan_in_std_macros( + source_map, + &mut child.span, + backtrace + ); + } + let msg = if level == &Error { + "this error originates in a macro outside of the current crate \ + (in Nightly builds, run with -Z external-macro-backtrace \ + for more info)".to_string() + } else { + "this warning originates in a macro outside of the current crate \ + (in Nightly builds, run with -Z external-macro-backtrace \ + for more info)".to_string() + }; + + if spans_updated { + children.push(SubDiagnostic { + level: Level::Note, + message: vec![ + (msg, + Style::NoStyle), + ], + span: MultiSpan::new(), + render_span: None, + }); + } + } + + // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of + // <*macros>. Since these locations are often difficult to read, we move these Spans from + // <*macros> to their corresponding use site. + fn fix_multispan_in_std_macros(&self, + source_map: &Option>, + span: &mut MultiSpan, + always_backtrace: bool) -> bool { + let mut spans_updated = false; + + if let Some(ref sm) = source_map { + let mut before_after: Vec<(Span, Span)> = vec![]; + let mut new_labels: Vec<(Span, String)> = vec![]; + + // First, find all the spans in <*macros> and point instead at their use site + for sp in span.primary_spans() { + if sp.is_dummy() { + continue; + } + let call_sp = sm.call_span_if_macro(*sp); + if call_sp != *sp && !always_backtrace { + before_after.push((*sp, call_sp)); + } + let backtrace_len = sp.macro_backtrace().len(); + for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { + // Only show macro locations that are local + // and display them like a span_note + if trace.def_site_span.is_dummy() { + continue; + } + if always_backtrace { + new_labels.push((trace.def_site_span, + format!("in this expansion of `{}`{}", + trace.macro_decl_name, + if backtrace_len > 2 { + // if backtrace_len == 1 it'll be pointed + // at by "in this macro invocation" + format!(" (#{})", i + 1) + } else { + String::new() + }))); + } + // Check to make sure we're not in any <*macros> + if !sm.span_to_filename(trace.def_site_span).is_macros() && + !trace.macro_decl_name.starts_with("desugaring of ") && + !trace.macro_decl_name.starts_with("#[") || + always_backtrace { + new_labels.push((trace.call_site, + format!("in this macro invocation{}", + if backtrace_len > 2 && always_backtrace { + // only specify order when the macro + // backtrace is multiple levels deep + format!(" (#{})", i + 1) + } else { + String::new() + }))); + if !always_backtrace { + break; + } + } + } + } + for (label_span, label_text) in new_labels { + span.push_span_label(label_span, label_text); + } + for sp_label in span.span_labels() { + if sp_label.span.is_dummy() { + continue; + } + if sm.span_to_filename(sp_label.span.clone()).is_macros() && + !always_backtrace + { + let v = sp_label.span.macro_backtrace(); + if let Some(use_site) = v.last() { + before_after.push((sp_label.span.clone(), use_site.call_site.clone())); + } + } + } + // After we have them, make sure we replace these 'bad' def sites with their use sites + for (before, after) in before_after { + span.replace(before, after); + spans_updated = true; + } + } + + spans_updated + } } impl Emitter for EmitterWriter { @@ -254,7 +381,8 @@ impl Emitter for EmitterWriter { let mut children = db.children.clone(); let (mut primary_span, suggestions) = self.primary_span_formatted(&db); - self.fix_multispans_in_std_macros(&mut primary_span, + self.fix_multispans_in_std_macros(&self.sm, + &mut primary_span, &mut children, &db.level, db.handler.flags.external_macro_backtrace); @@ -919,127 +1047,6 @@ impl EmitterWriter { max } - // This "fixes" MultiSpans that contain Spans that are pointing to locations inside of - // <*macros>. Since these locations are often difficult to read, we move these Spans from - // <*macros> to their corresponding use site. - fn fix_multispan_in_std_macros(&mut self, - span: &mut MultiSpan, - always_backtrace: bool) -> bool { - let mut spans_updated = false; - - if let Some(ref sm) = self.sm { - let mut before_after: Vec<(Span, Span)> = vec![]; - let mut new_labels: Vec<(Span, String)> = vec![]; - - // First, find all the spans in <*macros> and point instead at their use site - for sp in span.primary_spans() { - if sp.is_dummy() { - continue; - } - let call_sp = sm.call_span_if_macro(*sp); - if call_sp != *sp && !always_backtrace { - before_after.push((*sp, call_sp)); - } - let backtrace_len = sp.macro_backtrace().len(); - for (i, trace) in sp.macro_backtrace().iter().rev().enumerate() { - // Only show macro locations that are local - // and display them like a span_note - if trace.def_site_span.is_dummy() { - continue; - } - if always_backtrace { - new_labels.push((trace.def_site_span, - format!("in this expansion of `{}`{}", - trace.macro_decl_name, - if backtrace_len > 2 { - // if backtrace_len == 1 it'll be pointed - // at by "in this macro invocation" - format!(" (#{})", i + 1) - } else { - String::new() - }))); - } - // Check to make sure we're not in any <*macros> - if !sm.span_to_filename(trace.def_site_span).is_macros() && - !trace.macro_decl_name.starts_with("desugaring of ") && - !trace.macro_decl_name.starts_with("#[") || - always_backtrace { - new_labels.push((trace.call_site, - format!("in this macro invocation{}", - if backtrace_len > 2 && always_backtrace { - // only specify order when the macro - // backtrace is multiple levels deep - format!(" (#{})", i + 1) - } else { - String::new() - }))); - if !always_backtrace { - break; - } - } - } - } - for (label_span, label_text) in new_labels { - span.push_span_label(label_span, label_text); - } - for sp_label in span.span_labels() { - if sp_label.span.is_dummy() { - continue; - } - if sm.span_to_filename(sp_label.span.clone()).is_macros() && - !always_backtrace - { - let v = sp_label.span.macro_backtrace(); - if let Some(use_site) = v.last() { - before_after.push((sp_label.span.clone(), use_site.call_site.clone())); - } - } - } - // After we have them, make sure we replace these 'bad' def sites with their use sites - for (before, after) in before_after { - span.replace(before, after); - spans_updated = true; - } - } - - spans_updated - } - - // This does a small "fix" for multispans by looking to see if it can find any that - // point directly at <*macros>. Since these are often difficult to read, this - // will change the span to point at the use site. - fn fix_multispans_in_std_macros(&mut self, - span: &mut MultiSpan, - children: &mut Vec, - level: &Level, - backtrace: bool) { - let mut spans_updated = self.fix_multispan_in_std_macros(span, backtrace); - for child in children.iter_mut() { - spans_updated |= self.fix_multispan_in_std_macros(&mut child.span, backtrace); - } - let msg = if level == &Error { - "this error originates in a macro outside of the current crate \ - (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() - } else { - "this warning originates in a macro outside of the current crate \ - (in Nightly builds, run with -Z external-macro-backtrace \ - for more info)".to_string() - }; - - if spans_updated { - children.push(SubDiagnostic { - level: Level::Note, - message: vec![ - (msg, - Style::NoStyle), - ], - span: MultiSpan::new(), - render_span: None, - }); - } - } - /// Adds a left margin to every line but the first, given a padding length and the label being /// displayed, keeping the provided highlighting. fn msg_to_buffer(&self,