diff options
Diffstat (limited to 'crates/proc_macro_srv/src/proc_macro/diagnostic.rs')
-rw-r--r-- | crates/proc_macro_srv/src/proc_macro/diagnostic.rs | 172 |
1 files changed, 172 insertions, 0 deletions
diff --git a/crates/proc_macro_srv/src/proc_macro/diagnostic.rs b/crates/proc_macro_srv/src/proc_macro/diagnostic.rs new file mode 100644 index 000000000..55d93917c --- /dev/null +++ b/crates/proc_macro_srv/src/proc_macro/diagnostic.rs | |||
@@ -0,0 +1,172 @@ | |||
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 crate::proc_macro::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 | /// Adds a new child diagnostic message to `self` with the level | ||
59 | /// identified by this method's name with the given `spans` and | ||
60 | /// `message`. | ||
61 | pub fn $spanned<S, T>(mut self, spans: S, message: T) -> Diagnostic | ||
62 | where | ||
63 | S: MultiSpan, | ||
64 | T: Into<String>, | ||
65 | { | ||
66 | self.children.push(Diagnostic::spanned(spans, $level, message)); | ||
67 | self | ||
68 | } | ||
69 | |||
70 | /// Adds a new child diagnostic message to `self` with the level | ||
71 | /// identified by this method's name with the given `message`. | ||
72 | pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic { | ||
73 | self.children.push(Diagnostic::new($level, message)); | ||
74 | self | ||
75 | } | ||
76 | }; | ||
77 | } | ||
78 | |||
79 | /// Iterator over the children diagnostics of a `Diagnostic`. | ||
80 | #[derive(Debug, Clone)] | ||
81 | pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>); | ||
82 | |||
83 | impl<'a> Iterator for Children<'a> { | ||
84 | type Item = &'a Diagnostic; | ||
85 | |||
86 | fn next(&mut self) -> Option<Self::Item> { | ||
87 | self.0.next() | ||
88 | } | ||
89 | } | ||
90 | |||
91 | impl Diagnostic { | ||
92 | /// Creates a new diagnostic with the given `level` and `message`. | ||
93 | pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic { | ||
94 | Diagnostic { level: level, message: message.into(), spans: vec![], children: vec![] } | ||
95 | } | ||
96 | |||
97 | /// Creates a new diagnostic with the given `level` and `message` pointing to | ||
98 | /// the given set of `spans`. | ||
99 | pub fn spanned<S, T>(spans: S, level: Level, message: T) -> Diagnostic | ||
100 | where | ||
101 | S: MultiSpan, | ||
102 | T: Into<String>, | ||
103 | { | ||
104 | Diagnostic { | ||
105 | level: level, | ||
106 | message: message.into(), | ||
107 | spans: spans.into_spans(), | ||
108 | children: vec![], | ||
109 | } | ||
110 | } | ||
111 | |||
112 | diagnostic_child_methods!(span_error, error, Level::Error); | ||
113 | diagnostic_child_methods!(span_warning, warning, Level::Warning); | ||
114 | diagnostic_child_methods!(span_note, note, Level::Note); | ||
115 | diagnostic_child_methods!(span_help, help, Level::Help); | ||
116 | |||
117 | /// Returns the diagnostic `level` for `self`. | ||
118 | pub fn level(&self) -> Level { | ||
119 | self.level | ||
120 | } | ||
121 | |||
122 | /// Sets the level in `self` to `level`. | ||
123 | pub fn set_level(&mut self, level: Level) { | ||
124 | self.level = level; | ||
125 | } | ||
126 | |||
127 | /// Returns the message in `self`. | ||
128 | pub fn message(&self) -> &str { | ||
129 | &self.message | ||
130 | } | ||
131 | |||
132 | /// Sets the message in `self` to `message`. | ||
133 | pub fn set_message<T: Into<String>>(&mut self, message: T) { | ||
134 | self.message = message.into(); | ||
135 | } | ||
136 | |||
137 | /// Returns the `Span`s in `self`. | ||
138 | pub fn spans(&self) -> &[Span] { | ||
139 | &self.spans | ||
140 | } | ||
141 | |||
142 | /// Sets the `Span`s in `self` to `spans`. | ||
143 | pub fn set_spans<S: MultiSpan>(&mut self, spans: S) { | ||
144 | self.spans = spans.into_spans(); | ||
145 | } | ||
146 | |||
147 | /// Returns an iterator over the children diagnostics of `self`. | ||
148 | pub fn children(&self) -> Children<'_> { | ||
149 | Children(self.children.iter()) | ||
150 | } | ||
151 | |||
152 | /// Emit the diagnostic. | ||
153 | pub fn emit(self) { | ||
154 | fn to_internal(spans: Vec<Span>) -> crate::proc_macro::bridge::client::MultiSpan { | ||
155 | let mut multi_span = crate::proc_macro::bridge::client::MultiSpan::new(); | ||
156 | for span in spans { | ||
157 | multi_span.push(span.0); | ||
158 | } | ||
159 | multi_span | ||
160 | } | ||
161 | |||
162 | let mut diag = crate::proc_macro::bridge::client::Diagnostic::new( | ||
163 | self.level, | ||
164 | &self.message[..], | ||
165 | to_internal(self.spans), | ||
166 | ); | ||
167 | for c in self.children { | ||
168 | diag.sub(c.level, &c.message[..], to_internal(c.spans)); | ||
169 | } | ||
170 | diag.emit(); | ||
171 | } | ||
172 | } | ||