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