1 use crate::snippet
::Style
;
2 use crate::Applicability
;
3 use crate::CodeSuggestion
;
5 use crate::Substitution
;
6 use crate::SubstitutionPart
;
7 use crate::SuggestionStyle
;
8 use rustc_span
::{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 push
<S
: Into
<String
>>(&mut self, t
: S
, highlight
: bool
) {
57 self.push_highlighted(t
);
62 pub fn normal
<S
: Into
<String
>>(t
: S
) -> DiagnosticStyledString
{
63 DiagnosticStyledString(vec
![StringPart
::Normal(t
.into())])
66 pub fn highlighted
<S
: Into
<String
>>(t
: S
) -> DiagnosticStyledString
{
67 DiagnosticStyledString(vec
![StringPart
::Highlighted(t
.into())])
70 pub fn content(&self) -> String
{
71 self.0.iter
().map(|x
| x
.content()).collect
::<String
>()
75 #[derive(Debug, PartialEq, Eq)]
82 pub fn content(&self) -> &str {
84 &StringPart
::Normal(ref s
) | &StringPart
::Highlighted(ref s
) => s
,
90 pub fn new(level
: Level
, message
: &str) -> Self {
91 Diagnostic
::new_with_code(level
, None
, message
)
94 pub fn new_with_code(level
: Level
, code
: Option
<DiagnosticId
>, message
: &str) -> Self {
97 message
: vec
![(message
.to_owned(), Style
::NoStyle
)],
99 span
: MultiSpan
::new(),
106 pub fn is_error(&self) -> bool
{
108 Level
::Bug
| Level
::Fatal
| Level
::Error
| Level
::FailureNote
=> true,
110 Level
::Warning
| Level
::Note
| Level
::Help
| Level
::Cancelled
=> false,
114 /// Cancel the diagnostic (a structured diagnostic must either be emitted or
115 /// canceled or it will panic when dropped).
116 pub fn cancel(&mut self) {
117 self.level
= Level
::Cancelled
;
120 pub fn cancelled(&self) -> bool
{
121 self.level
== Level
::Cancelled
124 /// Set the sorting span.
125 pub fn set_sort_span(&mut self, sp
: Span
) {
129 /// Adds a span/label to be included in the resulting snippet.
130 /// This label will be shown together with the original span/label used when creating the
131 /// diagnostic, *not* a span added by one of the `span_*` methods.
133 /// This is pushed onto the `MultiSpan` that was created when the
134 /// diagnostic was first built. If you don't call this function at
135 /// all, and you just supplied a `Span` to create the diagnostic,
136 /// then the snippet will just include that `Span`, which is
137 /// called the primary span.
138 pub fn span_label
<T
: Into
<String
>>(&mut self, span
: Span
, label
: T
) -> &mut Self {
139 self.span
.push_span_label(span
, label
.into());
143 pub fn replace_span_with(&mut self, after
: Span
) -> &mut Self {
144 let before
= self.span
.clone();
145 self.set_span(after
);
146 for span_label
in before
.span_labels() {
147 if let Some(label
) = span_label
.label
{
148 self.span_label(after
, label
);
154 pub fn note_expected_found(
156 expected_label
: &dyn fmt
::Display
,
157 expected
: DiagnosticStyledString
,
158 found_label
: &dyn fmt
::Display
,
159 found
: DiagnosticStyledString
,
161 self.note_expected_found_extra(expected_label
, expected
, found_label
, found
, &"", &"")
164 pub fn note_unsuccessfull_coercion(
166 expected
: DiagnosticStyledString
,
167 found
: DiagnosticStyledString
,
169 let mut msg
: Vec
<_
> =
170 vec
![("required when trying to coerce from type `".to_string(), Style
::NoStyle
)];
171 msg
.extend(expected
.0.iter
().map(|x
| match *x
{
172 StringPart
::Normal(ref s
) => (s
.to_owned(), Style
::NoStyle
),
173 StringPart
::Highlighted(ref s
) => (s
.to_owned(), Style
::Highlight
),
175 msg
.push(("` to type '".to_string(), Style
::NoStyle
));
176 msg
.extend(found
.0.iter
().map(|x
| match *x
{
177 StringPart
::Normal(ref s
) => (s
.to_owned(), Style
::NoStyle
),
178 StringPart
::Highlighted(ref s
) => (s
.to_owned(), Style
::Highlight
),
180 msg
.push(("`".to_string(), Style
::NoStyle
));
182 // For now, just attach these as notes
183 self.highlighted_note(msg
);
187 pub fn note_expected_found_extra(
189 expected_label
: &dyn fmt
::Display
,
190 expected
: DiagnosticStyledString
,
191 found_label
: &dyn fmt
::Display
,
192 found
: DiagnosticStyledString
,
193 expected_extra
: &dyn fmt
::Display
,
194 found_extra
: &dyn fmt
::Display
,
196 let expected_label
= expected_label
.to_string();
197 let expected_label
= if expected_label
.is_empty() {
198 "expected".to_string()
200 format
!("expected {}", expected_label
)
202 let found_label
= found_label
.to_string();
203 let found_label
= if found_label
.is_empty() {
206 format
!("found {}", found_label
)
208 let (found_padding
, expected_padding
) = if expected_label
.len() > found_label
.len() {
209 (expected_label
.len() - found_label
.len(), 0)
211 (0, found_label
.len() - expected_label
.len())
213 let mut msg
: Vec
<_
> =
214 vec
![(format
!("{}{} `", " ".repeat(expected_padding
), expected_label
), Style
::NoStyle
)];
215 msg
.extend(expected
.0.iter
().map(|x
| match *x
{
216 StringPart
::Normal(ref s
) => (s
.to_owned(), Style
::NoStyle
),
217 StringPart
::Highlighted(ref s
) => (s
.to_owned(), Style
::Highlight
),
219 msg
.push((format
!("`{}\n", expected_extra
), Style
::NoStyle
));
220 msg
.push((format
!("{}{} `", " ".repeat(found_padding
), found_label
), Style
::NoStyle
));
221 msg
.extend(found
.0.iter
().map(|x
| match *x
{
222 StringPart
::Normal(ref s
) => (s
.to_owned(), Style
::NoStyle
),
223 StringPart
::Highlighted(ref s
) => (s
.to_owned(), Style
::Highlight
),
225 msg
.push((format
!("`{}", found_extra
), Style
::NoStyle
));
227 // For now, just attach these as notes.
228 self.highlighted_note(msg
);
232 pub fn note_trait_signature(&mut self, name
: String
, signature
: String
) -> &mut Self {
233 self.highlighted_note(vec
![
234 (format
!("`{}` from trait: `", name
), Style
::NoStyle
),
235 (signature
, Style
::Highlight
),
236 ("`".to_string(), Style
::NoStyle
),
241 pub fn note(&mut self, msg
: &str) -> &mut Self {
242 self.sub(Level
::Note
, msg
, MultiSpan
::new(), None
);
246 pub fn highlighted_note(&mut self, msg
: Vec
<(String
, Style
)>) -> &mut Self {
247 self.sub_with_highlights(Level
::Note
, msg
, MultiSpan
::new(), None
);
251 /// Prints the span with a note above it.
252 pub fn span_note
<S
: Into
<MultiSpan
>>(&mut self, sp
: S
, msg
: &str) -> &mut Self {
253 self.sub(Level
::Note
, msg
, sp
.into(), None
);
257 pub fn warn(&mut self, msg
: &str) -> &mut Self {
258 self.sub(Level
::Warning
, msg
, MultiSpan
::new(), None
);
262 /// Prints the span with a warn above it.
263 pub fn span_warn
<S
: Into
<MultiSpan
>>(&mut self, sp
: S
, msg
: &str) -> &mut Self {
264 self.sub(Level
::Warning
, msg
, sp
.into(), None
);
268 pub fn help(&mut self, msg
: &str) -> &mut Self {
269 self.sub(Level
::Help
, msg
, MultiSpan
::new(), None
);
273 /// Prints the span with some help above it.
274 pub fn span_help
<S
: Into
<MultiSpan
>>(&mut self, sp
: S
, msg
: &str) -> &mut Self {
275 self.sub(Level
::Help
, msg
, sp
.into(), None
);
279 pub fn multipart_suggestion(
282 suggestion
: Vec
<(Span
, String
)>,
283 applicability
: Applicability
,
285 self.suggestions
.push(CodeSuggestion
{
286 substitutions
: vec
![Substitution
{
289 .map(|(span
, snippet
)| SubstitutionPart { snippet, span }
)
293 style
: SuggestionStyle
::ShowCode
,
299 pub fn multipart_suggestions(
302 suggestions
: Vec
<Vec
<(Span
, String
)>>,
303 applicability
: Applicability
,
305 self.suggestions
.push(CodeSuggestion
{
306 substitutions
: suggestions
308 .map(|suggestion
| Substitution
{
311 .map(|(span
, snippet
)| SubstitutionPart { snippet, span }
)
316 style
: SuggestionStyle
::ShowCode
,
322 /// Prints out a message with for a multipart suggestion without showing the suggested code.
324 /// This is intended to be used for suggestions that are obvious in what the changes need to
325 /// be from the message, showing the span label inline would be visually unpleasant
326 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
327 /// improve understandability.
328 pub fn tool_only_multipart_suggestion(
331 suggestion
: Vec
<(Span
, String
)>,
332 applicability
: Applicability
,
334 self.suggestions
.push(CodeSuggestion
{
335 substitutions
: vec
![Substitution
{
338 .map(|(span
, snippet
)| SubstitutionPart { snippet, span }
)
342 style
: SuggestionStyle
::CompletelyHidden
,
348 /// Prints out a message with a suggested edit of the code.
350 /// In case of short messages and a simple suggestion, rustc displays it as a label:
353 /// try adding parentheses: `(tup.0).1`
358 /// * should not end in any punctuation (a `:` is added automatically)
359 /// * should not be a question (avoid language like "did you mean")
360 /// * should not contain any phrases like "the following", "as shown", etc.
361 /// * may look like "to do xyz, use" or "to do xyz, use abc"
362 /// * may contain a name of a function, variable, or type, but not whole expressions
364 /// See `CodeSuggestion` for more information.
365 pub fn span_suggestion(
370 applicability
: Applicability
,
372 self.span_suggestion_with_style(
377 SuggestionStyle
::ShowCode
,
382 pub fn span_suggestion_with_style(
387 applicability
: Applicability
,
388 style
: SuggestionStyle
,
390 self.suggestions
.push(CodeSuggestion
{
391 substitutions
: vec
![Substitution
{
392 parts
: vec
![SubstitutionPart { snippet: suggestion, span: sp }
],
401 pub fn span_suggestion_verbose(
406 applicability
: Applicability
,
408 self.span_suggestion_with_style(
413 SuggestionStyle
::ShowAlways
,
418 /// Prints out a message with multiple suggested edits of the code.
419 pub fn span_suggestions(
423 suggestions
: impl Iterator
<Item
= String
>,
424 applicability
: Applicability
,
426 self.suggestions
.push(CodeSuggestion
{
427 substitutions
: suggestions
428 .map(|snippet
| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }
] })
431 style
: SuggestionStyle
::ShowCode
,
437 /// Prints out a message with a suggested edit of the code. If the suggestion is presented
438 /// inline, it will only show the message and not the suggestion.
440 /// See `CodeSuggestion` for more information.
441 pub fn span_suggestion_short(
446 applicability
: Applicability
,
448 self.span_suggestion_with_style(
453 SuggestionStyle
::HideCodeInline
,
458 /// Prints out a message with for a suggestion without showing the suggested code.
460 /// This is intended to be used for suggestions that are obvious in what the changes need to
461 /// be from the message, showing the span label inline would be visually unpleasant
462 /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't
463 /// improve understandability.
464 pub fn span_suggestion_hidden(
469 applicability
: Applicability
,
471 self.span_suggestion_with_style(
476 SuggestionStyle
::HideCodeAlways
,
481 /// Adds a suggestion to the json output, but otherwise remains silent/undisplayed in the cli.
483 /// This is intended to be used for suggestions that are *very* obvious in what the changes
484 /// need to be from the message, but we still want other tools to be able to apply them.
485 pub fn tool_only_span_suggestion(
490 applicability
: Applicability
,
492 self.span_suggestion_with_style(
497 SuggestionStyle
::CompletelyHidden
,
502 pub fn set_span
<S
: Into
<MultiSpan
>>(&mut self, sp
: S
) -> &mut Self {
503 self.span
= sp
.into();
504 if let Some(span
) = self.span
.primary_span() {
505 self.sort_span
= span
;
510 pub fn code(&mut self, s
: DiagnosticId
) -> &mut Self {
515 pub fn clear_code(&mut self) -> &mut Self {
520 pub fn get_code(&self) -> Option
<DiagnosticId
> {
524 pub fn set_primary_message
<M
: Into
<String
>>(&mut self, msg
: M
) -> &mut Self {
525 self.message
[0] = (msg
.into(), Style
::NoStyle
);
529 pub fn message(&self) -> String
{
530 self.message
.iter().map(|i
| i
.0.as_str()).collect
::<String
>()
533 pub fn styled_message(&self) -> &Vec
<(String
, Style
)> {
537 /// Used by a lint. Copies over all details *but* the "main
539 pub fn copy_details_not_message(&mut self, from
: &Diagnostic
) {
540 self.span
= from
.span
.clone();
541 self.code
= from
.code
.clone();
542 self.children
.extend(from
.children
.iter().cloned())
545 /// Convenience function for internal use, clients should use one of the
546 /// public methods above.
552 render_span
: Option
<MultiSpan
>,
554 let sub
= SubDiagnostic
{
556 message
: vec
![(message
.to_owned(), Style
::NoStyle
)],
560 self.children
.push(sub
);
563 /// Convenience function for internal use, clients should use one of the
564 /// public methods above.
565 fn sub_with_highlights(
568 message
: Vec
<(String
, Style
)>,
570 render_span
: Option
<MultiSpan
>,
572 let sub
= SubDiagnostic { level, message, span, render_span }
;
573 self.children
.push(sub
);
578 pub fn message(&self) -> String
{
579 self.message
.iter().map(|i
| i
.0.as_str()).collect
::<String
>()
582 pub fn styled_message(&self) -> &Vec
<(String
, Style
)> {