]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/diagnostic.rs
Auto merge of #54265 - arielb1:civilize-proc-macros, r=alexcrichton
[rust.git] / src / librustc_errors / diagnostic.rs
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;
12 use SubstitutionPart;
13 use Substitution;
14 use Applicability;
15 use Level;
16 use std::fmt;
17 use syntax_pos::{MultiSpan, Span};
18 use snippet::Style;
19
20 #[must_use]
21 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
22 pub struct Diagnostic {
23     pub level: Level,
24     pub message: Vec<(String, Style)>,
25     pub code: Option<DiagnosticId>,
26     pub span: MultiSpan,
27     pub children: Vec<SubDiagnostic>,
28     pub suggestions: Vec<CodeSuggestion>,
29 }
30
31 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
32 pub enum DiagnosticId {
33     Error(String),
34     Lint(String),
35 }
36
37 /// For example a note attached to an error.
38 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
39 pub struct SubDiagnostic {
40     pub level: Level,
41     pub message: Vec<(String, Style)>,
42     pub span: MultiSpan,
43     pub render_span: Option<MultiSpan>,
44 }
45
46 #[derive(PartialEq, Eq)]
47 pub struct DiagnosticStyledString(pub Vec<StringPart>);
48
49 impl DiagnosticStyledString {
50     pub fn new() -> DiagnosticStyledString {
51         DiagnosticStyledString(vec![])
52     }
53     pub fn push_normal<S: Into<String>>(&mut self, t: S) {
54         self.0.push(StringPart::Normal(t.into()));
55     }
56     pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
57         self.0.push(StringPart::Highlighted(t.into()));
58     }
59     pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
60         DiagnosticStyledString(vec![StringPart::Normal(t.into())])
61     }
62
63     pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
64         DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
65     }
66
67     pub fn content(&self) -> String {
68         self.0.iter().map(|x| x.content()).collect::<String>()
69     }
70 }
71
72 #[derive(PartialEq, Eq)]
73 pub enum StringPart {
74     Normal(String),
75     Highlighted(String),
76 }
77
78 impl StringPart {
79     pub fn content(&self) -> String {
80         match self {
81             &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s.to_owned()
82         }
83     }
84 }
85
86 impl Diagnostic {
87     pub fn new(level: Level, message: &str) -> Self {
88         Diagnostic::new_with_code(level, None, message)
89     }
90
91     pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
92         Diagnostic {
93             level,
94             message: vec![(message.to_owned(), Style::NoStyle)],
95             code,
96             span: MultiSpan::new(),
97             children: vec![],
98             suggestions: vec![],
99         }
100     }
101
102     pub fn is_error(&self) -> bool {
103         match self.level {
104             Level::Bug |
105             Level::Fatal |
106             Level::PhaseFatal |
107             Level::Error |
108             Level::FailureNote => {
109                 true
110             }
111
112             Level::Warning |
113             Level::Note |
114             Level::Help |
115             Level::Cancelled => {
116                 false
117             }
118         }
119     }
120
121     /// Cancel the diagnostic (a structured diagnostic must either be emitted or
122     /// canceled or it will panic when dropped).
123     pub fn cancel(&mut self) {
124         self.level = Level::Cancelled;
125     }
126
127     pub fn cancelled(&self) -> bool {
128         self.level == Level::Cancelled
129     }
130
131     /// Add a span/label to be included in the resulting snippet.
132     /// This is pushed onto the `MultiSpan` that was created when the
133     /// diagnostic was first built. If you don't call this function at
134     /// all, and you just supplied a `Span` to create the diagnostic,
135     /// then the snippet will just include that `Span`, which is
136     /// called the primary span.
137     pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
138         self.span.push_span_label(span, label.into());
139         self
140     }
141
142     pub fn note_expected_found(&mut self,
143                                label: &dyn fmt::Display,
144                                expected: DiagnosticStyledString,
145                                found: DiagnosticStyledString)
146                                -> &mut Self
147     {
148         self.note_expected_found_extra(label, expected, found, &"", &"")
149     }
150
151     pub fn note_expected_found_extra(&mut self,
152                                      label: &dyn fmt::Display,
153                                      expected: DiagnosticStyledString,
154                                      found: DiagnosticStyledString,
155                                      expected_extra: &dyn fmt::Display,
156                                      found_extra: &dyn fmt::Display)
157                                      -> &mut Self
158     {
159         let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
160         msg.extend(expected.0.iter()
161                    .map(|x| match *x {
162                        StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
163                        StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
164                    }));
165         msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
166         msg.push((format!("   found {} `", label), Style::NoStyle));
167         msg.extend(found.0.iter()
168                    .map(|x| match *x {
169                        StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
170                        StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
171                    }));
172         msg.push((format!("`{}", found_extra), Style::NoStyle));
173
174         // For now, just attach these as notes
175         self.highlighted_note(msg);
176         self
177     }
178
179     pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
180         self.highlighted_note(vec![
181             (format!("`{}` from trait: `", name), Style::NoStyle),
182             (signature, Style::Highlight),
183             ("`".to_string(), Style::NoStyle)]);
184         self
185     }
186
187     pub fn note(&mut self, msg: &str) -> &mut Self {
188         self.sub(Level::Note, msg, MultiSpan::new(), None);
189         self
190     }
191
192     pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
193         self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
194         self
195     }
196
197     pub fn span_note<S: Into<MultiSpan>>(&mut self,
198                                          sp: S,
199                                          msg: &str)
200                                          -> &mut Self {
201         self.sub(Level::Note, msg, sp.into(), None);
202         self
203     }
204
205     pub fn warn(&mut self, msg: &str) -> &mut Self {
206         self.sub(Level::Warning, msg, MultiSpan::new(), None);
207         self
208     }
209
210     pub fn span_warn<S: Into<MultiSpan>>(&mut self,
211                                          sp: S,
212                                          msg: &str)
213                                          -> &mut Self {
214         self.sub(Level::Warning, msg, sp.into(), None);
215         self
216     }
217
218     pub fn help(&mut self , msg: &str) -> &mut Self {
219         self.sub(Level::Help, msg, MultiSpan::new(), None);
220         self
221     }
222
223     pub fn span_help<S: Into<MultiSpan>>(&mut self,
224                                          sp: S,
225                                          msg: &str)
226                                          -> &mut Self {
227         self.sub(Level::Help, msg, sp.into(), None);
228         self
229     }
230
231     /// Prints out a message with a suggested edit of the code. If the suggestion is presented
232     /// inline it will only show the text message and not the text.
233     ///
234     /// See `CodeSuggestion` for more information.
235     #[deprecated(note = "Use `span_suggestion_short_with_applicability`")]
236     pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
237         self.suggestions.push(CodeSuggestion {
238             substitutions: vec![Substitution {
239                 parts: vec![SubstitutionPart {
240                     snippet: suggestion,
241                     span: sp,
242                 }],
243             }],
244             msg: msg.to_owned(),
245             show_code_when_inline: false,
246             applicability: Applicability::Unspecified,
247         });
248         self
249     }
250
251     /// Prints out a message with a suggested edit of the code.
252     ///
253     /// In case of short messages and a simple suggestion,
254     /// rustc displays it as a label like
255     ///
256     /// "try adding parentheses: `(tup.0).1`"
257     ///
258     /// The message
259     ///
260     /// * should not end in any punctuation (a `:` is added automatically)
261     /// * should not be a question
262     /// * should not contain any parts like "the following", "as shown"
263     /// * may look like "to do xyz, use" or "to do xyz, use abc"
264     /// * may contain a name of a function, variable or type, but not whole expressions
265     ///
266     /// See `CodeSuggestion` for more information.
267     #[deprecated(note = "Use `span_suggestion_with_applicability`")]
268     pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
269         self.suggestions.push(CodeSuggestion {
270             substitutions: vec![Substitution {
271                 parts: vec![SubstitutionPart {
272                     snippet: suggestion,
273                     span: sp,
274                 }],
275             }],
276             msg: msg.to_owned(),
277             show_code_when_inline: true,
278             applicability: Applicability::Unspecified,
279         });
280         self
281     }
282
283     pub fn multipart_suggestion_with_applicability(
284         &mut self,
285         msg: &str,
286         suggestion: Vec<(Span, String)>,
287         applicability: Applicability,
288     ) -> &mut Self {
289         self.suggestions.push(CodeSuggestion {
290             substitutions: vec![Substitution {
291                 parts: suggestion
292                     .into_iter()
293                     .map(|(span, snippet)| SubstitutionPart { snippet, span })
294                     .collect(),
295             }],
296             msg: msg.to_owned(),
297             show_code_when_inline: true,
298             applicability,
299         });
300         self
301     }
302
303     #[deprecated(note = "Use `multipart_suggestion_with_applicability`")]
304     pub fn multipart_suggestion(
305         &mut self,
306         msg: &str,
307         suggestion: Vec<(Span, String)>,
308     ) -> &mut Self {
309         self.multipart_suggestion_with_applicability(
310             msg,
311             suggestion,
312             Applicability::Unspecified,
313         )
314     }
315
316     /// Prints out a message with multiple suggested edits of the code.
317     #[deprecated(note = "Use `span_suggestions_with_applicability`")]
318     pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
319         self.suggestions.push(CodeSuggestion {
320             substitutions: suggestions.into_iter().map(|snippet| Substitution {
321                 parts: vec![SubstitutionPart {
322                     snippet,
323                     span: sp,
324                 }],
325             }).collect(),
326             msg: msg.to_owned(),
327             show_code_when_inline: true,
328             applicability: Applicability::Unspecified,
329         });
330         self
331     }
332
333     /// This is a suggestion that may contain mistakes or fillers and should
334     /// be read and understood by a human.
335     pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str,
336                                        suggestion: String,
337                                        applicability: Applicability) -> &mut Self {
338         self.suggestions.push(CodeSuggestion {
339             substitutions: vec![Substitution {
340                 parts: vec![SubstitutionPart {
341                     snippet: suggestion,
342                     span: sp,
343                 }],
344             }],
345             msg: msg.to_owned(),
346             show_code_when_inline: true,
347             applicability,
348         });
349         self
350     }
351
352     pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str,
353                                         suggestions: Vec<String>,
354                                         applicability: Applicability) -> &mut Self {
355         self.suggestions.push(CodeSuggestion {
356             substitutions: suggestions.into_iter().map(|snippet| Substitution {
357                 parts: vec![SubstitutionPart {
358                     snippet,
359                     span: sp,
360                 }],
361             }).collect(),
362             msg: msg.to_owned(),
363             show_code_when_inline: true,
364             applicability,
365         });
366         self
367     }
368
369     pub fn span_suggestion_short_with_applicability(
370         &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
371     ) -> &mut Self {
372         self.suggestions.push(CodeSuggestion {
373             substitutions: vec![Substitution {
374                 parts: vec![SubstitutionPart {
375                     snippet: suggestion,
376                     span: sp,
377                 }],
378             }],
379             msg: msg.to_owned(),
380             show_code_when_inline: false,
381             applicability: applicability,
382         });
383         self
384     }
385
386     pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
387         self.span = sp.into();
388         self
389     }
390
391     pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
392         self.code = Some(s);
393         self
394     }
395
396     pub fn get_code(&self) -> Option<DiagnosticId> {
397         self.code.clone()
398     }
399
400     pub fn message(&self) -> String {
401         self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
402     }
403
404     pub fn styled_message(&self) -> &Vec<(String, Style)> {
405         &self.message
406     }
407
408     /// Used by a lint. Copies over all details *but* the "main
409     /// message".
410     pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
411         self.span = from.span.clone();
412         self.code = from.code.clone();
413         self.children.extend(from.children.iter().cloned())
414     }
415
416     /// Convenience function for internal use, clients should use one of the
417     /// public methods above.
418     pub fn sub(&mut self,
419            level: Level,
420            message: &str,
421            span: MultiSpan,
422            render_span: Option<MultiSpan>) {
423         let sub = SubDiagnostic {
424             level,
425             message: vec![(message.to_owned(), Style::NoStyle)],
426             span,
427             render_span,
428         };
429         self.children.push(sub);
430     }
431
432     /// Convenience function for internal use, clients should use one of the
433     /// public methods above.
434     fn sub_with_highlights(&mut self,
435                            level: Level,
436                            message: Vec<(String, Style)>,
437                            span: MultiSpan,
438                            render_span: Option<MultiSpan>) {
439         let sub = SubDiagnostic {
440             level,
441             message,
442             span,
443             render_span,
444         };
445         self.children.push(sub);
446     }
447 }
448
449 impl SubDiagnostic {
450     pub fn message(&self) -> String {
451         self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
452     }
453
454     pub fn styled_message(&self) -> &Vec<(String, Style)> {
455         &self.message
456     }
457 }