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, DUMMY_SP};
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>,
21 /// This is not used for highlighting or rendering any error message. Rather, it can be used
22 /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
23 /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
27 #[derive(Clone, Debug, PartialEq, Eq, Hash, RustcEncodable, RustcDecodable)]
28 pub enum DiagnosticId {
33 /// For example a note attached to an error.
34 #[derive(Clone, Debug, PartialEq, Hash, RustcEncodable, RustcDecodable)]
35 pub struct SubDiagnostic {
37 pub message: Vec<(String, Style)>,
39 pub render_span: Option<MultiSpan>,
42 #[derive(Debug, PartialEq, Eq)]
43 pub struct DiagnosticStyledString(pub Vec<StringPart>);
45 impl DiagnosticStyledString {
46 pub fn new() -> DiagnosticStyledString {
47 DiagnosticStyledString(vec![])
49 pub fn push_normal<S: Into<String>>(&mut self, t: S) {
50 self.0.push(StringPart::Normal(t.into()));
52 pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
53 self.0.push(StringPart::Highlighted(t.into()));
55 pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
56 DiagnosticStyledString(vec![StringPart::Normal(t.into())])
59 pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
60 DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
63 pub fn content(&self) -> String {
64 self.0.iter().map(|x| x.content()).collect::<String>()
68 #[derive(Debug, PartialEq, Eq)]
75 pub fn content(&self) -> &str {
77 &StringPart::Normal(ref s) | & StringPart::Highlighted(ref s) => s
83 pub fn new(level: Level, message: &str) -> Self {
84 Diagnostic::new_with_code(level, None, message)
87 pub fn new_with_code(level: Level, code: Option<DiagnosticId>, message: &str) -> Self {
90 message: vec![(message.to_owned(), Style::NoStyle)],
92 span: MultiSpan::new(),
99 pub fn is_error(&self) -> bool {
104 Level::FailureNote => {
111 Level::Cancelled => {
117 /// Cancel the diagnostic (a structured diagnostic must either be emitted or
118 /// canceled or it will panic when dropped).
119 pub fn cancel(&mut self) {
120 self.level = Level::Cancelled;
123 pub fn cancelled(&self) -> bool {
124 self.level == Level::Cancelled
127 /// Set the sorting span.
128 pub fn set_sort_span(&mut self, sp: Span) {
132 /// Adds a span/label to be included in the resulting snippet.
133 /// This label will be shown together with the original span/label used when creating the
134 /// diagnostic, *not* a span added by one of the `span_*` methods.
136 /// This is pushed onto the `MultiSpan` that was created when the
137 /// diagnostic was first built. If you don't call this function at
138 /// all, and you just supplied a `Span` to create the diagnostic,
139 /// then the snippet will just include that `Span`, which is
140 /// called the primary span.
141 pub fn span_label<T: Into<String>>(&mut self, span: Span, label: T) -> &mut Self {
142 self.span.push_span_label(span, label.into());
146 pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
147 let before = self.span.clone();
148 self.set_span(after);
149 for span_label in before.span_labels() {
150 if let Some(label) = span_label.label {
151 self.span_label(after, label);
157 pub fn note_expected_found(&mut self,
158 label: &dyn fmt::Display,
159 expected: DiagnosticStyledString,
160 found: DiagnosticStyledString)
163 self.note_expected_found_extra(label, expected, found, &"", &"")
166 pub fn note_unsuccessfull_coercion(&mut self,
167 expected: DiagnosticStyledString,
168 found: DiagnosticStyledString)
171 let mut msg: Vec<_> =
172 vec![(format!("required when trying to coerce from type `"),
174 msg.extend(expected.0.iter()
176 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
177 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
179 msg.push((format!("` to type '"), Style::NoStyle));
180 msg.extend(found.0.iter()
182 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
183 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
185 msg.push((format!("`"), Style::NoStyle));
187 // For now, just attach these as notes
188 self.highlighted_note(msg);
192 pub fn note_expected_found_extra(&mut self,
193 label: &dyn fmt::Display,
194 expected: DiagnosticStyledString,
195 found: DiagnosticStyledString,
196 expected_extra: &dyn fmt::Display,
197 found_extra: &dyn fmt::Display)
200 let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
201 msg.extend(expected.0.iter()
203 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
204 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
206 msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
207 msg.push((format!(" found {} `", label), Style::NoStyle));
208 msg.extend(found.0.iter()
210 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
211 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
213 msg.push((format!("`{}", found_extra), Style::NoStyle));
215 // For now, just attach these as notes
216 self.highlighted_note(msg);
220 pub fn note_trait_signature(&mut self, name: String, signature: String) -> &mut Self {
221 self.highlighted_note(vec![
222 (format!("`{}` from trait: `", name), Style::NoStyle),
223 (signature, Style::Highlight),
224 ("`".to_string(), Style::NoStyle)]);
228 pub fn note(&mut self, msg: &str) -> &mut Self {
229 self.sub(Level::Note, msg, MultiSpan::new(), None);
233 pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
234 self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
238 /// Prints the span with a note above it.
239 pub fn span_note<S: Into<MultiSpan>>(&mut self,
243 self.sub(Level::Note, msg, sp.into(), None);
247 pub fn warn(&mut self, msg: &str) -> &mut Self {
248 self.sub(Level::Warning, msg, MultiSpan::new(), None);
252 /// Prints the span with a warn above it.
253 pub fn span_warn<S: Into<MultiSpan>>(&mut self,
257 self.sub(Level::Warning, msg, sp.into(), None);
261 pub fn help(&mut self , msg: &str) -> &mut Self {
262 self.sub(Level::Help, msg, MultiSpan::new(), None);
266 /// Prints the span with some help above it.
267 pub fn span_help<S: Into<MultiSpan>>(&mut self,
271 self.sub(Level::Help, msg, sp.into(), None);
275 pub fn multipart_suggestion(
278 suggestion: Vec<(Span, String)>,
279 applicability: Applicability,
281 self.suggestions.push(CodeSuggestion {
282 substitutions: vec![Substitution {
285 .map(|(span, snippet)| SubstitutionPart { snippet, span })
289 style: SuggestionStyle::ShowCode,
295 /// Prints out a message with for a multipart suggestion without showing the suggested code.
297 /// This is intended to be used for suggestions that are obvious in what the changes need to
298 /// be from the message, showing the span label inline would be visually unpleasant
299 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
300 /// improve understandability.
301 pub fn tool_only_multipart_suggestion(
304 suggestion: Vec<(Span, String)>,
305 applicability: Applicability,
307 self.suggestions.push(CodeSuggestion {
308 substitutions: vec![Substitution {
311 .map(|(span, snippet)| SubstitutionPart { snippet, span })
315 style: SuggestionStyle::CompletelyHidden,
321 /// Prints out a message with a suggested edit of the code.
323 /// In case of short messages and a simple suggestion, rustc displays it as a label:
326 /// try adding parentheses: `(tup.0).1`
331 /// * should not end in any punctuation (a `:` is added automatically)
332 /// * should not be a question (avoid language like "did you mean")
333 /// * should not contain any phrases like "the following", "as shown", etc.
334 /// * may look like "to do xyz, use" or "to do xyz, use abc"
335 /// * may contain a name of a function, variable, or type, but not whole expressions
337 /// See `CodeSuggestion` for more information.
338 pub fn span_suggestion(
343 applicability: Applicability,
345 self.span_suggestion_with_style(
350 SuggestionStyle::ShowCode,
355 pub fn span_suggestion_with_style(
360 applicability: Applicability,
361 style: SuggestionStyle,
363 self.suggestions.push(CodeSuggestion {
364 substitutions: vec![Substitution {
365 parts: vec![SubstitutionPart {
377 pub fn span_suggestion_verbose(
382 applicability: Applicability,
384 self.span_suggestion_with_style(
389 SuggestionStyle::ShowAlways,
394 /// Prints out a message with multiple suggested edits of the code.
395 pub fn span_suggestions(
399 suggestions: impl Iterator<Item = String>,
400 applicability: Applicability,
402 self.suggestions.push(CodeSuggestion {
403 substitutions: suggestions.map(|snippet| Substitution {
404 parts: vec![SubstitutionPart {
410 style: SuggestionStyle::ShowCode,
416 /// Prints out a message with a suggested edit of the code. If the suggestion is presented
417 /// inline, it will only show the message and not the suggestion.
419 /// See `CodeSuggestion` for more information.
420 pub fn span_suggestion_short(
421 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
423 self.span_suggestion_with_style(
428 SuggestionStyle::HideCodeInline,
433 /// Prints out a message with for a suggestion without showing the suggested code.
435 /// This is intended to be used for suggestions that are obvious in what the changes need to
436 /// be from the message, showing the span label inline would be visually unpleasant
437 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
438 /// improve understandability.
439 pub fn span_suggestion_hidden(
440 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
442 self.span_suggestion_with_style(
447 SuggestionStyle::HideCodeAlways,
452 /// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli.
454 /// This is intended to be used for suggestions that are *very* obvious in what the changes
455 /// need to be from the message, but we still want other tools to be able to apply them.
456 pub fn tool_only_span_suggestion(
457 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
459 self.span_suggestion_with_style(
464 SuggestionStyle::CompletelyHidden,
469 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
470 self.span = sp.into();
471 if let Some(span) = self.span.primary_span() {
472 self.sort_span = span;
477 pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
482 pub fn get_code(&self) -> Option<DiagnosticId> {
486 pub fn message(&self) -> String {
487 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
490 pub fn styled_message(&self) -> &Vec<(String, Style)> {
494 /// Used by a lint. Copies over all details *but* the "main
496 pub fn copy_details_not_message(&mut self, from: &Diagnostic) {
497 self.span = from.span.clone();
498 self.code = from.code.clone();
499 self.children.extend(from.children.iter().cloned())
502 /// Convenience function for internal use, clients should use one of the
503 /// public methods above.
504 pub fn sub(&mut self,
508 render_span: Option<MultiSpan>) {
509 let sub = SubDiagnostic {
511 message: vec![(message.to_owned(), Style::NoStyle)],
515 self.children.push(sub);
518 /// Convenience function for internal use, clients should use one of the
519 /// public methods above.
520 fn sub_with_highlights(&mut self,
522 message: Vec<(String, Style)>,
524 render_span: Option<MultiSpan>) {
525 let sub = SubDiagnostic {
531 self.children.push(sub);
536 pub fn message(&self) -> String {
537 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
540 pub fn styled_message(&self) -> &Vec<(String, Style)> {