1 use crate::CodeSuggestion;
2 use crate::SuggestionStyle;
3 use crate::SubstitutionPart;
4 use crate::Substitution;
5 use crate::Applicability;
7 use crate::snippet::Style;
9 use syntax_pos::{MultiSpan, Span};
12 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
13 pub struct Diagnostic {
15 pub message: Vec<(String, Style)>,
16 pub code: Option<DiagnosticId>,
18 pub children: Vec<SubDiagnostic>,
19 pub suggestions: Vec<CodeSuggestion>,
22 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
23 pub enum DiagnosticId {
28 /// For example a note attached to an error.
29 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
30 pub struct SubDiagnostic {
32 pub message: Vec<(String, Style)>,
34 pub render_span: Option<MultiSpan>,
37 #[derive(Debug, PartialEq, Eq)]
38 pub struct DiagnosticStyledString(pub Vec<StringPart>);
40 impl DiagnosticStyledString {
41 pub fn new() -> DiagnosticStyledString {
42 DiagnosticStyledString(vec![])
44 pub fn push_normal<S: Into<String>>(&mut self, t: S) {
45 self.0.push(StringPart::Normal(t.into()));
47 pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
48 self.0.push(StringPart::Highlighted(t.into()));
50 pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
51 DiagnosticStyledString(vec![StringPart::Normal(t.into())])
54 pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
55 DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
58 pub fn content(&self) -> String {
59 self.0.iter().map(|x| x.content()).collect::<String>()
63 #[derive(Debug, PartialEq, Eq)]
70 pub fn content(&self) -> &str {
72 &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s
78 pub fn new(level: Level, message: &str) -> Self {
79 Diagnostic::new_with_code(level, None, message)
82 pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
85 message: vec![(message.to_owned(), Style::NoStyle)],
87 span: MultiSpan::new(),
93 pub fn is_error(&self) -> bool {
98 Level::FailureNote => {
105 Level::Cancelled => {
111 /// Cancel the diagnostic (a structured diagnostic must either be emitted or
112 /// canceled or it will panic when dropped).
113 pub fn cancel(&mut self) {
114 self.level = Level::Cancelled;
117 pub fn cancelled(&self) -> bool {
118 self.level == Level::Cancelled
121 /// Adds a span/label to be included in the resulting snippet.
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.
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.
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());
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);
146 pub fn note_expected_found(&mut self,
147 label: &dyn fmt::Display,
148 expected: DiagnosticStyledString,
149 found: DiagnosticStyledString)
152 self.note_expected_found_extra(label, expected, found, &"", &"")
155 pub fn note_unsuccessfull_coercion(&mut self,
156 expected: DiagnosticStyledString,
157 found: DiagnosticStyledString)
160 let mut msg: Vec<_> =
161 vec![(format!("required when trying to coerce from type `"),
163 msg.extend(expected.0.iter()
165 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
166 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
168 msg.push((format!("` to type '"), Style::NoStyle));
169 msg.extend(found.0.iter()
171 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
172 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
174 msg.push((format!("`"), Style::NoStyle));
176 // For now, just attach these as notes
177 self.highlighted_note(msg);
181 pub fn note_expected_found_extra(&mut self,
182 label: &dyn fmt::Display,
183 expected: DiagnosticStyledString,
184 found: DiagnosticStyledString,
185 expected_extra: &dyn fmt::Display,
186 found_extra: &dyn fmt::Display)
189 let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
190 msg.extend(expected.0.iter()
192 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
193 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
195 msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
196 msg.push((format!(" found {} `", label), Style::NoStyle));
197 msg.extend(found.0.iter()
199 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
200 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
202 msg.push((format!("`{}", found_extra), Style::NoStyle));
204 // For now, just attach these as notes
205 self.highlighted_note(msg);
209 pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
210 self.highlighted_note(vec![
211 (format!("`{}` from trait: `", name), Style::NoStyle),
212 (signature, Style::Highlight),
213 ("`".to_string(), Style::NoStyle)]);
217 pub fn note(&mut self, msg: &str) -> &mut Self {
218 self.sub(Level::Note, msg, MultiSpan::new(), None);
222 pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
223 self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
227 /// Prints the span with a note above it.
228 pub fn span_note<S: Into<MultiSpan>>(&mut self,
232 self.sub(Level::Note, msg, sp.into(), None);
236 pub fn warn(&mut self, msg: &str) -> &mut Self {
237 self.sub(Level::Warning, msg, MultiSpan::new(), None);
241 /// Prints the span with a warn above it.
242 pub fn span_warn<S: Into<MultiSpan>>(&mut self,
246 self.sub(Level::Warning, msg, sp.into(), None);
250 pub fn help(&mut self , msg: &str) -> &mut Self {
251 self.sub(Level::Help, msg, MultiSpan::new(), None);
255 /// Prints the span with some help above it.
256 pub fn span_help<S: Into<MultiSpan>>(&mut self,
260 self.sub(Level::Help, msg, sp.into(), None);
264 pub fn multipart_suggestion(
267 suggestion: Vec<(Span, String)>,
268 applicability: Applicability,
270 self.suggestions.push(CodeSuggestion {
271 substitutions: vec![Substitution {
274 .map(|(span, snippet)| SubstitutionPart { snippet, span })
278 style: SuggestionStyle::ShowCode,
284 /// Prints out a message with for a multipart suggestion without showing the suggested code.
286 /// This is intended to be used for suggestions that are obvious in what the changes need to
287 /// be from the message, showing the span label inline would be visually unpleasant
288 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
289 /// improve understandability.
290 pub fn tool_only_multipart_suggestion(
293 suggestion: Vec<(Span, String)>,
294 applicability: Applicability,
296 self.suggestions.push(CodeSuggestion {
297 substitutions: vec![Substitution {
300 .map(|(span, snippet)| SubstitutionPart { snippet, span })
304 style: SuggestionStyle::CompletelyHidden,
310 /// Prints out a message with a suggested edit of the code.
312 /// In case of short messages and a simple suggestion, rustc displays it as a label:
315 /// try adding parentheses: `(tup.0).1`
320 /// * should not end in any punctuation (a `:` is added automatically)
321 /// * should not be a question (avoid language like "did you mean")
322 /// * should not contain any phrases like "the following", "as shown", etc.
323 /// * may look like "to do xyz, use" or "to do xyz, use abc"
324 /// * may contain a name of a function, variable, or type, but not whole expressions
326 /// See `CodeSuggestion` for more information.
327 pub fn span_suggestion(
332 applicability: Applicability,
334 self.span_suggestion_with_style(
339 SuggestionStyle::ShowCode,
344 pub fn span_suggestion_with_style(
349 applicability: Applicability,
350 style: SuggestionStyle,
352 self.suggestions.push(CodeSuggestion {
353 substitutions: vec![Substitution {
354 parts: vec![SubstitutionPart {
366 pub fn span_suggestion_verbose(
371 applicability: Applicability,
373 self.span_suggestion_with_style(
378 SuggestionStyle::ShowAlways,
383 /// Prints out a message with multiple suggested edits of the code.
384 pub fn span_suggestions(
388 suggestions: impl Iterator<Item = String>,
389 applicability: Applicability,
391 self.suggestions.push(CodeSuggestion {
392 substitutions: suggestions.map(|snippet| Substitution {
393 parts: vec![SubstitutionPart {
399 style: SuggestionStyle::ShowCode,
405 /// Prints out a message with a suggested edit of the code. If the suggestion is presented
406 /// inline, it will only show the message and not the suggestion.
408 /// See `CodeSuggestion` for more information.
409 pub fn span_suggestion_short(
410 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
412 self.span_suggestion_with_style(
417 SuggestionStyle::HideCodeInline,
422 /// Prints out a message with for a suggestion without showing the suggested code.
424 /// This is intended to be used for suggestions that are obvious in what the changes need to
425 /// be from the message, showing the span label inline would be visually unpleasant
426 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
427 /// improve understandability.
428 pub fn span_suggestion_hidden(
429 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
431 self.span_suggestion_with_style(
436 SuggestionStyle::HideCodeAlways,
441 /// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli.
443 /// This is intended to be used for suggestions that are *very* obvious in what the changes
444 /// need to be from the message, but we still want other tools to be able to apply them.
445 pub fn tool_only_span_suggestion(
446 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
448 self.span_suggestion_with_style(
453 SuggestionStyle::CompletelyHidden,
458 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
459 self.span = sp.into();
463 pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
468 pub fn get_code(&self) -> Option<DiagnosticId> {
472 pub fn message(&self) -> String {
473 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
476 pub fn styled_message(&self) -> &Vec<(String, Style)> {
480 /// Used by a lint. Copies over all details *but* the "main
482 pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
483 self.span = from.span.clone();
484 self.code = from.code.clone();
485 self.children.extend(from.children.iter().cloned())
488 /// Convenience function for internal use, clients should use one of the
489 /// public methods above.
490 pub fn sub(&mut self,
494 render_span: Option<MultiSpan>) {
495 let sub = SubDiagnostic {
497 message: vec![(message.to_owned(), Style::NoStyle)],
501 self.children.push(sub);
504 /// Convenience function for internal use, clients should use one of the
505 /// public methods above.
506 fn sub_with_highlights(&mut self,
508 message: Vec<(String, Style)>,
510 render_span: Option<MultiSpan>) {
511 let sub = SubDiagnostic {
517 self.children.push(sub);
522 pub fn message(&self) -> String {
523 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
526 pub fn styled_message(&self) -> &Vec<(String, Style)> {