]>
Commit | Line | Data |
---|---|---|
c30ab7b3 SL |
1 | // Copyright 2012-2015 The Rust Project Developers. See the COPYRIGHT |
2 | // file at the top-level directory of this distribution and at | |
3 | // http://rust-lang.org/COPYRIGHT. | |
4 | // | |
5 | // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or | |
6 | // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license | |
7 | // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your | |
8 | // option. This file may not be copied, modified, or distributed | |
9 | // except according to those terms. | |
10 | ||
11 | use CodeSuggestion; | |
abe05a73 | 12 | use SubstitutionPart; |
7cac9316 | 13 | use Substitution; |
c30ab7b3 | 14 | use Level; |
c30ab7b3 SL |
15 | use std::fmt; |
16 | use syntax_pos::{MultiSpan, Span}; | |
32a655c1 | 17 | use snippet::Style; |
c30ab7b3 SL |
18 | |
19 | #[must_use] | |
abe05a73 | 20 | #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] |
c30ab7b3 SL |
21 | pub struct Diagnostic { |
22 | pub level: Level, | |
32a655c1 | 23 | pub message: Vec<(String, Style)>, |
abe05a73 | 24 | pub code: Option<DiagnosticId>, |
c30ab7b3 SL |
25 | pub span: MultiSpan, |
26 | pub children: Vec<SubDiagnostic>, | |
7cac9316 | 27 | pub suggestions: Vec<CodeSuggestion>, |
c30ab7b3 SL |
28 | } |
29 | ||
abe05a73 XL |
30 | #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] |
31 | pub enum DiagnosticId { | |
32 | Error(String), | |
33 | Lint(String), | |
34 | } | |
35 | ||
c30ab7b3 | 36 | /// For example a note attached to an error. |
abe05a73 | 37 | #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)] |
c30ab7b3 SL |
38 | pub struct SubDiagnostic { |
39 | pub level: Level, | |
32a655c1 | 40 | pub message: Vec<(String, Style)>, |
c30ab7b3 | 41 | pub span: MultiSpan, |
abe05a73 | 42 | pub render_span: Option<MultiSpan>, |
c30ab7b3 SL |
43 | } |
44 | ||
cc61c64b XL |
45 | #[derive(PartialEq, Eq)] |
46 | pub struct DiagnosticStyledString(pub Vec<StringPart>); | |
47 | ||
48 | impl DiagnosticStyledString { | |
49 | pub fn new() -> DiagnosticStyledString { | |
50 | DiagnosticStyledString(vec![]) | |
51 | } | |
52 | pub fn push_normal<S: Into<String>>(&mut self, t: S) { | |
53 | self.0.push(StringPart::Normal(t.into())); | |
54 | } | |
55 | pub fn push_highlighted<S: Into<String>>(&mut self, t: S) { | |
56 | self.0.push(StringPart::Highlighted(t.into())); | |
57 | } | |
58 | pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString { | |
59 | DiagnosticStyledString(vec![StringPart::Normal(t.into())]) | |
60 | } | |
61 | ||
62 | pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString { | |
63 | DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) | |
64 | } | |
65 | ||
66 | pub fn content(&self) -> String { | |
67 | self.0.iter().map(|x| x.content()).collect::<String>() | |
68 | } | |
69 | } | |
70 | ||
71 | #[derive(PartialEq, Eq)] | |
72 | pub enum StringPart { | |
73 | Normal(String), | |
74 | Highlighted(String), | |
75 | } | |
76 | ||
77 | impl StringPart { | |
78 | pub fn content(&self) -> String { | |
79 | match self { | |
80 | &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned() | |
81 | } | |
82 | } | |
83 | } | |
84 | ||
c30ab7b3 SL |
85 | impl Diagnostic { |
86 | pub fn new(level: Level, message: &str) -> Self { | |
87 | Diagnostic::new_with_code(level, None, message) | |
88 | } | |
89 | ||
abe05a73 | 90 | pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self { |
c30ab7b3 | 91 | Diagnostic { |
3b2f2976 | 92 | level, |
32a655c1 | 93 | message: vec![(message.to_owned(), Style::NoStyle)], |
3b2f2976 | 94 | code, |
c30ab7b3 SL |
95 | span: MultiSpan::new(), |
96 | children: vec![], | |
7cac9316 | 97 | suggestions: vec![], |
c30ab7b3 SL |
98 | } |
99 | } | |
100 | ||
101 | /// Cancel the diagnostic (a structured diagnostic must either be emitted or | |
3b2f2976 | 102 | /// canceled or it will panic when dropped). |
c30ab7b3 | 103 | /// BEWARE: if this DiagnosticBuilder is an error, then creating it will |
3b2f2976 | 104 | /// bump the error count on the Handler and canceling it won't undo that. |
c30ab7b3 SL |
105 | /// If you want to decrement the error count you should use `Handler::cancel`. |
106 | pub fn cancel(&mut self) { | |
107 | self.level = Level::Cancelled; | |
108 | } | |
109 | ||
110 | pub fn cancelled(&self) -> bool { | |
111 | self.level == Level::Cancelled | |
112 | } | |
113 | ||
c30ab7b3 SL |
114 | /// Add a span/label to be included in the resulting snippet. |
115 | /// This is pushed onto the `MultiSpan` that was created when the | |
116 | /// diagnostic was first built. If you don't call this function at | |
117 | /// all, and you just supplied a `Span` to create the diagnostic, | |
118 | /// then the snippet will just include that `Span`, which is | |
119 | /// called the primary span. | |
7cac9316 XL |
120 | pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self { |
121 | self.span.push_span_label(span, label.into()); | |
c30ab7b3 SL |
122 | self |
123 | } | |
124 | ||
125 | pub fn note_expected_found(&mut self, | |
126 | label: &fmt::Display, | |
cc61c64b XL |
127 | expected: DiagnosticStyledString, |
128 | found: DiagnosticStyledString) | |
c30ab7b3 SL |
129 | -> &mut Self |
130 | { | |
131 | self.note_expected_found_extra(label, expected, found, &"", &"") | |
132 | } | |
133 | ||
134 | pub fn note_expected_found_extra(&mut self, | |
135 | label: &fmt::Display, | |
cc61c64b XL |
136 | expected: DiagnosticStyledString, |
137 | found: DiagnosticStyledString, | |
c30ab7b3 SL |
138 | expected_extra: &fmt::Display, |
139 | found_extra: &fmt::Display) | |
140 | -> &mut Self | |
141 | { | |
cc61c64b XL |
142 | let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)]; |
143 | msg.extend(expected.0.iter() | |
144 | .map(|x| match *x { | |
145 | StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), | |
146 | StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), | |
147 | })); | |
148 | msg.push((format!("`{}\n", expected_extra), Style::NoStyle)); | |
149 | msg.push((format!(" found {} `", label), Style::NoStyle)); | |
150 | msg.extend(found.0.iter() | |
151 | .map(|x| match *x { | |
152 | StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), | |
153 | StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), | |
154 | })); | |
155 | msg.push((format!("`{}", found_extra), Style::NoStyle)); | |
156 | ||
c30ab7b3 | 157 | // For now, just attach these as notes |
cc61c64b | 158 | self.highlighted_note(msg); |
c30ab7b3 SL |
159 | self |
160 | } | |
161 | ||
7cac9316 XL |
162 | pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self { |
163 | self.highlighted_note(vec![ | |
164 | (format!("`{}` from trait: `", name), Style::NoStyle), | |
165 | (signature, Style::Highlight), | |
166 | ("`".to_string(), Style::NoStyle)]); | |
167 | self | |
168 | } | |
169 | ||
c30ab7b3 SL |
170 | pub fn note(&mut self, msg: &str) -> &mut Self { |
171 | self.sub(Level::Note, msg, MultiSpan::new(), None); | |
172 | self | |
173 | } | |
174 | ||
32a655c1 SL |
175 | pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self { |
176 | self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None); | |
177 | self | |
178 | } | |
179 | ||
c30ab7b3 SL |
180 | pub fn span_note<S: Into<MultiSpan>>(&mut self, |
181 | sp: S, | |
182 | msg: &str) | |
183 | -> &mut Self { | |
184 | self.sub(Level::Note, msg, sp.into(), None); | |
185 | self | |
186 | } | |
187 | ||
188 | pub fn warn(&mut self, msg: &str) -> &mut Self { | |
189 | self.sub(Level::Warning, msg, MultiSpan::new(), None); | |
190 | self | |
191 | } | |
192 | ||
193 | pub fn span_warn<S: Into<MultiSpan>>(&mut self, | |
194 | sp: S, | |
195 | msg: &str) | |
196 | -> &mut Self { | |
197 | self.sub(Level::Warning, msg, sp.into(), None); | |
198 | self | |
199 | } | |
200 | ||
201 | pub fn help(&mut self , msg: &str) -> &mut Self { | |
202 | self.sub(Level::Help, msg, MultiSpan::new(), None); | |
203 | self | |
204 | } | |
205 | ||
206 | pub fn span_help<S: Into<MultiSpan>>(&mut self, | |
207 | sp: S, | |
208 | msg: &str) | |
209 | -> &mut Self { | |
210 | self.sub(Level::Help, msg, sp.into(), None); | |
211 | self | |
212 | } | |
213 | ||
3b2f2976 XL |
214 | /// Prints out a message with a suggested edit of the code. If the suggestion is presented |
215 | /// inline it will only show the text message and not the text. | |
216 | /// | |
ea8adc8c | 217 | /// See `CodeSuggestion` for more information. |
3b2f2976 XL |
218 | pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { |
219 | self.suggestions.push(CodeSuggestion { | |
abe05a73 XL |
220 | substitutions: vec![Substitution { |
221 | parts: vec![SubstitutionPart { | |
222 | snippet: suggestion, | |
223 | span: sp, | |
224 | }], | |
3b2f2976 XL |
225 | }], |
226 | msg: msg.to_owned(), | |
227 | show_code_when_inline: false, | |
228 | }); | |
229 | self | |
230 | } | |
231 | ||
c30ab7b3 SL |
232 | /// Prints out a message with a suggested edit of the code. |
233 | /// | |
041b39d2 XL |
234 | /// In case of short messages and a simple suggestion, |
235 | /// rustc displays it as a label like | |
236 | /// | |
237 | /// "try adding parentheses: `(tup.0).1`" | |
238 | /// | |
239 | /// The message | |
abe05a73 | 240 | /// |
041b39d2 XL |
241 | /// * should not end in any punctuation (a `:` is added automatically) |
242 | /// * should not be a question | |
243 | /// * should not contain any parts like "the following", "as shown" | |
244 | /// * may look like "to do xyz, use" or "to do xyz, use abc" | |
245 | /// * may contain a name of a function, variable or type, but not whole expressions | |
246 | /// | |
ea8adc8c | 247 | /// See `CodeSuggestion` for more information. |
7cac9316 XL |
248 | pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self { |
249 | self.suggestions.push(CodeSuggestion { | |
abe05a73 XL |
250 | substitutions: vec![Substitution { |
251 | parts: vec![SubstitutionPart { | |
252 | snippet: suggestion, | |
253 | span: sp, | |
254 | }], | |
7cac9316 XL |
255 | }], |
256 | msg: msg.to_owned(), | |
3b2f2976 | 257 | show_code_when_inline: true, |
7cac9316 XL |
258 | }); |
259 | self | |
260 | } | |
261 | ||
abe05a73 | 262 | /// Prints out a message with multiple suggested edits of the code. |
7cac9316 XL |
263 | pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self { |
264 | self.suggestions.push(CodeSuggestion { | |
abe05a73 XL |
265 | substitutions: suggestions.into_iter().map(|snippet| Substitution { |
266 | parts: vec![SubstitutionPart { | |
267 | snippet, | |
268 | span: sp, | |
269 | }], | |
270 | }).collect(), | |
7cac9316 | 271 | msg: msg.to_owned(), |
3b2f2976 | 272 | show_code_when_inline: true, |
7cac9316 | 273 | }); |
c30ab7b3 SL |
274 | self |
275 | } | |
276 | ||
277 | pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { | |
278 | self.span = sp.into(); | |
279 | self | |
280 | } | |
281 | ||
abe05a73 | 282 | pub fn code(&mut self, s: DiagnosticId) -> &mut Self { |
c30ab7b3 SL |
283 | self.code = Some(s); |
284 | self | |
285 | } | |
286 | ||
32a655c1 SL |
287 | pub fn message(&self) -> String { |
288 | self.message.iter().map(|i| i.0.to_owned()).collect::<String>() | |
289 | } | |
290 | ||
291 | pub fn styled_message(&self) -> &Vec<(String, Style)> { | |
c30ab7b3 SL |
292 | &self.message |
293 | } | |
294 | ||
c30ab7b3 SL |
295 | /// Used by a lint. Copies over all details *but* the "main |
296 | /// message". | |
297 | pub fn copy_details_not_message(&mut self, from: &Diagnostic) { | |
298 | self.span = from.span.clone(); | |
299 | self.code = from.code.clone(); | |
300 | self.children.extend(from.children.iter().cloned()) | |
301 | } | |
302 | ||
303 | /// Convenience function for internal use, clients should use one of the | |
304 | /// public methods above. | |
ea8adc8c | 305 | pub(crate) fn sub(&mut self, |
c30ab7b3 SL |
306 | level: Level, |
307 | message: &str, | |
308 | span: MultiSpan, | |
abe05a73 | 309 | render_span: Option<MultiSpan>) { |
c30ab7b3 | 310 | let sub = SubDiagnostic { |
3b2f2976 | 311 | level, |
32a655c1 | 312 | message: vec![(message.to_owned(), Style::NoStyle)], |
3b2f2976 XL |
313 | span, |
314 | render_span, | |
c30ab7b3 SL |
315 | }; |
316 | self.children.push(sub); | |
317 | } | |
32a655c1 SL |
318 | |
319 | /// Convenience function for internal use, clients should use one of the | |
320 | /// public methods above. | |
321 | fn sub_with_highlights(&mut self, | |
322 | level: Level, | |
323 | message: Vec<(String, Style)>, | |
324 | span: MultiSpan, | |
abe05a73 | 325 | render_span: Option<MultiSpan>) { |
32a655c1 | 326 | let sub = SubDiagnostic { |
3b2f2976 XL |
327 | level, |
328 | message, | |
329 | span, | |
330 | render_span, | |
32a655c1 SL |
331 | }; |
332 | self.children.push(sub); | |
333 | } | |
334 | } | |
335 | ||
336 | impl SubDiagnostic { | |
337 | pub fn message(&self) -> String { | |
338 | self.message.iter().map(|i| i.0.to_owned()).collect::<String>() | |
339 | } | |
340 | ||
341 | pub fn styled_message(&self) -> &Vec<(String, Style)> { | |
342 | &self.message | |
343 | } | |
c30ab7b3 | 344 | } |