Skip to main content

rustc_lint/
internal.rs

1//! Some lints that are only useful in the compiler or crates that use compiler internals, such as
2//! Clippy.
3
4use rustc_ast as ast;
5use rustc_ast::{Pat, PatKind, Path};
6use rustc_attr_ir::find_attr;
7use rustc_hir as hir;
8use rustc_hir::def::Res;
9use rustc_hir::def_id::DefId;
10use rustc_hir::{Expr, ExprKind, HirId};
11use rustc_lint_defs::{declare_lint_pass, declare_tool_lint};
12use rustc_middle::ty::{self, ClausePolarity, GenericArgsRef};
13use rustc_span::hygiene::{ExpnKind, MacroKind};
14use rustc_span::{Span, sym};
15
16use crate::diagnostics::{
17    AttributeKindInFindAttr, BadOptAccessDiag, DefaultHashTypesDiag,
18    ImplicitSysrootCrateImportDiag, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability,
19    QueryUntracked, RustcMustMatchExhaustivelyNotExhaustive, SpanUseEqCtxtDiag,
20    SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind, TypeIrDirectUse,
21    TypeIrInherentUsage, TypeIrTraitUsage,
22};
23use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
24
25#[doc =
r" The `default_hash_type` lint detects use of [`std::collections::HashMap`] and"]
#[doc =
r" [`std::collections::HashSet`], suggesting the use of `FxHashMap`/`FxHashSet`."]
#[doc = r""]
#[doc =
r" This can help as `FxHasher` can perform better than the default hasher. DOS protection is"]
#[doc = r" not required as input is assumed to be trusted."]
pub static DEFAULT_HASH_TYPES: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::DEFAULT_HASH_TYPES",
            default_level: ::rustc_lint_defs::Allow,
            desc: "forbid HashMap and HashSet and suggest the FxHash* variants",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
26    /// The `default_hash_type` lint detects use of [`std::collections::HashMap`] and
27    /// [`std::collections::HashSet`], suggesting the use of `FxHashMap`/`FxHashSet`.
28    ///
29    /// This can help as `FxHasher` can perform better than the default hasher. DOS protection is
30    /// not required as input is assumed to be trusted.
31    pub rustc::DEFAULT_HASH_TYPES,
32    Allow,
33    "forbid HashMap and HashSet and suggest the FxHash* variants",
34    report_in_external_macro: true
35}
36
37pub struct DefaultHashTypes;
#[automatically_derived]
impl ::core::marker::Copy for DefaultHashTypes { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for DefaultHashTypes { }
#[automatically_derived]
impl ::core::clone::Clone for DefaultHashTypes {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for DefaultHashTypes {
    fn name(&self) -> &'static str { "DefaultHashTypes" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [DEFAULT_HASH_TYPES]))
    }
}
impl DefaultHashTypes {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [DEFAULT_HASH_TYPES]))
    }
}declare_lint_pass!(DefaultHashTypes => [DEFAULT_HASH_TYPES]);
38
39impl LateLintPass<'_> for DefaultHashTypes {
40    fn check_path(&mut self, cx: &LateContext<'_>, path: &hir::Path<'_>, hir_id: HirId) {
41        let Res::Def(rustc_hir::def::DefKind::Struct, def_id) = path.res else { return };
42        if #[allow(non_exhaustive_omitted_patterns)] match cx.tcx.hir_node(hir_id) {
    hir::Node::Item(hir::Item { kind: hir::ItemKind::Use(..), .. }) |
        hir::Node::NestedUseTree(_) => true,
    _ => false,
}matches!(
43            cx.tcx.hir_node(hir_id),
44            hir::Node::Item(hir::Item { kind: hir::ItemKind::Use(..), .. })
45                | hir::Node::NestedUseTree(_)
46        ) {
47            // Don't lint imports, only actual usages.
48            return;
49        }
50        let preferred = match cx.tcx.get_diagnostic_name(def_id) {
51            Some(sym::HashMap) => "FxHashMap",
52            Some(sym::HashSet) => "FxHashSet",
53            _ => return,
54        };
55        cx.emit_span_lint(
56            DEFAULT_HASH_TYPES,
57            path.span,
58            DefaultHashTypesDiag { preferred, used: cx.tcx.item_name(def_id) },
59        );
60    }
61}
62
63#[doc =
r" The `potential_query_instability` lint detects use of methods which can lead to"]
#[doc = r" potential query instability, such as iterating over a `HashMap`."]
#[doc = r""]
#[doc =
r" Due to the [incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation.html) model,"]
#[doc =
r" queries must return deterministic, stable results. `HashMap` iteration order can change"]
#[doc =
r" between compilations, and will introduce instability if query results expose the order."]
pub static POTENTIAL_QUERY_INSTABILITY: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::POTENTIAL_QUERY_INSTABILITY",
            default_level: ::rustc_lint_defs::Allow,
            desc: "require explicit opt-in when using potentially unstable methods or functions",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
64    /// The `potential_query_instability` lint detects use of methods which can lead to
65    /// potential query instability, such as iterating over a `HashMap`.
66    ///
67    /// Due to the [incremental compilation](https://rustc-dev-guide.rust-lang.org/queries/incremental-compilation.html) model,
68    /// queries must return deterministic, stable results. `HashMap` iteration order can change
69    /// between compilations, and will introduce instability if query results expose the order.
70    pub rustc::POTENTIAL_QUERY_INSTABILITY,
71    Allow,
72    "require explicit opt-in when using potentially unstable methods or functions",
73    report_in_external_macro: true
74}
75
76#[doc =
r" The `untracked_query_information` lint detects use of methods which leak information not"]
#[doc =
r" tracked by the query system, such as whether a `Steal<T>` value has already been stolen. In"]
#[doc =
r" order not to break incremental compilation, such methods must be used very carefully or not"]
#[doc = r" at all."]
pub static UNTRACKED_QUERY_INFORMATION: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::UNTRACKED_QUERY_INFORMATION",
            default_level: ::rustc_lint_defs::Allow,
            desc: "require explicit opt-in when accessing information not tracked by the query system",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
77    /// The `untracked_query_information` lint detects use of methods which leak information not
78    /// tracked by the query system, such as whether a `Steal<T>` value has already been stolen. In
79    /// order not to break incremental compilation, such methods must be used very carefully or not
80    /// at all.
81    pub rustc::UNTRACKED_QUERY_INFORMATION,
82    Allow,
83    "require explicit opt-in when accessing information not tracked by the query system",
84    report_in_external_macro: true
85}
86
87pub struct QueryStability;
#[automatically_derived]
impl ::core::marker::Copy for QueryStability { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for QueryStability { }
#[automatically_derived]
impl ::core::clone::Clone for QueryStability {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for QueryStability {
    fn name(&self) -> &'static str { "QueryStability" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]))
    }
}
impl QueryStability {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]))
    }
}declare_lint_pass!(QueryStability => [POTENTIAL_QUERY_INSTABILITY, UNTRACKED_QUERY_INFORMATION]);
88
89impl<'tcx> LateLintPass<'tcx> for QueryStability {
90    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
91        if let Some((callee_def_id, span, generic_args, _recv, _args)) =
92            get_callee_span_generic_args_and_args(cx, expr)
93            && let Ok(Some(instance)) =
94                ty::Instance::try_resolve(cx.tcx, cx.typing_env(), callee_def_id, generic_args)
95        {
96            let def_id = instance.def_id();
97            if {
        {
            'done:
                {
                for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &cx.tcx)
                    {
                    #[allow(unused_imports)]
                    use ::rustc_attr_ir::AttributeKind::*;
                    let i: &::rustc_attr_ir::Attribute = i;
                    match i {
                        ::rustc_attr_ir::Attribute::Parsed(RustcLintQueryInstability)
                            => {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(cx.tcx, def_id, RustcLintQueryInstability) {
98                cx.emit_span_lint(
99                    POTENTIAL_QUERY_INSTABILITY,
100                    span,
101                    QueryInstability { query: cx.tcx.item_name(def_id) },
102                );
103            } else if has_unstable_into_iter_predicate(cx, callee_def_id, generic_args) {
104                let call_span = span.with_hi(expr.span.hi());
105                cx.emit_span_lint(
106                    POTENTIAL_QUERY_INSTABILITY,
107                    call_span,
108                    QueryInstability { query: sym::into_iter },
109                );
110            }
111
112            if {
        {
            'done:
                {
                for i in ::rustc_attr_ir::HasAttrs::get_attrs(def_id, &cx.tcx)
                    {
                    #[allow(unused_imports)]
                    use ::rustc_attr_ir::AttributeKind::*;
                    let i: &::rustc_attr_ir::Attribute = i;
                    match i {
                        ::rustc_attr_ir::Attribute::Parsed(RustcLintUntrackedQueryInformation)
                            => {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(cx.tcx, def_id, RustcLintUntrackedQueryInformation) {
113                cx.emit_span_lint(
114                    UNTRACKED_QUERY_INFORMATION,
115                    span,
116                    QueryUntracked { method: cx.tcx.item_name(def_id) },
117                );
118            }
119        }
120    }
121}
122
123fn has_unstable_into_iter_predicate<'tcx>(
124    cx: &LateContext<'tcx>,
125    callee_def_id: DefId,
126    generic_args: GenericArgsRef<'tcx>,
127) -> bool {
128    let Some(into_iterator_def_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else {
129        return false;
130    };
131    let Some(into_iter_fn_def_id) = cx.tcx.lang_items().into_iter_fn() else {
132        return false;
133    };
134    let clauses = cx.tcx.clauses_of(callee_def_id).instantiate(cx.tcx, generic_args);
135    for (clause, _) in clauses {
136        let Some(trait_clause) = clause.as_trait_clause() else {
137            continue;
138        };
139        if trait_clause.def_id() != into_iterator_def_id
140            || trait_clause.polarity() != ClausePolarity::Positive
141        {
142            continue;
143        }
144        // `IntoIterator::into_iter` has no additional method args.
145        let into_iter_fn_args = cx
146            .tcx
147            .instantiate_bound_regions_with_erased(trait_clause.skip_norm_wip())
148            .trait_ref
149            .args;
150        let Ok(Some(instance)) = ty::Instance::try_resolve(
151            cx.tcx,
152            cx.typing_env(),
153            into_iter_fn_def_id,
154            into_iter_fn_args,
155        ) else {
156            continue;
157        };
158        // Does the input type's `IntoIterator` implementation have the
159        // `rustc_lint_query_instability` attribute on its `into_iter` method?
160        if {
        {
            'done:
                {
                for i in
                    ::rustc_attr_ir::HasAttrs::get_attrs(instance.def_id(),
                        &cx.tcx) {
                    #[allow(unused_imports)]
                    use ::rustc_attr_ir::AttributeKind::*;
                    let i: &::rustc_attr_ir::Attribute = i;
                    match i {
                        ::rustc_attr_ir::Attribute::Parsed(RustcLintQueryInstability)
                            => {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(cx.tcx, instance.def_id(), RustcLintQueryInstability) {
161            return true;
162        }
163    }
164    false
165}
166
167/// Checks whether an expression is a function or method call and, if so, returns its `DefId`,
168/// `Span`, `GenericArgs`, and arguments. This is a slight augmentation of a similarly named Clippy
169/// function, `get_callee_generic_args_and_args`.
170fn get_callee_span_generic_args_and_args<'tcx>(
171    cx: &LateContext<'tcx>,
172    expr: &'tcx Expr<'tcx>,
173) -> Option<(DefId, Span, GenericArgsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
174    if let ExprKind::Call(callee, args) = expr.kind
175        && let callee_ty = cx.typeck_results().expr_ty(callee)
176        && let ty::FnDef(callee_def_id, generic_args) = callee_ty.kind()
177    {
178        return Some((
179            *callee_def_id,
180            callee.span,
181            generic_args.no_bound_vars().unwrap(),
182            None,
183            args,
184        ));
185    }
186    if let ExprKind::MethodCall(segment, recv, args, _) = expr.kind
187        && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
188    {
189        let generic_args = cx.typeck_results().node_args(expr.hir_id);
190        return Some((method_def_id, segment.ident.span, generic_args, Some(recv), args));
191    }
192    None
193}
194
195#[doc =
r" The `usage_of_ty_tykind` lint detects usages of `ty::TyKind::<kind>`,"]
#[doc = r" where `ty::<kind>` would suffice."]
pub static USAGE_OF_TY_TYKIND: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::USAGE_OF_TY_TYKIND",
            default_level: ::rustc_lint_defs::Allow,
            desc: "usage of `ty::TyKind` outside of the `ty::sty` module",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
196    /// The `usage_of_ty_tykind` lint detects usages of `ty::TyKind::<kind>`,
197    /// where `ty::<kind>` would suffice.
198    pub rustc::USAGE_OF_TY_TYKIND,
199    Allow,
200    "usage of `ty::TyKind` outside of the `ty::sty` module",
201    report_in_external_macro: true
202}
203
204#[doc = r" The `usage_of_qualified_ty` lint detects usages of `ty::TyKind`,"]
#[doc = r" where `Ty` should be used instead."]
pub static USAGE_OF_QUALIFIED_TY: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::USAGE_OF_QUALIFIED_TY",
            default_level: ::rustc_lint_defs::Allow,
            desc: "using `ty::{Ty,TyCtxt}` instead of importing it",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
205    /// The `usage_of_qualified_ty` lint detects usages of `ty::TyKind`,
206    /// where `Ty` should be used instead.
207    pub rustc::USAGE_OF_QUALIFIED_TY,
208    Allow,
209    "using `ty::{Ty,TyCtxt}` instead of importing it",
210    report_in_external_macro: true
211}
212
213pub struct TyTyKind;
#[automatically_derived]
impl ::core::marker::Copy for TyTyKind { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for TyTyKind { }
#[automatically_derived]
impl ::core::clone::Clone for TyTyKind {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for TyTyKind {
    fn name(&self) -> &'static str { "TyTyKind" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [USAGE_OF_TY_TYKIND, USAGE_OF_QUALIFIED_TY]))
    }
}
impl TyTyKind {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [USAGE_OF_TY_TYKIND, USAGE_OF_QUALIFIED_TY]))
    }
}declare_lint_pass!(TyTyKind => [
214    USAGE_OF_TY_TYKIND,
215    USAGE_OF_QUALIFIED_TY,
216]);
217
218impl<'tcx> LateLintPass<'tcx> for TyTyKind {
219    fn check_path(
220        &mut self,
221        cx: &LateContext<'tcx>,
222        path: &rustc_hir::Path<'tcx>,
223        _: rustc_hir::HirId,
224    ) {
225        if let Some(segment) = path.segments.iter().nth_back(1)
226            && lint_ty_kind_usage(cx, &segment.res)
227        {
228            let span =
229                path.span.with_hi(segment.args.map_or(segment.ident.span, |a| a.span_ext).hi());
230            cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span });
231        }
232    }
233
234    fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) {
235        match &ty.kind {
236            hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
237                if lint_ty_kind_usage(cx, &path.res) {
238                    let span = match cx.tcx.parent_hir_node(ty.hir_id) {
239                        hir::Node::PatExpr(hir::PatExpr {
240                            kind: hir::PatExprKind::Path(qpath),
241                            ..
242                        })
243                        | hir::Node::Pat(hir::Pat {
244                            kind:
245                                hir::PatKind::TupleStruct(qpath, ..) | hir::PatKind::Struct(qpath, ..),
246                            ..
247                        })
248                        | hir::Node::Expr(
249                            hir::Expr { kind: hir::ExprKind::Path(qpath), .. }
250                            | &hir::Expr { kind: hir::ExprKind::Struct(qpath, ..), .. },
251                        ) => {
252                            if let hir::QPath::TypeRelative(qpath_ty, ..) = qpath
253                                && qpath_ty.hir_id == ty.hir_id
254                            {
255                                Some(path.span)
256                            } else {
257                                None
258                            }
259                        }
260                        _ => None,
261                    };
262
263                    match span {
264                        Some(span) => {
265                            cx.emit_span_lint(
266                                USAGE_OF_TY_TYKIND,
267                                path.span,
268                                TykindKind { suggestion: span },
269                            );
270                        }
271                        None => cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
272                    }
273                } else if !ty.span.from_expansion()
274                    && path.segments.len() > 1
275                    && let Some(ty) = is_ty_or_ty_ctxt(cx, path)
276                {
277                    cx.emit_span_lint(
278                        USAGE_OF_QUALIFIED_TY,
279                        path.span,
280                        TyQualified { ty, suggestion: path.span },
281                    );
282                }
283            }
284            _ => {}
285        }
286    }
287}
288
289fn lint_ty_kind_usage(cx: &LateContext<'_>, res: &Res) -> bool {
290    if let Some(did) = res.opt_def_id() {
291        cx.tcx.is_diagnostic_item(sym::TyKind, did) || cx.tcx.is_diagnostic_item(sym::IrTyKind, did)
292    } else {
293        false
294    }
295}
296
297fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &hir::Path<'_>) -> Option<String> {
298    match path.res {
299        Res::Def(_, def_id) => {
300            if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) {
301                return Some(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}{1}", name,
                gen_args(path.segments.last().unwrap())))
    })format!("{}{}", name, gen_args(path.segments.last().unwrap())));
302            }
303        }
304        // Only lint on `&Ty` and `&TyCtxt` if it is used outside of a trait.
305        Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
306            if let ty::Adt(adt, args) =
307                cx.tcx.type_of(did).instantiate_identity().skip_norm_wip().kind()
308                && let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
309            {
310                return Some(::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("{0}<{1}>", name, args[0]))
    })format!("{}<{}>", name, args[0]));
311            }
312        }
313        _ => (),
314    }
315
316    None
317}
318
319fn gen_args(segment: &hir::PathSegment<'_>) -> String {
320    if let Some(args) = &segment.args {
321        let lifetimes = args
322            .args
323            .iter()
324            .filter_map(|arg| {
325                if let hir::GenericArg::Lifetime(lt) = arg {
326                    Some(lt.ident.to_string())
327                } else {
328                    None
329                }
330            })
331            .collect::<Vec<_>>();
332
333        if !lifetimes.is_empty() {
334            return ::alloc::__export::must_use({
        ::alloc::fmt::format(format_args!("<{0}>", lifetimes.join(", ")))
    })format!("<{}>", lifetimes.join(", "));
335        }
336    }
337
338    String::new()
339}
340
341#[doc = r" The `non_glob_import_of_type_ir_inherent_item` lint detects"]
#[doc = r" non-glob imports of module `rustc_type_ir::inherent`."]
pub static NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT",
            default_level: ::rustc_lint_defs::Allow,
            desc: "non-glob import of `rustc_type_ir::inherent`",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
342    /// The `non_glob_import_of_type_ir_inherent_item` lint detects
343    /// non-glob imports of module `rustc_type_ir::inherent`.
344    pub rustc::NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
345    Allow,
346    "non-glob import of `rustc_type_ir::inherent`",
347    report_in_external_macro: true
348}
349
350#[doc =
r" The `usage_of_type_ir_inherent` lint detects usage of `rustc_type_ir::inherent`."]
#[doc = r""]
#[doc = r" This module should only be used within the trait solver."]
pub static USAGE_OF_TYPE_IR_INHERENT: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::USAGE_OF_TYPE_IR_INHERENT",
            default_level: ::rustc_lint_defs::Allow,
            desc: "usage `rustc_type_ir::inherent` outside of trait system",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
351    /// The `usage_of_type_ir_inherent` lint detects usage of `rustc_type_ir::inherent`.
352    ///
353    /// This module should only be used within the trait solver.
354    pub rustc::USAGE_OF_TYPE_IR_INHERENT,
355    Allow,
356    "usage `rustc_type_ir::inherent` outside of trait system",
357    report_in_external_macro: true
358}
359
360#[doc =
r" The `usage_of_type_ir_traits` lint detects usage of `rustc_type_ir::Interner`,"]
#[doc = r" or `rustc_infer::InferCtxtLike`."]
#[doc = r""]
#[doc =
r" Methods of this trait should only be used within the type system abstraction layer,"]
#[doc =
r" and in the generic next trait solver implementation. Look for an analogously named"]
#[doc = r" method on `TyCtxt` or `InferCtxt` (respectively)."]
pub static USAGE_OF_TYPE_IR_TRAITS: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::USAGE_OF_TYPE_IR_TRAITS",
            default_level: ::rustc_lint_defs::Allow,
            desc: "usage `rustc_type_ir`-specific abstraction traits outside of trait system",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
361    /// The `usage_of_type_ir_traits` lint detects usage of `rustc_type_ir::Interner`,
362    /// or `rustc_infer::InferCtxtLike`.
363    ///
364    /// Methods of this trait should only be used within the type system abstraction layer,
365    /// and in the generic next trait solver implementation. Look for an analogously named
366    /// method on `TyCtxt` or `InferCtxt` (respectively).
367    pub rustc::USAGE_OF_TYPE_IR_TRAITS,
368    Allow,
369    "usage `rustc_type_ir`-specific abstraction traits outside of trait system",
370    report_in_external_macro: true
371}
372#[doc =
r" The `direct_use_of_rustc_type_ir` lint detects usage of `rustc_type_ir`."]
#[doc = r""]
#[doc =
r" This module should only be used within the trait solver and some desirable"]
#[doc = r" crates like rustc_middle."]
pub static DIRECT_USE_OF_RUSTC_TYPE_IR: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::DIRECT_USE_OF_RUSTC_TYPE_IR",
            default_level: ::rustc_lint_defs::Allow,
            desc: "usage `rustc_type_ir` abstraction outside of trait system",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
373    /// The `direct_use_of_rustc_type_ir` lint detects usage of `rustc_type_ir`.
374    ///
375    /// This module should only be used within the trait solver and some desirable
376    /// crates like rustc_middle.
377    pub rustc::DIRECT_USE_OF_RUSTC_TYPE_IR,
378    Allow,
379    "usage `rustc_type_ir` abstraction outside of trait system",
380    report_in_external_macro: true
381}
382
383pub struct TypeIr;
#[automatically_derived]
impl ::core::marker::Copy for TypeIr { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for TypeIr { }
#[automatically_derived]
impl ::core::clone::Clone for TypeIr {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for TypeIr {
    fn name(&self) -> &'static str { "TypeIr" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [DIRECT_USE_OF_RUSTC_TYPE_IR,
                        NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
                        USAGE_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_TRAITS]))
    }
}
impl TypeIr {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [DIRECT_USE_OF_RUSTC_TYPE_IR,
                        NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
                        USAGE_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_TRAITS]))
    }
}declare_lint_pass!(TypeIr => [
384    DIRECT_USE_OF_RUSTC_TYPE_IR,
385    NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
386    USAGE_OF_TYPE_IR_INHERENT,
387    USAGE_OF_TYPE_IR_TRAITS
388]);
389
390impl<'tcx> LateLintPass<'tcx> for TypeIr {
391    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
392        let res_def_id = match expr.kind {
393            hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => path.res.opt_def_id(),
394            hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::MethodCall(..) => {
395                cx.typeck_results().type_dependent_def_id(expr.hir_id)
396            }
397            _ => return,
398        };
399        let Some(res_def_id) = res_def_id else {
400            return;
401        };
402        if let Some(assoc_item) = cx.tcx.opt_associated_item(res_def_id)
403            && let Some(trait_def_id) = assoc_item.trait_container(cx.tcx)
404            && (cx.tcx.is_diagnostic_item(sym::type_ir_interner, trait_def_id)
405                | cx.tcx.is_diagnostic_item(sym::type_ir_infer_ctxt_like, trait_def_id))
406        {
407            cx.emit_span_lint(USAGE_OF_TYPE_IR_TRAITS, expr.span, TypeIrTraitUsage);
408        }
409    }
410
411    fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
412        let rustc_hir::ItemKind::Use(tree) = item.kind else {
413            return;
414        };
415
416        check_use(cx, tree, ::alloc::vec::Vec::new()vec![]);
417
418        fn check_use<'tcx>(
419            cx: &LateContext<'_>,
420            tree: hir::UseTree<'tcx>,
421            mut prefix: Vec<&'tcx hir::PathSegment<'tcx>>,
422        ) {
423            let is_mod_inherent = |res: Res| {
424                res.opt_def_id()
425                    .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id))
426            };
427
428            prefix.extend(tree.prefix.segments);
429
430            match tree.kind {
431                rustc_hir::UseKind::Single(_) | rustc_hir::UseKind::Glob => {}
432                rustc_hir::UseKind::Nested { items } => {
433                    for (nested, _, _) in items {
434                        check_use(cx, *nested, prefix.clone())
435                    }
436                }
437            }
438
439            // Path segments except for the final.
440            if let Some(seg) = prefix.iter().find(|seg| is_mod_inherent(seg.res)) {
441                cx.emit_span_lint(USAGE_OF_TYPE_IR_INHERENT, seg.ident.span, TypeIrInherentUsage);
442            }
443            // Final path resolutions, like `use rustc_type_ir::inherent`
444            else if let Some(type_ns) = tree.prefix.res.type_ns
445                && is_mod_inherent(type_ns)
446            {
447                cx.emit_span_lint(
448                    USAGE_OF_TYPE_IR_INHERENT,
449                    prefix.last().unwrap().ident.span,
450                    TypeIrInherentUsage,
451                );
452            }
453
454            let (lo, hi, snippet) = match prefix {
455                [.., penultimate, segment]
456                    if is_mod_inherent(penultimate.res)
457                        && let rustc_hir::UseKind::Single(ident) = tree.kind =>
458                {
459                    (segment.ident.span, ident.span, "*")
460                }
461                [.., segment]
462                    if let Some(type_ns) = tree.prefix.res.type_ns
463                        && is_mod_inherent(type_ns)
464                        && let rustc_hir::UseKind::Single(ident) = tree.kind =>
465                {
466                    let (lo, snippet) =
467                        match cx.tcx.sess.source_map().span_to_snippet(tree.prefix.span).as_deref()
468                        {
469                            Ok("self") => (tree.prefix.span, "*"),
470                            _ => (segment.ident.span.shrink_to_hi(), "::*"),
471                        };
472                    (lo, if segment.ident == ident { lo } else { ident.span }, snippet)
473                }
474                _ => return,
475            };
476            cx.emit_span_lint(
477                NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
478                tree.prefix.span,
479                NonGlobImportTypeIrInherent {
480                    suggestion: lo.eq_ctxt(hi).then(|| lo.to(hi)),
481                    snippet,
482                },
483            );
484        }
485    }
486
487    fn check_path(
488        &mut self,
489        cx: &LateContext<'tcx>,
490        path: &rustc_hir::Path<'tcx>,
491        _: rustc_hir::HirId,
492    ) {
493        if let Some(seg) = path.segments.iter().find(|seg| {
494            seg.res
495                .opt_def_id()
496                .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir, def_id))
497        }) {
498            cx.emit_span_lint(DIRECT_USE_OF_RUSTC_TYPE_IR, seg.ident.span, TypeIrDirectUse);
499        }
500    }
501}
502
503#[doc =
r" The `lint_pass_impl_without_macro` detects manual implementations of a lint"]
#[doc = r" pass, without using [`declare_lint_pass`] or [`impl_lint_pass`]."]
pub static LINT_PASS_IMPL_WITHOUT_MACRO: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::LINT_PASS_IMPL_WITHOUT_MACRO",
            default_level: ::rustc_lint_defs::Allow,
            desc: "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros",
            edition_lint_opts: None,
            report_in_external_macro: false,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
504    /// The `lint_pass_impl_without_macro` detects manual implementations of a lint
505    /// pass, without using [`declare_lint_pass`] or [`impl_lint_pass`].
506    pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO,
507    Allow,
508    "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
509}
510
511pub struct LintPassImpl;
#[automatically_derived]
impl ::core::marker::Copy for LintPassImpl { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for LintPassImpl { }
#[automatically_derived]
impl ::core::clone::Clone for LintPassImpl {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for LintPassImpl {
    fn name(&self) -> &'static str { "LintPassImpl" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [LINT_PASS_IMPL_WITHOUT_MACRO]))
    }
}
impl LintPassImpl {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [LINT_PASS_IMPL_WITHOUT_MACRO]))
    }
}declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
512
513impl EarlyLintPass for LintPassImpl {
514    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
515        if let ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) = &item.kind
516            && let Some(last) = of_trait.trait_ref.path.segments.last()
517            && last.ident.name == sym::LintPass
518        {
519            let expn_data = of_trait.trait_ref.path.span.ctxt().outer_expn_data();
520            let call_site = expn_data.call_site;
521            if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
522                && call_site.ctxt().outer_expn_data().kind
523                    != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
524            {
525                cx.emit_span_lint(
526                    LINT_PASS_IMPL_WITHOUT_MACRO,
527                    of_trait.trait_ref.path.span,
528                    LintPassByHand,
529                );
530            }
531        }
532    }
533}
534
535#[doc =
r" The `bad_opt_access` lint detects accessing options by field instead of"]
#[doc = r" the wrapper function."]
pub static BAD_OPT_ACCESS: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::BAD_OPT_ACCESS",
            default_level: ::rustc_lint_defs::Deny,
            desc: "prevent using options by field access when there is a wrapper function",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
536    /// The `bad_opt_access` lint detects accessing options by field instead of
537    /// the wrapper function.
538    pub rustc::BAD_OPT_ACCESS,
539    Deny,
540    "prevent using options by field access when there is a wrapper function",
541    report_in_external_macro: true
542}
543
544pub struct BadOptAccess;
#[automatically_derived]
impl ::core::marker::Copy for BadOptAccess { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for BadOptAccess { }
#[automatically_derived]
impl ::core::clone::Clone for BadOptAccess {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for BadOptAccess {
    fn name(&self) -> &'static str { "BadOptAccess" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [BAD_OPT_ACCESS]))
    }
}
impl BadOptAccess {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [BAD_OPT_ACCESS]))
    }
}declare_lint_pass!(BadOptAccess => [BAD_OPT_ACCESS]);
545
546impl LateLintPass<'_> for BadOptAccess {
547    fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
548        let hir::ExprKind::Field(base, target) = expr.kind else { return };
549        let Some(adt_def) = cx.typeck_results().expr_ty(base).ty_adt_def() else { return };
550        // Skip types without `#[rustc_lint_opt_ty]` - only so that the rest of the lint can be
551        // avoided.
552        if !{
        {
            'done:
                {
                for i in
                    ::rustc_attr_ir::HasAttrs::get_attrs(adt_def.did(), &cx.tcx)
                    {
                    #[allow(unused_imports)]
                    use ::rustc_attr_ir::AttributeKind::*;
                    let i: &::rustc_attr_ir::Attribute = i;
                    match i {
                        ::rustc_attr_ir::Attribute::Parsed(RustcLintOptTy) => {
                            break 'done Some(());
                        }
                        ::rustc_attr_ir::Attribute::Unparsed(..) =>
                            {}
                            #[deny(unreachable_patterns)]
                            _ => {}
                    }
                }
                None
            }
        }
    }.is_some()find_attr!(cx.tcx, adt_def.did(), RustcLintOptTy) {
553            return;
554        }
555
556        for field in adt_def.all_fields() {
557            if field.name == target.name
558                && let Some(lint_message) = {
    {
        'done:
            {
            for i in ::rustc_attr_ir::HasAttrs::get_attrs(field.did, &cx.tcx)
                {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(RustcLintOptDenyFieldAccess {
                        lint_message }) => {
                        break 'done Some(lint_message);
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(cx.tcx, field.did, RustcLintOptDenyFieldAccess { lint_message, } => lint_message)
559            {
560                cx.emit_span_lint(
561                    BAD_OPT_ACCESS,
562                    expr.span,
563                    BadOptAccessDiag { msg: lint_message.as_str() },
564                );
565            }
566        }
567    }
568}
569
570pub static SPAN_USE_EQ_CTXT: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::SPAN_USE_EQ_CTXT",
            default_level: ::rustc_lint_defs::Allow,
            desc: "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
571    pub rustc::SPAN_USE_EQ_CTXT,
572    Allow,
573    "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead",
574    report_in_external_macro: true
575}
576
577pub struct SpanUseEqCtxt;
#[automatically_derived]
impl ::core::marker::Copy for SpanUseEqCtxt { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SpanUseEqCtxt { }
#[automatically_derived]
impl ::core::clone::Clone for SpanUseEqCtxt {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for SpanUseEqCtxt {
    fn name(&self) -> &'static str { "SpanUseEqCtxt" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [SPAN_USE_EQ_CTXT]))
    }
}
impl SpanUseEqCtxt {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [SPAN_USE_EQ_CTXT]))
    }
}declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
578
579impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
580    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
581        if let hir::ExprKind::Binary(
582            hir::BinOp { node: hir::BinOpKind::Eq | hir::BinOpKind::Ne, .. },
583            lhs,
584            rhs,
585        ) = expr.kind
586        {
587            if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
588                cx.emit_span_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
589            }
590        }
591    }
592}
593
594fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
595    match &expr.kind {
596        hir::ExprKind::MethodCall(..) => cx
597            .typeck_results()
598            .type_dependent_def_id(expr.hir_id)
599            .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)),
600
601        _ => false,
602    }
603}
604
605#[doc =
r" The `symbol_intern_string_literal` lint detects `Symbol::intern` or `Ident::from_str_and_span` being called on a string literal"]
pub static SYMBOL_INTERN_STRING_LITERAL: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::SYMBOL_INTERN_STRING_LITERAL",
            default_level: ::rustc_lint_defs::Allow,
            desc: "Forbid uses of string literals in `Symbol::intern` or `Ident::from_str_and_span`, suggesting preinterning instead",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
606    /// The `symbol_intern_string_literal` lint detects `Symbol::intern` or `Ident::from_str_and_span` being called on a string literal
607    pub rustc::SYMBOL_INTERN_STRING_LITERAL,
608    Allow,
609    "Forbid uses of string literals in `Symbol::intern` or `Ident::from_str_and_span`, suggesting preinterning instead",
610    report_in_external_macro: true
611}
612
613pub struct SymbolInternStringLiteral;
#[automatically_derived]
impl ::core::marker::Copy for SymbolInternStringLiteral { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for SymbolInternStringLiteral { }
#[automatically_derived]
impl ::core::clone::Clone for SymbolInternStringLiteral {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for SymbolInternStringLiteral {
    fn name(&self) -> &'static str { "SymbolInternStringLiteral" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [SYMBOL_INTERN_STRING_LITERAL]))
    }
}
impl SymbolInternStringLiteral {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [SYMBOL_INTERN_STRING_LITERAL]))
    }
}declare_lint_pass!(SymbolInternStringLiteral => [SYMBOL_INTERN_STRING_LITERAL]);
614
615impl<'tcx> LateLintPass<'tcx> for SymbolInternStringLiteral {
616    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
617        if let hir::ExprKind::Call(path, args) = expr.kind
618            && let hir::ExprKind::Path(ref qpath) = path.kind
619            && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
620        {
621            let (arg, fn_name) = if cx.tcx.is_diagnostic_item(sym::SymbolIntern, def_id)
622                && let [arg] = args
623            {
624                (arg, "Symbol::intern")
625            } else if cx.tcx.is_diagnostic_item(sym::ident_from_str_and_span, def_id)
626                && let [arg, _] = args
627            {
628                (arg, "Ident::from_str_and_span")
629            } else {
630                return;
631            };
632            if let hir::ExprKind::Lit(kind) = arg.kind
633                && let rustc_ast::LitKind::Str(_, _) = kind.node
634            {
635                cx.emit_span_lint(
636                    SYMBOL_INTERN_STRING_LITERAL,
637                    kind.span,
638                    SymbolInternStringLiteralDiag { fn_name },
639                );
640            }
641        }
642    }
643}
644
645#[doc =
r" The `implicit_sysroot_crate_import` detects use of `extern crate` to import non-sysroot crates"]
#[doc =
r" (e.g. crates.io deps) from the sysroot, which is dangerous because these crates are not guaranteed"]
#[doc =
r" to exist exactly once, and so may be missing entirely or appear multiple times resulting in ambiguity."]
pub static IMPLICIT_SYSROOT_CRATE_IMPORT: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::IMPLICIT_SYSROOT_CRATE_IMPORT",
            default_level: ::rustc_lint_defs::Allow,
            desc: "Forbid uses of non-sysroot crates in `extern crate`",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
646    /// The `implicit_sysroot_crate_import` detects use of `extern crate` to import non-sysroot crates
647    /// (e.g. crates.io deps) from the sysroot, which is dangerous because these crates are not guaranteed
648    /// to exist exactly once, and so may be missing entirely or appear multiple times resulting in ambiguity.
649    pub rustc::IMPLICIT_SYSROOT_CRATE_IMPORT,
650    Allow,
651    "Forbid uses of non-sysroot crates in `extern crate`",
652    report_in_external_macro: true
653}
654
655pub struct ImplicitSysrootCrateImport;
#[automatically_derived]
impl ::core::marker::Copy for ImplicitSysrootCrateImport { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for ImplicitSysrootCrateImport { }
#[automatically_derived]
impl ::core::clone::Clone for ImplicitSysrootCrateImport {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for ImplicitSysrootCrateImport {
    fn name(&self) -> &'static str { "ImplicitSysrootCrateImport" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [IMPLICIT_SYSROOT_CRATE_IMPORT]))
    }
}
impl ImplicitSysrootCrateImport {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [IMPLICIT_SYSROOT_CRATE_IMPORT]))
    }
}declare_lint_pass!(ImplicitSysrootCrateImport => [IMPLICIT_SYSROOT_CRATE_IMPORT]);
656
657impl EarlyLintPass for ImplicitSysrootCrateImport {
658    fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
659        fn is_whitelisted(crate_name: &str) -> bool {
660            // Whitelist of allowed crates.
661            crate_name.starts_with("rustc_")
662                || #[allow(non_exhaustive_omitted_patterns)] match crate_name {
    "test" | "self" | "core" | "alloc" | "std" | "proc_macro" |
        "tikv_jemalloc_sys" => true,
    _ => false,
}matches!(
663                    crate_name,
664                    "test" | "self" | "core" | "alloc" | "std" | "proc_macro" | "tikv_jemalloc_sys"
665                )
666        }
667
668        if let ast::ItemKind::ExternCrate(original_name, imported_name) = &item.kind {
669            let name = original_name.as_ref().unwrap_or(&imported_name.name).as_str();
670            let externs = &cx.builder.sess().opts.externs;
671            if externs.get(name).is_none() && !is_whitelisted(name) {
672                cx.emit_span_lint(
673                    IMPLICIT_SYSROOT_CRATE_IMPORT,
674                    item.span,
675                    ImplicitSysrootCrateImportDiag { name },
676                );
677            }
678        }
679    }
680}
681
682pub static BAD_USE_OF_FIND_ATTR: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::BAD_USE_OF_FIND_ATTR",
            default_level: ::rustc_lint_defs::Allow,
            desc: "Forbid `AttributeKind::` as a prefix in `find_attr!` macros.",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
683    pub rustc::BAD_USE_OF_FIND_ATTR,
684    Allow,
685    "Forbid `AttributeKind::` as a prefix in `find_attr!` macros.",
686    report_in_external_macro: true
687}
688pub struct BadUseOfFindAttr;
#[automatically_derived]
impl ::core::marker::Copy for BadUseOfFindAttr { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for BadUseOfFindAttr { }
#[automatically_derived]
impl ::core::clone::Clone for BadUseOfFindAttr {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for BadUseOfFindAttr {
    fn name(&self) -> &'static str { "BadUseOfFindAttr" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [BAD_USE_OF_FIND_ATTR]))
    }
}
impl BadUseOfFindAttr {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [BAD_USE_OF_FIND_ATTR]))
    }
}declare_lint_pass!(BadUseOfFindAttr => [BAD_USE_OF_FIND_ATTR]);
689
690impl EarlyLintPass for BadUseOfFindAttr {
691    fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &rustc_ast::Arm) {
692        fn path_contains_attribute_kind(cx: &EarlyContext<'_>, path: &Path) {
693            for segment in &path.segments {
694                if segment.ident.as_str() == "AttributeKind" {
695                    cx.emit_span_lint(
696                        BAD_USE_OF_FIND_ATTR,
697                        segment.span(),
698                        AttributeKindInFindAttr,
699                    );
700                }
701            }
702        }
703
704        fn find_attr_kind_in_pat(cx: &EarlyContext<'_>, pat: &Pat) {
705            match &pat.kind {
706                PatKind::Struct(_, path, fields, _) => {
707                    path_contains_attribute_kind(cx, path);
708                    for field in fields {
709                        find_attr_kind_in_pat(cx, &field.pat);
710                    }
711                }
712                PatKind::TupleStruct(_, path, fields) => {
713                    path_contains_attribute_kind(cx, path);
714                    for field in fields {
715                        find_attr_kind_in_pat(cx, &field);
716                    }
717                }
718                PatKind::Or(options) => {
719                    for pat in options {
720                        find_attr_kind_in_pat(cx, pat);
721                    }
722                }
723                PatKind::Path(_, path) => {
724                    path_contains_attribute_kind(cx, path);
725                }
726                PatKind::Tuple(elems) => {
727                    for pat in elems {
728                        find_attr_kind_in_pat(cx, pat);
729                    }
730                }
731                PatKind::Deref(pat) => {
732                    find_attr_kind_in_pat(cx, pat);
733                }
734                PatKind::Ref(..) => {
735                    find_attr_kind_in_pat(cx, pat);
736                }
737                PatKind::Slice(elems) => {
738                    for pat in elems {
739                        find_attr_kind_in_pat(cx, pat);
740                    }
741                }
742
743                PatKind::Guard(pat, ..) => {
744                    find_attr_kind_in_pat(cx, pat);
745                }
746                PatKind::Paren(pat) => {
747                    find_attr_kind_in_pat(cx, pat);
748                }
749                PatKind::Expr(..)
750                | PatKind::Range(..)
751                | PatKind::MacCall(..)
752                | PatKind::Rest
753                | PatKind::Missing
754                | PatKind::Err(..)
755                | PatKind::Ident(..)
756                | PatKind::Never
757                | PatKind::Wild => {}
758            }
759        }
760
761        if let Some(expn_data) = arm.span.source_callee()
762            && let ExpnKind::Macro(_, name) = expn_data.kind
763            && name.as_str() == "find_attr"
764        {
765            find_attr_kind_in_pat(cx, &arm.pat);
766        }
767    }
768}
769
770pub static RUSTC_MUST_MATCH_EXHAUSTIVELY: &::rustc_lint_defs::Lint =
    &::rustc_lint_defs::Lint {
            name: &"rustc::RUSTC_MUST_MATCH_EXHAUSTIVELY",
            default_level: ::rustc_lint_defs::Allow,
            desc: "Forbids matches with wildcards, or if-let matching on enums marked with `#[rustc_must_match_exhaustively]`",
            edition_lint_opts: None,
            report_in_external_macro: true,
            future_incompatible: None,
            is_externally_loaded: true,
            crate_level_only: false,
            ..::rustc_lint_defs::Lint::default_fields_for_macro()
        };declare_tool_lint! {
771    pub rustc::RUSTC_MUST_MATCH_EXHAUSTIVELY,
772    Allow,
773    "Forbids matches with wildcards, or if-let matching on enums marked with `#[rustc_must_match_exhaustively]`",
774    report_in_external_macro: true
775}
776pub struct RustcMustMatchExhaustively;
#[automatically_derived]
impl ::core::marker::Copy for RustcMustMatchExhaustively { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for RustcMustMatchExhaustively { }
#[automatically_derived]
impl ::core::clone::Clone for RustcMustMatchExhaustively {
    #[inline]
    fn clone(&self) -> Self { *self }
}
impl ::rustc_lint_defs::LintPass for RustcMustMatchExhaustively {
    fn name(&self) -> &'static str { "RustcMustMatchExhaustively" }
    fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [RUSTC_MUST_MATCH_EXHAUSTIVELY]))
    }
}
impl RustcMustMatchExhaustively {
    #[allow(unused)]
    pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
        ::alloc::boxed::box_assume_init_into_vec_unsafe(::alloc::intrinsics::write_box_via_move(::alloc::boxed::Box::new_uninit(),
                [RUSTC_MUST_MATCH_EXHAUSTIVELY]))
    }
}declare_lint_pass!(RustcMustMatchExhaustively => [RUSTC_MUST_MATCH_EXHAUSTIVELY]);
777
778fn is_rustc_must_match_exhaustively(cx: &LateContext<'_>, id: HirId) -> Option<Span> {
779    let res = cx.typeck_results();
780
781    let ty = res.node_type(id);
782
783    let ty = if let ty::Ref(_, ty, _) = ty.kind() { *ty } else { ty };
784
785    if let Some(adt_def) = ty.ty_adt_def()
786        && adt_def.is_enum()
787    {
788        {
    {
        'done:
            {
            for i in
                ::rustc_attr_ir::HasAttrs::get_attrs(adt_def.did(), &cx.tcx) {
                #[allow(unused_imports)]
                use ::rustc_attr_ir::AttributeKind::*;
                let i: &::rustc_attr_ir::Attribute = i;
                match i {
                    ::rustc_attr_ir::Attribute::Parsed(RustcMustMatchExhaustively(span))
                        => {
                        break 'done Some(*span);
                    }
                    ::rustc_attr_ir::Attribute::Unparsed(..) =>
                        {}
                        #[deny(unreachable_patterns)]
                        _ => {}
                }
            }
            None
        }
    }
}find_attr!(cx.tcx, adt_def.did(), RustcMustMatchExhaustively(span) => *span)
789    } else {
790        None
791    }
792}
793
794fn pat_is_not_exhaustive_heuristic(pat: &hir::Pat<'_>) -> Option<(Span, &'static str)> {
795    match pat.kind {
796        hir::PatKind::Missing => None,
797        hir::PatKind::Wild => Some((pat.span, "because of this wildcard pattern")),
798        hir::PatKind::Binding(_, _, _, Some(pat)) => pat_is_not_exhaustive_heuristic(pat),
799        hir::PatKind::Binding(..) => Some((pat.span, "because of this variable binding")),
800        hir::PatKind::Struct(..) => None,
801        hir::PatKind::TupleStruct(..) => None,
802        hir::PatKind::Or(..) => None,
803        hir::PatKind::Never => None,
804        hir::PatKind::Tuple(..) => None,
805        hir::PatKind::Deref(pat) => pat_is_not_exhaustive_heuristic(&*pat),
806        hir::PatKind::Ref(pat, _, _) => pat_is_not_exhaustive_heuristic(&*pat),
807        hir::PatKind::Expr(..) => None,
808        hir::PatKind::Guard(..) => None,
809        hir::PatKind::Range(..) => None,
810        hir::PatKind::Slice(..) => None,
811        hir::PatKind::Err(..) => None,
812    }
813}
814
815impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively {
816    fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
817        match expr.kind {
818            // This is not perfect exhaustiveness checking, that's why this is just a rustc internal
819            // attribute. But it catches most reasonable cases
820            hir::ExprKind::Match(expr, arms, _) => {
821                if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.hir_id) {
822                    for arm in arms {
823                        if let Some((span, message)) = pat_is_not_exhaustive_heuristic(arm.pat) {
824                            cx.emit_span_lint(
825                                RUSTC_MUST_MATCH_EXHAUSTIVELY,
826                                expr.span,
827                                RustcMustMatchExhaustivelyNotExhaustive {
828                                    attr_span,
829                                    pat_span: span,
830                                    message,
831                                },
832                            );
833                        }
834                    }
835                }
836            }
837            hir::ExprKind::Let(expr, ..) => {
838                if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.init.hir_id) {
839                    cx.emit_span_lint(
840                        RUSTC_MUST_MATCH_EXHAUSTIVELY,
841                        expr.span,
842                        RustcMustMatchExhaustivelyNotExhaustive {
843                            attr_span,
844                            pat_span: expr.span,
845                            message: "using `if let` only matches on one variant (try using `match`)",
846                        },
847                    );
848                }
849            }
850            _ => {}
851        }
852    }
853
854    fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) {
855        match stmt.kind {
856            rustc_hir::StmtKind::Let(let_stmt) => {
857                if let_stmt.els.is_some()
858                    && let Some(attr_span) =
859                        is_rustc_must_match_exhaustively(cx, let_stmt.pat.hir_id)
860                {
861                    cx.emit_span_lint(
862                        RUSTC_MUST_MATCH_EXHAUSTIVELY,
863                        let_stmt.span,
864                        RustcMustMatchExhaustivelyNotExhaustive {
865                            attr_span,
866                            pat_span: let_stmt.pat.span,
867                            message: "using `let else` only matches on one variant (try using `match`)",
868                        },
869                    );
870                }
871            }
872            _ => {}
873        }
874    }
875}