From b2844917ad29e967043bea4e187421a6a3f61682 Mon Sep 17 00:00:00 2001 From: Edwin Cheng Date: Sat, 4 Apr 2020 16:04:01 +0800 Subject: Add proc_macro mod (copy from lib_proc_macro) --- .../ra_proc_macro_srv/src/proc_macro/diagnostic.rs | 170 +++++++++++++++++++++ 1 file changed, 170 insertions(+) create mode 100644 crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs (limited to 'crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs') diff --git a/crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs b/crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs new file mode 100644 index 000000000..9029f8815 --- /dev/null +++ b/crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs @@ -0,0 +1,170 @@ +//! lib-proc-macro diagnostic +//! +//! Copy from https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/diagnostic.rs +//! augmented with removing unstable features + +use crate::proc_macro::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) => ( + /// Adds a new child diagnostic message to `self` with the level + /// identified by this method's name with 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 + } + + /// Adds a new child diagnostic message to `self` with the level + /// identified by this method's name with 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: 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: 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) -> crate::proc_macro::bridge::client::MultiSpan { + let mut multi_span = crate::proc_macro::bridge::client::MultiSpan::new(); + for span in spans { + multi_span.push(span.0); + } + multi_span + } + + let mut diag = crate::proc_macro::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(); + } +} -- cgit v1.2.3