1use std::borrow::Cow;
2
3use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
4use rustc_errors::{
5 Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
6 elided_lifetime_in_path_suggestion,
7};
8use rustc_hir::lints::{AttributeLintKind, FormatWarning};
9use rustc_middle::middle::stability;
10use rustc_middle::ty::TyCtxt;
11use rustc_session::Session;
12use rustc_session::lint::BuiltinLintDiag;
13use rustc_span::BytePos;
14use tracing::debug;
15
16use crate::lints;
17
18mod check_cfg;
19
20pub struct DecorateBuiltinLint<'sess, 'tcx> {
23 pub sess: &'sess Session,
24 pub tcx: Option<TyCtxt<'tcx>>,
25 pub diagnostic: BuiltinLintDiag,
26}
27
28impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
29 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
30 match self.diagnostic {
31 BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
32 let spans: Vec<_> = content
33 .char_indices()
34 .filter_map(|(i, c)| {
35 TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
36 let lo = comment_span.lo() + BytePos(2 + i as u32);
37 (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
38 })
39 })
40 .collect();
41 let characters = spans
42 .iter()
43 .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0:?}", c))
})format!("{c:?}") })
44 .collect();
45 let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
46 spans: spans.iter().map(|(_c, span)| *span).collect(),
47 });
48
49 lints::UnicodeTextFlow {
50 comment_span,
51 characters,
52 suggestions,
53 num_codepoints: spans.len(),
54 }
55 .into_diag(dcx, level)
56 }
57 BuiltinLintDiag::AbsPathWithModule(mod_span) => {
58 let (replacement, applicability) =
59 match self.sess.source_map().span_to_snippet(mod_span) {
60 Ok(ref s) => {
61 let opt_colon =
64 if s.trim_start().starts_with("::") { "" } else { "::" };
65
66 (::alloc::__export::must_use({
::alloc::fmt::format(format_args!("crate{0}{1}", opt_colon, s))
})format!("crate{opt_colon}{s}"), Applicability::MachineApplicable)
67 }
68 Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
69 };
70 lints::AbsPathWithModule {
71 sugg: lints::AbsPathWithModuleSugg {
72 span: mod_span,
73 applicability,
74 replacement,
75 },
76 }
77 .into_diag(dcx, level)
78 }
79 BuiltinLintDiag::ElidedLifetimesInPaths(
80 n,
81 path_span,
82 incl_angl_brckt,
83 insertion_span,
84 ) => lints::ElidedLifetimesInPaths {
85 subdiag: elided_lifetime_in_path_suggestion(
86 self.sess.source_map(),
87 n,
88 path_span,
89 incl_angl_brckt,
90 insertion_span,
91 ),
92 }
93 .into_diag(dcx, level),
94 BuiltinLintDiag::UnusedImports {
95 remove_whole_use,
96 num_to_remove,
97 remove_spans,
98 test_module_span,
99 span_snippets,
100 } => {
101 let sugg = if remove_whole_use {
102 lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
103 } else {
104 lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
105 };
106 let test_module_span =
107 test_module_span.map(|span| self.sess.source_map().guess_head_span(span));
108
109 lints::UnusedImports {
110 sugg,
111 test_module_span,
112 num_snippets: span_snippets.len(),
113 span_snippets: DiagArgValue::StrListSepByAnd(
114 span_snippets.into_iter().map(Cow::Owned).collect(),
115 ),
116 }
117 .into_diag(dcx, level)
118 }
119 BuiltinLintDiag::RedundantImport(spans, ident) => {
120 let subs = spans
121 .into_iter()
122 .map(|(span, is_imported)| match (span.is_dummy(), is_imported) {
123 (false, true) => lints::RedundantImportSub::ImportedHere { span, ident },
124 (false, false) => lints::RedundantImportSub::DefinedHere { span, ident },
125 (true, true) => lints::RedundantImportSub::ImportedPrelude { span, ident },
126 (true, false) => lints::RedundantImportSub::DefinedPrelude { span, ident },
127 })
128 .collect();
129 lints::RedundantImport { subs, ident }.into_diag(dcx, level)
130 }
131 BuiltinLintDiag::DeprecatedMacro {
132 suggestion,
133 suggestion_span,
134 note,
135 path,
136 since_kind,
137 } => {
138 let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion {
139 span: suggestion_span,
140 kind: "macro".to_owned(),
141 suggestion,
142 });
143
144 stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }
145 .into_diag(dcx, level)
146 }
147 BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => {
148 let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span };
149 if is_foreign {
150 lints::PatternsInFnsWithoutBody::Foreign { sub }
151 } else {
152 lints::PatternsInFnsWithoutBody::Bodiless { sub }
153 }
154 .into_diag(dcx, level)
155 }
156 BuiltinLintDiag::ReservedPrefix(label_span, prefix) => lints::ReservedPrefix {
157 label: label_span,
158 suggestion: label_span.shrink_to_hi(),
159 prefix,
160 }
161 .into_diag(dcx, level),
162 BuiltinLintDiag::RawPrefix(label_span) => {
163 lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }
164 .into_diag(dcx, level)
165 }
166 BuiltinLintDiag::ReservedString { is_string, suggestion } => {
167 if is_string {
168 lints::ReservedString { suggestion }.into_diag(dcx, level)
169 } else {
170 lints::ReservedMultihash { suggestion }.into_diag(dcx, level)
171 }
172 }
173 BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => lints::BreakWithLabelAndLoop {
174 sub: lints::BreakWithLabelAndLoopSub {
175 left: sugg_span.shrink_to_lo(),
176 right: sugg_span.shrink_to_hi(),
177 },
178 }
179 .into_diag(dcx, level),
180 BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
181 let suggestion = match sugg {
182 Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
183 left: left_sp,
184 right: right_sp,
185 sugg,
186 },
187 None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp },
188 };
189 lints::DeprecatedWhereClauseLocation { suggestion }.into_diag(dcx, level)
190 }
191 BuiltinLintDiag::SingleUseLifetime {
192 param_span,
193 use_span: Some((use_span, elide)),
194 deletion_span,
195 ident,
196 } => {
197 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/early/diagnostics.rs:197",
"rustc_lint::early::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/early/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(197u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::early::diagnostics"),
::tracing_core::field::FieldSet::new(&["param_span",
"use_span", "deletion_span"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(¶m_span)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&use_span)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&deletion_span)
as &dyn Value))])
});
} else { ; }
};debug!(?param_span, ?use_span, ?deletion_span);
198 let suggestion = if let Some(deletion_span) = deletion_span {
199 let (use_span, replace_lt) = if elide {
200 let use_span =
201 self.sess.source_map().span_extend_while_whitespace(use_span);
202 (use_span, String::new())
203 } else {
204 (use_span, "'_".to_owned())
205 };
206 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/early/diagnostics.rs:206",
"rustc_lint::early::diagnostics", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/early/diagnostics.rs"),
::tracing_core::__macro_support::Option::Some(206u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::early::diagnostics"),
::tracing_core::field::FieldSet::new(&["deletion_span",
"use_span"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&deletion_span)
as &dyn Value)),
(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&use_span)
as &dyn Value))])
});
} else { ; }
};debug!(?deletion_span, ?use_span);
207
208 let deletion_span =
211 if deletion_span.is_empty() { None } else { Some(deletion_span) };
212 Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt })
213 } else {
214 None
215 };
216
217 lints::SingleUseLifetime { suggestion, param_span, use_span, ident }
218 .into_diag(dcx, level)
219 }
220 BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => {
221 lints::UnusedLifetime { deletion_span, ident }.into_diag(dcx, level)
222 }
223 BuiltinLintDiag::NamedArgumentUsedPositionally {
224 position_sp_to_replace,
225 position_sp_for_msg,
226 named_arg_sp,
227 named_arg_name,
228 is_formatting_arg,
229 } => {
230 let (suggestion, name) =
231 if let Some(positional_arg_to_replace) = position_sp_to_replace {
232 let mut name = named_arg_name.clone();
233 if is_formatting_arg {
234 name.push('$')
235 };
236 let span_to_replace = if let Ok(positional_arg_content) =
237 self.sess.source_map().span_to_snippet(positional_arg_to_replace)
238 && positional_arg_content.starts_with(':')
239 {
240 positional_arg_to_replace.shrink_to_lo()
241 } else {
242 positional_arg_to_replace
243 };
244 (Some(span_to_replace), name)
245 } else {
246 (None, String::new())
247 };
248
249 lints::NamedArgumentUsedPositionally {
250 named_arg_sp,
251 position_label_sp: position_sp_for_msg,
252 suggestion,
253 name,
254 named_arg_name,
255 }
256 .into_diag(dcx, level)
257 }
258 BuiltinLintDiag::AmbiguousGlobReexports {
259 name,
260 namespace,
261 first_reexport_span,
262 duplicate_reexport_span,
263 } => lints::AmbiguousGlobReexports {
264 first_reexport: first_reexport_span,
265 duplicate_reexport: duplicate_reexport_span,
266 name,
267 namespace,
268 }
269 .into_diag(dcx, level),
270 BuiltinLintDiag::HiddenGlobReexports {
271 name,
272 namespace,
273 glob_reexport_span,
274 private_item_span,
275 } => lints::HiddenGlobReexports {
276 glob_reexport: glob_reexport_span,
277 private_item: private_item_span,
278
279 name,
280 namespace,
281 }
282 .into_diag(dcx, level),
283 BuiltinLintDiag::UnusedQualifications { removal_span } => {
284 lints::UnusedQualifications { removal_span }.into_diag(dcx, level)
285 }
286 BuiltinLintDiag::AssociatedConstElidedLifetime {
287 elided,
288 span: lt_span,
289 lifetimes_in_scope,
290 } => {
291 let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span };
292 let code = if elided { "'static " } else { "'static" };
293 lints::AssociatedConstElidedLifetime {
294 span: lt_span,
295 code,
296 elided,
297 lifetimes_in_scope,
298 }
299 .into_diag(dcx, level)
300 }
301 BuiltinLintDiag::UnreachableCfg { span, wildcard_span } => match wildcard_span {
302 Some(wildcard_span) => {
303 lints::UnreachableCfgSelectPredicateWildcard { span, wildcard_span }
304 .into_diag(dcx, level)
305 }
306 None => lints::UnreachableCfgSelectPredicate { span }.into_diag(dcx, level),
307 },
308
309 BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
310 lints::UnusedCrateDependency { extern_crate, local_crate }.into_diag(dcx, level)
311 }
312 BuiltinLintDiag::UnusedVisibility(span) => {
313 lints::UnusedVisibility { span }.into_diag(dcx, level)
314 }
315 BuiltinLintDiag::AttributeLint(kind) => {
316 DecorateAttrLint { sess: self.sess, tcx: self.tcx, diagnostic: &kind }
317 .into_diag(dcx, level)
318 }
319 }
320 }
321}
322
323pub struct DecorateAttrLint<'a, 'sess, 'tcx> {
326 pub sess: &'sess Session,
327 pub tcx: Option<TyCtxt<'tcx>>,
328 pub diagnostic: &'a AttributeLintKind,
329}
330
331impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
332 fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
333 match self.diagnostic {
334 &AttributeLintKind::UnusedDuplicate { this, other, warning } => {
335 lints::UnusedDuplicate { this, other, warning }.into_diag(dcx, level)
336 }
337 AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => {
338 lints::IllFormedAttributeInput {
339 num_suggestions: suggestions.len(),
340 suggestions: DiagArgValue::StrListSepByAnd(
341 suggestions.into_iter().map(|s| ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("`{0}`", s))
})format!("`{s}`").into()).collect(),
342 ),
343 has_docs: docs.is_some(),
344 docs: docs.unwrap_or(""),
345 }
346 .into_diag(dcx, level)
347 }
348 AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => {
349 lints::EmptyAttributeList {
350 attr_span: *first_span,
351 attr_path: attr_path.clone(),
352 valid_without_list: *valid_without_list,
353 }
354 .into_diag(dcx, level)
355 }
356 AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => {
357 lints::InvalidTargetLint {
358 name: name.clone(),
359 target,
360 applied: DiagArgValue::StrListSepByAnd(
361 applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(),
362 ),
363 only,
364 attr_span: *attr_span,
365 }
366 .into_diag(dcx, level)
367 }
368 &AttributeLintKind::InvalidStyle {
369 ref name,
370 is_used_as_inner,
371 target,
372 target_span,
373 } => lints::InvalidAttrStyle {
374 name: name.clone(),
375 is_used_as_inner,
376 target_span: (!is_used_as_inner).then_some(target_span),
377 target,
378 }
379 .into_diag(dcx, level),
380 &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => {
381 lints::UnsafeAttrOutsideUnsafeLint {
382 span: attribute_name_span,
383 suggestion: sugg_spans.map(|(left, right)| {
384 lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }
385 }),
386 }
387 .into_diag(dcx, level)
388 }
389 &AttributeLintKind::UnexpectedCfgName(name, value) => {
390 check_cfg::unexpected_cfg_name(self.sess, self.tcx, name, value)
391 .into_diag(dcx, level)
392 }
393 &AttributeLintKind::UnexpectedCfgValue(name, value) => {
394 check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value)
395 .into_diag(dcx, level)
396 }
397 &AttributeLintKind::DuplicateDocAlias { first_definition } => {
398 lints::DocAliasDuplicated { first_defn: first_definition }.into_diag(dcx, level)
399 }
400
401 &AttributeLintKind::DocAutoCfgExpectsHideOrShow => {
402 lints::DocAutoCfgExpectsHideOrShow.into_diag(dcx, level)
403 }
404
405 &AttributeLintKind::AmbiguousDeriveHelpers => {
406 lints::AmbiguousDeriveHelpers.into_diag(dcx, level)
407 }
408
409 &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => {
410 lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.into_diag(dcx, level)
411 }
412
413 &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => {
414 lints::DocAutoCfgHideShowExpectsList { attr_name }.into_diag(dcx, level)
415 }
416
417 &AttributeLintKind::DocInvalid => lints::DocInvalid.into_diag(dcx, level),
418
419 &AttributeLintKind::DocUnknownInclude { span, inner, value } => {
420 lints::DocUnknownInclude {
421 inner,
422 value,
423 sugg: (span, Applicability::MaybeIncorrect),
424 }
425 .into_diag(dcx, level)
426 }
427
428 &AttributeLintKind::DocUnknownSpotlight { span } => {
429 lints::DocUnknownSpotlight { sugg_span: span }.into_diag(dcx, level)
430 }
431
432 &AttributeLintKind::DocUnknownPasses { name, span } => {
433 lints::DocUnknownPasses { name, note_span: span }.into_diag(dcx, level)
434 }
435
436 &AttributeLintKind::DocUnknownPlugins { span } => {
437 lints::DocUnknownPlugins { label_span: span }.into_diag(dcx, level)
438 }
439
440 &AttributeLintKind::DocUnknownAny { name } => {
441 lints::DocUnknownAny { name }.into_diag(dcx, level)
442 }
443
444 &AttributeLintKind::DocAutoCfgWrongLiteral => {
445 lints::DocAutoCfgWrongLiteral.into_diag(dcx, level)
446 }
447
448 &AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.into_diag(dcx, level),
449
450 &AttributeLintKind::DocTestUnknown { name } => {
451 lints::DocTestUnknown { name }.into_diag(dcx, level)
452 }
453
454 &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.into_diag(dcx, level),
455
456 &AttributeLintKind::AttrCrateLevelOnly => {
457 lints::AttrCrateLevelOnly.into_diag(dcx, level)
458 }
459
460 &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => {
461 lints::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level)
462 }
463
464 &AttributeLintKind::CrateTypeUnknown { span, suggested } => lints::UnknownCrateTypes {
465 sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }),
466 }
467 .into_diag(dcx, level),
468
469 &AttributeLintKind::MalformedDoc => lints::MalformedDoc.into_diag(dcx, level),
470
471 &AttributeLintKind::ExpectedNoArgs => lints::ExpectedNoArgs.into_diag(dcx, level),
472
473 &AttributeLintKind::ExpectedNameValue => lints::ExpectedNameValue.into_diag(dcx, level),
474 &AttributeLintKind::MalformedOnUnimplementedAttr { span } => {
475 lints::MalformedOnUnimplementedAttrLint { span }.into_diag(dcx, level)
476 }
477 &AttributeLintKind::MalformedOnConstAttr { span } => {
478 lints::MalformedOnConstAttrLint { span }.into_diag(dcx, level)
479 }
480 AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning {
481 FormatWarning::PositionalArgument { .. } => {
482 lints::DisallowedPositionalArgument.into_diag(dcx, level)
483 }
484 FormatWarning::InvalidSpecifier { .. } => {
485 lints::InvalidFormatSpecifier.into_diag(dcx, level)
486 }
487 },
488 AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => {
489 lints::WrappedParserError { description, label, span: *span }.into_diag(dcx, level)
490 }
491 &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => {
492 lints::IgnoredDiagnosticOption { option_name, first_span, later_span }
493 .into_diag(dcx, level)
494 }
495 &AttributeLintKind::MissingOptionsForOnUnimplemented => {
496 lints::MissingOptionsForOnUnimplementedAttr.into_diag(dcx, level)
497 }
498 &AttributeLintKind::MissingOptionsForOnConst => {
499 lints::MissingOptionsForOnConstAttr.into_diag(dcx, level)
500 }
501 }
502 }
503}