1use rustc_ast as ast;
5use rustc_ast::{Pat, PatKind, Path};
6use rustc_hir as hir;
7use rustc_hir::def::Res;
8use rustc_hir::def_id::DefId;
9use rustc_hir::{Expr, ExprKind, HirId, find_attr};
10use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity};
11use rustc_session::{declare_lint_pass, declare_tool_lint};
12use rustc_span::hygiene::{ExpnKind, MacroKind};
13use rustc_span::{Span, sym};
14
15use crate::lints::{
16 AttributeKindInFindAttr, BadOptAccessDiag, DefaultHashTypesDiag,
17 ImplicitSysrootCrateImportDiag, LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability,
18 QueryUntracked, SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag,
19 TykindKind, TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage,
20};
21use crate::{EarlyContext, EarlyLintPass, LateContext, LateLintPass, LintContext};
22
23#[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! {
24 pub rustc::DEFAULT_HASH_TYPES,
30 Allow,
31 "forbid HashMap and HashSet and suggest the FxHash* variants",
32 report_in_external_macro: true
33}
34
35pub 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) -> DefaultHashTypes { *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]);
36
37impl LateLintPass<'_> for DefaultHashTypes {
38 fn check_path(&mut self, cx: &LateContext<'_>, path: &hir::Path<'_>, hir_id: HirId) {
39 let Res::Def(rustc_hir::def::DefKind::Struct, def_id) = path.res else { return };
40 if #[allow(non_exhaustive_omitted_patterns)] match cx.tcx.hir_node(hir_id) {
hir::Node::Item(hir::Item { kind: hir::ItemKind::Use(..), .. }) => true,
_ => false,
}matches!(
41 cx.tcx.hir_node(hir_id),
42 hir::Node::Item(hir::Item { kind: hir::ItemKind::Use(..), .. })
43 ) {
44 return;
46 }
47 let preferred = match cx.tcx.get_diagnostic_name(def_id) {
48 Some(sym::HashMap) => "FxHashMap",
49 Some(sym::HashSet) => "FxHashSet",
50 _ => return,
51 };
52 cx.emit_span_lint(
53 DEFAULT_HASH_TYPES,
54 path.span,
55 DefaultHashTypesDiag { preferred, used: cx.tcx.item_name(def_id) },
56 );
57 }
58}
59
60#[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! {
61 pub rustc::POTENTIAL_QUERY_INSTABILITY,
68 Allow,
69 "require explicit opt-in when using potentially unstable methods or functions",
70 report_in_external_macro: true
71}
72
73#[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! {
74 pub rustc::UNTRACKED_QUERY_INFORMATION,
79 Allow,
80 "require explicit opt-in when accessing information not tracked by the query system",
81 report_in_external_macro: true
82}
83
84pub 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) -> QueryStability { *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]);
85
86impl<'tcx> LateLintPass<'tcx> for QueryStability {
87 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) {
88 if let Some((callee_def_id, span, generic_args, _recv, _args)) =
89 get_callee_span_generic_args_and_args(cx, expr)
90 && let Ok(Some(instance)) =
91 ty::Instance::try_resolve(cx.tcx, cx.typing_env(), callee_def_id, generic_args)
92 {
93 let def_id = instance.def_id();
94 if {
#[allow(deprecated)]
{
{
'done:
{
for i in cx.tcx.get_all_attrs(def_id) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcLintQueryInstability) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}.is_some()find_attr!(cx.tcx, def_id, RustcLintQueryInstability) {
95 cx.emit_span_lint(
96 POTENTIAL_QUERY_INSTABILITY,
97 span,
98 QueryInstability { query: cx.tcx.item_name(def_id) },
99 );
100 } else if has_unstable_into_iter_predicate(cx, callee_def_id, generic_args) {
101 let call_span = span.with_hi(expr.span.hi());
102 cx.emit_span_lint(
103 POTENTIAL_QUERY_INSTABILITY,
104 call_span,
105 QueryInstability { query: sym::into_iter },
106 );
107 }
108
109 if {
#[allow(deprecated)]
{
{
'done:
{
for i in cx.tcx.get_all_attrs(def_id) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcLintUntrackedQueryInformation)
=> {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}.is_some()find_attr!(cx.tcx, def_id, RustcLintUntrackedQueryInformation) {
110 cx.emit_span_lint(
111 UNTRACKED_QUERY_INFORMATION,
112 span,
113 QueryUntracked { method: cx.tcx.item_name(def_id) },
114 );
115 }
116 }
117 }
118}
119
120fn has_unstable_into_iter_predicate<'tcx>(
121 cx: &LateContext<'tcx>,
122 callee_def_id: DefId,
123 generic_args: GenericArgsRef<'tcx>,
124) -> bool {
125 let Some(into_iterator_def_id) = cx.tcx.get_diagnostic_item(sym::IntoIterator) else {
126 return false;
127 };
128 let Some(into_iter_fn_def_id) = cx.tcx.lang_items().into_iter_fn() else {
129 return false;
130 };
131 let predicates = cx.tcx.predicates_of(callee_def_id).instantiate(cx.tcx, generic_args);
132 for (predicate, _) in predicates {
133 let Some(trait_pred) = predicate.as_trait_clause() else {
134 continue;
135 };
136 if trait_pred.def_id() != into_iterator_def_id
137 || trait_pred.polarity() != PredicatePolarity::Positive
138 {
139 continue;
140 }
141 let into_iter_fn_args =
143 cx.tcx.instantiate_bound_regions_with_erased(trait_pred).trait_ref.args;
144 let Ok(Some(instance)) = ty::Instance::try_resolve(
145 cx.tcx,
146 cx.typing_env(),
147 into_iter_fn_def_id,
148 into_iter_fn_args,
149 ) else {
150 continue;
151 };
152 if {
#[allow(deprecated)]
{
{
'done:
{
for i in cx.tcx.get_all_attrs(instance.def_id()) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcLintQueryInstability) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}.is_some()find_attr!(cx.tcx, instance.def_id(), RustcLintQueryInstability) {
155 return true;
156 }
157 }
158 false
159}
160
161fn get_callee_span_generic_args_and_args<'tcx>(
165 cx: &LateContext<'tcx>,
166 expr: &'tcx Expr<'tcx>,
167) -> Option<(DefId, Span, GenericArgsRef<'tcx>, Option<&'tcx Expr<'tcx>>, &'tcx [Expr<'tcx>])> {
168 if let ExprKind::Call(callee, args) = expr.kind
169 && let callee_ty = cx.typeck_results().expr_ty(callee)
170 && let ty::FnDef(callee_def_id, generic_args) = callee_ty.kind()
171 {
172 return Some((*callee_def_id, callee.span, generic_args, None, args));
173 }
174 if let ExprKind::MethodCall(segment, recv, args, _) = expr.kind
175 && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
176 {
177 let generic_args = cx.typeck_results().node_args(expr.hir_id);
178 return Some((method_def_id, segment.ident.span, generic_args, Some(recv), args));
179 }
180 None
181}
182
183#[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! {
184 pub rustc::USAGE_OF_TY_TYKIND,
187 Allow,
188 "usage of `ty::TyKind` outside of the `ty::sty` module",
189 report_in_external_macro: true
190}
191
192#[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! {
193 pub rustc::USAGE_OF_QUALIFIED_TY,
196 Allow,
197 "using `ty::{Ty,TyCtxt}` instead of importing it",
198 report_in_external_macro: true
199}
200
201pub 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) -> TyTyKind { *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 => [
202 USAGE_OF_TY_TYKIND,
203 USAGE_OF_QUALIFIED_TY,
204]);
205
206impl<'tcx> LateLintPass<'tcx> for TyTyKind {
207 fn check_path(
208 &mut self,
209 cx: &LateContext<'tcx>,
210 path: &rustc_hir::Path<'tcx>,
211 _: rustc_hir::HirId,
212 ) {
213 if let Some(segment) = path.segments.iter().nth_back(1)
214 && lint_ty_kind_usage(cx, &segment.res)
215 {
216 let span =
217 path.span.with_hi(segment.args.map_or(segment.ident.span, |a| a.span_ext).hi());
218 cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span });
219 }
220 }
221
222 fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) {
223 match &ty.kind {
224 hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
225 if lint_ty_kind_usage(cx, &path.res) {
226 let span = match cx.tcx.parent_hir_node(ty.hir_id) {
227 hir::Node::PatExpr(hir::PatExpr {
228 kind: hir::PatExprKind::Path(qpath),
229 ..
230 })
231 | hir::Node::Pat(hir::Pat {
232 kind:
233 hir::PatKind::TupleStruct(qpath, ..) | hir::PatKind::Struct(qpath, ..),
234 ..
235 })
236 | hir::Node::Expr(
237 hir::Expr { kind: hir::ExprKind::Path(qpath), .. }
238 | &hir::Expr { kind: hir::ExprKind::Struct(qpath, ..), .. },
239 ) => {
240 if let hir::QPath::TypeRelative(qpath_ty, ..) = qpath
241 && qpath_ty.hir_id == ty.hir_id
242 {
243 Some(path.span)
244 } else {
245 None
246 }
247 }
248 _ => None,
249 };
250
251 match span {
252 Some(span) => {
253 cx.emit_span_lint(
254 USAGE_OF_TY_TYKIND,
255 path.span,
256 TykindKind { suggestion: span },
257 );
258 }
259 None => cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
260 }
261 } else if !ty.span.from_expansion()
262 && path.segments.len() > 1
263 && let Some(ty) = is_ty_or_ty_ctxt(cx, path)
264 {
265 cx.emit_span_lint(
266 USAGE_OF_QUALIFIED_TY,
267 path.span,
268 TyQualified { ty, suggestion: path.span },
269 );
270 }
271 }
272 _ => {}
273 }
274 }
275}
276
277fn lint_ty_kind_usage(cx: &LateContext<'_>, res: &Res) -> bool {
278 if let Some(did) = res.opt_def_id() {
279 cx.tcx.is_diagnostic_item(sym::TyKind, did) || cx.tcx.is_diagnostic_item(sym::IrTyKind, did)
280 } else {
281 false
282 }
283}
284
285fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &hir::Path<'_>) -> Option<String> {
286 match path.res {
287 Res::Def(_, def_id) => {
288 if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(def_id) {
289 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())));
290 }
291 }
292 Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
294 if let ty::Adt(adt, args) = cx.tcx.type_of(did).instantiate_identity().kind()
295 && let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
296 {
297 return Some(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}<{1}>", name, args[0]))
})format!("{}<{}>", name, args[0]));
298 }
299 }
300 _ => (),
301 }
302
303 None
304}
305
306fn gen_args(segment: &hir::PathSegment<'_>) -> String {
307 if let Some(args) = &segment.args {
308 let lifetimes = args
309 .args
310 .iter()
311 .filter_map(|arg| {
312 if let hir::GenericArg::Lifetime(lt) = arg {
313 Some(lt.ident.to_string())
314 } else {
315 None
316 }
317 })
318 .collect::<Vec<_>>();
319
320 if !lifetimes.is_empty() {
321 return ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}>", lifetimes.join(", ")))
})format!("<{}>", lifetimes.join(", "));
322 }
323 }
324
325 String::new()
326}
327
328#[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! {
329 pub rustc::NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
332 Allow,
333 "non-glob import of `rustc_type_ir::inherent`",
334 report_in_external_macro: true
335}
336
337#[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! {
338 pub rustc::USAGE_OF_TYPE_IR_INHERENT,
342 Allow,
343 "usage `rustc_type_ir::inherent` outside of trait system",
344 report_in_external_macro: true
345}
346
347#[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! {
348 pub rustc::USAGE_OF_TYPE_IR_TRAITS,
355 Allow,
356 "usage `rustc_type_ir`-specific abstraction traits outside of trait system",
357 report_in_external_macro: true
358}
359#[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! {
360 pub rustc::DIRECT_USE_OF_RUSTC_TYPE_IR,
365 Allow,
366 "usage `rustc_type_ir` abstraction outside of trait system",
367 report_in_external_macro: true
368}
369
370pub 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) -> TypeIr { *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 => [DIRECT_USE_OF_RUSTC_TYPE_IR, NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_INHERENT, USAGE_OF_TYPE_IR_TRAITS]);
371
372impl<'tcx> LateLintPass<'tcx> for TypeIr {
373 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
374 let res_def_id = match expr.kind {
375 hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => path.res.opt_def_id(),
376 hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::MethodCall(..) => {
377 cx.typeck_results().type_dependent_def_id(expr.hir_id)
378 }
379 _ => return,
380 };
381 let Some(res_def_id) = res_def_id else {
382 return;
383 };
384 if let Some(assoc_item) = cx.tcx.opt_associated_item(res_def_id)
385 && let Some(trait_def_id) = assoc_item.trait_container(cx.tcx)
386 && (cx.tcx.is_diagnostic_item(sym::type_ir_interner, trait_def_id)
387 | cx.tcx.is_diagnostic_item(sym::type_ir_infer_ctxt_like, trait_def_id))
388 {
389 cx.emit_span_lint(USAGE_OF_TYPE_IR_TRAITS, expr.span, TypeIrTraitUsage);
390 }
391 }
392
393 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
394 let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return };
395
396 let is_mod_inherent = |res: Res| {
397 res.opt_def_id()
398 .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id))
399 };
400
401 if let Some(seg) = path.segments.iter().find(|seg| is_mod_inherent(seg.res)) {
403 cx.emit_span_lint(USAGE_OF_TYPE_IR_INHERENT, seg.ident.span, TypeIrInherentUsage);
404 }
405 else if let Some(type_ns) = path.res.type_ns
407 && is_mod_inherent(type_ns)
408 {
409 cx.emit_span_lint(
410 USAGE_OF_TYPE_IR_INHERENT,
411 path.segments.last().unwrap().ident.span,
412 TypeIrInherentUsage,
413 );
414 }
415
416 let (lo, hi, snippet) = match path.segments {
417 [.., penultimate, segment] if is_mod_inherent(penultimate.res) => {
418 (segment.ident.span, item.kind.ident().unwrap().span, "*")
419 }
420 [.., segment]
421 if let Some(type_ns) = path.res.type_ns
422 && is_mod_inherent(type_ns)
423 && let rustc_hir::UseKind::Single(ident) = kind =>
424 {
425 let (lo, snippet) =
426 match cx.tcx.sess.source_map().span_to_snippet(path.span).as_deref() {
427 Ok("self") => (path.span, "*"),
428 _ => (segment.ident.span.shrink_to_hi(), "::*"),
429 };
430 (lo, if segment.ident == ident { lo } else { ident.span }, snippet)
431 }
432 _ => return,
433 };
434 cx.emit_span_lint(
435 NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
436 path.span,
437 NonGlobImportTypeIrInherent { suggestion: lo.eq_ctxt(hi).then(|| lo.to(hi)), snippet },
438 );
439 }
440
441 fn check_path(
442 &mut self,
443 cx: &LateContext<'tcx>,
444 path: &rustc_hir::Path<'tcx>,
445 _: rustc_hir::HirId,
446 ) {
447 if let Some(seg) = path.segments.iter().find(|seg| {
448 seg.res
449 .opt_def_id()
450 .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir, def_id))
451 }) {
452 cx.emit_span_lint(DIRECT_USE_OF_RUSTC_TYPE_IR, seg.ident.span, TypeIrDirectUse);
453 }
454 }
455}
456
457#[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! {
458 pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO,
461 Allow,
462 "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
463}
464
465pub 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) -> LintPassImpl { *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]);
466
467impl EarlyLintPass for LintPassImpl {
468 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
469 if let ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) = &item.kind
470 && let Some(last) = of_trait.trait_ref.path.segments.last()
471 && last.ident.name == sym::LintPass
472 {
473 let expn_data = of_trait.trait_ref.path.span.ctxt().outer_expn_data();
474 let call_site = expn_data.call_site;
475 if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
476 && call_site.ctxt().outer_expn_data().kind
477 != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
478 {
479 cx.emit_span_lint(
480 LINT_PASS_IMPL_WITHOUT_MACRO,
481 of_trait.trait_ref.path.span,
482 LintPassByHand,
483 );
484 }
485 }
486 }
487}
488
489#[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! {
490 pub rustc::BAD_OPT_ACCESS,
493 Deny,
494 "prevent using options by field access when there is a wrapper function",
495 report_in_external_macro: true
496}
497
498pub 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) -> BadOptAccess { *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]);
499
500impl LateLintPass<'_> for BadOptAccess {
501 fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
502 let hir::ExprKind::Field(base, target) = expr.kind else { return };
503 let Some(adt_def) = cx.typeck_results().expr_ty(base).ty_adt_def() else { return };
504 if !{
#[allow(deprecated)]
{
{
'done:
{
for i in cx.tcx.get_all_attrs(adt_def.did()) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcLintOptTy) => {
break 'done Some(());
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}.is_some()find_attr!(cx.tcx, adt_def.did(), RustcLintOptTy) {
507 return;
508 }
509
510 for field in adt_def.all_fields() {
511 if field.name == target.name
512 && let Some(lint_message) = {
#[allow(deprecated)]
{
{
'done:
{
for i in cx.tcx.get_all_attrs(field.did) {
#[allow(unused_imports)]
use rustc_hir::attrs::AttributeKind::*;
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(RustcLintOptDenyFieldAccess {
lint_message }) => {
break 'done Some(lint_message);
}
rustc_hir::Attribute::Unparsed(..) =>
{}
#[deny(unreachable_patterns)]
_ => {}
}
}
None
}
}
}
}find_attr!(cx.tcx, field.did, RustcLintOptDenyFieldAccess { lint_message, } => lint_message)
513 {
514 cx.emit_span_lint(
515 BAD_OPT_ACCESS,
516 expr.span,
517 BadOptAccessDiag { msg: lint_message.as_str() },
518 );
519 }
520 }
521 }
522}
523
524pub 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! {
525 pub rustc::SPAN_USE_EQ_CTXT,
526 Allow,
527 "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead",
528 report_in_external_macro: true
529}
530
531pub 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) -> SpanUseEqCtxt { *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]);
532
533impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
534 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
535 if let hir::ExprKind::Binary(
536 hir::BinOp { node: hir::BinOpKind::Eq | hir::BinOpKind::Ne, .. },
537 lhs,
538 rhs,
539 ) = expr.kind
540 {
541 if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
542 cx.emit_span_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
543 }
544 }
545 }
546}
547
548fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
549 match &expr.kind {
550 hir::ExprKind::MethodCall(..) => cx
551 .typeck_results()
552 .type_dependent_def_id(expr.hir_id)
553 .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)),
554
555 _ => false,
556 }
557}
558
559#[doc =
r" The `symbol_intern_string_literal` detects `Symbol::intern` 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`, 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! {
560 pub rustc::SYMBOL_INTERN_STRING_LITERAL,
562 Allow,
565 "Forbid uses of string literals in `Symbol::intern`, suggesting preinterning instead",
566 report_in_external_macro: true
567}
568
569pub 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) -> SymbolInternStringLiteral { *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]);
570
571impl<'tcx> LateLintPass<'tcx> for SymbolInternStringLiteral {
572 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
573 if let hir::ExprKind::Call(path, [arg]) = expr.kind
574 && let hir::ExprKind::Path(ref qpath) = path.kind
575 && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
576 && cx.tcx.is_diagnostic_item(sym::SymbolIntern, def_id)
577 && let hir::ExprKind::Lit(kind) = arg.kind
578 && let rustc_ast::LitKind::Str(_, _) = kind.node
579 {
580 cx.emit_span_lint(
581 SYMBOL_INTERN_STRING_LITERAL,
582 kind.span,
583 SymbolInternStringLiteralDiag,
584 );
585 }
586 }
587}
588
589#[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! {
590 pub rustc::IMPLICIT_SYSROOT_CRATE_IMPORT,
594 Allow,
595 "Forbid uses of non-sysroot crates in `extern crate`",
596 report_in_external_macro: true
597}
598
599pub 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) -> ImplicitSysrootCrateImport { *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]);
600
601impl EarlyLintPass for ImplicitSysrootCrateImport {
602 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
603 fn is_whitelisted(crate_name: &str) -> bool {
604 crate_name.starts_with("rustc_")
606 || #[allow(non_exhaustive_omitted_patterns)] match crate_name {
"test" | "self" | "core" | "alloc" | "std" | "proc_macro" |
"tikv_jemalloc_sys" => true,
_ => false,
}matches!(
607 crate_name,
608 "test" | "self" | "core" | "alloc" | "std" | "proc_macro" | "tikv_jemalloc_sys"
609 )
610 }
611
612 if let ast::ItemKind::ExternCrate(original_name, imported_name) = &item.kind {
613 let name = original_name.as_ref().unwrap_or(&imported_name.name).as_str();
614 let externs = &cx.builder.sess().opts.externs;
615 if externs.get(name).is_none() && !is_whitelisted(name) {
616 cx.emit_span_lint(
617 IMPLICIT_SYSROOT_CRATE_IMPORT,
618 item.span,
619 ImplicitSysrootCrateImportDiag { name },
620 );
621 }
622 }
623 }
624}
625
626pub 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! {
627 pub rustc::BAD_USE_OF_FIND_ATTR,
628 Allow,
629 "Forbid `AttributeKind::` as a prefix in `find_attr!` macros.",
630 report_in_external_macro: true
631}
632pub 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) -> BadUseOfFindAttr { *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]);
633
634impl EarlyLintPass for BadUseOfFindAttr {
635 fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &rustc_ast::Arm) {
636 fn path_contains_attribute_kind(cx: &EarlyContext<'_>, path: &Path) {
637 for segment in &path.segments {
638 if segment.ident.as_str() == "AttributeKind" {
639 cx.emit_span_lint(
640 BAD_USE_OF_FIND_ATTR,
641 segment.span(),
642 AttributeKindInFindAttr,
643 );
644 }
645 }
646 }
647
648 fn find_attr_kind_in_pat(cx: &EarlyContext<'_>, pat: &Pat) {
649 match &pat.kind {
650 PatKind::Struct(_, path, fields, _) => {
651 path_contains_attribute_kind(cx, path);
652 for field in fields {
653 find_attr_kind_in_pat(cx, &field.pat);
654 }
655 }
656 PatKind::TupleStruct(_, path, fields) => {
657 path_contains_attribute_kind(cx, path);
658 for field in fields {
659 find_attr_kind_in_pat(cx, &field);
660 }
661 }
662 PatKind::Or(options) => {
663 for pat in options {
664 find_attr_kind_in_pat(cx, pat);
665 }
666 }
667 PatKind::Path(_, path) => {
668 path_contains_attribute_kind(cx, path);
669 }
670 PatKind::Tuple(elems) => {
671 for pat in elems {
672 find_attr_kind_in_pat(cx, pat);
673 }
674 }
675 PatKind::Box(pat) => {
676 find_attr_kind_in_pat(cx, pat);
677 }
678 PatKind::Deref(pat) => {
679 find_attr_kind_in_pat(cx, pat);
680 }
681 PatKind::Ref(..) => {
682 find_attr_kind_in_pat(cx, pat);
683 }
684 PatKind::Slice(elems) => {
685 for pat in elems {
686 find_attr_kind_in_pat(cx, pat);
687 }
688 }
689
690 PatKind::Guard(pat, ..) => {
691 find_attr_kind_in_pat(cx, pat);
692 }
693 PatKind::Paren(pat) => {
694 find_attr_kind_in_pat(cx, pat);
695 }
696 PatKind::Expr(..)
697 | PatKind::Range(..)
698 | PatKind::MacCall(..)
699 | PatKind::Rest
700 | PatKind::Missing
701 | PatKind::Err(..)
702 | PatKind::Ident(..)
703 | PatKind::Never
704 | PatKind::Wild => {}
705 }
706 }
707
708 if let Some(expn_data) = arm.span.source_callee()
709 && let ExpnKind::Macro(_, name) = expn_data.kind
710 && name.as_str() == "find_attr"
711 {
712 find_attr_kind_in_pat(cx, &arm.pat);
713 }
714 }
715}