Skip to main content

rustc_lint/early/
diagnostics.rs

1use std::borrow::Cow;
2
3use rustc_errors::{
4    Applicability, Diag, DiagArgValue, DiagCtxtHandle, Diagnostic, Level,
5    elided_lifetime_in_path_suggestion,
6};
7use rustc_hir::lints::{AttributeLintKind, FormatWarning};
8use rustc_middle::ty::TyCtxt;
9use rustc_session::Session;
10use rustc_session::lint::BuiltinLintDiag;
11use tracing::debug;
12
13use crate::lints;
14
15mod check_cfg;
16
17/// This is a diagnostic struct that will decorate a `BuiltinLintDiag`
18/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
19pub struct DecorateBuiltinLint<'sess, 'tcx> {
20    pub sess: &'sess Session,
21    pub tcx: Option<TyCtxt<'tcx>>,
22    pub diagnostic: BuiltinLintDiag,
23}
24
25impl<'a> Diagnostic<'a, ()> for DecorateBuiltinLint<'_, '_> {
26    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
27        match self.diagnostic {
28            BuiltinLintDiag::AbsPathWithModule(mod_span) => {
29                let (replacement, applicability) =
30                    match self.sess.source_map().span_to_snippet(mod_span) {
31                        Ok(ref s) => {
32                            // FIXME(Manishearth) ideally the emitting code
33                            // can tell us whether or not this is global
34                            let opt_colon =
35                                if s.trim_start().starts_with("::") { "" } else { "::" };
36
37                            (::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("crate{0}{1}", opt_colon, s))
    })format!("crate{opt_colon}{s}"), Applicability::MachineApplicable)
38                        }
39                        Err(_) => ("crate::<path>".to_string(), Applicability::HasPlaceholders),
40                    };
41                lints::AbsPathWithModule {
42                    sugg: lints::AbsPathWithModuleSugg {
43                        span: mod_span,
44                        applicability,
45                        replacement,
46                    },
47                }
48                .into_diag(dcx, level)
49            }
50            BuiltinLintDiag::ElidedLifetimesInPaths(
51                n,
52                path_span,
53                incl_angl_brckt,
54                insertion_span,
55            ) => lints::ElidedLifetimesInPaths {
56                subdiag: elided_lifetime_in_path_suggestion(
57                    self.sess.source_map(),
58                    n,
59                    path_span,
60                    incl_angl_brckt,
61                    insertion_span,
62                ),
63            }
64            .into_diag(dcx, level),
65            BuiltinLintDiag::UnusedImports {
66                remove_whole_use,
67                num_to_remove,
68                remove_spans,
69                test_module_span,
70                span_snippets,
71            } => {
72                let sugg = if remove_whole_use {
73                    lints::UnusedImportsSugg::RemoveWholeUse { span: remove_spans[0] }
74                } else {
75                    lints::UnusedImportsSugg::RemoveImports { remove_spans, num_to_remove }
76                };
77                let test_module_span =
78                    test_module_span.map(|span| self.sess.source_map().guess_head_span(span));
79
80                lints::UnusedImports {
81                    sugg,
82                    test_module_span,
83                    num_snippets: span_snippets.len(),
84                    span_snippets: DiagArgValue::StrListSepByAnd(
85                        span_snippets.into_iter().map(Cow::Owned).collect(),
86                    ),
87                }
88                .into_diag(dcx, level)
89            }
90            BuiltinLintDiag::SingleUseLifetime {
91                param_span,
92                use_span,
93                elidable,
94                deletion_span,
95                ident,
96            } => {
97                {
    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:97",
                        "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(97u32),
                        ::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(&param_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);
98                let suggestion = if let Some(deletion_span) = deletion_span {
99                    let (use_span, replace_lt) = if elidable {
100                        let use_span =
101                            self.sess.source_map().span_extend_while_whitespace(use_span);
102                        (use_span, String::new())
103                    } else {
104                        (use_span, "'_".to_owned())
105                    };
106                    {
    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:106",
                        "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(106u32),
                        ::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);
107
108                    // issue 107998 for the case such as a wrong function pointer type
109                    // `deletion_span` is empty and there is no need to report lifetime uses here
110                    let deletion_span =
111                        if deletion_span.is_empty() { None } else { Some(deletion_span) };
112                    Some(lints::SingleUseLifetimeSugg { deletion_span, use_span, replace_lt })
113                } else {
114                    None
115                };
116
117                lints::SingleUseLifetime { suggestion, param_span, use_span, ident }
118                    .into_diag(dcx, level)
119            }
120            BuiltinLintDiag::NamedArgumentUsedPositionally {
121                position_sp_to_replace,
122                position_sp_for_msg,
123                named_arg_sp,
124                named_arg_name,
125                is_formatting_arg,
126            } => {
127                let (suggestion, name) =
128                    if let Some(positional_arg_to_replace) = position_sp_to_replace {
129                        let mut name = named_arg_name.clone();
130                        if is_formatting_arg {
131                            name.push('$')
132                        };
133                        let span_to_replace = if let Ok(positional_arg_content) =
134                            self.sess.source_map().span_to_snippet(positional_arg_to_replace)
135                            && positional_arg_content.starts_with(':')
136                        {
137                            positional_arg_to_replace.shrink_to_lo()
138                        } else {
139                            positional_arg_to_replace
140                        };
141                        (Some(span_to_replace), name)
142                    } else {
143                        (None, String::new())
144                    };
145
146                lints::NamedArgumentUsedPositionally {
147                    named_arg_sp,
148                    position_label_sp: position_sp_for_msg,
149                    suggestion,
150                    name,
151                    named_arg_name,
152                }
153                .into_diag(dcx, level)
154            }
155
156            BuiltinLintDiag::AttributeLint(kind) => {
157                DecorateAttrLint { sess: self.sess, tcx: self.tcx, diagnostic: &kind }
158                    .into_diag(dcx, level)
159            }
160        }
161    }
162}
163
164/// This is a diagnostic struct that will decorate a `AttributeLintKind`
165/// Directly creating the lint structs is expensive, using this will only decorate the lint structs when needed.
166pub struct DecorateAttrLint<'a, 'sess, 'tcx> {
167    pub sess: &'sess Session,
168    pub tcx: Option<TyCtxt<'tcx>>,
169    pub diagnostic: &'a AttributeLintKind,
170}
171
172impl<'a> Diagnostic<'a, ()> for DecorateAttrLint<'_, '_, '_> {
173    fn into_diag(self, dcx: DiagCtxtHandle<'a>, level: Level) -> Diag<'a, ()> {
174        match self.diagnostic {
175            &AttributeLintKind::UnusedDuplicate { this, other, warning } => {
176                lints::UnusedDuplicate { this, other, warning }.into_diag(dcx, level)
177            }
178            AttributeLintKind::IllFormedAttributeInput { suggestions, docs } => {
179                lints::IllFormedAttributeInput {
180                    num_suggestions: suggestions.len(),
181                    suggestions: DiagArgValue::StrListSepByAnd(
182                        suggestions.into_iter().map(|s| ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("`{0}`", s))
    })format!("`{s}`").into()).collect(),
183                    ),
184                    has_docs: docs.is_some(),
185                    docs: docs.unwrap_or(""),
186                }
187                .into_diag(dcx, level)
188            }
189            AttributeLintKind::EmptyAttribute { first_span, attr_path, valid_without_list } => {
190                lints::EmptyAttributeList {
191                    attr_span: *first_span,
192                    attr_path: attr_path.clone(),
193                    valid_without_list: *valid_without_list,
194                }
195                .into_diag(dcx, level)
196            }
197            AttributeLintKind::InvalidTarget { name, target, applied, only, attr_span } => {
198                lints::InvalidTargetLint {
199                    name: name.clone(),
200                    target,
201                    applied: DiagArgValue::StrListSepByAnd(
202                        applied.into_iter().map(|i| Cow::Owned(i.to_string())).collect(),
203                    ),
204                    only,
205                    attr_span: *attr_span,
206                }
207                .into_diag(dcx, level)
208            }
209            &AttributeLintKind::InvalidStyle {
210                ref name,
211                is_used_as_inner,
212                target,
213                target_span,
214            } => lints::InvalidAttrStyle {
215                name: name.clone(),
216                is_used_as_inner,
217                target_span: (!is_used_as_inner).then_some(target_span),
218                target,
219            }
220            .into_diag(dcx, level),
221            &AttributeLintKind::UnsafeAttrOutsideUnsafe { attribute_name_span, sugg_spans } => {
222                lints::UnsafeAttrOutsideUnsafeLint {
223                    span: attribute_name_span,
224                    suggestion: sugg_spans.map(|(left, right)| {
225                        lints::UnsafeAttrOutsideUnsafeSuggestion { left, right }
226                    }),
227                }
228                .into_diag(dcx, level)
229            }
230            &AttributeLintKind::UnexpectedCfgName(name, value) => {
231                check_cfg::unexpected_cfg_name(self.sess, self.tcx, name, value)
232                    .into_diag(dcx, level)
233            }
234            &AttributeLintKind::UnexpectedCfgValue(name, value) => {
235                check_cfg::unexpected_cfg_value(self.sess, self.tcx, name, value)
236                    .into_diag(dcx, level)
237            }
238            &AttributeLintKind::DuplicateDocAlias { first_definition } => {
239                lints::DocAliasDuplicated { first_defn: first_definition }.into_diag(dcx, level)
240            }
241
242            &AttributeLintKind::DocAutoCfgExpectsHideOrShow => {
243                lints::DocAutoCfgExpectsHideOrShow.into_diag(dcx, level)
244            }
245
246            &AttributeLintKind::AmbiguousDeriveHelpers => {
247                lints::AmbiguousDeriveHelpers.into_diag(dcx, level)
248            }
249
250            &AttributeLintKind::DocAutoCfgHideShowUnexpectedItem { attr_name } => {
251                lints::DocAutoCfgHideShowUnexpectedItem { attr_name }.into_diag(dcx, level)
252            }
253
254            &AttributeLintKind::DocAutoCfgHideShowExpectsList { attr_name } => {
255                lints::DocAutoCfgHideShowExpectsList { attr_name }.into_diag(dcx, level)
256            }
257
258            &AttributeLintKind::DocInvalid => lints::DocInvalid.into_diag(dcx, level),
259
260            &AttributeLintKind::DocUnknownInclude { span, inner, value } => {
261                lints::DocUnknownInclude {
262                    inner,
263                    value,
264                    sugg: (span, Applicability::MaybeIncorrect),
265                }
266                .into_diag(dcx, level)
267            }
268
269            &AttributeLintKind::DocUnknownSpotlight { span } => {
270                lints::DocUnknownSpotlight { sugg_span: span }.into_diag(dcx, level)
271            }
272
273            &AttributeLintKind::DocUnknownPasses { name, span } => {
274                lints::DocUnknownPasses { name, note_span: span }.into_diag(dcx, level)
275            }
276
277            &AttributeLintKind::DocUnknownPlugins { span } => {
278                lints::DocUnknownPlugins { label_span: span }.into_diag(dcx, level)
279            }
280
281            &AttributeLintKind::DocUnknownAny { name } => {
282                lints::DocUnknownAny { name }.into_diag(dcx, level)
283            }
284
285            &AttributeLintKind::DocAutoCfgWrongLiteral => {
286                lints::DocAutoCfgWrongLiteral.into_diag(dcx, level)
287            }
288
289            &AttributeLintKind::DocTestTakesList => lints::DocTestTakesList.into_diag(dcx, level),
290
291            &AttributeLintKind::DocTestUnknown { name } => {
292                lints::DocTestUnknown { name }.into_diag(dcx, level)
293            }
294
295            &AttributeLintKind::DocTestLiteral => lints::DocTestLiteral.into_diag(dcx, level),
296
297            &AttributeLintKind::AttrCrateLevelOnly => {
298                lints::AttrCrateLevelOnly.into_diag(dcx, level)
299            }
300
301            &AttributeLintKind::DoNotRecommendDoesNotExpectArgs => {
302                lints::DoNotRecommendDoesNotExpectArgs.into_diag(dcx, level)
303            }
304
305            &AttributeLintKind::CrateTypeUnknown { span, suggested } => lints::UnknownCrateTypes {
306                sugg: suggested.map(|s| lints::UnknownCrateTypesSuggestion { span, snippet: s }),
307            }
308            .into_diag(dcx, level),
309
310            &AttributeLintKind::MalformedDoc => lints::MalformedDoc.into_diag(dcx, level),
311
312            &AttributeLintKind::ExpectedNoArgs => lints::ExpectedNoArgs.into_diag(dcx, level),
313
314            &AttributeLintKind::ExpectedNameValue => lints::ExpectedNameValue.into_diag(dcx, level),
315            &AttributeLintKind::MalformedOnUnimplementedAttr { span } => {
316                lints::MalformedOnUnimplementedAttrLint { span }.into_diag(dcx, level)
317            }
318            &AttributeLintKind::MalformedOnConstAttr { span } => {
319                lints::MalformedOnConstAttrLint { span }.into_diag(dcx, level)
320            }
321            AttributeLintKind::MalformedDiagnosticFormat { warning } => match warning {
322                FormatWarning::PositionalArgument { .. } => {
323                    lints::DisallowedPositionalArgument.into_diag(dcx, level)
324                }
325                FormatWarning::InvalidSpecifier { .. } => {
326                    lints::InvalidFormatSpecifier.into_diag(dcx, level)
327                }
328            },
329            AttributeLintKind::DiagnosticWrappedParserError { description, label, span } => {
330                lints::WrappedParserError { description, label, span: *span }.into_diag(dcx, level)
331            }
332            &AttributeLintKind::IgnoredDiagnosticOption { option_name, first_span, later_span } => {
333                lints::IgnoredDiagnosticOption { option_name, first_span, later_span }
334                    .into_diag(dcx, level)
335            }
336            &AttributeLintKind::MissingOptionsForOnUnimplemented => {
337                lints::MissingOptionsForOnUnimplementedAttr.into_diag(dcx, level)
338            }
339            &AttributeLintKind::MissingOptionsForOnConst => {
340                lints::MissingOptionsForOnConstAttr.into_diag(dcx, level)
341            }
342            &AttributeLintKind::MalformedOnMoveAttr { span } => {
343                lints::MalformedOnMoveAttrLint { span }.into_diag(dcx, level)
344            }
345            &AttributeLintKind::OnMoveMalformedFormatLiterals { name } => {
346                lints::OnMoveMalformedFormatLiterals { name }.into_diag(dcx, level)
347            }
348            &AttributeLintKind::OnMoveMalformedAttrExpectedLiteralOrDelimiter => {
349                lints::OnMoveMalformedAttrExpectedLiteralOrDelimiter.into_diag(dcx, level)
350            }
351            &AttributeLintKind::MissingOptionsForOnMove => {
352                lints::MissingOptionsForOnMoveAttr.into_diag(dcx, level)
353            }
354        }
355    }
356}