]> git.lizzy.rs Git - rust.git/blob - src/librustc_errors/diagnostic.rs
Rollup merge of #52769 - sinkuu:stray_test, 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     pub fn span_suggestion_short(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
236         self.suggestions.push(CodeSuggestion {
237             substitutions: vec![Substitution {
238                 parts: vec![SubstitutionPart {
239                     snippet: suggestion,
240                     span: sp,
241                 }],
242             }],
243             msg: msg.to_owned(),
244             show_code_when_inline: false,
245             applicability: Applicability::Unspecified,
246         });
247         self
248     }
249
250     /// Prints out a message with a suggested edit of the code.
251     ///
252     /// In case of short messages and a simple suggestion,
253     /// rustc displays it as a label like
254     ///
255     /// "try adding parentheses: `(tup.0).1`"
256     ///
257     /// The message
258     ///
259     /// * should not end in any punctuation (a `:` is added automatically)
260     /// * should not be a question
261     /// * should not contain any parts like "the following", "as shown"
262     /// * may look like "to do xyz, use" or "to do xyz, use abc"
263     /// * may contain a name of a function, variable or type, but not whole expressions
264     ///
265     /// See `CodeSuggestion` for more information.
266     pub fn span_suggestion(&mut self, sp: Span, msg: &str, suggestion: String) -> &mut Self {
267         self.suggestions.push(CodeSuggestion {
268             substitutions: vec![Substitution {
269                 parts: vec![SubstitutionPart {
270                     snippet: suggestion,
271                     span: sp,
272                 }],
273             }],
274             msg: msg.to_owned(),
275             show_code_when_inline: true,
276             applicability: Applicability::Unspecified,
277         });
278         self
279     }
280
281     pub fn multipart_suggestion(
282         &mut self,
283         msg: &str,
284         suggestion: Vec<(Span, String)>,
285     ) -> &mut Self {
286         self.suggestions.push(CodeSuggestion {
287             substitutions: vec![Substitution {
288                 parts: suggestion
289                     .into_iter()
290                     .map(|(span, snippet)| SubstitutionPart { snippet, span })
291                     .collect(),
292             }],
293             msg: msg.to_owned(),
294             show_code_when_inline: true,
295             applicability: Applicability::Unspecified,
296         });
297         self
298     }
299
300     /// Prints out a message with multiple suggested edits of the code.
301     pub fn span_suggestions(&mut self, sp: Span, msg: &str, suggestions: Vec<String>) -> &mut Self {
302         self.suggestions.push(CodeSuggestion {
303             substitutions: suggestions.into_iter().map(|snippet| Substitution {
304                 parts: vec![SubstitutionPart {
305                     snippet,
306                     span: sp,
307                 }],
308             }).collect(),
309             msg: msg.to_owned(),
310             show_code_when_inline: true,
311             applicability: Applicability::Unspecified,
312         });
313         self
314     }
315
316     /// This is a suggestion that may contain mistakes or fillers and should
317     /// be read and understood by a human.
318     pub fn span_suggestion_with_applicability(&mut self, sp: Span, msg: &str,
319                                        suggestion: String,
320                                        applicability: Applicability) -> &mut Self {
321         self.suggestions.push(CodeSuggestion {
322             substitutions: vec![Substitution {
323                 parts: vec![SubstitutionPart {
324                     snippet: suggestion,
325                     span: sp,
326                 }],
327             }],
328             msg: msg.to_owned(),
329             show_code_when_inline: true,
330             applicability,
331         });
332         self
333     }
334
335     pub fn span_suggestions_with_applicability(&mut self, sp: Span, msg: &str,
336                                         suggestions: Vec<String>,
337                                         applicability: Applicability) -> &mut Self {
338         self.suggestions.push(CodeSuggestion {
339             substitutions: suggestions.into_iter().map(|snippet| Substitution {
340                 parts: vec![SubstitutionPart {
341                     snippet,
342                     span: sp,
343                 }],
344             }).collect(),
345             msg: msg.to_owned(),
346             show_code_when_inline: true,
347             applicability,
348         });
349         self
350     }
351
352     pub fn span_suggestion_short_with_applicability(
353         &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
354     ) -> &mut Self {
355         self.suggestions.push(CodeSuggestion {
356             substitutions: vec![Substitution {
357                 parts: vec![SubstitutionPart {
358                     snippet: suggestion,
359                     span: sp,
360                 }],
361             }],
362             msg: msg.to_owned(),
363             show_code_when_inline: false,
364             applicability: applicability,
365         });
366         self
367     }
368
369     pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
370         self.span = sp.into();
371         self
372     }
373
374     pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
375         self.code = Some(s);
376         self
377     }
378
379     pub fn get_code(&self) -> Option<DiagnosticId> {
380         self.code.clone()
381     }
382
383     pub fn message(&self) -> String {
384         self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
385     }
386
387     pub fn styled_message(&self) -> &Vec<(String, Style)> {
388         &self.message
389     }
390
391     /// Used by a lint. Copies over all details *but* the "main
392     /// message".
393     pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
394         self.span = from.span.clone();
395         self.code = from.code.clone();
396         self.children.extend(from.children.iter().cloned())
397     }
398
399     /// Convenience function for internal use, clients should use one of the
400     /// public methods above.
401     pub fn sub(&mut self,
402            level: Level,
403            message: &str,
404            span: MultiSpan,
405            render_span: Option<MultiSpan>) {
406         let sub = SubDiagnostic {
407             level,
408             message: vec![(message.to_owned(), Style::NoStyle)],
409             span,
410             render_span,
411         };
412         self.children.push(sub);
413     }
414
415     /// Convenience function for internal use, clients should use one of the
416     /// public methods above.
417     fn sub_with_highlights(&mut self,
418                            level: Level,
419                            message: Vec<(String, Style)>,
420                            span: MultiSpan,
421                            render_span: Option<MultiSpan>) {
422         let sub = SubDiagnostic {
423             level,
424             message,
425             span,
426             render_span,
427         };
428         self.children.push(sub);
429     }
430 }
431
432 impl SubDiagnostic {
433     pub fn message(&self) -> String {
434         self.message.iter().map(|i| i.0.to_owned()).collect::<String>()
435     }
436
437     pub fn styled_message(&self) -> &Vec<(String, Style)> {
438         &self.message
439     }
440 }