]> git.lizzy.rs Git - rust.git/blob - src/libsyntax/errors/mod.rs
Add an --output option for specifying an error emitter
[rust.git] / src / libsyntax / errors / mod.rs
1 // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 pub use errors::emitter::ColorConfig;
12
13 use self::Level::*;
14 use self::RenderSpan::*;
15
16 use codemap::{self, Span};
17 use diagnostics;
18 use errors::emitter::{Emitter, EmitterWriter};
19
20 use std::cell::{RefCell, Cell};
21 use std::{error, fmt};
22 use std::io::prelude::*;
23 use std::rc::Rc;
24 use term;
25
26 pub mod emitter;
27 pub mod json;
28
29 #[derive(Clone)]
30 pub enum RenderSpan {
31     /// A FullSpan renders with both with an initial line for the
32     /// message, prefixed by file:linenum, followed by a summary of
33     /// the source code covered by the span.
34     FullSpan(Span),
35
36     /// Similar to a FullSpan, but the cited position is the end of
37     /// the span, instead of the start. Used, at least, for telling
38     /// compiletest/runtest to look at the last line of the span
39     /// (since `end_highlight_lines` displays an arrow to the end
40     /// of the span).
41     EndSpan(Span),
42
43     /// A suggestion renders with both with an initial line for the
44     /// message, prefixed by file:linenum, followed by a summary
45     /// of hypothetical source code, where the `String` is spliced
46     /// into the lines in place of the code covered by the span.
47     Suggestion(Span, String),
48
49     /// A FileLine renders with just a line for the message prefixed
50     /// by file:linenum.
51     FileLine(Span),
52 }
53
54 impl RenderSpan {
55     fn span(&self) -> Span {
56         match *self {
57             FullSpan(s) |
58             Suggestion(s, _) |
59             EndSpan(s) |
60             FileLine(s) =>
61                 s
62         }
63     }
64 }
65
66 /// Used as a return value to signify a fatal error occurred. (It is also
67 /// used as the argument to panic at the moment, but that will eventually
68 /// not be true.)
69 #[derive(Copy, Clone, Debug)]
70 #[must_use]
71 pub struct FatalError;
72
73 impl fmt::Display for FatalError {
74     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
75         write!(f, "parser fatal error")
76     }
77 }
78
79 impl error::Error for FatalError {
80     fn description(&self) -> &str {
81         "The parser has encountered a fatal error"
82     }
83 }
84
85 /// Signifies that the compiler died with an explicit call to `.bug`
86 /// or `.span_bug` rather than a failed assertion, etc.
87 #[derive(Copy, Clone, Debug)]
88 pub struct ExplicitBug;
89
90 impl fmt::Display for ExplicitBug {
91     fn fmt(&self, f: &mut fmt::Formatter) -> Result<(), fmt::Error> {
92         write!(f, "parser internal bug")
93     }
94 }
95
96 impl error::Error for ExplicitBug {
97     fn description(&self) -> &str {
98         "The parser has encountered an internal bug"
99     }
100 }
101
102 /// Used for emitting structured error messages and other diagnostic information.
103 #[must_use]
104 pub struct DiagnosticBuilder<'a> {
105     emitter: &'a RefCell<Box<Emitter>>,
106     level: Level,
107     message: String,
108     code: Option<String>,
109     span: Option<Span>,
110     children: Vec<SubDiagnostic>,
111 }
112
113 /// For example a note attached to an error.
114 struct SubDiagnostic {
115     level: Level,
116     message: String,
117     span: Option<Span>,
118     render_span: Option<RenderSpan>,
119 }
120
121 impl<'a> DiagnosticBuilder<'a> {
122     /// Emit the diagnostic.
123     pub fn emit(&mut self) {
124         if self.cancelled() {
125             return;
126         }
127
128         self.emitter.borrow_mut().emit_struct(&self);
129         self.cancel();
130
131         // if self.is_fatal() {
132         //     panic!(FatalError);
133         // }
134     }
135
136     /// Cancel the diagnostic (a structured diagnostic must either be emitted or
137     /// cancelled or it will panic when dropped).
138     /// BEWARE: if this DiagnosticBuilder is an error, then creating it will
139     /// bump the error count on the Handler and cancelling it won't undo that.
140     /// If you want to decrement the error count you should use `Handler::cancel`.
141     pub fn cancel(&mut self) {
142         self.level = Level::Cancelled;
143     }
144
145     pub fn cancelled(&self) -> bool {
146         self.level == Level::Cancelled
147     }
148
149     pub fn is_fatal(&self) -> bool {
150         self.level == Level::Fatal
151     }
152
153     pub fn note(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a>  {
154         self.sub(Level::Note, msg, None, None);
155         self
156     }
157     pub fn span_note(&mut self ,
158                      sp: Span,
159                      msg: &str)
160                      -> &mut DiagnosticBuilder<'a> {
161         self.sub(Level::Note, msg, Some(sp), None);
162         self
163     }
164     pub fn help(&mut self , msg: &str) -> &mut DiagnosticBuilder<'a>  {
165         self.sub(Level::Help, msg, None, None);
166         self
167     }
168     pub fn span_help(&mut self ,
169                      sp: Span,
170                      msg: &str)
171                      -> &mut DiagnosticBuilder<'a>  {
172         self.sub(Level::Help, msg, Some(sp), None);
173         self
174     }
175     /// Prints out a message with a suggested edit of the code.
176     ///
177     /// See `diagnostic::RenderSpan::Suggestion` for more information.
178     pub fn span_suggestion(&mut self ,
179                            sp: Span,
180                            msg: &str,
181                            suggestion: String)
182                            -> &mut DiagnosticBuilder<'a>  {
183         self.sub(Level::Help, msg, Some(sp), Some(Suggestion(sp, suggestion)));
184         self
185     }
186     pub fn span_end_note(&mut self ,
187                          sp: Span,
188                          msg: &str)
189                          -> &mut DiagnosticBuilder<'a>  {
190         self.sub(Level::Note, msg, Some(sp), Some(EndSpan(sp)));
191         self
192     }
193     pub fn fileline_note(&mut self ,
194                          sp: Span,
195                          msg: &str)
196                          -> &mut DiagnosticBuilder<'a>  {
197         self.sub(Level::Note, msg, Some(sp), Some(FileLine(sp)));
198         self
199     }
200     pub fn fileline_help(&mut self ,
201                          sp: Span,
202                          msg: &str)
203                          -> &mut DiagnosticBuilder<'a>  {
204         self.sub(Level::Help, msg, Some(sp), Some(FileLine(sp)));
205         self
206     }
207
208     pub fn span(&mut self, sp: Span) -> &mut Self {
209         self.span = Some(sp);
210         self
211     }
212
213     pub fn code(&mut self, s: String) -> &mut Self {
214         self.code = Some(s);
215         self
216     }
217
218     /// Convenience function for internal use, clients should use one of the
219     /// struct_* methods on Handler.
220     fn new(emitter: &'a RefCell<Box<Emitter>>,
221            level: Level,
222            message: &str) -> DiagnosticBuilder<'a>  {
223         DiagnosticBuilder {
224             emitter: emitter,
225             level: level,
226             message: message.to_owned(),
227             code: None,
228             span: None,
229             children: vec![],
230         }
231     }
232
233     /// Convenience function for internal use, clients should use one of the
234     /// public methods above.
235     fn sub(&mut self,
236            level: Level,
237            message: &str,
238            span: Option<Span>,
239            render_span: Option<RenderSpan>) {
240         let sub = SubDiagnostic {
241             level: level,
242             message: message.to_owned(),
243             span: span,
244             render_span: render_span,
245         };
246         self.children.push(sub);
247     }
248 }
249
250 impl<'a> fmt::Debug for DiagnosticBuilder<'a> {
251     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
252         self.message.fmt(f)
253     }
254 }
255
256 /// Destructor bomb - a DiagnosticBuilder must be either emitted or cancelled or
257 /// we emit a bug.
258 impl<'a> Drop for DiagnosticBuilder<'a> {
259     fn drop(&mut self) {
260         if !self.cancelled() {
261             self.emitter.borrow_mut().emit(None, "Error constructed but not emitted", None, Bug);
262             panic!();
263         }
264     }
265 }
266
267 /// A handler deals with errors; certain errors
268 /// (fatal, bug, unimpl) may cause immediate exit,
269 /// others log errors for later reporting.
270 pub struct Handler {
271     err_count: Cell<usize>,
272     emit: RefCell<Box<Emitter>>,
273     pub can_emit_warnings: bool,
274     treat_err_as_bug: bool,
275     delayed_span_bug: RefCell<Option<(codemap::Span, String)>>,
276 }
277
278 impl Handler {
279     // TODO remove
280     pub fn new(color_config: ColorConfig,
281                registry: Option<diagnostics::registry::Registry>,
282                can_emit_warnings: bool,
283                treat_err_as_bug: bool,
284                cm: Rc<codemap::CodeMap>)
285                -> Handler {
286         let emitter = Box::new(EmitterWriter::stderr(color_config, registry, cm));
287         Handler::with_emitter(can_emit_warnings, treat_err_as_bug, emitter)
288     }
289
290     pub fn with_emitter(can_emit_warnings: bool,
291                         treat_err_as_bug: bool,
292                         e: Box<Emitter>) -> Handler {
293         Handler {
294             err_count: Cell::new(0),
295             emit: RefCell::new(e),
296             can_emit_warnings: can_emit_warnings,
297             treat_err_as_bug: treat_err_as_bug,
298             delayed_span_bug: RefCell::new(None),
299         }
300     }
301
302     pub fn struct_dummy<'a>(&'a self) -> DiagnosticBuilder<'a> {
303         DiagnosticBuilder::new(&self.emit, Level::Cancelled, "")
304     }
305
306     pub fn struct_span_warn<'a>(&'a self,
307                                 sp: Span,
308                                 msg: &str)
309                                 -> DiagnosticBuilder<'a> {
310         let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
311         result.span(sp);
312         if !self.can_emit_warnings {
313             result.cancel();
314         }
315         result
316     }
317     pub fn struct_span_warn_with_code<'a>(&'a self,
318                                           sp: Span,
319                                           msg: &str,
320                                           code: &str)
321                                           -> DiagnosticBuilder<'a> {
322         let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
323         result.span(sp);
324         result.code(code.to_owned());
325         if !self.can_emit_warnings {
326             result.cancel();
327         }
328         result
329     }
330     pub fn struct_warn<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
331         let mut result = DiagnosticBuilder::new(&self.emit, Level::Warning, msg);
332         if !self.can_emit_warnings {
333             result.cancel();
334         }
335         result
336     }
337     pub fn struct_span_err<'a>(&'a self,
338                                sp: Span,
339                                msg: &str)
340                                -> DiagnosticBuilder<'a> {
341         self.bump_err_count();
342         let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
343         result.span(sp);
344         result
345     }
346     pub fn struct_span_err_with_code<'a>(&'a self,
347                                          sp: Span,
348                                          msg: &str,
349                                          code: &str)
350                                          -> DiagnosticBuilder<'a> {
351         self.bump_err_count();
352         let mut result = DiagnosticBuilder::new(&self.emit, Level::Error, msg);
353         result.span(sp);
354         result.code(code.to_owned());
355         result
356     }
357     pub fn struct_err<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
358         self.bump_err_count();
359         DiagnosticBuilder::new(&self.emit, Level::Error, msg)
360     }
361     pub fn struct_span_fatal<'a>(&'a self,
362                                  sp: Span,
363                                  msg: &str)
364                                  -> DiagnosticBuilder<'a> {
365         self.bump_err_count();
366         let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
367         result.span(sp);
368         result
369     }
370     pub fn struct_span_fatal_with_code<'a>(&'a self,
371                                            sp: Span,
372                                            msg: &str,
373                                            code: &str)
374                                            -> DiagnosticBuilder<'a> {
375         self.bump_err_count();
376         let mut result = DiagnosticBuilder::new(&self.emit, Level::Fatal, msg);
377         result.span(sp);
378         result.code(code.to_owned());
379         result
380     }
381     pub fn struct_fatal<'a>(&'a self, msg: &str) -> DiagnosticBuilder<'a> {
382         self.bump_err_count();
383         DiagnosticBuilder::new(&self.emit, Level::Fatal, msg)
384     }
385
386     pub fn cancel(&mut self, err: &mut DiagnosticBuilder) {
387         if err.level == Level::Error || err.level == Level::Fatal {
388             assert!(self.has_errors());
389             self.err_count.set(self.err_count.get() + 1);
390         }
391         err.cancel();
392     }
393
394     pub fn span_fatal(&self, sp: Span, msg: &str) -> FatalError {
395         if self.treat_err_as_bug {
396             self.span_bug(sp, msg);
397         }
398         self.emit(Some(sp), msg, Fatal);
399         self.bump_err_count();
400         return FatalError;
401     }
402     pub fn span_fatal_with_code(&self, sp: Span, msg: &str, code: &str) -> FatalError {
403         if self.treat_err_as_bug {
404             self.span_bug(sp, msg);
405         }
406         self.emit_with_code(Some(sp), msg, code, Fatal);
407         self.bump_err_count();
408         return FatalError;
409     }
410     pub fn span_err(&self, sp: Span, msg: &str) {
411         if self.treat_err_as_bug {
412             self.span_bug(sp, msg);
413         }
414         self.emit(Some(sp), msg, Error);
415         self.bump_err_count();
416     }
417     pub fn span_err_with_code(&self, sp: Span, msg: &str, code: &str) {
418         if self.treat_err_as_bug {
419             self.span_bug(sp, msg);
420         }
421         self.emit_with_code(Some(sp), msg, code, Error);
422         self.bump_err_count();
423     }
424     pub fn span_warn(&self, sp: Span, msg: &str) {
425         self.emit(Some(sp), msg, Warning);
426     }
427     pub fn span_warn_with_code(&self, sp: Span, msg: &str, code: &str) {
428         self.emit_with_code(Some(sp), msg, code, Warning);
429     }
430     pub fn span_bug(&self, sp: Span, msg: &str) -> ! {
431         self.emit(Some(sp), msg, Bug);
432         panic!(ExplicitBug);
433     }
434     pub fn delay_span_bug(&self, sp: Span, msg: &str) {
435         let mut delayed = self.delayed_span_bug.borrow_mut();
436         *delayed = Some((sp, msg.to_string()));
437     }
438     pub fn span_bug_no_panic(&self, sp: Span, msg: &str) {
439         self.emit(Some(sp), msg, Bug);
440         self.bump_err_count();
441     }
442     pub fn span_note_without_error(&self, sp: Span, msg: &str) {
443         self.emit.borrow_mut().emit(Some(sp), msg, None, Note);
444     }
445     pub fn span_unimpl(&self, sp: Span, msg: &str) -> ! {
446         self.span_bug(sp, &format!("unimplemented {}", msg));
447     }
448     pub fn fatal(&self, msg: &str) -> FatalError {
449         if self.treat_err_as_bug {
450             self.bug(msg);
451         }
452         self.emit.borrow_mut().emit(None, msg, None, Fatal);
453         self.bump_err_count();
454         FatalError
455     }
456     pub fn err(&self, msg: &str) {
457         if self.treat_err_as_bug {
458             self.bug(msg);
459         }
460         self.emit.borrow_mut().emit(None, msg, None, Error);
461         self.bump_err_count();
462     }
463     pub fn warn(&self, msg: &str) {
464         self.emit.borrow_mut().emit(None, msg, None, Warning);
465     }
466     pub fn note_without_error(&self, msg: &str) {
467         self.emit.borrow_mut().emit(None, msg, None, Note);
468     }
469     pub fn bug(&self, msg: &str) -> ! {
470         self.emit.borrow_mut().emit(None, msg, None, Bug);
471         panic!(ExplicitBug);
472     }
473     pub fn unimpl(&self, msg: &str) -> ! {
474         self.bug(&format!("unimplemented {}", msg));
475     }
476
477     pub fn bump_err_count(&self) {
478         self.err_count.set(self.err_count.get() + 1);
479     }
480
481     pub fn err_count(&self) -> usize {
482         self.err_count.get()
483     }
484
485     pub fn has_errors(&self) -> bool {
486         self.err_count.get() > 0
487     }
488
489     pub fn abort_if_errors(&self) {
490         let s;
491         match self.err_count.get() {
492             0 => {
493                 let delayed_bug = self.delayed_span_bug.borrow();
494                 match *delayed_bug {
495                     Some((span, ref errmsg)) => {
496                         self.span_bug(span, errmsg);
497                     },
498                     _ => {}
499                 }
500
501                 return;
502             }
503             1 => s = "aborting due to previous error".to_string(),
504             _  => {
505                 s = format!("aborting due to {} previous errors",
506                             self.err_count.get());
507             }
508         }
509
510         panic!(self.fatal(&s));
511     }
512
513     pub fn emit(&self,
514                 sp: Option<Span>,
515                 msg: &str,
516                 lvl: Level) {
517         if lvl == Warning && !self.can_emit_warnings { return }
518         self.emit.borrow_mut().emit(sp, msg, None, lvl);
519     }
520
521     pub fn emit_with_code(&self,
522                           sp: Option<Span>,
523                           msg: &str,
524                           code: &str,
525                           lvl: Level) {
526         if lvl == Warning && !self.can_emit_warnings { return }
527         self.emit.borrow_mut().emit(sp, msg, Some(code), lvl);
528     }
529
530     pub fn custom_emit(&self, sp: RenderSpan, msg: &str, lvl: Level) {
531         if lvl == Warning && !self.can_emit_warnings { return }
532         self.emit.borrow_mut().custom_emit(sp, msg, lvl);
533     }
534 }
535
536
537 #[derive(Copy, PartialEq, Clone, Debug)]
538 pub enum Level {
539     Bug,
540     Fatal,
541     Error,
542     Warning,
543     Note,
544     Help,
545     Cancelled,
546 }
547
548 impl fmt::Display for Level {
549     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
550         use std::fmt::Display;
551
552         match *self {
553             Bug => "error: internal compiler error".fmt(f),
554             Fatal | Error => "error".fmt(f),
555             Warning => "warning".fmt(f),
556             Note => "note".fmt(f),
557             Help => "help".fmt(f),
558             Cancelled => unreachable!(),
559         }
560     }
561 }
562
563 impl Level {
564     fn color(self) -> term::color::Color {
565         match self {
566             Bug | Fatal | Error => term::color::BRIGHT_RED,
567             Warning => term::color::BRIGHT_YELLOW,
568             Note => term::color::BRIGHT_GREEN,
569             Help => term::color::BRIGHT_CYAN,
570             Cancelled => unreachable!(),
571         }
572     }
573 }
574
575 pub fn expect<T, M>(diag: &Handler, opt: Option<T>, msg: M) -> T where
576     M: FnOnce() -> String,
577 {
578     match opt {
579         Some(t) => t,
580         None => diag.bug(&msg()),
581     }
582 }