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(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(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_expected_found_extra(&mut self,
156 label: &dyn fmt::Display,
157 expected: DiagnosticStyledString,
158 found: DiagnosticStyledString,
159 expected_extra: &dyn fmt::Display,
160 found_extra: &dyn fmt::Display)
163 let mut msg: Vec<_> = vec![(format!("expected {} `", label), Style::NoStyle)];
164 msg.extend(expected.0.iter()
166 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
167 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
169 msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
170 msg.push((format!(" found {} `", label), Style::NoStyle));
171 msg.extend(found.0.iter()
173 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
174 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
176 msg.push((format!("`{}", found_extra), Style::NoStyle));
178 // For now, just attach these as notes
179 self.highlighted_note(msg);
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)]);
191 pub fn note(&mut self, msg: &str) -> &mut Self {
192 self.sub(Level::Note, msg, MultiSpan::new(), None);
196 pub fn highlighted_note(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
197 self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
201 /// Prints the span with a note above it.
202 pub fn span_note<S: Into<MultiSpan>>(&mut self,
206 self.sub(Level::Note, msg, sp.into(), None);
210 pub fn warn(&mut self, msg: &str) -> &mut Self {
211 self.sub(Level::Warning, msg, MultiSpan::new(), None);
215 /// Prints the span with a warn above it.
216 pub fn span_warn<S: Into<MultiSpan>>(&mut self,
220 self.sub(Level::Warning, msg, sp.into(), None);
224 pub fn help(&mut self , msg: &str) -> &mut Self {
225 self.sub(Level::Help, msg, MultiSpan::new(), None);
229 /// Prints the span with some help above it.
230 pub fn span_help<S: Into<MultiSpan>>(&mut self,
234 self.sub(Level::Help, msg, sp.into(), None);
238 pub fn multipart_suggestion(
241 suggestion: Vec<(Span, String)>,
242 applicability: Applicability,
244 self.suggestions.push(CodeSuggestion {
245 substitutions: vec![Substitution {
248 .map(|(span, snippet)| SubstitutionPart { snippet, span })
252 style: SuggestionStyle::ShowCode,
258 /// Prints out a message with for a multipart suggestion without showing the suggested code.
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(
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::CompletelyHidden,
284 /// Prints out a message with a suggested edit of the code.
286 /// In case of short messages and a simple suggestion, rustc displays it as a label:
289 /// try adding parentheses: `(tup.0).1`
294 /// * should not end in any punctuation (a `:` is added automatically)
295 /// * should not be a question (avoid language like "did you mean")
296 /// * should not contain any phrases like "the following", "as shown", etc.
297 /// * may look like "to do xyz, use" or "to do xyz, use abc"
298 /// * may contain a name of a function, variable, or type, but not whole expressions
300 /// See `CodeSuggestion` for more information.
301 pub fn span_suggestion(&mut self, sp: Span, msg: &str,
303 applicability: Applicability) -> &mut Self {
304 self.suggestions.push(CodeSuggestion {
305 substitutions: vec![Substitution {
306 parts: vec![SubstitutionPart {
312 style: SuggestionStyle::ShowCode,
318 /// Prints out a message with multiple suggested edits of the code.
319 pub fn span_suggestions(&mut self, sp: Span, msg: &str,
320 suggestions: impl Iterator<Item = String>, applicability: Applicability) -> &mut Self
322 self.suggestions.push(CodeSuggestion {
323 substitutions: suggestions.map(|snippet| Substitution {
324 parts: vec![SubstitutionPart {
330 style: SuggestionStyle::ShowCode,
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.
339 /// See `CodeSuggestion` for more information.
340 pub fn span_suggestion_short(
341 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
343 self.suggestions.push(CodeSuggestion {
344 substitutions: vec![Substitution {
345 parts: vec![SubstitutionPart {
351 style: SuggestionStyle::HideCodeInline,
357 /// Prints out a message with for a suggestion without showing the suggested code.
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
366 self.suggestions.push(CodeSuggestion {
367 substitutions: vec![Substitution {
368 parts: vec![SubstitutionPart {
374 style: SuggestionStyle::HideCodeAlways,
380 /// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli.
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(
385 &mut self, sp: Span, msg: &str, suggestion: String, applicability: Applicability
387 self.suggestions.push(CodeSuggestion {
388 substitutions: vec![Substitution {
389 parts: vec![SubstitutionPart {
395 style: SuggestionStyle::CompletelyHidden,
401 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
402 self.span = sp.into();
406 pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
411 pub fn get_code(&self) -> Option<DiagnosticId> {
415 pub fn message(&self) -> String {
416 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
419 pub fn styled_message(&self) -> &Vec<(String, Style)> {
423 /// Used by a lint. Copies over all details *but* the "main
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())
431 /// Convenience function for internal use, clients should use one of the
432 /// public methods above.
433 pub fn sub(&mut self,
437 render_span: Option<MultiSpan>) {
438 let sub = SubDiagnostic {
440 message: vec![(message.to_owned(), Style::NoStyle)],
444 self.children.push(sub);
447 /// Convenience function for internal use, clients should use one of the
448 /// public methods above.
449 fn sub_with_highlights(&mut self,
451 message: Vec<(String, Style)>,
453 render_span: Option<MultiSpan>) {
454 let sub = SubDiagnostic {
460 self.children.push(sub);
465 pub fn message(&self) -> String {
466 self.message.iter().map(|i| i.0.as_str()).collect::<String>()
469 pub fn styled_message(&self) -> &Vec<(String, Style)> {