1 use crate::snippet::Style;
3 CodeSuggestion, DiagnosticBuilder, DiagnosticMessage, EmissionGuarantee, Level, MultiSpan,
4 SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle,
6 use rustc_data_structures::fx::FxHashMap;
7 use rustc_error_messages::fluent_value_from_str_list_sep_by_and;
8 use rustc_error_messages::FluentValue;
9 use rustc_lint_defs::{Applicability, LintExpectationId};
10 use rustc_span::edition::LATEST_STABLE_EDITION;
11 use rustc_span::symbol::Symbol;
12 use rustc_span::{Span, DUMMY_SP};
15 use std::hash::{Hash, Hasher};
16 use std::panic::Location;
18 /// Error type for `Diagnostic`'s `suggestions` field, indicating that
19 /// `.disable_suggestions()` was called on the `Diagnostic`.
20 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
21 pub struct SuggestionsDisabled;
23 /// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of
24 /// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of
25 /// diagnostic emission.
26 pub type DiagnosticArg<'iter, 'source> =
27 (&'iter DiagnosticArgName<'source>, &'iter DiagnosticArgValue<'source>);
29 /// Name of a diagnostic argument.
30 pub type DiagnosticArgName<'source> = Cow<'source, str>;
32 /// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted
33 /// to a `FluentValue` by the emitter to be used in diagnostic translation.
34 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
35 pub enum DiagnosticArgValue<'source> {
36 Str(Cow<'source, str>),
38 StrListSepByAnd(Vec<Cow<'source, str>>),
41 /// Converts a value of a type into a `DiagnosticArg` (typically a field of an `IntoDiagnostic`
42 /// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type
43 /// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*`
44 /// crates to implement this.
45 pub trait IntoDiagnosticArg {
46 fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>;
49 impl<'source> IntoDiagnosticArg for DiagnosticArgValue<'source> {
50 fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> {
52 DiagnosticArgValue::Str(s) => DiagnosticArgValue::Str(Cow::Owned(s.into_owned())),
53 DiagnosticArgValue::Number(n) => DiagnosticArgValue::Number(n),
58 impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> {
59 fn into(self) -> FluentValue<'source> {
61 DiagnosticArgValue::Str(s) => From::from(s),
62 DiagnosticArgValue::Number(n) => From::from(n),
63 DiagnosticArgValue::StrListSepByAnd(l) => fluent_value_from_str_list_sep_by_and(l),
68 /// Trait implemented by error types. This should not be implemented manually. Instead, use
69 /// `#[derive(Subdiagnostic)]` -- see [rustc_macros::Subdiagnostic].
70 #[rustc_diagnostic_item = "AddToDiagnostic"]
71 pub trait AddToDiagnostic
75 /// Add a subdiagnostic to an existing diagnostic.
76 fn add_to_diagnostic(self, diag: &mut Diagnostic) {
77 self.add_to_diagnostic_with(diag, |_, m| m);
80 /// Add a subdiagnostic to an existing diagnostic where `f` is invoked on every message used
81 /// (to optionally perform eager translation).
82 fn add_to_diagnostic_with<F>(self, diag: &mut Diagnostic, f: F)
84 F: Fn(&mut Diagnostic, SubdiagnosticMessage) -> SubdiagnosticMessage;
87 /// Trait implemented by lint types. This should not be implemented manually. Instead, use
88 /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic].
89 #[rustc_diagnostic_item = "DecorateLint"]
90 pub trait DecorateLint<'a, G: EmissionGuarantee> {
91 /// Decorate and emit a lint.
94 diag: &'b mut DiagnosticBuilder<'a, G>,
95 ) -> &'b mut DiagnosticBuilder<'a, G>;
97 fn msg(&self) -> DiagnosticMessage;
101 #[derive(Clone, Debug, Encodable, Decodable)]
102 pub struct Diagnostic {
103 // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes,
104 // outside of what methods in this crate themselves allow.
105 pub(crate) level: Level,
107 pub message: Vec<(DiagnosticMessage, Style)>,
108 pub code: Option<DiagnosticId>,
110 pub children: Vec<SubDiagnostic>,
111 pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
112 args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
114 /// This is not used for highlighting or rendering any error message. Rather, it can be used
115 /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of
116 /// `span` if there is one. Otherwise, it is `DUMMY_SP`.
119 /// If diagnostic is from Lint, custom hash function ignores notes
120 /// otherwise hash is based on the all the fields
123 /// With `-Ztrack_diagnostics` enabled,
124 /// we print where in rustc this error was emitted.
125 pub emitted_at: DiagnosticLocation,
128 #[derive(Clone, Debug, Encodable, Decodable)]
129 pub struct DiagnosticLocation {
130 file: Cow<'static, str>,
135 impl DiagnosticLocation {
137 fn caller() -> Self {
138 let loc = Location::caller();
139 DiagnosticLocation { file: loc.file().into(), line: loc.line(), col: loc.column() }
143 impl fmt::Display for DiagnosticLocation {
144 fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
145 write!(f, "{}:{}:{}", self.file, self.line, self.col)
149 #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)]
150 pub enum DiagnosticId {
152 Lint { name: String, has_future_breakage: bool, is_force_warn: bool },
155 /// A "sub"-diagnostic attached to a parent diagnostic.
156 /// For example, a note attached to an error.
157 #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)]
158 pub struct SubDiagnostic {
160 pub message: Vec<(DiagnosticMessage, Style)>,
162 pub render_span: Option<MultiSpan>,
165 #[derive(Debug, PartialEq, Eq)]
166 pub struct DiagnosticStyledString(pub Vec<StringPart>);
168 impl DiagnosticStyledString {
169 pub fn new() -> DiagnosticStyledString {
170 DiagnosticStyledString(vec![])
172 pub fn push_normal<S: Into<String>>(&mut self, t: S) {
173 self.0.push(StringPart::Normal(t.into()));
175 pub fn push_highlighted<S: Into<String>>(&mut self, t: S) {
176 self.0.push(StringPart::Highlighted(t.into()));
178 pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) {
180 self.push_highlighted(t);
185 pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString {
186 DiagnosticStyledString(vec![StringPart::Normal(t.into())])
189 pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString {
190 DiagnosticStyledString(vec![StringPart::Highlighted(t.into())])
193 pub fn content(&self) -> String {
194 self.0.iter().map(|x| x.content()).collect::<String>()
198 #[derive(Debug, PartialEq, Eq)]
199 pub enum StringPart {
205 pub fn content(&self) -> &str {
207 &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s,
214 pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self {
215 Diagnostic::new_with_code(level, None, message)
219 pub fn new_with_messages(level: Level, messages: Vec<(DiagnosticMessage, Style)>) -> Self {
224 span: MultiSpan::new(),
226 suggestions: Ok(vec![]),
227 args: Default::default(),
230 emitted_at: DiagnosticLocation::caller(),
235 pub fn new_with_code<M: Into<DiagnosticMessage>>(
237 code: Option<DiagnosticId>,
242 message: vec![(message.into(), Style::NoStyle)],
244 span: MultiSpan::new(),
246 suggestions: Ok(vec![]),
247 args: Default::default(),
250 emitted_at: DiagnosticLocation::caller(),
255 pub fn level(&self) -> Level {
259 pub fn is_error(&self) -> bool {
264 | Level::Error { .. }
265 | Level::FailureNote => true,
272 | Level::Expect(_) => false,
276 pub fn update_unstable_expectation_id(
278 unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>,
280 if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) =
283 if expectation_id.is_stable() {
287 // The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index.
288 // The lint index inside the attribute is manually transferred here.
289 let lint_index = expectation_id.get_lint_index();
290 expectation_id.set_lint_index(None);
291 let mut stable_id = unstable_to_stable
292 .get(&expectation_id)
293 .expect("each unstable `LintExpectationId` must have a matching stable id")
296 stable_id.set_lint_index(lint_index);
297 *expectation_id = stable_id;
301 pub fn has_future_breakage(&self) -> bool {
303 Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage,
308 pub fn is_force_warn(&self) -> bool {
310 Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn,
315 /// Delay emission of this diagnostic as a bug.
317 /// This can be useful in contexts where an error indicates a bug but
318 /// typically this only happens when other compilation errors have already
319 /// happened. In those cases this can be used to defer emission of this
320 /// diagnostic as a bug in the compiler only if no other errors have been
323 /// In the meantime, though, callsites are required to deal with the "bug"
324 /// locally in whichever way makes the most sense.
326 pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self {
329 "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error",
332 self.level = Level::DelayedBug;
337 /// Adds a span/label to be included in the resulting snippet.
339 /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic
340 /// was first built. That means it will be shown together with the original
341 /// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods.
343 /// This span is *not* considered a ["primary span"][`MultiSpan`]; only
344 /// the `Span` supplied when creating the diagnostic is primary.
345 #[rustc_lint_diagnostics]
346 pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self {
347 self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label));
351 /// Labels all the given spans with the provided label.
352 /// See [`Self::span_label()`] for more information.
355 spans: impl IntoIterator<Item = Span>,
356 label: impl AsRef<str>,
358 let label = label.as_ref();
360 self.span_label(span, label);
365 pub fn replace_span_with(&mut self, after: Span) -> &mut Self {
366 let before = self.span.clone();
367 self.set_span(after);
368 for span_label in before.span_labels() {
369 if let Some(label) = span_label.label {
370 self.span.push_span_label(after, label);
376 pub fn note_expected_found(
378 expected_label: &dyn fmt::Display,
379 expected: DiagnosticStyledString,
380 found_label: &dyn fmt::Display,
381 found: DiagnosticStyledString,
383 self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"")
386 pub fn note_unsuccessful_coercion(
388 expected: DiagnosticStyledString,
389 found: DiagnosticStyledString,
391 let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)];
392 msg.extend(expected.0.iter().map(|x| match *x {
393 StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
394 StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
396 msg.push(("` to type '", Style::NoStyle));
397 msg.extend(found.0.iter().map(|x| match *x {
398 StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle),
399 StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight),
401 msg.push(("`", Style::NoStyle));
403 // For now, just attach these as notes
404 self.highlighted_note(msg);
408 pub fn note_expected_found_extra(
410 expected_label: &dyn fmt::Display,
411 expected: DiagnosticStyledString,
412 found_label: &dyn fmt::Display,
413 found: DiagnosticStyledString,
414 expected_extra: &dyn fmt::Display,
415 found_extra: &dyn fmt::Display,
417 let expected_label = expected_label.to_string();
418 let expected_label = if expected_label.is_empty() {
419 "expected".to_string()
421 format!("expected {}", expected_label)
423 let found_label = found_label.to_string();
424 let found_label = if found_label.is_empty() {
427 format!("found {}", found_label)
429 let (found_padding, expected_padding) = if expected_label.len() > found_label.len() {
430 (expected_label.len() - found_label.len(), 0)
432 (0, found_label.len() - expected_label.len())
434 let mut msg: Vec<_> =
435 vec![(format!("{}{} `", " ".repeat(expected_padding), expected_label), Style::NoStyle)];
436 msg.extend(expected.0.iter().map(|x| match *x {
437 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
438 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
440 msg.push((format!("`{}\n", expected_extra), Style::NoStyle));
441 msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle));
442 msg.extend(found.0.iter().map(|x| match *x {
443 StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle),
444 StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight),
446 msg.push((format!("`{}", found_extra), Style::NoStyle));
448 // For now, just attach these as notes.
449 self.highlighted_note(msg);
453 pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self {
454 self.highlighted_note(vec![
455 (format!("`{}` from trait: `", name), Style::NoStyle),
456 (signature, Style::Highlight),
457 ("`".to_string(), Style::NoStyle),
462 /// Add a note attached to this diagnostic.
463 #[rustc_lint_diagnostics]
464 pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
465 self.sub(Level::Note, msg, MultiSpan::new(), None);
469 pub fn highlighted_note<M: Into<SubdiagnosticMessage>>(
471 msg: Vec<(M, Style)>,
473 self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None);
477 /// Prints the span with a note above it.
478 /// This is like [`Diagnostic::note()`], but it gets its own span.
479 pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
480 self.sub(Level::OnceNote, msg, MultiSpan::new(), None);
484 /// Prints the span with a note above it.
485 /// This is like [`Diagnostic::note()`], but it gets its own span.
486 #[rustc_lint_diagnostics]
487 pub fn span_note<S: Into<MultiSpan>>(
490 msg: impl Into<SubdiagnosticMessage>,
492 self.sub(Level::Note, msg, sp.into(), None);
496 /// Prints the span with a note above it.
497 /// This is like [`Diagnostic::note()`], but it gets its own span.
498 pub fn span_note_once<S: Into<MultiSpan>>(
501 msg: impl Into<SubdiagnosticMessage>,
503 self.sub(Level::OnceNote, msg, sp.into(), None);
507 /// Add a warning attached to this diagnostic.
508 #[rustc_lint_diagnostics]
509 pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
510 self.sub(Level::Warning(None), msg, MultiSpan::new(), None);
514 /// Prints the span with a warning above it.
515 /// This is like [`Diagnostic::warn()`], but it gets its own span.
516 #[rustc_lint_diagnostics]
517 pub fn span_warn<S: Into<MultiSpan>>(
520 msg: impl Into<SubdiagnosticMessage>,
522 self.sub(Level::Warning(None), msg, sp.into(), None);
526 /// Add a help message attached to this diagnostic.
527 #[rustc_lint_diagnostics]
528 pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self {
529 self.sub(Level::Help, msg, MultiSpan::new(), None);
533 /// Add a help message attached to this diagnostic with a customizable highlighted message.
534 pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self {
535 self.sub_with_highlights(Level::Help, msg, MultiSpan::new(), None);
539 /// Prints the span with some help above it.
540 /// This is like [`Diagnostic::help()`], but it gets its own span.
541 #[rustc_lint_diagnostics]
542 pub fn span_help<S: Into<MultiSpan>>(
545 msg: impl Into<SubdiagnosticMessage>,
547 self.sub(Level::Help, msg, sp.into(), None);
551 /// Help the user upgrade to the latest edition.
552 /// This is factored out to make sure it does the right thing with `Cargo.toml`.
553 pub fn help_use_latest_edition(&mut self) -> &mut Self {
554 if std::env::var_os("CARGO").is_some() {
555 self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION));
557 self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION));
559 self.note("for more on editions, read https://doc.rust-lang.org/edition-guide");
563 /// Disallow attaching suggestions this diagnostic.
564 /// Any suggestions attached e.g. with the `span_suggestion_*` methods
565 /// (before and after the call to `disable_suggestions`) will be ignored.
566 pub fn disable_suggestions(&mut self) -> &mut Self {
567 self.suggestions = Err(SuggestionsDisabled);
571 /// Clear any existing suggestions.
572 pub fn clear_suggestions(&mut self) -> &mut Self {
573 if let Ok(suggestions) = &mut self.suggestions {
579 /// Helper for pushing to `self.suggestions`, if available (not disable).
580 fn push_suggestion(&mut self, suggestion: CodeSuggestion) {
581 if let Ok(suggestions) = &mut self.suggestions {
582 suggestions.push(suggestion);
586 /// Show a suggestion that has multiple parts to it.
587 /// In other words, multiple changes need to be applied as part of this suggestion.
588 pub fn multipart_suggestion(
590 msg: impl Into<SubdiagnosticMessage>,
591 suggestion: Vec<(Span, String)>,
592 applicability: Applicability,
594 self.multipart_suggestion_with_style(
598 SuggestionStyle::ShowCode,
602 /// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic.
603 /// In other words, multiple changes need to be applied as part of this suggestion.
604 pub fn multipart_suggestion_verbose(
606 msg: impl Into<SubdiagnosticMessage>,
607 suggestion: Vec<(Span, String)>,
608 applicability: Applicability,
610 self.multipart_suggestion_with_style(
614 SuggestionStyle::ShowAlways,
617 /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`].
618 pub fn multipart_suggestion_with_style(
620 msg: impl Into<SubdiagnosticMessage>,
621 suggestion: Vec<(Span, String)>,
622 applicability: Applicability,
623 style: SuggestionStyle,
625 assert!(!suggestion.is_empty());
627 !(suggestion.iter().any(|(sp, text)| sp.is_empty() && text.is_empty())),
628 "Span must not be empty and have no suggestion"
631 self.push_suggestion(CodeSuggestion {
632 substitutions: vec![Substitution {
635 .map(|(span, snippet)| SubstitutionPart { snippet, span })
638 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
645 /// Prints out a message with for a multipart suggestion without showing the suggested code.
647 /// This is intended to be used for suggestions that are obvious in what the changes need to
648 /// be from the message, showing the span label inline would be visually unpleasant
649 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
650 /// improve understandability.
651 pub fn tool_only_multipart_suggestion(
653 msg: impl Into<SubdiagnosticMessage>,
654 suggestion: Vec<(Span, String)>,
655 applicability: Applicability,
657 self.multipart_suggestion_with_style(
661 SuggestionStyle::CompletelyHidden,
665 /// Prints out a message with a suggested edit of the code.
667 /// In case of short messages and a simple suggestion, rustc displays it as a label:
670 /// try adding parentheses: `(tup.0).1`
675 /// * should not end in any punctuation (a `:` is added automatically)
676 /// * should not be a question (avoid language like "did you mean")
677 /// * should not contain any phrases like "the following", "as shown", etc.
678 /// * may look like "to do xyz, use" or "to do xyz, use abc"
679 /// * may contain a name of a function, variable, or type, but not whole expressions
681 /// See `CodeSuggestion` for more information.
682 pub fn span_suggestion(
685 msg: impl Into<SubdiagnosticMessage>,
686 suggestion: impl ToString,
687 applicability: Applicability,
689 self.span_suggestion_with_style(
694 SuggestionStyle::ShowCode,
699 /// [`Diagnostic::span_suggestion()`] but you can set the [`SuggestionStyle`].
700 pub fn span_suggestion_with_style(
703 msg: impl Into<SubdiagnosticMessage>,
704 suggestion: impl ToString,
705 applicability: Applicability,
706 style: SuggestionStyle,
709 !(sp.is_empty() && suggestion.to_string().is_empty()),
710 "Span must not be empty and have no suggestion"
712 self.push_suggestion(CodeSuggestion {
713 substitutions: vec![Substitution {
714 parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }],
716 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
723 /// Always show the suggested change.
724 pub fn span_suggestion_verbose(
727 msg: impl Into<SubdiagnosticMessage>,
728 suggestion: impl ToString,
729 applicability: Applicability,
731 self.span_suggestion_with_style(
736 SuggestionStyle::ShowAlways,
741 /// Prints out a message with multiple suggested edits of the code.
742 /// See also [`Diagnostic::span_suggestion()`].
743 pub fn span_suggestions(
746 msg: impl Into<SubdiagnosticMessage>,
747 suggestions: impl IntoIterator<Item = String>,
748 applicability: Applicability,
750 self.span_suggestions_with_style(
755 SuggestionStyle::ShowCode,
759 /// [`Diagnostic::span_suggestions()`] but you can set the [`SuggestionStyle`].
760 pub fn span_suggestions_with_style(
763 msg: impl Into<SubdiagnosticMessage>,
764 suggestions: impl IntoIterator<Item = String>,
765 applicability: Applicability,
766 style: SuggestionStyle,
768 let mut suggestions: Vec<_> = suggestions.into_iter().collect();
772 !(sp.is_empty() && suggestions.iter().any(|suggestion| suggestion.is_empty())),
773 "Span must not be empty and have no suggestion"
776 let substitutions = suggestions
778 .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] })
780 self.push_suggestion(CodeSuggestion {
782 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
789 /// Prints out a message with multiple suggested edits of the code, where each edit consists of
791 /// See also [`Diagnostic::multipart_suggestion()`].
792 pub fn multipart_suggestions(
794 msg: impl Into<SubdiagnosticMessage>,
795 suggestions: impl IntoIterator<Item = Vec<(Span, String)>>,
796 applicability: Applicability,
798 let suggestions: Vec<_> = suggestions.into_iter().collect();
802 .flat_map(|suggs| suggs)
803 .any(|(sp, suggestion)| sp.is_empty() && suggestion.is_empty())),
804 "Span must not be empty and have no suggestion"
807 self.push_suggestion(CodeSuggestion {
808 substitutions: suggestions
810 .map(|sugg| Substitution {
813 .map(|(span, snippet)| SubstitutionPart { snippet, span })
817 msg: self.subdiagnostic_message_to_diagnostic_message(msg),
818 style: SuggestionStyle::ShowCode,
824 /// Prints out a message with a suggested edit of the code. If the suggestion is presented
825 /// inline, it will only show the message and not the suggestion.
827 /// See `CodeSuggestion` for more information.
828 pub fn span_suggestion_short(
831 msg: impl Into<SubdiagnosticMessage>,
832 suggestion: impl ToString,
833 applicability: Applicability,
835 self.span_suggestion_with_style(
840 SuggestionStyle::HideCodeInline,
845 /// Prints out a message for a suggestion without showing the suggested code.
847 /// This is intended to be used for suggestions that are obvious in what the changes need to
848 /// be from the message, showing the span label inline would be visually unpleasant
849 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
850 /// improve understandability.
851 pub fn span_suggestion_hidden(
854 msg: impl Into<SubdiagnosticMessage>,
855 suggestion: impl ToString,
856 applicability: Applicability,
858 self.span_suggestion_with_style(
863 SuggestionStyle::HideCodeAlways,
868 /// Adds a suggestion to the JSON output that will not be shown in the CLI.
870 /// This is intended to be used for suggestions that are *very* obvious in what the changes
871 /// need to be from the message, but we still want other tools to be able to apply them.
872 pub fn tool_only_span_suggestion(
875 msg: impl Into<SubdiagnosticMessage>,
876 suggestion: impl ToString,
877 applicability: Applicability,
879 self.span_suggestion_with_style(
884 SuggestionStyle::CompletelyHidden,
889 /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
890 /// [rustc_macros::Subdiagnostic]).
891 pub fn subdiagnostic(&mut self, subdiagnostic: impl AddToDiagnostic) -> &mut Self {
892 subdiagnostic.add_to_diagnostic(self);
896 /// Add a subdiagnostic from a type that implements `Subdiagnostic` (see
897 /// [rustc_macros::Subdiagnostic]). Performs eager translation of any translatable messages
898 /// used in the subdiagnostic, so suitable for use with repeated messages (i.e. re-use of
899 /// interpolated variables).
900 pub fn eager_subdiagnostic(
902 handler: &crate::Handler,
903 subdiagnostic: impl AddToDiagnostic,
905 subdiagnostic.add_to_diagnostic_with(self, |diag, msg| {
906 let args = diag.args();
907 let msg = diag.subdiagnostic_message_to_diagnostic_message(msg);
908 handler.eagerly_translate(msg, args)
913 pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self {
914 self.span = sp.into();
915 if let Some(span) = self.span.primary_span() {
916 self.sort_span = span;
921 pub fn set_is_lint(&mut self) -> &mut Self {
926 pub fn code(&mut self, s: DiagnosticId) -> &mut Self {
931 pub fn clear_code(&mut self) -> &mut Self {
936 pub fn get_code(&self) -> Option<DiagnosticId> {
940 pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self {
941 self.message[0] = (msg.into(), Style::NoStyle);
945 // Exact iteration order of diagnostic arguments shouldn't make a difference to output because
946 // they're only used in interpolation.
947 #[allow(rustc::potential_query_instability)]
948 pub fn args<'a>(&'a self) -> impl Iterator<Item = DiagnosticArg<'a, 'static>> {
954 name: impl Into<Cow<'static, str>>,
955 arg: impl IntoDiagnosticArg,
957 self.args.insert(name.into(), arg.into_diagnostic_arg());
963 args: FxHashMap<DiagnosticArgName<'static>, DiagnosticArgValue<'static>>,
968 pub fn styled_message(&self) -> &[(DiagnosticMessage, Style)] {
972 /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by
973 /// combining it with the primary message of the diagnostic (if translatable, otherwise it just
974 /// passes the user's string along).
975 pub(crate) fn subdiagnostic_message_to_diagnostic_message(
977 attr: impl Into<SubdiagnosticMessage>,
978 ) -> DiagnosticMessage {
980 self.message.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages");
981 msg.with_subdiagnostic_message(attr.into())
984 /// Convenience function for internal use, clients should use one of the
985 /// public methods above.
987 /// Used by `proc_macro_server` for implementing `server::Diagnostic`.
991 message: impl Into<SubdiagnosticMessage>,
993 render_span: Option<MultiSpan>,
995 let sub = SubDiagnostic {
998 self.subdiagnostic_message_to_diagnostic_message(message),
1004 self.children.push(sub);
1007 /// Convenience function for internal use, clients should use one of the
1008 /// public methods above.
1009 fn sub_with_highlights<M: Into<SubdiagnosticMessage>>(
1012 message: Vec<(M, Style)>,
1014 render_span: Option<MultiSpan>,
1016 let message = message
1018 .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1))
1020 let sub = SubDiagnostic { level, message, span, render_span };
1021 self.children.push(sub);
1024 /// Fields used for Hash, and PartialEq trait
1029 &[(DiagnosticMessage, Style)],
1030 &Option<DiagnosticId>,
1032 &Result<Vec<CodeSuggestion>, SuggestionsDisabled>,
1033 Option<&[SubDiagnostic]>,
1041 (if self.is_lint { None } else { Some(&self.children) }),
1046 impl Hash for Diagnostic {
1047 fn hash<H>(&self, state: &mut H)
1051 self.keys().hash(state);
1055 impl PartialEq for Diagnostic {
1056 fn eq(&self, other: &Self) -> bool {
1057 self.keys() == other.keys()