1#![allow(rustc::diagnostic_outside_of_impl)]
2#![allow(rustc::untranslatable_diagnostic)]
3
4use std::borrow::Cow;
5
6use rustc_ast::util::unicode::TEXT_FLOW_CONTROL_CHARS;
7use rustc_errors::{
8 Applicability, Diag, DiagArgValue, LintDiagnostic, elided_lifetime_in_path_suggestion,
9};
10use rustc_middle::middle::stability;
11use rustc_middle::ty::TyCtxt;
12use rustc_session::Session;
13use rustc_session::lint::{BuiltinLintDiag, ElidedLifetimeResolution};
14use rustc_span::{BytePos, kw};
15use tracing::debug;
16
17use crate::lints::{self, ElidedNamedLifetime};
18
19mod check_cfg;
20
21pub(super) fn decorate_lint(
22 sess: &Session,
23 tcx: Option<TyCtxt<'_>>,
24 diagnostic: BuiltinLintDiag,
25 diag: &mut Diag<'_, ()>,
26) {
27 match diagnostic {
28 BuiltinLintDiag::UnicodeTextFlow(comment_span, content) => {
29 let spans: Vec<_> = content
30 .char_indices()
31 .filter_map(|(i, c)| {
32 TEXT_FLOW_CONTROL_CHARS.contains(&c).then(|| {
33 let lo = comment_span.lo() + BytePos(2 + i as u32);
34 (c, comment_span.with_lo(lo).with_hi(lo + BytePos(c.len_utf8() as u32)))
35 })
36 })
37 .collect();
38 let characters = spans
39 .iter()
40 .map(|&(c, span)| lints::UnicodeCharNoteSub { span, c_debug: format!("{c:?}") })
41 .collect();
42 let suggestions = (!spans.is_empty()).then_some(lints::UnicodeTextFlowSuggestion {
43 spans: spans.iter().map(|(_c, span)| *span).collect(),
44 });
45
46 lints::UnicodeTextFlow {
47 comment_span,
48 characters,
49 suggestions,
50 num_codepoints: spans.len(),
51 }
52 .decorate_lint(diag);
53 }
54 BuiltinLintDiag::AbsPathWithModule(mod_span) => {
55 let (replacement, applicability) = match sess.source_map().span_to_snippet(mod_span) {
56 Ok(ref s) => {
57 let opt_colon = if s.trim_start().starts_with("::") { "" } else { "::" };
60
61 (format!("crate{opt_colon}{s}"), Applicability::MachineApplicable)
62 }
63 Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
64 };
65 lints::AbsPathWithModule {
66 sugg: lints::AbsPathWithModuleSugg { span: mod_span, applicability, replacement },
67 }
68 .decorate_lint(diag);
69 }
70 BuiltinLintDiag::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident } => {
71 lints::ProcMacroDeriveResolutionFallback { span: macro_span, ns, ident }
72 .decorate_lint(diag)
73 }
74 BuiltinLintDiag::MacroExpandedMacroExportsAccessedByAbsolutePaths(span_def) => {
75 lints::MacroExpandedMacroExportsAccessedByAbsolutePaths { definition: span_def }
76 .decorate_lint(diag)
77 }
78
79 BuiltinLintDiag::ElidedLifetimesInPaths(n, path_span, incl_angl_brckt, insertion_span) => {
80 lints::ElidedLifetimesInPaths {
81 subdiag: elided_lifetime_in_path_suggestion(
82 sess.source_map(),
83 n,
84 path_span,
85 incl_angl_brckt,
86 insertion_span,
87 ),
88 }
89 .decorate_lint(diag);
90 }
91 BuiltinLintDiag::UnknownCrateTypes { span, candidate } => {
92 let sugg = candidate.map(|candidate| lints::UnknownCrateTypesSub { span, candidate });
93 lints::UnknownCrateTypes { sugg }.decorate_lint(diag);
94 }
95 BuiltinLintDiag::UnusedImports {
96 remove_whole_use,
97 num_to_remove,
98 remove_spans,
99 test_module_span,
100 span_snippets,
101 } => {
102 let sugg = if remove_whole_use {
103 lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
104 } else {
105 lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
106 };
107 let test_module_span =
108 test_module_span.map(|span| sess.source_map().guess_head_span(span));
109
110 lints::UnusedImports {
111 sugg,
112 test_module_span,
113 num_snippets: span_snippets.len(),
114 span_snippets: DiagArgValue::StrListSepByAnd(
115 span_snippets.into_iter().map(Cow::Owned).collect(),
116 ),
117 }
118 .decorate_lint(diag);
119 }
120 BuiltinLintDiag::RedundantImport(spans, ident) => {
121 let subs = spans
122 .into_iter()
123 .map(|(span, is_imported)| {
124 (match (span.is_dummy(), is_imported) {
125 (false, true) => lints::RedundantImportSub::ImportedHere,
126 (false, false) => lints::RedundantImportSub::DefinedHere,
127 (true, true) => lints::RedundantImportSub::ImportedPrelude,
128 (true, false) => lints::RedundantImportSub::DefinedPrelude,
129 })(span)
130 })
131 .collect();
132 lints::RedundantImport { subs, ident }.decorate_lint(diag);
133 }
134 BuiltinLintDiag::DeprecatedMacro {
135 suggestion,
136 suggestion_span,
137 note,
138 path,
139 since_kind,
140 } => {
141 let sub = suggestion.map(|suggestion| stability::DeprecationSuggestion {
142 span: suggestion_span,
143 kind: "macro".to_owned(),
144 suggestion,
145 });
146
147 stability::Deprecated { sub, kind: "macro".to_owned(), path, note, since_kind }
148 .decorate_lint(diag);
149 }
150 BuiltinLintDiag::UnusedDocComment(attr_span) => {
151 lints::UnusedDocComment { span: attr_span }.decorate_lint(diag);
152 }
153 BuiltinLintDiag::PatternsInFnsWithoutBody { span: remove_span, ident, is_foreign } => {
154 let sub = lints::PatternsInFnsWithoutBodySub { ident, span: remove_span };
155 if is_foreign {
156 lints::PatternsInFnsWithoutBody::Foreign { sub }
157 } else {
158 lints::PatternsInFnsWithoutBody::Bodiless { sub }
159 }
160 .decorate_lint(diag);
161 }
162 BuiltinLintDiag::MissingAbi(label_span, default_abi) => {
163 lints::MissingAbi { span: label_span, default_abi }.decorate_lint(diag);
164 }
165 BuiltinLintDiag::LegacyDeriveHelpers(label_span) => {
166 lints::LegacyDeriveHelpers { span: label_span }.decorate_lint(diag);
167 }
168 BuiltinLintDiag::OrPatternsBackCompat(suggestion_span, suggestion) => {
169 lints::OrPatternsBackCompat { span: suggestion_span, suggestion }.decorate_lint(diag);
170 }
171 BuiltinLintDiag::ReservedPrefix(label_span, prefix) => {
172 lints::ReservedPrefix {
173 label: label_span,
174 suggestion: label_span.shrink_to_hi(),
175 prefix,
176 }
177 .decorate_lint(diag);
178 }
179 BuiltinLintDiag::RawPrefix(label_span) => {
180 lints::RawPrefix { label: label_span, suggestion: label_span.shrink_to_hi() }
181 .decorate_lint(diag);
182 }
183 BuiltinLintDiag::ReservedString { is_string, suggestion } => {
184 if is_string {
185 lints::ReservedString { suggestion }.decorate_lint(diag);
186 } else {
187 lints::ReservedMultihash { suggestion }.decorate_lint(diag);
188 }
189 }
190 BuiltinLintDiag::UnusedBuiltinAttribute { attr_name, macro_name, invoc_span } => {
191 lints::UnusedBuiltinAttribute { invoc_span, attr_name, macro_name }.decorate_lint(diag);
192 }
193 BuiltinLintDiag::TrailingMacro(is_trailing, name) => {
194 lints::TrailingMacro { is_trailing, name }.decorate_lint(diag);
195 }
196 BuiltinLintDiag::BreakWithLabelAndLoop(sugg_span) => {
197 lints::BreakWithLabelAndLoop {
198 sub: lints::BreakWithLabelAndLoopSub {
199 left: sugg_span.shrink_to_lo(),
200 right: sugg_span.shrink_to_hi(),
201 },
202 }
203 .decorate_lint(diag);
204 }
205 BuiltinLintDiag::UnexpectedCfgName(name, value) => {
206 check_cfg::unexpected_cfg_name(sess, tcx, name, value).decorate_lint(diag);
207 }
208 BuiltinLintDiag::UnexpectedCfgValue(name, value) => {
209 check_cfg::unexpected_cfg_value(sess, tcx, name, value).decorate_lint(diag);
210 }
211 BuiltinLintDiag::DeprecatedWhereclauseLocation(left_sp, sugg) => {
212 let suggestion = match sugg {
213 Some((right_sp, sugg)) => lints::DeprecatedWhereClauseLocationSugg::MoveToEnd {
214 left: left_sp,
215 right: right_sp,
216 sugg,
217 },
218 None => lints::DeprecatedWhereClauseLocationSugg::RemoveWhere { span: left_sp },
219 };
220 lints::DeprecatedWhereClauseLocation { suggestion }.decorate_lint(diag);
221 }
222 BuiltinLintDiag::MissingUnsafeOnExtern { suggestion } => {
223 lints::MissingUnsafeOnExtern { suggestion }.decorate_lint(diag);
224 }
225 BuiltinLintDiag::SingleUseLifetime {
226 param_span,
227 use_span: Some((use_span, elide)),
228 deletion_span,
229 ident,
230 } => {
231 debug!(?param_span, ?use_span, ?deletion_span);
232 let suggestion = if let Some(deletion_span) = deletion_span {
233 let (use_span, replace_lt) = if elide {
234 let use_span = sess.source_map().span_extend_while_whitespace(use_span);
235 (use_span, String::new())
236 } else {
237 (use_span, "'_".to_owned())
238 };
239 debug!(?deletion_span, ?use_span);
240
241 let deletion_span =
244 if deletion_span.is_empty() { None } else { Some(deletion_span) };
245 Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt })
246 } else {
247 None
248 };
249
250 lints::SingleUseLifetime { suggestion, param_span, use_span, ident }
251 .decorate_lint(diag);
252 }
253 BuiltinLintDiag::SingleUseLifetime { use_span: None, deletion_span, ident, .. } => {
254 debug!(?deletion_span);
255 lints::UnusedLifetime { deletion_span, ident }.decorate_lint(diag);
256 }
257 BuiltinLintDiag::NamedArgumentUsedPositionally {
258 position_sp_to_replace,
259 position_sp_for_msg,
260 named_arg_sp,
261 named_arg_name,
262 is_formatting_arg,
263 } => {
264 let (suggestion, name) = if let Some(positional_arg_to_replace) = position_sp_to_replace
265 {
266 let mut name = named_arg_name.clone();
267 if is_formatting_arg {
268 name.push('$')
269 };
270 let span_to_replace = if let Ok(positional_arg_content) =
271 sess.source_map().span_to_snippet(positional_arg_to_replace)
272 && positional_arg_content.starts_with(':')
273 {
274 positional_arg_to_replace.shrink_to_lo()
275 } else {
276 positional_arg_to_replace
277 };
278 (Some(span_to_replace), name)
279 } else {
280 (None, String::new())
281 };
282
283 lints::NamedArgumentUsedPositionally {
284 named_arg_sp,
285 position_label_sp: position_sp_for_msg,
286 suggestion,
287 name,
288 named_arg_name,
289 }
290 .decorate_lint(diag);
291 }
292 BuiltinLintDiag::ByteSliceInPackedStructWithDerive { ty } => {
293 lints::ByteSliceInPackedStructWithDerive { ty }.decorate_lint(diag);
294 }
295 BuiltinLintDiag::UnusedExternCrate { removal_span } => {
296 lints::UnusedExternCrate { removal_span }.decorate_lint(diag);
297 }
298 BuiltinLintDiag::ExternCrateNotIdiomatic { vis_span, ident_span } => {
299 let suggestion_span = vis_span.between(ident_span);
300 let code = if vis_span.is_empty() { "use " } else { " use " };
301
302 lints::ExternCrateNotIdiomatic { span: suggestion_span, code }.decorate_lint(diag);
303 }
304 BuiltinLintDiag::AmbiguousGlobImports { diag: ambiguity } => {
305 lints::AmbiguousGlobImports { ambiguity }.decorate_lint(diag);
306 }
307 BuiltinLintDiag::AmbiguousGlobReexports {
308 name,
309 namespace,
310 first_reexport_span,
311 duplicate_reexport_span,
312 } => {
313 lints::AmbiguousGlobReexports {
314 first_reexport: first_reexport_span,
315 duplicate_reexport: duplicate_reexport_span,
316 name,
317 namespace,
318 }
319 .decorate_lint(diag);
320 }
321 BuiltinLintDiag::HiddenGlobReexports {
322 name,
323 namespace,
324 glob_reexport_span,
325 private_item_span,
326 } => {
327 lints::HiddenGlobReexports {
328 glob_reexport: glob_reexport_span,
329 private_item: private_item_span,
330
331 name,
332 namespace,
333 }
334 .decorate_lint(diag);
335 }
336 BuiltinLintDiag::UnusedQualifications { removal_span } => {
337 lints::UnusedQualifications { removal_span }.decorate_lint(diag);
338 }
339 BuiltinLintDiag::UnsafeAttrOutsideUnsafe {
340 attribute_name_span,
341 sugg_spans: (left, right),
342 } => {
343 lints::UnsafeAttrOutsideUnsafe {
344 span: attribute_name_span,
345 suggestion: lints::UnsafeAttrOutsideUnsafeSuggestion { left, right },
346 }
347 .decorate_lint(diag);
348 }
349 BuiltinLintDiag::AssociatedConstElidedLifetime {
350 elided,
351 span: lt_span,
352 lifetimes_in_scope,
353 } => {
354 let lt_span = if elided { lt_span.shrink_to_hi() } else { lt_span };
355 let code = if elided { "'static " } else { "'static" };
356 lints::AssociatedConstElidedLifetime {
357 span: lt_span,
358 code,
359 elided,
360 lifetimes_in_scope,
361 }
362 .decorate_lint(diag);
363 }
364 BuiltinLintDiag::RedundantImportVisibility { max_vis, span: vis_span, import_vis } => {
365 lints::RedundantImportVisibility { span: vis_span, help: (), max_vis, import_vis }
366 .decorate_lint(diag);
367 }
368 BuiltinLintDiag::UnknownDiagnosticAttribute { span: typo_span, typo_name } => {
369 let typo = typo_name.map(|typo_name| lints::UnknownDiagnosticAttributeTypoSugg {
370 span: typo_span,
371 typo_name,
372 });
373 lints::UnknownDiagnosticAttribute { typo }.decorate_lint(diag);
374 }
375 BuiltinLintDiag::MacroUseDeprecated => {
376 lints::MacroUseDeprecated.decorate_lint(diag);
377 }
378 BuiltinLintDiag::UnusedMacroUse => lints::UnusedMacroUse.decorate_lint(diag),
379 BuiltinLintDiag::PrivateExternCrateReexport { source: ident, extern_crate_span } => {
380 lints::PrivateExternCrateReexport { ident, sugg: extern_crate_span.shrink_to_lo() }
381 .decorate_lint(diag);
382 }
383 BuiltinLintDiag::UnusedLabel => lints::UnusedLabel.decorate_lint(diag),
384 BuiltinLintDiag::MacroIsPrivate(ident) => {
385 lints::MacroIsPrivate { ident }.decorate_lint(diag);
386 }
387 BuiltinLintDiag::UnusedMacroDefinition(name) => {
388 lints::UnusedMacroDefinition { name }.decorate_lint(diag);
389 }
390 BuiltinLintDiag::MacroRuleNeverUsed(n, name) => {
391 lints::MacroRuleNeverUsed { n: n + 1, name }.decorate_lint(diag);
392 }
393 BuiltinLintDiag::UnstableFeature(msg) => {
394 lints::UnstableFeature { msg }.decorate_lint(diag);
395 }
396 BuiltinLintDiag::AvoidUsingIntelSyntax => {
397 lints::AvoidIntelSyntax.decorate_lint(diag);
398 }
399 BuiltinLintDiag::AvoidUsingAttSyntax => {
400 lints::AvoidAttSyntax.decorate_lint(diag);
401 }
402 BuiltinLintDiag::IncompleteInclude => {
403 lints::IncompleteInclude.decorate_lint(diag);
404 }
405 BuiltinLintDiag::UnnameableTestItems => {
406 lints::UnnameableTestItems.decorate_lint(diag);
407 }
408 BuiltinLintDiag::DuplicateMacroAttribute => {
409 lints::DuplicateMacroAttribute.decorate_lint(diag);
410 }
411 BuiltinLintDiag::CfgAttrNoAttributes => {
412 lints::CfgAttrNoAttributes.decorate_lint(diag);
413 }
414 BuiltinLintDiag::MissingFragmentSpecifier => {
415 lints::MissingFragmentSpecifier.decorate_lint(diag);
416 }
417 BuiltinLintDiag::MetaVariableStillRepeating(name) => {
418 lints::MetaVariableStillRepeating { name }.decorate_lint(diag);
419 }
420 BuiltinLintDiag::MetaVariableWrongOperator => {
421 lints::MetaVariableWrongOperator.decorate_lint(diag);
422 }
423 BuiltinLintDiag::DuplicateMatcherBinding => {
424 lints::DuplicateMatcherBinding.decorate_lint(diag);
425 }
426 BuiltinLintDiag::UnknownMacroVariable(name) => {
427 lints::UnknownMacroVariable { name }.decorate_lint(diag);
428 }
429 BuiltinLintDiag::UnusedCrateDependency { extern_crate, local_crate } => {
430 lints::UnusedCrateDependency { extern_crate, local_crate }.decorate_lint(diag)
431 }
432 BuiltinLintDiag::IllFormedAttributeInput { suggestions } => {
433 lints::IllFormedAttributeInput {
434 num_suggestions: suggestions.len(),
435 suggestions: DiagArgValue::StrListSepByAnd(
436 suggestions.into_iter().map(|s| format!("`{s}`").into()).collect(),
437 ),
438 }
439 .decorate_lint(diag)
440 }
441 BuiltinLintDiag::InnerAttributeUnstable { is_macro } => if is_macro {
442 lints::InnerAttributeUnstable::InnerMacroAttribute
443 } else {
444 lints::InnerAttributeUnstable::CustomInnerAttribute
445 }
446 .decorate_lint(diag),
447 BuiltinLintDiag::OutOfScopeMacroCalls { path } => {
448 lints::OutOfScopeMacroCalls { path }.decorate_lint(diag)
449 }
450 BuiltinLintDiag::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by } => {
451 lints::UnexpectedBuiltinCfg { cfg, cfg_name, controlled_by }.decorate_lint(diag)
452 }
453 BuiltinLintDiag::ElidedNamedLifetimes { elided: (span, kind), resolution } => {
454 match resolution {
455 ElidedLifetimeResolution::Static => {
456 ElidedNamedLifetime { span, kind, name: kw::StaticLifetime, declaration: None }
457 }
458 ElidedLifetimeResolution::Param(name, declaration) => {
459 ElidedNamedLifetime { span, kind, name, declaration: Some(declaration) }
460 }
461 }
462 .decorate_lint(diag)
463 }
464 }
465}