]> git.lizzy.rs Git - rust.git/blob - crates/proc_macro_srv/src/abis/abi_1_58/proc_macro/diagnostic.rs
Add proc macro ABI for rustc 1.58
[rust.git] / crates / proc_macro_srv / src / abis / abi_1_58 / proc_macro / diagnostic.rs
1 //! lib-proc-macro diagnostic
2 //!
3 //! Copy from <https://github.com/rust-lang/rust/blob/6050e523bae6de61de4e060facc43dc512adaccd/src/libproc_macro/diagnostic.rs>
4 //! augmented with removing unstable features
5
6 use super::Span;
7
8 /// An enum representing a diagnostic level.
9 #[derive(Copy, Clone, Debug)]
10 #[non_exhaustive]
11 pub enum Level {
12     /// An error.
13     Error,
14     /// A warning.
15     Warning,
16     /// A note.
17     Note,
18     /// A help message.
19     Help,
20 }
21
22 /// Trait implemented by types that can be converted into a set of `Span`s.
23 pub trait MultiSpan {
24     /// Converts `self` into a `Vec<Span>`.
25     fn into_spans(self) -> Vec<Span>;
26 }
27
28 impl MultiSpan for Span {
29     fn into_spans(self) -> Vec<Span> {
30         vec![self]
31     }
32 }
33
34 impl MultiSpan for Vec<Span> {
35     fn into_spans(self) -> Vec<Span> {
36         self
37     }
38 }
39
40 impl<'a> MultiSpan for &'a [Span] {
41     fn into_spans(self) -> Vec<Span> {
42         self.to_vec()
43     }
44 }
45
46 /// A structure representing a diagnostic message and associated children
47 /// messages.
48 #[derive(Clone, Debug)]
49 pub struct Diagnostic {
50     level: Level,
51     message: String,
52     spans: Vec<Span>,
53     children: Vec<Diagnostic>,
54 }
55
56 macro_rules! diagnostic_child_methods {
57     ($spanned:ident, $regular:ident, $level:expr) => {
58         #[doc = concat!("Adds a new child diagnostics message to `self` with the [`",
59                         stringify!($level), "`] level, and the given `spans` and `message`.")]
60         pub fn $spanned<S, T>(mut self, spans: S, message: T) -> Diagnostic
61         where
62             S: MultiSpan,
63             T: Into<String>,
64         {
65             self.children.push(Diagnostic::spanned(spans, $level, message));
66             self
67         }
68
69         #[doc = concat!("Adds a new child diagnostic message to `self` with the [`",
70                         stringify!($level), "`] level, and the given `message`.")]
71         pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
72             self.children.push(Diagnostic::new($level, message));
73             self
74         }
75     };
76 }
77
78 /// Iterator over the children diagnostics of a `Diagnostic`.
79 #[derive(Debug, Clone)]
80 pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>);
81
82 impl<'a> Iterator for Children<'a> {
83     type Item = &'a Diagnostic;
84
85     fn next(&mut self) -> Option<Self::Item> {
86         self.0.next()
87     }
88 }
89
90 impl Diagnostic {
91     /// Creates a new diagnostic with the given `level` and `message`.
92     pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
93         Diagnostic { level, message: message.into(), spans: vec![], children: vec![] }
94     }
95
96     /// Creates a new diagnostic with the given `level` and `message` pointing to
97     /// the given set of `spans`.
98     pub fn spanned<S, T>(spans: S, level: Level, message: T) -> Diagnostic
99     where
100         S: MultiSpan,
101         T: Into<String>,
102     {
103         Diagnostic { level, message: message.into(), spans: spans.into_spans(), children: vec![] }
104     }
105
106     diagnostic_child_methods!(span_error, error, Level::Error);
107     diagnostic_child_methods!(span_warning, warning, Level::Warning);
108     diagnostic_child_methods!(span_note, note, Level::Note);
109     diagnostic_child_methods!(span_help, help, Level::Help);
110
111     /// Returns the diagnostic `level` for `self`.
112     pub fn level(&self) -> Level {
113         self.level
114     }
115
116     /// Sets the level in `self` to `level`.
117     pub fn set_level(&mut self, level: Level) {
118         self.level = level;
119     }
120
121     /// Returns the message in `self`.
122     pub fn message(&self) -> &str {
123         &self.message
124     }
125
126     /// Sets the message in `self` to `message`.
127     pub fn set_message<T: Into<String>>(&mut self, message: T) {
128         self.message = message.into();
129     }
130
131     /// Returns the `Span`s in `self`.
132     pub fn spans(&self) -> &[Span] {
133         &self.spans
134     }
135
136     /// Sets the `Span`s in `self` to `spans`.
137     pub fn set_spans<S: MultiSpan>(&mut self, spans: S) {
138         self.spans = spans.into_spans();
139     }
140
141     /// Returns an iterator over the children diagnostics of `self`.
142     pub fn children(&self) -> Children<'_> {
143         Children(self.children.iter())
144     }
145
146     /// Emit the diagnostic.
147     pub fn emit(self) {
148         fn to_internal(spans: Vec<Span>) -> super::bridge::client::MultiSpan {
149             let mut multi_span = super::bridge::client::MultiSpan::new();
150             for span in spans {
151                 multi_span.push(span.0);
152             }
153             multi_span
154         }
155
156         let mut diag = super::bridge::client::Diagnostic::new(
157             self.level,
158             &self.message[..],
159             to_internal(self.spans),
160         );
161         for c in self.children {
162             diag.sub(c.level, &c.message[..], to_internal(c.spans));
163         }
164         diag.emit();
165     }
166 }