solar_interface/diagnostics/emitter/
mod.rs

1use super::{DiagCtxt, Diagnostic, Level};
2use crate::SourceMap;
3use std::{any::Any, sync::Arc};
4
5mod human;
6pub use human::{HumanBufferEmitter, HumanEmitter};
7
8#[cfg(feature = "json")]
9mod json;
10#[cfg(feature = "json")]
11pub use json::JsonEmitter;
12
13mod rustc;
14
15/// Dynamic diagnostic emitter. See [`Emitter`].
16pub type DynEmitter = dyn Emitter + Send;
17
18/// Diagnostic emitter.
19pub trait Emitter: Any {
20    /// Emits a diagnostic.
21    fn emit_diagnostic(&mut self, diagnostic: &Diagnostic);
22
23    /// Returns a reference to the source map, if any.
24    #[inline]
25    fn source_map(&self) -> Option<&Arc<SourceMap>> {
26        None
27    }
28
29    /// Returns `true` if we can use colors in the current output stream.
30    #[inline]
31    fn supports_color(&self) -> bool {
32        false
33    }
34}
35
36impl DynEmitter {
37    pub(crate) fn local_buffer(&self) -> Option<&str> {
38        self.downcast_ref::<HumanBufferEmitter>().map(HumanBufferEmitter::buffer)
39    }
40
41    // TODO: Remove when dyn trait upcasting is stable.
42    fn downcast_ref<T: Any>(&self) -> Option<&T> {
43        if self.type_id() == std::any::TypeId::of::<T>() {
44            unsafe { Some(&*(self as *const dyn Emitter as *const T)) }
45        } else {
46            None
47        }
48    }
49}
50
51/// Diagnostic emitter that only emits fatal diagnostics.
52pub struct SilentEmitter {
53    fatal_dcx: DiagCtxt,
54    note: Option<String>,
55}
56
57impl SilentEmitter {
58    /// Creates a new `SilentEmitter`. `fatal_dcx` is only used to emit fatal diagnostics.
59    pub fn new(fatal_dcx: DiagCtxt) -> Self {
60        Self { fatal_dcx, note: None }
61    }
62
63    /// Sets the note to be emitted for fatal diagnostics.
64    pub fn with_note(mut self, note: Option<String>) -> Self {
65        self.note = note;
66        self
67    }
68}
69
70impl Emitter for SilentEmitter {
71    fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
72        if diagnostic.level != Level::Fatal {
73            return;
74        }
75
76        let mut diagnostic = diagnostic.clone();
77        if let Some(note) = &self.note {
78            diagnostic.note(note.clone());
79        }
80        let _ = self.fatal_dcx.emit_diagnostic(diagnostic);
81    }
82}
83
84/// Diagnostic emitter that only stores emitted diagnostics.
85#[derive(Clone, Debug)]
86pub struct LocalEmitter {
87    diagnostics: Vec<Diagnostic>,
88}
89
90impl Default for LocalEmitter {
91    fn default() -> Self {
92        Self::new()
93    }
94}
95
96impl LocalEmitter {
97    /// Creates a new `LocalEmitter`.
98    pub fn new() -> Self {
99        Self { diagnostics: Vec::new() }
100    }
101
102    /// Returns a reference to the emitted diagnostics.
103    pub fn diagnostics(&self) -> &[Diagnostic] {
104        &self.diagnostics
105    }
106
107    /// Consumes the emitter and returns the emitted diagnostics.
108    pub fn into_diagnostics(self) -> Vec<Diagnostic> {
109        self.diagnostics
110    }
111}
112
113impl Emitter for LocalEmitter {
114    fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
115        self.diagnostics.push(diagnostic.clone());
116    }
117}
118
119#[cold]
120#[inline(never)]
121fn io_panic(error: std::io::Error) -> ! {
122    panic!("failed to emit diagnostic: {error}");
123}