]>
Commit | Line | Data |
---|---|---|
dfeec247 | 1 | use crate::snippet::Style; |
04454e1e | 2 | use crate::{ |
064997fb FG |
3 | CodeSuggestion, DiagnosticMessage, EmissionGuarantee, Level, LintDiagnosticBuilder, MultiSpan, |
4 | SubdiagnosticMessage, Substitution, SubstitutionPart, SuggestionStyle, | |
04454e1e | 5 | }; |
064997fb | 6 | use rustc_data_structures::fx::FxHashMap; |
04454e1e | 7 | use rustc_error_messages::FluentValue; |
064997fb | 8 | use rustc_hir as hir; |
5e7ed085 | 9 | use rustc_lint_defs::{Applicability, LintExpectationId}; |
5e7ed085 | 10 | use rustc_span::edition::LATEST_STABLE_EDITION; |
f2b60f7d | 11 | use rustc_span::symbol::{Ident, MacroRulesNormalizedIdent, Symbol}; |
064997fb | 12 | use rustc_span::{edition::Edition, Span, DUMMY_SP}; |
f2b60f7d | 13 | use rustc_target::spec::{PanicStrategy, SplitDebuginfo, StackProtector, TargetTriple}; |
04454e1e | 14 | use std::borrow::Cow; |
c30ab7b3 | 15 | use std::fmt; |
c295e0f8 | 16 | use std::hash::{Hash, Hasher}; |
f2b60f7d FG |
17 | use std::num::ParseIntError; |
18 | use std::path::{Path, PathBuf}; | |
c30ab7b3 | 19 | |
5099ac24 FG |
20 | /// Error type for `Diagnostic`'s `suggestions` field, indicating that |
21 | /// `.disable_suggestions()` was called on the `Diagnostic`. | |
22 | #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] | |
23 | pub struct SuggestionsDisabled; | |
24 | ||
04454e1e FG |
25 | /// Simplified version of `FluentArg` that can implement `Encodable` and `Decodable`. Collection of |
26 | /// `DiagnosticArg` are converted to `FluentArgs` (consuming the collection) at the start of | |
27 | /// diagnostic emission. | |
28 | pub type DiagnosticArg<'source> = (Cow<'source, str>, DiagnosticArgValue<'source>); | |
29 | ||
30 | /// Simplified version of `FluentValue` that can implement `Encodable` and `Decodable`. Converted | |
31 | /// to a `FluentValue` by the emitter to be used in diagnostic translation. | |
32 | #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] | |
33 | pub enum DiagnosticArgValue<'source> { | |
34 | Str(Cow<'source, str>), | |
35 | Number(usize), | |
36 | } | |
37 | ||
38 | /// Converts a value of a type into a `DiagnosticArg` (typically a field of a `SessionDiagnostic` | |
39 | /// struct). Implemented as a custom trait rather than `From` so that it is implemented on the type | |
40 | /// being converted rather than on `DiagnosticArgValue`, which enables types from other `rustc_*` | |
41 | /// crates to implement this. | |
42 | pub trait IntoDiagnosticArg { | |
43 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static>; | |
44 | } | |
45 | ||
064997fb FG |
46 | pub struct DiagnosticArgFromDisplay<'a>(pub &'a dyn fmt::Display); |
47 | ||
48 | impl IntoDiagnosticArg for DiagnosticArgFromDisplay<'_> { | |
04454e1e | 49 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { |
064997fb FG |
50 | self.0.to_string().into_diagnostic_arg() |
51 | } | |
52 | } | |
53 | ||
54 | impl<'a> From<&'a dyn fmt::Display> for DiagnosticArgFromDisplay<'a> { | |
55 | fn from(t: &'a dyn fmt::Display) -> Self { | |
56 | DiagnosticArgFromDisplay(t) | |
57 | } | |
58 | } | |
59 | ||
60 | impl<'a, T: fmt::Display> From<&'a T> for DiagnosticArgFromDisplay<'a> { | |
61 | fn from(t: &'a T) -> Self { | |
62 | DiagnosticArgFromDisplay(t) | |
63 | } | |
64 | } | |
65 | ||
66 | macro_rules! into_diagnostic_arg_using_display { | |
67 | ($( $ty:ty ),+ $(,)?) => { | |
68 | $( | |
69 | impl IntoDiagnosticArg for $ty { | |
70 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
71 | self.to_string().into_diagnostic_arg() | |
72 | } | |
73 | } | |
74 | )+ | |
75 | } | |
76 | } | |
77 | ||
78 | into_diagnostic_arg_using_display!( | |
79 | i8, | |
80 | u8, | |
81 | i16, | |
82 | u16, | |
83 | i32, | |
84 | u32, | |
85 | i64, | |
86 | u64, | |
87 | i128, | |
88 | u128, | |
f2b60f7d | 89 | std::io::Error, |
064997fb FG |
90 | std::num::NonZeroU32, |
91 | hir::Target, | |
92 | Edition, | |
93 | Ident, | |
f2b60f7d FG |
94 | MacroRulesNormalizedIdent, |
95 | ParseIntError, | |
96 | StackProtector, | |
97 | &TargetTriple, | |
98 | SplitDebuginfo | |
064997fb FG |
99 | ); |
100 | ||
101 | impl IntoDiagnosticArg for bool { | |
102 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
103 | if self { | |
104 | DiagnosticArgValue::Str(Cow::Borrowed("true")) | |
105 | } else { | |
106 | DiagnosticArgValue::Str(Cow::Borrowed("false")) | |
107 | } | |
108 | } | |
109 | } | |
110 | ||
111 | impl IntoDiagnosticArg for char { | |
112 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
113 | DiagnosticArgValue::Str(Cow::Owned(format!("{:?}", self))) | |
04454e1e FG |
114 | } |
115 | } | |
116 | ||
117 | impl IntoDiagnosticArg for Symbol { | |
118 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
119 | self.to_ident_string().into_diagnostic_arg() | |
120 | } | |
121 | } | |
122 | ||
064997fb | 123 | impl<'a> IntoDiagnosticArg for &'a str { |
04454e1e FG |
124 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { |
125 | self.to_string().into_diagnostic_arg() | |
126 | } | |
127 | } | |
128 | ||
064997fb | 129 | impl IntoDiagnosticArg for String { |
04454e1e | 130 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { |
064997fb | 131 | DiagnosticArgValue::Str(Cow::Owned(self)) |
04454e1e FG |
132 | } |
133 | } | |
134 | ||
f2b60f7d FG |
135 | impl<'a> IntoDiagnosticArg for &'a Path { |
136 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
137 | DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) | |
138 | } | |
139 | } | |
140 | ||
141 | impl IntoDiagnosticArg for PathBuf { | |
142 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
143 | DiagnosticArgValue::Str(Cow::Owned(self.display().to_string())) | |
144 | } | |
145 | } | |
146 | ||
04454e1e FG |
147 | impl IntoDiagnosticArg for usize { |
148 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
149 | DiagnosticArgValue::Number(self) | |
150 | } | |
151 | } | |
152 | ||
f2b60f7d FG |
153 | impl IntoDiagnosticArg for PanicStrategy { |
154 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
155 | DiagnosticArgValue::Str(Cow::Owned(self.desc().to_string())) | |
156 | } | |
157 | } | |
158 | ||
04454e1e FG |
159 | impl<'source> Into<FluentValue<'source>> for DiagnosticArgValue<'source> { |
160 | fn into(self) -> FluentValue<'source> { | |
161 | match self { | |
162 | DiagnosticArgValue::Str(s) => From::from(s), | |
163 | DiagnosticArgValue::Number(n) => From::from(n), | |
164 | } | |
165 | } | |
166 | } | |
167 | ||
064997fb FG |
168 | impl IntoDiagnosticArg for hir::ConstContext { |
169 | fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { | |
170 | DiagnosticArgValue::Str(Cow::Borrowed(match self { | |
171 | hir::ConstContext::ConstFn => "constant function", | |
172 | hir::ConstContext::Static(_) => "static", | |
173 | hir::ConstContext::Const => "constant", | |
174 | })) | |
175 | } | |
176 | } | |
177 | ||
04454e1e FG |
178 | /// Trait implemented by error types. This should not be implemented manually. Instead, use |
179 | /// `#[derive(SessionSubdiagnostic)]` -- see [rustc_macros::SessionSubdiagnostic]. | |
923072b8 | 180 | #[rustc_diagnostic_item = "AddSubdiagnostic"] |
04454e1e FG |
181 | pub trait AddSubdiagnostic { |
182 | /// Add a subdiagnostic to an existing diagnostic. | |
183 | fn add_to_diagnostic(self, diag: &mut Diagnostic); | |
184 | } | |
185 | ||
064997fb FG |
186 | /// Trait implemented by lint types. This should not be implemented manually. Instead, use |
187 | /// `#[derive(LintDiagnostic)]` -- see [rustc_macros::LintDiagnostic]. | |
188 | #[rustc_diagnostic_item = "DecorateLint"] | |
189 | pub trait DecorateLint<'a, G: EmissionGuarantee> { | |
190 | /// Decorate and emit a lint. | |
191 | fn decorate_lint(self, diag: LintDiagnosticBuilder<'a, G>); | |
192 | } | |
193 | ||
c30ab7b3 | 194 | #[must_use] |
c295e0f8 | 195 | #[derive(Clone, Debug, Encodable, Decodable)] |
c30ab7b3 | 196 | pub struct Diagnostic { |
5e7ed085 FG |
197 | // NOTE(eddyb) this is private to disallow arbitrary after-the-fact changes, |
198 | // outside of what methods in this crate themselves allow. | |
923072b8 | 199 | pub(crate) level: Level, |
5e7ed085 | 200 | |
04454e1e | 201 | pub message: Vec<(DiagnosticMessage, Style)>, |
abe05a73 | 202 | pub code: Option<DiagnosticId>, |
c30ab7b3 SL |
203 | pub span: MultiSpan, |
204 | pub children: Vec<SubDiagnostic>, | |
5099ac24 | 205 | pub suggestions: Result<Vec<CodeSuggestion>, SuggestionsDisabled>, |
04454e1e | 206 | args: Vec<DiagnosticArg<'static>>, |
60c5eb7d XL |
207 | |
208 | /// This is not used for highlighting or rendering any error message. Rather, it can be used | |
209 | /// as a sort key to sort a buffer of diagnostics. By default, it is the primary span of | |
210 | /// `span` if there is one. Otherwise, it is `DUMMY_SP`. | |
211 | pub sort_span: Span, | |
c295e0f8 XL |
212 | |
213 | /// If diagnostic is from Lint, custom hash function ignores notes | |
214 | /// otherwise hash is based on the all the fields | |
215 | pub is_lint: bool, | |
c30ab7b3 SL |
216 | } |
217 | ||
3dfed10e | 218 | #[derive(Clone, Debug, PartialEq, Eq, Hash, Encodable, Decodable)] |
abe05a73 XL |
219 | pub enum DiagnosticId { |
220 | Error(String), | |
136023e0 | 221 | Lint { name: String, has_future_breakage: bool, is_force_warn: bool }, |
abe05a73 XL |
222 | } |
223 | ||
fc512014 XL |
224 | /// A "sub"-diagnostic attached to a parent diagnostic. |
225 | /// For example, a note attached to an error. | |
3dfed10e | 226 | #[derive(Clone, Debug, PartialEq, Hash, Encodable, Decodable)] |
c30ab7b3 SL |
227 | pub struct SubDiagnostic { |
228 | pub level: Level, | |
04454e1e | 229 | pub message: Vec<(DiagnosticMessage, Style)>, |
c30ab7b3 | 230 | pub span: MultiSpan, |
abe05a73 | 231 | pub render_span: Option<MultiSpan>, |
c30ab7b3 SL |
232 | } |
233 | ||
e74abb32 | 234 | #[derive(Debug, PartialEq, Eq)] |
cc61c64b XL |
235 | pub struct DiagnosticStyledString(pub Vec<StringPart>); |
236 | ||
237 | impl DiagnosticStyledString { | |
238 | pub fn new() -> DiagnosticStyledString { | |
239 | DiagnosticStyledString(vec![]) | |
240 | } | |
241 | pub fn push_normal<S: Into<String>>(&mut self, t: S) { | |
242 | self.0.push(StringPart::Normal(t.into())); | |
243 | } | |
244 | pub fn push_highlighted<S: Into<String>>(&mut self, t: S) { | |
245 | self.0.push(StringPart::Highlighted(t.into())); | |
246 | } | |
60c5eb7d XL |
247 | pub fn push<S: Into<String>>(&mut self, t: S, highlight: bool) { |
248 | if highlight { | |
249 | self.push_highlighted(t); | |
250 | } else { | |
251 | self.push_normal(t); | |
252 | } | |
253 | } | |
cc61c64b XL |
254 | pub fn normal<S: Into<String>>(t: S) -> DiagnosticStyledString { |
255 | DiagnosticStyledString(vec![StringPart::Normal(t.into())]) | |
256 | } | |
257 | ||
258 | pub fn highlighted<S: Into<String>>(t: S) -> DiagnosticStyledString { | |
259 | DiagnosticStyledString(vec![StringPart::Highlighted(t.into())]) | |
260 | } | |
c295e0f8 XL |
261 | |
262 | pub fn content(&self) -> String { | |
263 | self.0.iter().map(|x| x.content()).collect::<String>() | |
264 | } | |
cc61c64b XL |
265 | } |
266 | ||
e74abb32 | 267 | #[derive(Debug, PartialEq, Eq)] |
cc61c64b XL |
268 | pub enum StringPart { |
269 | Normal(String), | |
270 | Highlighted(String), | |
271 | } | |
272 | ||
c295e0f8 XL |
273 | impl StringPart { |
274 | pub fn content(&self) -> &str { | |
275 | match self { | |
276 | &StringPart::Normal(ref s) | &StringPart::Highlighted(ref s) => s, | |
277 | } | |
278 | } | |
279 | } | |
280 | ||
c30ab7b3 | 281 | impl Diagnostic { |
04454e1e | 282 | pub fn new<M: Into<DiagnosticMessage>>(level: Level, message: M) -> Self { |
c30ab7b3 SL |
283 | Diagnostic::new_with_code(level, None, message) |
284 | } | |
285 | ||
04454e1e FG |
286 | pub fn new_with_code<M: Into<DiagnosticMessage>>( |
287 | level: Level, | |
288 | code: Option<DiagnosticId>, | |
289 | message: M, | |
290 | ) -> Self { | |
c30ab7b3 | 291 | Diagnostic { |
3b2f2976 | 292 | level, |
04454e1e | 293 | message: vec![(message.into(), Style::NoStyle)], |
3b2f2976 | 294 | code, |
c30ab7b3 SL |
295 | span: MultiSpan::new(), |
296 | children: vec![], | |
5099ac24 | 297 | suggestions: Ok(vec![]), |
04454e1e | 298 | args: vec![], |
60c5eb7d | 299 | sort_span: DUMMY_SP, |
c295e0f8 | 300 | is_lint: false, |
c30ab7b3 SL |
301 | } |
302 | } | |
303 | ||
5e7ed085 FG |
304 | #[inline(always)] |
305 | pub fn level(&self) -> Level { | |
306 | self.level | |
307 | } | |
308 | ||
8faf50e0 XL |
309 | pub fn is_error(&self) -> bool { |
310 | match self.level { | |
5e7ed085 FG |
311 | Level::Bug |
312 | | Level::DelayedBug | |
313 | | Level::Fatal | |
314 | | Level::Error { .. } | |
315 | | Level::FailureNote => true, | |
316 | ||
923072b8 | 317 | Level::Warning(_) |
5e7ed085 FG |
318 | | Level::Note |
319 | | Level::OnceNote | |
320 | | Level::Help | |
321 | | Level::Allow | |
322 | | Level::Expect(_) => false, | |
323 | } | |
324 | } | |
325 | ||
326 | pub fn update_unstable_expectation_id( | |
327 | &mut self, | |
328 | unstable_to_stable: &FxHashMap<LintExpectationId, LintExpectationId>, | |
329 | ) { | |
923072b8 FG |
330 | if let Level::Expect(expectation_id) | Level::Warning(Some(expectation_id)) = |
331 | &mut self.level | |
332 | { | |
5e7ed085 FG |
333 | if expectation_id.is_stable() { |
334 | return; | |
335 | } | |
8faf50e0 | 336 | |
5e7ed085 FG |
337 | // The unstable to stable map only maps the unstable `AttrId` to a stable `HirId` with an attribute index. |
338 | // The lint index inside the attribute is manually transferred here. | |
339 | let lint_index = expectation_id.get_lint_index(); | |
340 | expectation_id.set_lint_index(None); | |
341 | let mut stable_id = *unstable_to_stable | |
342 | .get(&expectation_id) | |
343 | .expect("each unstable `LintExpectationId` must have a matching stable id"); | |
344 | ||
345 | stable_id.set_lint_index(lint_index); | |
346 | *expectation_id = stable_id; | |
29967ef6 XL |
347 | } |
348 | } | |
349 | ||
350 | pub fn has_future_breakage(&self) -> bool { | |
351 | match self.code { | |
352 | Some(DiagnosticId::Lint { has_future_breakage, .. }) => has_future_breakage, | |
353 | _ => false, | |
8faf50e0 XL |
354 | } |
355 | } | |
356 | ||
136023e0 XL |
357 | pub fn is_force_warn(&self) -> bool { |
358 | match self.code { | |
359 | Some(DiagnosticId::Lint { is_force_warn, .. }) => is_force_warn, | |
360 | _ => false, | |
361 | } | |
362 | } | |
363 | ||
5e7ed085 FG |
364 | /// Delay emission of this diagnostic as a bug. |
365 | /// | |
366 | /// This can be useful in contexts where an error indicates a bug but | |
367 | /// typically this only happens when other compilation errors have already | |
368 | /// happened. In those cases this can be used to defer emission of this | |
369 | /// diagnostic as a bug in the compiler only if no other errors have been | |
370 | /// emitted. | |
371 | /// | |
372 | /// In the meantime, though, callsites are required to deal with the "bug" | |
373 | /// locally in whichever way makes the most sense. | |
374 | #[track_caller] | |
375 | pub fn downgrade_to_delayed_bug(&mut self) -> &mut Self { | |
376 | assert!( | |
377 | self.is_error(), | |
378 | "downgrade_to_delayed_bug: cannot downgrade {:?} to DelayedBug: not an error", | |
379 | self.level | |
380 | ); | |
381 | self.level = Level::DelayedBug; | |
c30ab7b3 | 382 | |
5e7ed085 | 383 | self |
c30ab7b3 SL |
384 | } |
385 | ||
9fa01778 | 386 | /// Adds a span/label to be included in the resulting snippet. |
e1599b0c | 387 | /// |
3dfed10e XL |
388 | /// This is pushed onto the [`MultiSpan`] that was created when the diagnostic |
389 | /// was first built. That means it will be shown together with the original | |
390 | /// span/label, *not* a span added by one of the `span_{note,warn,help,suggestions}` methods. | |
391 | /// | |
392 | /// This span is *not* considered a ["primary span"][`MultiSpan`]; only | |
393 | /// the `Span` supplied when creating the diagnostic is primary. | |
064997fb | 394 | #[rustc_lint_diagnostics] |
923072b8 FG |
395 | pub fn span_label(&mut self, span: Span, label: impl Into<SubdiagnosticMessage>) -> &mut Self { |
396 | self.span.push_span_label(span, self.subdiagnostic_message_to_diagnostic_message(label)); | |
c30ab7b3 SL |
397 | self |
398 | } | |
399 | ||
5e7ed085 FG |
400 | /// Labels all the given spans with the provided label. |
401 | /// See [`Self::span_label()`] for more information. | |
402 | pub fn span_labels( | |
403 | &mut self, | |
404 | spans: impl IntoIterator<Item = Span>, | |
405 | label: impl AsRef<str>, | |
406 | ) -> &mut Self { | |
407 | let label = label.as_ref(); | |
408 | for span in spans { | |
409 | self.span_label(span, label); | |
410 | } | |
411 | self | |
412 | } | |
413 | ||
a1dfa0c6 XL |
414 | pub fn replace_span_with(&mut self, after: Span) -> &mut Self { |
415 | let before = self.span.clone(); | |
416 | self.set_span(after); | |
417 | for span_label in before.span_labels() { | |
418 | if let Some(label) = span_label.label { | |
04454e1e | 419 | self.span.push_span_label(after, label); |
a1dfa0c6 XL |
420 | } |
421 | } | |
422 | self | |
423 | } | |
424 | ||
5e7ed085 | 425 | pub fn note_expected_found( |
60c5eb7d XL |
426 | &mut self, |
427 | expected_label: &dyn fmt::Display, | |
428 | expected: DiagnosticStyledString, | |
429 | found_label: &dyn fmt::Display, | |
430 | found: DiagnosticStyledString, | |
431 | ) -> &mut Self { | |
432 | self.note_expected_found_extra(expected_label, expected, found_label, found, &"", &"") | |
c30ab7b3 SL |
433 | } |
434 | ||
5e7ed085 | 435 | pub fn note_unsuccessful_coercion( |
60c5eb7d XL |
436 | &mut self, |
437 | expected: DiagnosticStyledString, | |
438 | found: DiagnosticStyledString, | |
439 | ) -> &mut Self { | |
064997fb | 440 | let mut msg: Vec<_> = vec![("required when trying to coerce from type `", Style::NoStyle)]; |
dfeec247 | 441 | msg.extend(expected.0.iter().map(|x| match *x { |
064997fb FG |
442 | StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), |
443 | StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), | |
dfeec247 | 444 | })); |
064997fb | 445 | msg.push(("` to type '", Style::NoStyle)); |
dfeec247 | 446 | msg.extend(found.0.iter().map(|x| match *x { |
064997fb FG |
447 | StringPart::Normal(ref s) => (s.as_str(), Style::NoStyle), |
448 | StringPart::Highlighted(ref s) => (s.as_str(), Style::Highlight), | |
dfeec247 | 449 | })); |
064997fb | 450 | msg.push(("`", Style::NoStyle)); |
e74abb32 XL |
451 | |
452 | // For now, just attach these as notes | |
453 | self.highlighted_note(msg); | |
454 | self | |
455 | } | |
456 | ||
60c5eb7d XL |
457 | pub fn note_expected_found_extra( |
458 | &mut self, | |
459 | expected_label: &dyn fmt::Display, | |
460 | expected: DiagnosticStyledString, | |
461 | found_label: &dyn fmt::Display, | |
462 | found: DiagnosticStyledString, | |
463 | expected_extra: &dyn fmt::Display, | |
464 | found_extra: &dyn fmt::Display, | |
465 | ) -> &mut Self { | |
f9f354fc XL |
466 | let expected_label = expected_label.to_string(); |
467 | let expected_label = if expected_label.is_empty() { | |
468 | "expected".to_string() | |
469 | } else { | |
470 | format!("expected {}", expected_label) | |
471 | }; | |
472 | let found_label = found_label.to_string(); | |
473 | let found_label = if found_label.is_empty() { | |
474 | "found".to_string() | |
475 | } else { | |
476 | format!("found {}", found_label) | |
477 | }; | |
60c5eb7d XL |
478 | let (found_padding, expected_padding) = if expected_label.len() > found_label.len() { |
479 | (expected_label.len() - found_label.len(), 0) | |
480 | } else { | |
481 | (0, found_label.len() - expected_label.len()) | |
482 | }; | |
dfeec247 XL |
483 | let mut msg: Vec<_> = |
484 | vec![(format!("{}{} `", " ".repeat(expected_padding), expected_label), Style::NoStyle)]; | |
485 | msg.extend(expected.0.iter().map(|x| match *x { | |
486 | StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), | |
487 | StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), | |
488 | })); | |
cc61c64b | 489 | msg.push((format!("`{}\n", expected_extra), Style::NoStyle)); |
60c5eb7d | 490 | msg.push((format!("{}{} `", " ".repeat(found_padding), found_label), Style::NoStyle)); |
dfeec247 XL |
491 | msg.extend(found.0.iter().map(|x| match *x { |
492 | StringPart::Normal(ref s) => (s.to_owned(), Style::NoStyle), | |
493 | StringPart::Highlighted(ref s) => (s.to_owned(), Style::Highlight), | |
494 | })); | |
cc61c64b XL |
495 | msg.push((format!("`{}", found_extra), Style::NoStyle)); |
496 | ||
60c5eb7d | 497 | // For now, just attach these as notes. |
cc61c64b | 498 | self.highlighted_note(msg); |
c30ab7b3 SL |
499 | self |
500 | } | |
501 | ||
064997fb | 502 | pub fn note_trait_signature(&mut self, name: Symbol, signature: String) -> &mut Self { |
7cac9316 XL |
503 | self.highlighted_note(vec![ |
504 | (format!("`{}` from trait: `", name), Style::NoStyle), | |
505 | (signature, Style::Highlight), | |
dfeec247 XL |
506 | ("`".to_string(), Style::NoStyle), |
507 | ]); | |
7cac9316 XL |
508 | self |
509 | } | |
510 | ||
fc512014 | 511 | /// Add a note attached to this diagnostic. |
064997fb | 512 | #[rustc_lint_diagnostics] |
923072b8 | 513 | pub fn note(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { |
c30ab7b3 SL |
514 | self.sub(Level::Note, msg, MultiSpan::new(), None); |
515 | self | |
516 | } | |
517 | ||
923072b8 | 518 | pub fn highlighted_note<M: Into<SubdiagnosticMessage>>( |
04454e1e FG |
519 | &mut self, |
520 | msg: Vec<(M, Style)>, | |
521 | ) -> &mut Self { | |
32a655c1 SL |
522 | self.sub_with_highlights(Level::Note, msg, MultiSpan::new(), None); |
523 | self | |
524 | } | |
525 | ||
e1599b0c | 526 | /// Prints the span with a note above it. |
fc512014 | 527 | /// This is like [`Diagnostic::note()`], but it gets its own span. |
923072b8 | 528 | pub fn note_once(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { |
5e7ed085 FG |
529 | self.sub(Level::OnceNote, msg, MultiSpan::new(), None); |
530 | self | |
531 | } | |
532 | ||
533 | /// Prints the span with a note above it. | |
534 | /// This is like [`Diagnostic::note()`], but it gets its own span. | |
064997fb | 535 | #[rustc_lint_diagnostics] |
04454e1e FG |
536 | pub fn span_note<S: Into<MultiSpan>>( |
537 | &mut self, | |
538 | sp: S, | |
923072b8 | 539 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 540 | ) -> &mut Self { |
c30ab7b3 SL |
541 | self.sub(Level::Note, msg, sp.into(), None); |
542 | self | |
543 | } | |
544 | ||
5e7ed085 FG |
545 | /// Prints the span with a note above it. |
546 | /// This is like [`Diagnostic::note()`], but it gets its own span. | |
04454e1e FG |
547 | pub fn span_note_once<S: Into<MultiSpan>>( |
548 | &mut self, | |
549 | sp: S, | |
923072b8 | 550 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 551 | ) -> &mut Self { |
5e7ed085 FG |
552 | self.sub(Level::OnceNote, msg, sp.into(), None); |
553 | self | |
554 | } | |
555 | ||
fc512014 | 556 | /// Add a warning attached to this diagnostic. |
064997fb | 557 | #[rustc_lint_diagnostics] |
923072b8 FG |
558 | pub fn warn(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { |
559 | self.sub(Level::Warning(None), msg, MultiSpan::new(), None); | |
c30ab7b3 SL |
560 | self |
561 | } | |
562 | ||
fc512014 XL |
563 | /// Prints the span with a warning above it. |
564 | /// This is like [`Diagnostic::warn()`], but it gets its own span. | |
064997fb | 565 | #[rustc_lint_diagnostics] |
04454e1e FG |
566 | pub fn span_warn<S: Into<MultiSpan>>( |
567 | &mut self, | |
568 | sp: S, | |
923072b8 | 569 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 570 | ) -> &mut Self { |
923072b8 | 571 | self.sub(Level::Warning(None), msg, sp.into(), None); |
c30ab7b3 SL |
572 | self |
573 | } | |
574 | ||
fc512014 | 575 | /// Add a help message attached to this diagnostic. |
064997fb | 576 | #[rustc_lint_diagnostics] |
923072b8 | 577 | pub fn help(&mut self, msg: impl Into<SubdiagnosticMessage>) -> &mut Self { |
c30ab7b3 SL |
578 | self.sub(Level::Help, msg, MultiSpan::new(), None); |
579 | self | |
580 | } | |
581 | ||
04454e1e FG |
582 | /// Add a help message attached to this diagnostic with a customizable highlighted message. |
583 | pub fn highlighted_help(&mut self, msg: Vec<(String, Style)>) -> &mut Self { | |
584 | self.sub_with_highlights(Level::Help, msg, MultiSpan::new(), None); | |
585 | self | |
586 | } | |
587 | ||
e1599b0c | 588 | /// Prints the span with some help above it. |
fc512014 | 589 | /// This is like [`Diagnostic::help()`], but it gets its own span. |
064997fb | 590 | #[rustc_lint_diagnostics] |
04454e1e FG |
591 | pub fn span_help<S: Into<MultiSpan>>( |
592 | &mut self, | |
593 | sp: S, | |
923072b8 | 594 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 595 | ) -> &mut Self { |
c30ab7b3 SL |
596 | self.sub(Level::Help, msg, sp.into(), None); |
597 | self | |
598 | } | |
599 | ||
5e7ed085 FG |
600 | /// Help the user upgrade to the latest edition. |
601 | /// This is factored out to make sure it does the right thing with `Cargo.toml`. | |
602 | pub fn help_use_latest_edition(&mut self) -> &mut Self { | |
603 | if std::env::var_os("CARGO").is_some() { | |
604 | self.help(&format!("set `edition = \"{}\"` in `Cargo.toml`", LATEST_STABLE_EDITION)); | |
605 | } else { | |
606 | self.help(&format!("pass `--edition {}` to `rustc`", LATEST_STABLE_EDITION)); | |
607 | } | |
608 | self.note("for more on editions, read https://doc.rust-lang.org/edition-guide"); | |
609 | self | |
610 | } | |
611 | ||
5099ac24 FG |
612 | /// Disallow attaching suggestions this diagnostic. |
613 | /// Any suggestions attached e.g. with the `span_suggestion_*` methods | |
614 | /// (before and after the call to `disable_suggestions`) will be ignored. | |
615 | pub fn disable_suggestions(&mut self) -> &mut Self { | |
616 | self.suggestions = Err(SuggestionsDisabled); | |
617 | self | |
618 | } | |
619 | ||
064997fb FG |
620 | /// Clear any existing suggestions. |
621 | pub fn clear_suggestions(&mut self) -> &mut Self { | |
622 | if let Ok(suggestions) = &mut self.suggestions { | |
623 | suggestions.clear(); | |
624 | } | |
625 | self | |
626 | } | |
627 | ||
5099ac24 FG |
628 | /// Helper for pushing to `self.suggestions`, if available (not disable). |
629 | fn push_suggestion(&mut self, suggestion: CodeSuggestion) { | |
630 | if let Ok(suggestions) = &mut self.suggestions { | |
631 | suggestions.push(suggestion); | |
632 | } | |
633 | } | |
634 | ||
fc512014 XL |
635 | /// Show a suggestion that has multiple parts to it. |
636 | /// In other words, multiple changes need to be applied as part of this suggestion. | |
9fa01778 XL |
637 | pub fn multipart_suggestion( |
638 | &mut self, | |
923072b8 | 639 | msg: impl Into<SubdiagnosticMessage>, |
9fa01778 XL |
640 | suggestion: Vec<(Span, String)>, |
641 | applicability: Applicability, | |
17df50a5 XL |
642 | ) -> &mut Self { |
643 | self.multipart_suggestion_with_style( | |
644 | msg, | |
645 | suggestion, | |
646 | applicability, | |
647 | SuggestionStyle::ShowCode, | |
648 | ) | |
649 | } | |
650 | ||
c295e0f8 XL |
651 | /// Show a suggestion that has multiple parts to it, always as it's own subdiagnostic. |
652 | /// In other words, multiple changes need to be applied as part of this suggestion. | |
653 | pub fn multipart_suggestion_verbose( | |
654 | &mut self, | |
923072b8 | 655 | msg: impl Into<SubdiagnosticMessage>, |
c295e0f8 XL |
656 | suggestion: Vec<(Span, String)>, |
657 | applicability: Applicability, | |
658 | ) -> &mut Self { | |
659 | self.multipart_suggestion_with_style( | |
660 | msg, | |
661 | suggestion, | |
662 | applicability, | |
663 | SuggestionStyle::ShowAlways, | |
664 | ) | |
665 | } | |
17df50a5 XL |
666 | /// [`Diagnostic::multipart_suggestion()`] but you can set the [`SuggestionStyle`]. |
667 | pub fn multipart_suggestion_with_style( | |
668 | &mut self, | |
923072b8 | 669 | msg: impl Into<SubdiagnosticMessage>, |
17df50a5 XL |
670 | suggestion: Vec<(Span, String)>, |
671 | applicability: Applicability, | |
672 | style: SuggestionStyle, | |
9fa01778 | 673 | ) -> &mut Self { |
6a06907d | 674 | assert!(!suggestion.is_empty()); |
5099ac24 | 675 | self.push_suggestion(CodeSuggestion { |
9fa01778 XL |
676 | substitutions: vec![Substitution { |
677 | parts: suggestion | |
678 | .into_iter() | |
679 | .map(|(span, snippet)| SubstitutionPart { snippet, span }) | |
680 | .collect(), | |
681 | }], | |
923072b8 | 682 | msg: self.subdiagnostic_message_to_diagnostic_message(msg), |
17df50a5 | 683 | style, |
9fa01778 XL |
684 | applicability, |
685 | }); | |
686 | self | |
687 | } | |
688 | ||
689 | /// Prints out a message with for a multipart suggestion without showing the suggested code. | |
3b2f2976 | 690 | /// |
9fa01778 XL |
691 | /// This is intended to be used for suggestions that are obvious in what the changes need to |
692 | /// be from the message, showing the span label inline would be visually unpleasant | |
693 | /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't | |
694 | /// improve understandability. | |
695 | pub fn tool_only_multipart_suggestion( | |
696 | &mut self, | |
923072b8 | 697 | msg: impl Into<SubdiagnosticMessage>, |
9fa01778 XL |
698 | suggestion: Vec<(Span, String)>, |
699 | applicability: Applicability, | |
700 | ) -> &mut Self { | |
f2b60f7d FG |
701 | self.multipart_suggestion_with_style( |
702 | msg, | |
703 | suggestion, | |
9fa01778 | 704 | applicability, |
f2b60f7d FG |
705 | SuggestionStyle::CompletelyHidden, |
706 | ) | |
3b2f2976 XL |
707 | } |
708 | ||
c30ab7b3 SL |
709 | /// Prints out a message with a suggested edit of the code. |
710 | /// | |
9fa01778 | 711 | /// In case of short messages and a simple suggestion, rustc displays it as a label: |
041b39d2 | 712 | /// |
9fa01778 XL |
713 | /// ```text |
714 | /// try adding parentheses: `(tup.0).1` | |
715 | /// ``` | |
041b39d2 XL |
716 | /// |
717 | /// The message | |
abe05a73 | 718 | /// |
041b39d2 | 719 | /// * should not end in any punctuation (a `:` is added automatically) |
9fa01778 XL |
720 | /// * should not be a question (avoid language like "did you mean") |
721 | /// * should not contain any phrases like "the following", "as shown", etc. | |
041b39d2 | 722 | /// * may look like "to do xyz, use" or "to do xyz, use abc" |
9fa01778 | 723 | /// * may contain a name of a function, variable, or type, but not whole expressions |
041b39d2 | 724 | /// |
ea8adc8c | 725 | /// See `CodeSuggestion` for more information. |
e74abb32 XL |
726 | pub fn span_suggestion( |
727 | &mut self, | |
728 | sp: Span, | |
923072b8 | 729 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 730 | suggestion: impl ToString, |
e74abb32 XL |
731 | applicability: Applicability, |
732 | ) -> &mut Self { | |
733 | self.span_suggestion_with_style( | |
734 | sp, | |
735 | msg, | |
736 | suggestion, | |
737 | applicability, | |
738 | SuggestionStyle::ShowCode, | |
739 | ); | |
740 | self | |
741 | } | |
742 | ||
fc512014 | 743 | /// [`Diagnostic::span_suggestion()`] but you can set the [`SuggestionStyle`]. |
e74abb32 XL |
744 | pub fn span_suggestion_with_style( |
745 | &mut self, | |
746 | sp: Span, | |
923072b8 | 747 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 748 | suggestion: impl ToString, |
e74abb32 XL |
749 | applicability: Applicability, |
750 | style: SuggestionStyle, | |
751 | ) -> &mut Self { | |
5099ac24 | 752 | self.push_suggestion(CodeSuggestion { |
abe05a73 | 753 | substitutions: vec![Substitution { |
04454e1e | 754 | parts: vec![SubstitutionPart { snippet: suggestion.to_string(), span: sp }], |
7cac9316 | 755 | }], |
923072b8 | 756 | msg: self.subdiagnostic_message_to_diagnostic_message(msg), |
e74abb32 | 757 | style, |
0bf4aa26 | 758 | applicability, |
94b46f34 XL |
759 | }); |
760 | self | |
761 | } | |
762 | ||
fc512014 | 763 | /// Always show the suggested change. |
e74abb32 XL |
764 | pub fn span_suggestion_verbose( |
765 | &mut self, | |
766 | sp: Span, | |
923072b8 | 767 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 768 | suggestion: impl ToString, |
e74abb32 XL |
769 | applicability: Applicability, |
770 | ) -> &mut Self { | |
771 | self.span_suggestion_with_style( | |
772 | sp, | |
773 | msg, | |
774 | suggestion, | |
775 | applicability, | |
776 | SuggestionStyle::ShowAlways, | |
777 | ); | |
778 | self | |
779 | } | |
780 | ||
abe05a73 | 781 | /// Prints out a message with multiple suggested edits of the code. |
fc512014 | 782 | /// See also [`Diagnostic::span_suggestion()`]. |
e74abb32 XL |
783 | pub fn span_suggestions( |
784 | &mut self, | |
785 | sp: Span, | |
923072b8 | 786 | msg: impl Into<SubdiagnosticMessage>, |
e74abb32 XL |
787 | suggestions: impl Iterator<Item = String>, |
788 | applicability: Applicability, | |
789 | ) -> &mut Self { | |
3c0e092e XL |
790 | let mut suggestions: Vec<_> = suggestions.collect(); |
791 | suggestions.sort(); | |
792 | let substitutions = suggestions | |
793 | .into_iter() | |
794 | .map(|snippet| Substitution { parts: vec![SubstitutionPart { snippet, span: sp }] }) | |
795 | .collect(); | |
5099ac24 | 796 | self.push_suggestion(CodeSuggestion { |
3c0e092e | 797 | substitutions, |
923072b8 | 798 | msg: self.subdiagnostic_message_to_diagnostic_message(msg), |
9fa01778 XL |
799 | style: SuggestionStyle::ShowCode, |
800 | applicability, | |
2c00a5a8 XL |
801 | }); |
802 | self | |
803 | } | |
804 | ||
94222f64 XL |
805 | /// Prints out a message with multiple suggested edits of the code. |
806 | /// See also [`Diagnostic::span_suggestion()`]. | |
807 | pub fn multipart_suggestions( | |
808 | &mut self, | |
923072b8 | 809 | msg: impl Into<SubdiagnosticMessage>, |
94222f64 XL |
810 | suggestions: impl Iterator<Item = Vec<(Span, String)>>, |
811 | applicability: Applicability, | |
812 | ) -> &mut Self { | |
5099ac24 | 813 | self.push_suggestion(CodeSuggestion { |
94222f64 XL |
814 | substitutions: suggestions |
815 | .map(|sugg| Substitution { | |
816 | parts: sugg | |
817 | .into_iter() | |
818 | .map(|(span, snippet)| SubstitutionPart { snippet, span }) | |
819 | .collect(), | |
820 | }) | |
821 | .collect(), | |
923072b8 | 822 | msg: self.subdiagnostic_message_to_diagnostic_message(msg), |
94222f64 XL |
823 | style: SuggestionStyle::ShowCode, |
824 | applicability, | |
94222f64 XL |
825 | }); |
826 | self | |
827 | } | |
9fa01778 XL |
828 | /// Prints out a message with a suggested edit of the code. If the suggestion is presented |
829 | /// inline, it will only show the message and not the suggestion. | |
830 | /// | |
831 | /// See `CodeSuggestion` for more information. | |
832 | pub fn span_suggestion_short( | |
dfeec247 XL |
833 | &mut self, |
834 | sp: Span, | |
923072b8 | 835 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 836 | suggestion: impl ToString, |
dfeec247 | 837 | applicability: Applicability, |
9fa01778 | 838 | ) -> &mut Self { |
e74abb32 XL |
839 | self.span_suggestion_with_style( |
840 | sp, | |
841 | msg, | |
842 | suggestion, | |
83c7162d | 843 | applicability, |
e74abb32 XL |
844 | SuggestionStyle::HideCodeInline, |
845 | ); | |
2c00a5a8 XL |
846 | self |
847 | } | |
848 | ||
fc512014 | 849 | /// Prints out a message for a suggestion without showing the suggested code. |
9fa01778 XL |
850 | /// |
851 | /// This is intended to be used for suggestions that are obvious in what the changes need to | |
852 | /// be from the message, showing the span label inline would be visually unpleasant | |
853 | /// (marginally overlapping spans or multiline spans) and showing the snippet window wouldn't | |
854 | /// improve understandability. | |
855 | pub fn span_suggestion_hidden( | |
dfeec247 XL |
856 | &mut self, |
857 | sp: Span, | |
923072b8 | 858 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 859 | suggestion: impl ToString, |
dfeec247 | 860 | applicability: Applicability, |
9fa01778 | 861 | ) -> &mut Self { |
e74abb32 XL |
862 | self.span_suggestion_with_style( |
863 | sp, | |
864 | msg, | |
865 | suggestion, | |
83c7162d | 866 | applicability, |
e74abb32 XL |
867 | SuggestionStyle::HideCodeAlways, |
868 | ); | |
c30ab7b3 SL |
869 | self |
870 | } | |
94b46f34 | 871 | |
fc512014 | 872 | /// Adds a suggestion to the JSON output that will not be shown in the CLI. |
9fa01778 XL |
873 | /// |
874 | /// This is intended to be used for suggestions that are *very* obvious in what the changes | |
875 | /// need to be from the message, but we still want other tools to be able to apply them. | |
876 | pub fn tool_only_span_suggestion( | |
dfeec247 XL |
877 | &mut self, |
878 | sp: Span, | |
923072b8 | 879 | msg: impl Into<SubdiagnosticMessage>, |
04454e1e | 880 | suggestion: impl ToString, |
dfeec247 | 881 | applicability: Applicability, |
94b46f34 | 882 | ) -> &mut Self { |
e74abb32 XL |
883 | self.span_suggestion_with_style( |
884 | sp, | |
885 | msg, | |
886 | suggestion, | |
dc9dc135 | 887 | applicability, |
e74abb32 XL |
888 | SuggestionStyle::CompletelyHidden, |
889 | ); | |
94b46f34 XL |
890 | self |
891 | } | |
c30ab7b3 | 892 | |
04454e1e FG |
893 | /// Add a subdiagnostic from a type that implements `SessionSubdiagnostic` - see |
894 | /// [rustc_macros::SessionSubdiagnostic]. | |
895 | pub fn subdiagnostic(&mut self, subdiagnostic: impl AddSubdiagnostic) -> &mut Self { | |
896 | subdiagnostic.add_to_diagnostic(self); | |
897 | self | |
6a06907d XL |
898 | } |
899 | ||
c30ab7b3 SL |
900 | pub fn set_span<S: Into<MultiSpan>>(&mut self, sp: S) -> &mut Self { |
901 | self.span = sp.into(); | |
60c5eb7d XL |
902 | if let Some(span) = self.span.primary_span() { |
903 | self.sort_span = span; | |
904 | } | |
c30ab7b3 SL |
905 | self |
906 | } | |
907 | ||
c295e0f8 XL |
908 | pub fn set_is_lint(&mut self) -> &mut Self { |
909 | self.is_lint = true; | |
910 | self | |
911 | } | |
912 | ||
abe05a73 | 913 | pub fn code(&mut self, s: DiagnosticId) -> &mut Self { |
c30ab7b3 SL |
914 | self.code = Some(s); |
915 | self | |
916 | } | |
917 | ||
60c5eb7d XL |
918 | pub fn clear_code(&mut self) -> &mut Self { |
919 | self.code = None; | |
920 | self | |
921 | } | |
922 | ||
2c00a5a8 XL |
923 | pub fn get_code(&self) -> Option<DiagnosticId> { |
924 | self.code.clone() | |
925 | } | |
926 | ||
04454e1e | 927 | pub fn set_primary_message(&mut self, msg: impl Into<DiagnosticMessage>) -> &mut Self { |
60c5eb7d XL |
928 | self.message[0] = (msg.into(), Style::NoStyle); |
929 | self | |
930 | } | |
931 | ||
04454e1e FG |
932 | pub fn args(&self) -> &[DiagnosticArg<'static>] { |
933 | &self.args | |
32a655c1 SL |
934 | } |
935 | ||
04454e1e FG |
936 | pub fn set_arg( |
937 | &mut self, | |
938 | name: impl Into<Cow<'static, str>>, | |
939 | arg: impl IntoDiagnosticArg, | |
940 | ) -> &mut Self { | |
941 | self.args.push((name.into(), arg.into_diagnostic_arg())); | |
942 | self | |
943 | } | |
944 | ||
923072b8 | 945 | pub fn styled_message(&self) -> &[(DiagnosticMessage, Style)] { |
c30ab7b3 SL |
946 | &self.message |
947 | } | |
948 | ||
923072b8 FG |
949 | /// Helper function that takes a `SubdiagnosticMessage` and returns a `DiagnosticMessage` by |
950 | /// combining it with the primary message of the diagnostic (if translatable, otherwise it just | |
951 | /// passes the user's string along). | |
952 | fn subdiagnostic_message_to_diagnostic_message( | |
953 | &self, | |
954 | attr: impl Into<SubdiagnosticMessage>, | |
955 | ) -> DiagnosticMessage { | |
956 | let msg = | |
957 | self.message.iter().map(|(msg, _)| msg).next().expect("diagnostic with no messages"); | |
958 | msg.with_subdiagnostic_message(attr.into()) | |
959 | } | |
960 | ||
c30ab7b3 SL |
961 | /// Convenience function for internal use, clients should use one of the |
962 | /// public methods above. | |
cdc7bbd5 XL |
963 | /// |
964 | /// Used by `proc_macro_server` for implementing `server::Diagnostic`. | |
dfeec247 XL |
965 | pub fn sub( |
966 | &mut self, | |
967 | level: Level, | |
923072b8 | 968 | message: impl Into<SubdiagnosticMessage>, |
dfeec247 XL |
969 | span: MultiSpan, |
970 | render_span: Option<MultiSpan>, | |
971 | ) { | |
c30ab7b3 | 972 | let sub = SubDiagnostic { |
3b2f2976 | 973 | level, |
923072b8 FG |
974 | message: vec![( |
975 | self.subdiagnostic_message_to_diagnostic_message(message), | |
976 | Style::NoStyle, | |
977 | )], | |
3b2f2976 XL |
978 | span, |
979 | render_span, | |
c30ab7b3 SL |
980 | }; |
981 | self.children.push(sub); | |
982 | } | |
32a655c1 SL |
983 | |
984 | /// Convenience function for internal use, clients should use one of the | |
985 | /// public methods above. | |
923072b8 | 986 | fn sub_with_highlights<M: Into<SubdiagnosticMessage>>( |
dfeec247 XL |
987 | &mut self, |
988 | level: Level, | |
f2b60f7d | 989 | message: Vec<(M, Style)>, |
dfeec247 XL |
990 | span: MultiSpan, |
991 | render_span: Option<MultiSpan>, | |
992 | ) { | |
923072b8 | 993 | let message = message |
f2b60f7d | 994 | .into_iter() |
923072b8 FG |
995 | .map(|m| (self.subdiagnostic_message_to_diagnostic_message(m.0), m.1)) |
996 | .collect(); | |
dfeec247 | 997 | let sub = SubDiagnostic { level, message, span, render_span }; |
32a655c1 SL |
998 | self.children.push(sub); |
999 | } | |
c295e0f8 XL |
1000 | |
1001 | /// Fields used for Hash, and PartialEq trait | |
1002 | fn keys( | |
1003 | &self, | |
1004 | ) -> ( | |
1005 | &Level, | |
923072b8 | 1006 | &[(DiagnosticMessage, Style)], |
c295e0f8 XL |
1007 | &Option<DiagnosticId>, |
1008 | &MultiSpan, | |
5099ac24 | 1009 | &Result<Vec<CodeSuggestion>, SuggestionsDisabled>, |
923072b8 | 1010 | Option<&[SubDiagnostic]>, |
c295e0f8 XL |
1011 | ) { |
1012 | ( | |
1013 | &self.level, | |
1014 | &self.message, | |
1015 | &self.code, | |
1016 | &self.span, | |
1017 | &self.suggestions, | |
1018 | (if self.is_lint { None } else { Some(&self.children) }), | |
1019 | ) | |
1020 | } | |
1021 | } | |
1022 | ||
1023 | impl Hash for Diagnostic { | |
1024 | fn hash<H>(&self, state: &mut H) | |
1025 | where | |
1026 | H: Hasher, | |
1027 | { | |
1028 | self.keys().hash(state); | |
1029 | } | |
1030 | } | |
1031 | ||
1032 | impl PartialEq for Diagnostic { | |
1033 | fn eq(&self, other: &Self) -> bool { | |
1034 | self.keys() == other.keys() | |
1035 | } | |
32a655c1 | 1036 | } |