1use 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 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 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 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 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 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 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
167fn 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 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 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 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 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 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 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 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 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 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 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 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 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` 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! {
606 pub rustc::SYMBOL_INTERN_STRING_LITERAL,
608 Allow,
609 "Forbid uses of string literals in `Symbol::intern`, 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, [arg]) = 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 && cx.tcx.is_diagnostic_item(sym::SymbolIntern, def_id)
621 && let hir::ExprKind::Lit(kind) = arg.kind
622 && let rustc_ast::LitKind::Str(_, _) = kind.node
623 {
624 cx.emit_span_lint(
625 SYMBOL_INTERN_STRING_LITERAL,
626 kind.span,
627 SymbolInternStringLiteralDiag,
628 );
629 }
630 }
631}
632
633#[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! {
634 pub rustc::IMPLICIT_SYSROOT_CRATE_IMPORT,
638 Allow,
639 "Forbid uses of non-sysroot crates in `extern crate`",
640 report_in_external_macro: true
641}
642
643pub 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]);
644
645impl EarlyLintPass for ImplicitSysrootCrateImport {
646 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
647 fn is_whitelisted(crate_name: &str) -> bool {
648 crate_name.starts_with("rustc_")
650 || #[allow(non_exhaustive_omitted_patterns)] match crate_name {
"test" | "self" | "core" | "alloc" | "std" | "proc_macro" |
"tikv_jemalloc_sys" => true,
_ => false,
}matches!(
651 crate_name,
652 "test" | "self" | "core" | "alloc" | "std" | "proc_macro" | "tikv_jemalloc_sys"
653 )
654 }
655
656 if let ast::ItemKind::ExternCrate(original_name, imported_name) = &item.kind {
657 let name = original_name.as_ref().unwrap_or(&imported_name.name).as_str();
658 let externs = &cx.builder.sess().opts.externs;
659 if externs.get(name).is_none() && !is_whitelisted(name) {
660 cx.emit_span_lint(
661 IMPLICIT_SYSROOT_CRATE_IMPORT,
662 item.span,
663 ImplicitSysrootCrateImportDiag { name },
664 );
665 }
666 }
667 }
668}
669
670pub 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! {
671 pub rustc::BAD_USE_OF_FIND_ATTR,
672 Allow,
673 "Forbid `AttributeKind::` as a prefix in `find_attr!` macros.",
674 report_in_external_macro: true
675}
676pub 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]);
677
678impl EarlyLintPass for BadUseOfFindAttr {
679 fn check_arm(&mut self, cx: &EarlyContext<'_>, arm: &rustc_ast::Arm) {
680 fn path_contains_attribute_kind(cx: &EarlyContext<'_>, path: &Path) {
681 for segment in &path.segments {
682 if segment.ident.as_str() == "AttributeKind" {
683 cx.emit_span_lint(
684 BAD_USE_OF_FIND_ATTR,
685 segment.span(),
686 AttributeKindInFindAttr,
687 );
688 }
689 }
690 }
691
692 fn find_attr_kind_in_pat(cx: &EarlyContext<'_>, pat: &Pat) {
693 match &pat.kind {
694 PatKind::Struct(_, path, fields, _) => {
695 path_contains_attribute_kind(cx, path);
696 for field in fields {
697 find_attr_kind_in_pat(cx, &field.pat);
698 }
699 }
700 PatKind::TupleStruct(_, path, fields) => {
701 path_contains_attribute_kind(cx, path);
702 for field in fields {
703 find_attr_kind_in_pat(cx, &field);
704 }
705 }
706 PatKind::Or(options) => {
707 for pat in options {
708 find_attr_kind_in_pat(cx, pat);
709 }
710 }
711 PatKind::Path(_, path) => {
712 path_contains_attribute_kind(cx, path);
713 }
714 PatKind::Tuple(elems) => {
715 for pat in elems {
716 find_attr_kind_in_pat(cx, pat);
717 }
718 }
719 PatKind::Deref(pat) => {
720 find_attr_kind_in_pat(cx, pat);
721 }
722 PatKind::Ref(..) => {
723 find_attr_kind_in_pat(cx, pat);
724 }
725 PatKind::Slice(elems) => {
726 for pat in elems {
727 find_attr_kind_in_pat(cx, pat);
728 }
729 }
730
731 PatKind::Guard(pat, ..) => {
732 find_attr_kind_in_pat(cx, pat);
733 }
734 PatKind::Paren(pat) => {
735 find_attr_kind_in_pat(cx, pat);
736 }
737 PatKind::Expr(..)
738 | PatKind::Range(..)
739 | PatKind::MacCall(..)
740 | PatKind::Rest
741 | PatKind::Missing
742 | PatKind::Err(..)
743 | PatKind::Ident(..)
744 | PatKind::Never
745 | PatKind::Wild => {}
746 }
747 }
748
749 if let Some(expn_data) = arm.span.source_callee()
750 && let ExpnKind::Macro(_, name) = expn_data.kind
751 && name.as_str() == "find_attr"
752 {
753 find_attr_kind_in_pat(cx, &arm.pat);
754 }
755 }
756}
757
758pub 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! {
759 pub rustc::RUSTC_MUST_MATCH_EXHAUSTIVELY,
760 Allow,
761 "Forbids matches with wildcards, or if-let matching on enums marked with `#[rustc_must_match_exhaustively]`",
762 report_in_external_macro: true
763}
764pub 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]);
765
766fn is_rustc_must_match_exhaustively(cx: &LateContext<'_>, id: HirId) -> Option<Span> {
767 let res = cx.typeck_results();
768
769 let ty = res.node_type(id);
770
771 let ty = if let ty::Ref(_, ty, _) = ty.kind() { *ty } else { ty };
772
773 if let Some(adt_def) = ty.ty_adt_def()
774 && adt_def.is_enum()
775 {
776 {
{
'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)
777 } else {
778 None
779 }
780}
781
782fn pat_is_not_exhaustive_heuristic(pat: &hir::Pat<'_>) -> Option<(Span, &'static str)> {
783 match pat.kind {
784 hir::PatKind::Missing => None,
785 hir::PatKind::Wild => Some((pat.span, "because of this wildcard pattern")),
786 hir::PatKind::Binding(_, _, _, Some(pat)) => pat_is_not_exhaustive_heuristic(pat),
787 hir::PatKind::Binding(..) => Some((pat.span, "because of this variable binding")),
788 hir::PatKind::Struct(..) => None,
789 hir::PatKind::TupleStruct(..) => None,
790 hir::PatKind::Or(..) => None,
791 hir::PatKind::Never => None,
792 hir::PatKind::Tuple(..) => None,
793 hir::PatKind::Deref(pat) => pat_is_not_exhaustive_heuristic(&*pat),
794 hir::PatKind::Ref(pat, _, _) => pat_is_not_exhaustive_heuristic(&*pat),
795 hir::PatKind::Expr(..) => None,
796 hir::PatKind::Guard(..) => None,
797 hir::PatKind::Range(..) => None,
798 hir::PatKind::Slice(..) => None,
799 hir::PatKind::Err(..) => None,
800 }
801}
802
803impl<'tcx> LateLintPass<'tcx> for RustcMustMatchExhaustively {
804 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
805 match expr.kind {
806 hir::ExprKind::Match(expr, arms, _) => {
809 if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.hir_id) {
810 for arm in arms {
811 if let Some((span, message)) = pat_is_not_exhaustive_heuristic(arm.pat) {
812 cx.emit_span_lint(
813 RUSTC_MUST_MATCH_EXHAUSTIVELY,
814 expr.span,
815 RustcMustMatchExhaustivelyNotExhaustive {
816 attr_span,
817 pat_span: span,
818 message,
819 },
820 );
821 }
822 }
823 }
824 }
825 hir::ExprKind::Let(expr, ..) => {
826 if let Some(attr_span) = is_rustc_must_match_exhaustively(cx, expr.init.hir_id) {
827 cx.emit_span_lint(
828 RUSTC_MUST_MATCH_EXHAUSTIVELY,
829 expr.span,
830 RustcMustMatchExhaustivelyNotExhaustive {
831 attr_span,
832 pat_span: expr.span,
833 message: "using `if let` only matches on one variant (try using `match`)",
834 },
835 );
836 }
837 }
838 _ => {}
839 }
840 }
841
842 fn check_stmt(&mut self, cx: &LateContext<'tcx>, stmt: &'tcx rustc_hir::Stmt<'tcx>) {
843 match stmt.kind {
844 rustc_hir::StmtKind::Let(let_stmt) => {
845 if let_stmt.els.is_some()
846 && let Some(attr_span) =
847 is_rustc_must_match_exhaustively(cx, let_stmt.pat.hir_id)
848 {
849 cx.emit_span_lint(
850 RUSTC_MUST_MATCH_EXHAUSTIVELY,
851 let_stmt.span,
852 RustcMustMatchExhaustivelyNotExhaustive {
853 attr_span,
854 pat_span: let_stmt.pat.span,
855 message: "using `let else` only matches on one variant (try using `match`)",
856 },
857 );
858 }
859 }
860 _ => {}
861 }
862 }
863}