Structured diagnostics
This commit is contained in:
parent
c1035b3522
commit
253a1cefd8
@ -16,7 +16,7 @@ use util::nodemap::{NodeMap, FnvHashMap};
|
||||
|
||||
use syntax::ast::{NodeId, NodeIdAssigner, Name};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::errors;
|
||||
use syntax::errors::{self, DiagnosticBuilder};
|
||||
use syntax::errors::emitter::{Emitter, BasicEmitter};
|
||||
use syntax::diagnostics;
|
||||
use syntax::feature_gate;
|
||||
@ -80,6 +80,55 @@ pub struct Session {
|
||||
}
|
||||
|
||||
impl Session {
|
||||
pub fn struct_span_warn<'a, 'b>(&'a self,
|
||||
sp: Span,
|
||||
msg: &'b str)
|
||||
-> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_span_warn(sp, msg)
|
||||
}
|
||||
pub fn struct_span_warn_with_code<'a, 'b>(&'a self,
|
||||
sp: Span,
|
||||
msg: &'b str,
|
||||
code: &str)
|
||||
-> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_span_warn_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_warn<'a, 'b>(&'a self, msg: &'b str) -> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_warn(msg)
|
||||
}
|
||||
pub fn struct_span_err<'a, 'b>(&'a self,
|
||||
sp: Span,
|
||||
msg: &'b str)
|
||||
-> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_span_err(sp, msg)
|
||||
}
|
||||
pub fn struct_span_err_with_code<'a, 'b>(&'a self,
|
||||
sp: Span,
|
||||
msg: &'b str,
|
||||
code: &str)
|
||||
-> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_span_err_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_err<'a, 'b>(&'a self, msg: &'b str) -> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_err(msg)
|
||||
}
|
||||
pub fn struct_span_fatal<'a, 'b>(&'a self,
|
||||
sp: Span,
|
||||
msg: &'b str)
|
||||
-> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_span_fatal(sp, msg)
|
||||
}
|
||||
pub fn struct_span_fatal_with_code<'a, 'b>(&'a self,
|
||||
sp: Span,
|
||||
msg: &'b str,
|
||||
code: &str)
|
||||
-> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_span_fatal_with_code(sp, msg, code)
|
||||
}
|
||||
pub fn struct_fatal<'a, 'b>(&'a self, msg: &'b str) -> Box<DiagnosticBuilder<'a, 'b>> {
|
||||
self.diagnostic().struct_fatal(msg)
|
||||
}
|
||||
|
||||
pub fn span_fatal(&self, sp: Span, msg: &str) -> ! {
|
||||
panic!(self.diagnostic().span_fatal(sp, msg))
|
||||
}
|
||||
@ -144,34 +193,6 @@ impl Session {
|
||||
None => self.warn(msg),
|
||||
}
|
||||
}
|
||||
pub fn span_note(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_note(sp, msg)
|
||||
}
|
||||
pub fn span_end_note(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_end_note(sp, msg)
|
||||
}
|
||||
|
||||
/// Prints out a message with a suggested edit of the code.
|
||||
///
|
||||
/// See `errors::RenderSpan::Suggestion` for more information.
|
||||
pub fn span_suggestion(&self, sp: Span, msg: &str, suggestion: String) {
|
||||
self.diagnostic().span_suggestion(sp, msg, suggestion)
|
||||
}
|
||||
pub fn span_help(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().span_help(sp, msg)
|
||||
}
|
||||
pub fn fileline_note(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().fileline_note(sp, msg)
|
||||
}
|
||||
pub fn fileline_help(&self, sp: Span, msg: &str) {
|
||||
self.diagnostic().fileline_help(sp, msg)
|
||||
}
|
||||
pub fn note(&self, msg: &str) {
|
||||
self.diagnostic().note(msg)
|
||||
}
|
||||
pub fn help(&self, msg: &str) {
|
||||
self.diagnostic().help(msg)
|
||||
}
|
||||
pub fn opt_span_bug(&self, opt_sp: Option<Span>, msg: &str) -> ! {
|
||||
match opt_sp {
|
||||
Some(sp) => self.span_bug(sp, msg),
|
||||
|
@ -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.
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -98,6 +98,164 @@ 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>,
|
||||
cancelled: bool,
|
||||
}
|
||||
|
||||
// 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.cancel();
|
||||
self.emitter.borrow_mut().emit_struct(&self);
|
||||
|
||||
// if self.is_fatal() {
|
||||
// panic!(FatalError);
|
||||
// }
|
||||
}
|
||||
|
||||
// Cancel the diagnostic (a structured diagnostic must either be emitted or
|
||||
// cancelled or it will panic when dropped).
|
||||
pub fn cancel(&mut self) {
|
||||
self.cancelled = true;
|
||||
}
|
||||
|
||||
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 note_rfc_1214(&mut self , span: Span) -> &mut DiagnosticBuilder<'a> {
|
||||
self.span_note(span,
|
||||
"this warning results from recent bug fixes and clarifications; \
|
||||
it will become a HARD ERROR in the next release. \
|
||||
See RFC 1214 for details.")
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
// 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,
|
||||
code: Option<String>,
|
||||
span: Option<Span>) -> DiagnosticBuilder<'a> {
|
||||
DiagnosticBuilder {
|
||||
emitter: emitter,
|
||||
level: level,
|
||||
message: message.to_owned(),
|
||||
code: code,
|
||||
span: span,
|
||||
children: vec![],
|
||||
cancelled: false,
|
||||
}
|
||||
}
|
||||
|
||||
// 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 +290,85 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn struct_span_warn<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg, None, Some(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,
|
||||
Some(code.to_owned()),
|
||||
Some(sp));
|
||||
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, None, None);
|
||||
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();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Error, msg, None, Some(sp))
|
||||
}
|
||||
pub fn struct_span_err_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
// FIXME (and below) this is potentially inaccurate, since the DiagnosticBuilder
|
||||
// might be cancelled.
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Error, msg, Some(code.to_owned()), Some(sp))
|
||||
}
|
||||
pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Error, msg, None, None)
|
||||
}
|
||||
pub fn struct_span_fatal<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, None, Some(sp))
|
||||
}
|
||||
pub fn struct_span_fatal_with_code<'a>(&'a self,
|
||||
sp: Span,
|
||||
msg: &str,
|
||||
code: &str)
|
||||
-> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, Some(code.to_owned()), Some(sp))
|
||||
}
|
||||
pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
|
||||
self.bump_err_count();
|
||||
DiagnosticBuilder::new(&self.emit, Level::Fatal, msg, None, None)
|
||||
}
|
||||
|
||||
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 +376,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 +399,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 +411,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 +422,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 +435,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 +479,7 @@ impl Handler {
|
||||
}
|
||||
}
|
||||
|
||||
panic!(self.fatal(&s[..]));
|
||||
panic!(self.fatal(&s));
|
||||
}
|
||||
|
||||
pub fn emit(&self,
|
||||
|
Loading…
Reference in New Issue
Block a user