solar_interface/diagnostics/emitter/
mod.rs

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
use super::{DiagCtxt, Diagnostic, Level};
use crate::SourceMap;
use std::{any::Any, sync::Arc};

mod human;
pub use human::{HumanBufferEmitter, HumanEmitter};

#[cfg(feature = "json")]
mod json;
#[cfg(feature = "json")]
pub use json::JsonEmitter;

mod rustc;

/// Dynamic diagnostic emitter. See [`Emitter`].
pub type DynEmitter = dyn Emitter + Send;

/// Diagnostic emitter.
pub trait Emitter: Any {
    /// Emits a diagnostic.
    fn emit_diagnostic(&mut self, diagnostic: &Diagnostic);

    /// Returns a reference to the source map, if any.
    #[inline]
    fn source_map(&self) -> Option<&Arc<SourceMap>> {
        None
    }

    /// Returns `true` if we can use colors in the current output stream.
    #[inline]
    fn supports_color(&self) -> bool {
        false
    }
}

impl DynEmitter {
    pub(crate) fn local_buffer(&self) -> Option<&str> {
        self.downcast_ref::<HumanBufferEmitter>().map(HumanBufferEmitter::buffer)
    }

    // TODO: Remove when dyn trait upcasting is stable.
    fn downcast_ref<T: Any>(&self) -> Option<&T> {
        if self.type_id() == std::any::TypeId::of::<T>() {
            unsafe { Some(&*(self as *const dyn Emitter as *const T)) }
        } else {
            None
        }
    }
}

/// Diagnostic emitter that only emits fatal diagnostics.
pub struct SilentEmitter {
    fatal_dcx: DiagCtxt,
    note: Option<String>,
}

impl SilentEmitter {
    /// Creates a new `SilentEmitter`. `fatal_dcx` is only used to emit fatal diagnostics.
    pub fn new(fatal_dcx: DiagCtxt) -> Self {
        Self { fatal_dcx, note: None }
    }

    /// Sets the note to be emitted for fatal diagnostics.
    pub fn with_note(mut self, note: Option<String>) -> Self {
        self.note = note;
        self
    }
}

impl Emitter for SilentEmitter {
    fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
        if diagnostic.level != Level::Fatal {
            return;
        }

        let mut diagnostic = diagnostic.clone();
        if let Some(note) = &self.note {
            diagnostic.note(note.clone());
        }
        let _ = self.fatal_dcx.emit_diagnostic(diagnostic);
    }
}

/// Diagnostic emitter that only stores emitted diagnostics.
#[derive(Clone, Debug)]
pub struct LocalEmitter {
    diagnostics: Vec<Diagnostic>,
}

impl Default for LocalEmitter {
    fn default() -> Self {
        Self::new()
    }
}

impl LocalEmitter {
    /// Creates a new `LocalEmitter`.
    pub fn new() -> Self {
        Self { diagnostics: Vec::new() }
    }

    /// Returns a reference to the emitted diagnostics.
    pub fn diagnostics(&self) -> &[Diagnostic] {
        &self.diagnostics
    }

    /// Consumes the emitter and returns the emitted diagnostics.
    pub fn into_diagnostics(self) -> Vec<Diagnostic> {
        self.diagnostics
    }
}

impl Emitter for LocalEmitter {
    fn emit_diagnostic(&mut self, diagnostic: &Diagnostic) {
        self.diagnostics.push(diagnostic.clone());
    }
}

#[cold]
#[inline(never)]
fn io_panic(error: std::io::Error) -> ! {
    panic!("failed to emit diagnostic: {error}");
}