diff options
Diffstat (limited to 'src/libsyntax/errors')
| -rw-r--r-- | src/libsyntax/errors/emitter.rs | 22 | ||||
| -rw-r--r-- | src/libsyntax/errors/mod.rs | 294 |
2 files changed, 284 insertions, 32 deletions
diff --git a/src/libsyntax/errors/emitter.rs b/src/libsyntax/errors/emitter.rs index 7fef85a833e..a7bfdedf718 100644 --- a/src/libsyntax/errors/emitter.rs +++ b/src/libsyntax/errors/emitter.rs @@ -13,7 +13,7 @@ use self::Destination::*; use codemap::{self, COMMAND_LINE_SP, COMMAND_LINE_EXPN, Pos, Span}; use diagnostics; -use errors::{Level, RenderSpan}; +use errors::{Level, RenderSpan, DiagnosticBuilder}; use errors::RenderSpan::*; use errors::Level::*; @@ -27,6 +27,17 @@ use term; pub trait Emitter { fn emit(&mut self, span: Option<Span>, msg: &str, code: Option<&str>, lvl: Level); fn custom_emit(&mut self, sp: RenderSpan, msg: &str, lvl: Level); + + /// Emit a structured diagnostic. + fn emit_struct(&mut self, db: &DiagnosticBuilder) { + self.emit(db.span, &db.message, db.code.as_ref().map(|s| &**s), db.level); + for child in &db.children { + match child.render_span { + Some(ref sp) => self.custom_emit(sp.clone(), &child.message, child.level), + None => self.emit(child.span, &child.message, None, child.level), + } + } + } } /// maximum number of lines we will print for each error; arbitrary. @@ -49,8 +60,8 @@ impl ColorConfig { } } -// A basic emitter for when we don't have access to a codemap or registry. Used -// for reporting very early errors, etc. +/// A basic emitter for when we don't have access to a codemap or registry. Used +/// for reporting very early errors, etc. pub struct BasicEmitter { dst: Destination, } @@ -111,9 +122,8 @@ impl Emitter for EmitterWriter { sp: RenderSpan, msg: &str, lvl: Level) { - match self.emit_(sp, msg, None, lvl) { - Ok(()) => {} - Err(e) => panic!("failed to print diagnostics: {:?}", e), + if let Err(e) = self.emit_(sp, msg, None, lvl) { + panic!("failed to print diagnostics: {:?}", e); } } } diff --git a/src/libsyntax/errors/mod.rs b/src/libsyntax/errors/mod.rs index f2e61090ba2..a2fae975148 100644 --- a/src/libsyntax/errors/mod.rs +++ b/src/libsyntax/errors/mod.rs @@ -98,6 +98,171 @@ impl error::Error for ExplicitBug { } } +/// Used for emitting structured error messages and other diagnostic information. +#[must_use] +pub struct DiagnosticBuilder<'a> { + emitter: &'a RefCell<Box<Emitter>>, + level: Level, + message: String, + code: Option<String>, + span: Option<Span>, + children: Vec<SubDiagnostic>, +} + +/// For example a note attached to an error. +struct SubDiagnostic { + level: Level, + message: String, + span: Option<Span>, + render_span: Option<RenderSpan>, +} + +impl<'a> DiagnosticBuilder<'a> { + /// Emit the diagnostic. + pub fn emit(&mut self) { + if self.cancelled() { + return; + } + + self.emitter.borrow_mut().emit_struct(&self); + self.cancel(); + + // 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 + } + + pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, None, None); + self + } + pub fn span_note(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, Some(sp), None); + self + } + pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, None, None); + self + } + pub fn span_help(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, Some(sp), None); + self + } + /// Prints out a message with a suggested edit of the code. + /// + /// See `diagnostic::RenderSpan::Suggestion` for more information. + pub fn span_suggestion(&mut self , + sp: Span, + msg: &str, + suggestion: String) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, Some(sp), Some(Suggestion(sp, suggestion))); + self + } + pub fn span_end_note(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, Some(sp), Some(EndSpan(sp))); + self + } + pub fn fileline_note(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Note, msg, Some(sp), Some(FileLine(sp))); + self + } + pub fn fileline_help(&mut self , + sp: Span, + msg: &str) + -> &mut DiagnosticBuilder<'a> { + self.sub(Level::Help, msg, Some(sp), Some(FileLine(sp))); + self + } + + pub fn span(&mut self, sp: Span) -> &mut Self { + self.span = Some(sp); + self + } + + pub fn code(&mut self, s: String) -> &mut Self { + self.code = Some(s); + self + } + + /// Convenience function for internal use, clients should use one of the + /// struct_* methods on Handler. + fn new(emitter: &'a RefCell<Box<Emitter>>, + level: Level, + message: &str) -> DiagnosticBuilder<'a> { + DiagnosticBuilder { + emitter: emitter, + level: level, + message: message.to_owned(), + code: None, + span: None, + 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: Option<Span>, + 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 !self.cancelled() { + self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug); + panic!(); + } + } +} + /// A handler deals with errors; certain errors /// (fatal, bug, unimpl) may cause immediate exit, /// others log errors for later reporting. @@ -132,11 +297,104 @@ impl Handler { } } + pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> { + DiagnosticBuilder::new(&self.emit, Level::Cancelled, "") + } + + pub fn struct_span_warn<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); + result.span(sp); + if !self.can_emit_warnings { + result.cancel(); + } + result + } + pub fn struct_span_warn_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); + result.span(sp); + result.code(code.to_owned()); + if !self.can_emit_warnings { + result.cancel(); + } + result + } + pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { + let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg); + if !self.can_emit_warnings { + result.cancel(); + } + result + } + pub fn struct_span_err<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + self.bump_err_count(); + let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); + result.span(sp); + result + } + pub fn struct_span_err_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + self.bump_err_count(); + let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg); + result.span(sp); + result.code(code.to_owned()); + result + } + pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Error, msg) + } + pub fn struct_span_fatal<'a>(&'a self, + sp: Span, + msg: &str) + -> DiagnosticBuilder<'a> { + self.bump_err_count(); + let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); + result.span(sp); + result + } + pub fn struct_span_fatal_with_code<'a>(&'a self, + sp: Span, + msg: &str, + code: &str) + -> DiagnosticBuilder<'a> { + self.bump_err_count(); + let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg); + result.span(sp); + result.code(code.to_owned()); + result + } + pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> { + self.bump_err_count(); + DiagnosticBuilder::new(&self.emit, Level::Fatal, msg) + } + + pub fn cancel(&mut self, err: &mut DiagnosticBuilder) { + if err.level == Level::Error || err.level == Level::Fatal { + assert!(self.has_errors()); + self.err_count.set(self.err_count.get() + 1); + } + err.cancel(); + } + pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError { if self.treat_err_as_bug { self.span_bug(sp, msg); } self.emit(Some(sp), msg, Fatal); + self.bump_err_count(); return FatalError; } pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError { @@ -144,6 +402,7 @@ impl Handler { self.span_bug(sp, msg); } self.emit_with_code(Some(sp), msg, code, Fatal); + self.bump_err_count(); return FatalError; } pub fn span_err(&self, sp: Span, msg: &str) { @@ -166,27 +425,6 @@ impl Handler { pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) { self.emit_with_code(Some(sp), msg, code, Warning); } - pub fn span_note(&self, sp: Span, msg: &str) { - self.emit(Some(sp), msg, Note); - } - pub fn span_end_note(&self, sp: Span, msg: &str) { - self.custom_emit(EndSpan(sp), msg, Note); - } - pub fn span_help(&self, sp: Span, msg: &str) { - self.emit(Some(sp), msg, Help); - } - /// Prints out a message with a suggested edit of the code. - /// - /// See `diagnostic::RenderSpan::Suggestion` for more information. - pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) { - self.custom_emit(Suggestion(sp, suggestion), msg, Help); - } - pub fn fileline_note(&self, sp: Span, msg: &str) { - self.custom_emit(FileLine(sp), msg, Note); - } - pub fn fileline_help(&self, sp: Span, msg: &str) { - self.custom_emit(FileLine(sp), msg, Help); - } pub fn span_bug(&self, sp: Span, msg: &str) -> ! { self.emit(Some(sp), msg, Bug); panic!(ExplicitBug); @@ -199,6 +437,9 @@ impl Handler { self.emit(Some(sp), msg, Bug); self.bump_err_count(); } + pub fn span_note_without_error(&self, sp: Span, msg: &str) { + self.emit.borrow_mut().emit(Some(sp), msg, None, Note); + } pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! { self.span_bug(sp, &format!("unimplemented {}", msg)); } @@ -207,6 +448,7 @@ impl Handler { self.bug(msg); } self.emit.borrow_mut().emit(None, msg, None, Fatal); + self.bump_err_count(); FatalError } pub fn err(&self, msg: &str) { @@ -219,12 +461,9 @@ impl Handler { pub fn warn(&self, msg: &str) { self.emit.borrow_mut().emit(None, msg, None, Warning); } - pub fn note(&self, msg: &str) { + pub fn note_without_error(&self, msg: &str) { self.emit.borrow_mut().emit(None, msg, None, Note); } - pub fn help(&self, msg: &str) { - self.emit.borrow_mut().emit(None, msg, None, Help); - } pub fn bug(&self, msg: &str) -> ! { self.emit.borrow_mut().emit(None, msg, None, Bug); panic!(ExplicitBug); @@ -266,7 +505,7 @@ impl Handler { } } - panic!(self.fatal(&s[..])); + panic!(self.fatal(&s)); } pub fn emit(&self, @@ -301,6 +540,7 @@ pub enum Level { Warning, Note, Help, + Cancelled, } impl fmt::Display for Level { @@ -313,6 +553,7 @@ impl fmt::Display for Level { Warning => "warning".fmt(f), Note => "note".fmt(f), Help => "help".fmt(f), + Cancelled => unreachable!(), } } } @@ -324,6 +565,7 @@ impl Level { Warning => term::color::BRIGHT_YELLOW, Note => term::color::BRIGHT_GREEN, Help => term::color::BRIGHT_CYAN, + Cancelled => unreachable!(), } } } |
