//! lib-proc-macro diagnostic //! //! Copy from //! augmented with removing unstable features use super::Span; /// An enum representing a diagnostic level. #[derive(Copy, Clone, Debug)] #[non_exhaustive] pub enum Level { /// An error. Error, /// A warning. Warning, /// A note. Note, /// A help message. Help, } /// Trait implemented by types that can be converted into a set of `Span`s. pub trait MultiSpan { /// Converts `self` into a `Vec`. fn into_spans(self) -> Vec; } impl MultiSpan for Span { fn into_spans(self) -> Vec { vec![self] } } impl MultiSpan for Vec { fn into_spans(self) -> Vec { self } } impl<'a> MultiSpan for &'a [Span] { fn into_spans(self) -> Vec { self.to_vec() } } /// A structure representing a diagnostic message and associated children /// messages. #[derive(Clone, Debug)] pub struct Diagnostic { level: Level, message: String, spans: Vec, children: Vec, } macro_rules! diagnostic_child_methods { ($spanned:ident, $regular:ident, $level:expr) => { #[doc = concat!("Adds a new child diagnostics message to `self` with the [`", stringify!($level), "`] level, and the given `spans` and `message`.")] pub fn $spanned(mut self, spans: S, message: T) -> Diagnostic where S: MultiSpan, T: Into, { self.children.push(Diagnostic::spanned(spans, $level, message)); self } #[doc = concat!("Adds a new child diagnostic message to `self` with the [`", stringify!($level), "`] level, and the given `message`.")] pub fn $regular>(mut self, message: T) -> Diagnostic { self.children.push(Diagnostic::new($level, message)); self } }; } /// Iterator over the children diagnostics of a `Diagnostic`. #[derive(Debug, Clone)] pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); impl<'a> Iterator for Children<'a> { type Item = &'a Diagnostic; fn next(&mut self) -> Option { self.0.next() } } impl Diagnostic { /// Creates a new diagnostic with the given `level` and `message`. pub fn new>(level: Level, message: T) -> Diagnostic { Diagnostic { level, message: message.into(), spans: vec![], children: vec![] } } /// Creates a new diagnostic with the given `level` and `message` pointing to /// the given set of `spans`. pub fn spanned(spans: S, level: Level, message: T) -> Diagnostic where S: MultiSpan, T: Into, { Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] } } diagnostic_child_methods!(span_error, error, Level::Error); diagnostic_child_methods!(span_warning, warning, Level::Warning); diagnostic_child_methods!(span_note, note, Level::Note); diagnostic_child_methods!(span_help, help, Level::Help); /// Returns the diagnostic `level` for `self`. pub fn level(&self) -> Level { self.level } /// Sets the level in `self` to `level`. pub fn set_level(&mut self, level: Level) { self.level = level; } /// Returns the message in `self`. pub fn message(&self) -> &str { &self.message } /// Sets the message in `self` to `message`. pub fn set_message>(&mut self, message: T) { self.message = message.into(); } /// Returns the `Span`s in `self`. pub fn spans(&self) -> &[Span] { &self.spans } /// Sets the `Span`s in `self` to `spans`. pub fn set_spans(&mut self, spans: S) { self.spans = spans.into_spans(); } /// Returns an iterator over the children diagnostics of `self`. pub fn children(&self) -> Children<'_> { Children(self.children.iter()) } /// Emit the diagnostic. pub fn emit(self) { fn to_internal(spans: Vec) -> super::bridge::client::MultiSpan { let mut multi_span = super::bridge::client::MultiSpan::new(); for span in spans { multi_span.push(span.0); } multi_span } let mut diag = super::bridge::client::Diagnostic::new( self.level, &self.message[..], to_internal(self.spans), ); for c in self.children { diag.sub(c.level, &c.message[..], to_internal(c.spans)); } diag.emit(); } }