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