aboutsummaryrefslogtreecommitdiff
path: root/crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs
diff options
context:
space:
mode:
Diffstat (limited to 'crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs')
-rw-r--r--crates/ra_proc_macro_srv/src/proc_macro/diagnostic.rs170
1 files changed, 170 insertions, 0 deletions
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 @@
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
6use crate::proc_macro::Span;
7
8/// An enum representing a diagnostic level.
9#[derive(Copy, Clone, Debug)]
10#[non_exhaustive]
11pub 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.
23pub trait MultiSpan {
24 /// Converts `self` into a `Vec<Span>`.
25 fn into_spans(self) -> Vec<Span>;
26}
27
28impl MultiSpan for Span {
29 fn into_spans(self) -> Vec<Span> {
30 vec![self]
31 }
32}
33
34impl MultiSpan for Vec<Span> {
35 fn into_spans(self) -> Vec<Span> {
36 self
37 }
38}
39
40impl<'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)]
49pub struct Diagnostic {
50 level: Level,
51 message: String,
52 spans: Vec<Span>,
53 children: Vec<Diagnostic>,
54}
55
56macro_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 S: MultiSpan, T: Into<String>
63 {
64 self.children.push(Diagnostic::spanned(spans, $level, message));
65 self
66 }
67
68 /// Adds a new child diagnostic message to `self` with the level
69 /// identified by this method's name with the given `message`.
70 pub fn $regular<T: Into<String>>(mut self, message: T) -> Diagnostic {
71 self.children.push(Diagnostic::new($level, message));
72 self
73 }
74 )
75}
76
77/// Iterator over the children diagnostics of a `Diagnostic`.
78#[derive(Debug, Clone)]
79pub struct Children<'a>(std::slice::Iter<'a, Diagnostic>);
80
81impl<'a> Iterator for Children<'a> {
82 type Item = &'a Diagnostic;
83
84 fn next(&mut self) -> Option<Self::Item> {
85 self.0.next()
86 }
87}
88
89impl Diagnostic {
90 /// Creates a new diagnostic with the given `level` and `message`.
91 pub fn new<T: Into<String>>(level: Level, message: T) -> Diagnostic {
92 Diagnostic { level: level, message: message.into(), spans: vec![], children: vec![] }
93 }
94
95 /// Creates a new diagnostic with the given `level` and `message` pointing to
96 /// the given set of `spans`.
97 pub fn spanned<S, T>(spans: S, level: Level, message: T) -> Diagnostic
98 where
99 S: MultiSpan,
100 T: Into<String>,
101 {
102 Diagnostic {
103 level: level,
104 message: message.into(),
105 spans: spans.into_spans(),
106 children: vec![],
107 }
108 }
109
110 diagnostic_child_methods!(span_error, error, Level::Error);
111 diagnostic_child_methods!(span_warning, warning, Level::Warning);
112 diagnostic_child_methods!(span_note, note, Level::Note);
113 diagnostic_child_methods!(span_help, help, Level::Help);
114
115 /// Returns the diagnostic `level` for `self`.
116 pub fn level(&self) -> Level {
117 self.level
118 }
119
120 /// Sets the level in `self` to `level`.
121 pub fn set_level(&mut self, level: Level) {
122 self.level = level;
123 }
124
125 /// Returns the message in `self`.
126 pub fn message(&self) -> &str {
127 &self.message
128 }
129
130 /// Sets the message in `self` to `message`.
131 pub fn set_message<T: Into<String>>(&mut self, message: T) {
132 self.message = message.into();
133 }
134
135 /// Returns the `Span`s in `self`.
136 pub fn spans(&self) -> &[Span] {
137 &self.spans
138 }
139
140 /// Sets the `Span`s in `self` to `spans`.
141 pub fn set_spans<S: MultiSpan>(&mut self, spans: S) {
142 self.spans = spans.into_spans();
143 }
144
145 /// Returns an iterator over the children diagnostics of `self`.
146 pub fn children(&self) -> Children<'_> {
147 Children(self.children.iter())
148 }
149
150 /// Emit the diagnostic.
151 pub fn emit(self) {
152 fn to_internal(spans: Vec<Span>) -> crate::proc_macro::bridge::client::MultiSpan {
153 let mut multi_span = crate::proc_macro::bridge::client::MultiSpan::new();
154 for span in spans {
155 multi_span.push(span.0);
156 }
157 multi_span
158 }
159
160 let mut diag = crate::proc_macro::bridge::client::Diagnostic::new(
161 self.level,
162 &self.message[..],
163 to_internal(self.spans),
164 );
165 for c in self.children {
166 diag.sub(c.level, &c.message[..], to_internal(c.spans));
167 }
168 diag.emit();
169 }
170}