diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2016-10-11 12:26:32 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2016-11-01 14:07:45 -0400 |
| commit | 888a92cef37342c7878028eda967c85eb15afe43 (patch) | |
| tree | a26e908f88eac00cf57ed7123b80f761ec1c68c5 /src/librustc_errors | |
| parent | 75bc8bfa922e533f111e54b0d841d85d61c7f317 (diff) | |
| download | rust-888a92cef37342c7878028eda967c85eb15afe43.tar.gz rust-888a92cef37342c7878028eda967c85eb15afe43.zip | |
separate Diagnostic from DiagnosticBuilder
Diffstat (limited to 'src/librustc_errors')
| -rw-r--r-- | src/librustc_errors/diagnostic.rs | 190 | ||||
| -rw-r--r-- | src/librustc_errors/diagnostic_builder.rs | 164 | ||||
| -rw-r--r-- | src/librustc_errors/lib.rs | 219 |
3 files changed, 358 insertions, 215 deletions
diff --git a/src/librustc_errors/diagnostic.rs b/src/librustc_errors/diagnostic.rs new file mode 100644 index 00000000000..dab8fb665ac --- /dev/null +++ b/src/librustc_errors/diagnostic.rs @@ -0,0 +1,190 @@ +use CodeSuggestion; +use Level; +use RenderSpan; +use RenderSpan::Suggestion; +use std::fmt; +use syntax_pos::{MultiSpan, Span}; + +#[must_use] +#[derive(Clone)] +pub struct Diagnostic { + pub level: Level, + pub message: String, + pub code: Option<String>, + pub span: MultiSpan, + pub children: Vec<SubDiagnostic>, +} + +/// For example a note attached to an error. +#[derive(Clone)] +pub struct SubDiagnostic { + pub level: Level, + pub message: String, + pub span: MultiSpan, + pub render_span: Option<RenderSpan>, +} + +impl Diagnostic { + pub fn new(level: Level, message: &str) -> Self { + Diagnostic::new_with_code(level, None, message) + } + + pub fn new_with_code(level: Level, code: Option<String>, message: &str) -> Self { + Diagnostic { + level: level, + message: message.to_owned(), + code: code, + span: MultiSpan::new(), + children: vec![], + } + } + + /// Cancel the diagnostic (a structured diagnostic must either be emitted or + /// cancelled or it will panic when dropped). + /// BEWARE: if this DiagnosticBuilder is an error, then creating it will + /// bump the error count on the Handler and cancelling it won't undo that. + /// If you want to decrement the error count you should use `Handler::cancel`. + pub fn cancel(&mut self) { + self.level = Level::Cancelled; + } + + pub fn cancelled(&self) -> bool { + self.level == Level::Cancelled + } + + pub fn is_fatal(&self) -> bool { + self.level == Level::Fatal + } + + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + pub fn span_label(&mut self, span: Span, label: &fmt::Display) + -> &mut Self { + self.span.push_span_label(span, format!("{}", label)); + self + } + + pub fn note_expected_found(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> &mut Self + { + self.note_expected_found_extra(label, expected, found, &"", &"") + } + + pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut Self + { + // For now, just attach these as notes + self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); + self.note(&format!(" found {} `{}`{}", label, found, found_extra)); + self + } + + pub fn note(&mut self, msg: &str) -> &mut Self { + self.sub(Level::Note, msg, MultiSpan::new(), None); + self + } + + pub fn span_note<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Note, msg, sp.into(), None); + self + } + + pub fn warn(&mut self, msg: &str) -> &mut Self { + self.sub(Level::Warning, msg, MultiSpan::new(), None); + self + } + + pub fn span_warn<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Warning, msg, sp.into(), None); + self + } + + pub fn help(&mut self , msg: &str) -> &mut Self { + self.sub(Level::Help, msg, MultiSpan::new(), None); + self + } + + pub fn span_help<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str) + -> &mut Self { + self.sub(Level::Help, msg, sp.into(), None); + self + } + + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str, + suggestion: String) + -> &mut Self { + self.sub(Level::Help, + msg, + MultiSpan::new(), + Some(Suggestion(CodeSuggestion { + msp: sp.into(), + substitutes: vec![suggestion], + }))); + self + } + + pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { + self.span = sp.into(); + self + } + + pub fn code(&mut self, s: String) -> &mut Self { + self.code = Some(s); + self + } + + pub fn message(&self) -> &str { + &self.message + } + + pub fn level(&self) -> Level { + self.level + } + + /// Convenience function for internal use, clients should use one of the + /// public methods above. + fn sub(&mut self, + level: Level, + message: &str, + span: MultiSpan, + render_span: Option<RenderSpan>) { + let sub = SubDiagnostic { + level: level, + message: message.to_owned(), + span: span, + render_span: render_span, + }; + self.children.push(sub); + } +} + +impl fmt::Debug for Diagnostic { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.message.fmt(f) + } +} diff --git a/src/librustc_errors/diagnostic_builder.rs b/src/librustc_errors/diagnostic_builder.rs new file mode 100644 index 00000000000..69532823f5a --- /dev/null +++ b/src/librustc_errors/diagnostic_builder.rs @@ -0,0 +1,164 @@ +use Diagnostic; +use Level; +use Handler; +use std::fmt::{self, Debug}; +use std::ops::{Deref, DerefMut}; +use std::thread::panicking; +use syntax_pos::{MultiSpan, Span}; + +/// Used for emitting structured error messages and other diagnostic information. +#[must_use] +#[derive(Clone)] +pub struct DiagnosticBuilder<'a> { + handler: &'a Handler, + diagnostic: Diagnostic, +} + +/// In general, the `DiagnosticBuilder` uses deref to allow access to +/// the fields and methods of the embedded `diagnostic` in a +/// transparent way. *However,* many of the methods are intended to +/// be used in a chained way, and hence ought to return `self`. In +/// that case, we can't just naively forward to the method on the +/// `diagnostic`, because the return type would be a `&Diagnostic` +/// instead of a `&DiagnosticBuilder<'a>`. This `forward!` macro makes +/// it easy to declare such methods on the builder. +macro_rules! forward { + // Forward pattern for &self -> &Self + (pub fn $n:ident(&self, $($name:ident: $ty:ty),*) -> &Self) => { + pub fn $n(&self, $($name: $ty),*) -> &Self { + self.diagnostic.$n($($name),*); + self + } + }; + + // Forward pattern for &mut self -> &mut Self + (pub fn $n:ident(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => { + pub fn $n(&mut self, $($name: $ty),*) -> &mut Self { + self.diagnostic.$n($($name),*); + self + } + }; + + // Forward pattern for &mut self -> &mut Self, with S: Into<MultiSpan> + // type parameter. No obvious way to make this more generic. + (pub fn $n:ident<S: Into<MultiSpan>>(&mut self, $($name:ident: $ty:ty),*) -> &mut Self) => { + pub fn $n<S: Into<MultiSpan>>(&mut self, $($name: $ty),*) -> &mut Self { + self.diagnostic.$n($($name),*); + self + } + }; +} + +impl<'a> Deref for DiagnosticBuilder<'a> { + type Target = Diagnostic; + + fn deref(&self) -> &Diagnostic { + &self.diagnostic + } +} + +impl<'a> DerefMut for DiagnosticBuilder<'a> { + fn deref_mut(&mut self) -> &mut Diagnostic { + &mut self.diagnostic + } +} + +impl<'a> DiagnosticBuilder<'a> { + /// Emit the diagnostic. + pub fn emit(&mut self) { + if self.cancelled() { + return; + } + + self.handler.emitter.borrow_mut().emit(&self); + self.cancel(); + self.handler.panic_if_treat_err_as_bug(); + + // if self.is_fatal() { + // panic!(FatalError); + // } + } + + /// Add a span/label to be included in the resulting snippet. + /// This is pushed onto the `MultiSpan` that was created when the + /// diagnostic was first built. If you don't call this function at + /// all, and you just supplied a `Span` to create the diagnostic, + /// then the snippet will just include that `Span`, which is + /// called the primary span. + forward!(pub fn span_label(&mut self, span: Span, label: &fmt::Display) + -> &mut Self); + + forward!(pub fn note_expected_found(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display) + -> &mut Self); + + forward!(pub fn note_expected_found_extra(&mut self, + label: &fmt::Display, + expected: &fmt::Display, + found: &fmt::Display, + expected_extra: &fmt::Display, + found_extra: &fmt::Display) + -> &mut Self); + + forward!(pub fn note(&mut self, msg: &str) -> &mut Self); + forward!(pub fn span_note<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str) + -> &mut Self); + forward!(pub fn warn(&mut self, msg: &str) -> &mut Self); + forward!(pub fn span_warn<S: Into<MultiSpan>>(&mut self, sp: S, msg: &str) -> &mut Self); + forward!(pub fn help(&mut self , msg: &str) -> &mut Self); + forward!(pub fn span_help<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str) + -> &mut Self); + forward!(pub fn span_suggestion<S: Into<MultiSpan>>(&mut self, + sp: S, + msg: &str, + suggestion: String) + -> &mut Self); + forward!(pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self); + forward!(pub fn code(&mut self, s: String) -> &mut Self); + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + pub fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { + DiagnosticBuilder::new_with_code(handler, level, None, message) + } + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + pub fn new_with_code(handler: &'a Handler, + level: Level, + code: Option<String>, + message: &str) + -> DiagnosticBuilder<'a> { + DiagnosticBuilder { + handler: handler, + diagnostic: Diagnostic::new_with_code(level, code, message) + } + } +} + +impl<'a> Debug for DiagnosticBuilder<'a> { + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + self.diagnostic.fmt(f) + } +} + +/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or +/// we emit a bug. +impl<'a> Drop for DiagnosticBuilder<'a> { + fn drop(&mut self) { + if !panicking() && !self.cancelled() { + let mut db = DiagnosticBuilder::new(self.handler, + Level::Bug, + "Error constructed but not emitted"); + db.emit(); + panic!(); + } + } +} + diff --git a/src/librustc_errors/lib.rs b/src/librustc_errors/lib.rs index 25b314256b0..203b96d9f9a 100644 --- a/src/librustc_errors/lib.rs +++ b/src/librustc_errors/lib.rs @@ -39,15 +39,15 @@ extern crate syntax_pos; pub use emitter::ColorConfig; use self::Level::*; -use self::RenderSpan::*; use emitter::{Emitter, EmitterWriter}; use std::cell::{RefCell, Cell}; use std::{error, fmt}; use std::rc::Rc; -use std::thread::panicking; +pub mod diagnostic; +pub mod diagnostic_builder; pub mod emitter; pub mod snippet; pub mod registry; @@ -211,219 +211,8 @@ impl error::Error for ExplicitBug { } } -/// Used for emitting structured error messages and other diagnostic information. -#[must_use] -#[derive(Clone)] -pub struct DiagnosticBuilder<'a> { - handler: &'a Handler, - pub level: Level, - pub message: String, - pub code: Option<String>, - pub span: MultiSpan, - pub children: Vec<SubDiagnostic>, -} - -/// For example a note attached to an error. -#[derive(Clone)] -pub struct SubDiagnostic { - pub level: Level, - pub message: String, - pub span: MultiSpan, - pub render_span: Option<RenderSpan>, -} - -impl<'a> DiagnosticBuilder<'a> { - /// Emit the diagnostic. - pub fn emit(&mut self) { - if self.cancelled() { - return; - } - - self.handler.emitter.borrow_mut().emit(&self); - self.cancel(); - self.handler.panic_if_treat_err_as_bug(); - - // if self.is_fatal() { - // panic!(FatalError); - // } - } - - /// Cancel the diagnostic (a structured diagnostic must either be emitted or - /// cancelled or it will panic when dropped). - /// BEWARE: if this DiagnosticBuilder is an error, then creating it will - /// bump the error count on the Handler and cancelling it won't undo that. - /// If you want to decrement the error count you should use `Handler::cancel`. - pub fn cancel(&mut self) { - self.level = Level::Cancelled; - } - - pub fn cancelled(&self) -> bool { - self.level == Level::Cancelled - } - - pub fn is_fatal(&self) -> bool { - self.level == Level::Fatal - } - - /// Add a span/label to be included in the resulting snippet. - /// This is pushed onto the `MultiSpan` that was created when the - /// diagnostic was first built. If you don't call this function at - /// all, and you just supplied a `Span` to create the diagnostic, - /// then the snippet will just include that `Span`, which is - /// called the primary span. - pub fn span_label(&mut self, span: Span, label: &fmt::Display) -> &mut DiagnosticBuilder<'a> { - self.span.push_span_label(span, format!("{}", label)); - self - } - - pub fn note_expected_found(&mut self, - label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display) - -> &mut DiagnosticBuilder<'a> { - self.note_expected_found_extra(label, expected, found, &"", &"") - } - - pub fn note_expected_found_extra(&mut self, - label: &fmt::Display, - expected: &fmt::Display, - found: &fmt::Display, - expected_extra: &fmt::Display, - found_extra: &fmt::Display) - -> &mut DiagnosticBuilder<'a> { - // For now, just attach these as notes - self.note(&format!("expected {} `{}`{}", label, expected, expected_extra)); - self.note(&format!(" found {} `{}`{}", label, found, found_extra)); - self - } - - pub fn note(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, MultiSpan::new(), None); - self - } - pub fn span_note<S: Into<MultiSpan>>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Note, msg, sp.into(), None); - self - } - pub fn warn(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, MultiSpan::new(), None); - self - } - pub fn span_warn<S: Into<MultiSpan>>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Warning, msg, sp.into(), None); - self - } - pub fn help(&mut self, msg: &str) -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, MultiSpan::new(), None); - self - } - pub fn span_help<S: Into<MultiSpan>>(&mut self, - sp: S, - msg: &str) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, msg, sp.into(), None); - self - } - /// Prints out a message with a suggested edit of the code. - /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion<S: Into<MultiSpan>>(&mut self, - sp: S, - msg: &str, - suggestion: String) - -> &mut DiagnosticBuilder<'a> { - self.sub(Level::Help, - msg, - MultiSpan::new(), - Some(Suggestion(CodeSuggestion { - msp: sp.into(), - substitutes: vec![suggestion], - }))); - self - } - - pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { - self.span = sp.into(); - self - } - - pub fn code(&mut self, s: String) -> &mut Self { - self.code = Some(s); - self - } - - pub fn message(&self) -> &str { - &self.message - } - - pub fn level(&self) -> Level { - self.level - } - - /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. - fn new(handler: &'a Handler, level: Level, message: &str) -> DiagnosticBuilder<'a> { - DiagnosticBuilder::new_with_code(handler, level, None, message) - } - - /// Convenience function for internal use, clients should use one of the - /// struct_* methods on Handler. - fn new_with_code(handler: &'a Handler, - level: Level, - code: Option<String>, - message: &str) - -> DiagnosticBuilder<'a> { - DiagnosticBuilder { - handler: handler, - level: level, - message: message.to_owned(), - code: code, - span: MultiSpan::new(), - children: vec![], - } - } - - /// Convenience function for internal use, clients should use one of the - /// public methods above. - fn sub(&mut self, - level: Level, - message: &str, - span: MultiSpan, - render_span: Option<RenderSpan>) { - let sub = SubDiagnostic { - level: level, - message: message.to_owned(), - span: span, - render_span: render_span, - }; - self.children.push(sub); - } -} - -impl<'a> fmt::Debug for DiagnosticBuilder<'a> { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - self.message.fmt(f) - } -} - -/// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or -/// we emit a bug. -impl<'a> Drop for DiagnosticBuilder<'a> { - fn drop(&mut self) { - if !panicking() && !self.cancelled() { - let mut db = - DiagnosticBuilder::new(self.handler, Bug, "Error constructed but not emitted"); - db.emit(); - panic!(); - } - } -} +pub use diagnostic::{Diagnostic, SubDiagnostic}; +pub use diagnostic_builder::DiagnosticBuilder; /// A handler deals with errors; certain errors /// (fatal, bug, unimpl) may cause immediate exit, |
