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