1use rustc_hir::attrs::AttributeKind;
5use rustc_hir::def::Res;
6use rustc_hir::def_id::DefId;
7use rustc_hir::{Expr, ExprKind, HirId, find_attr};
8use rustc_middle::ty::{self, GenericArgsRef, PredicatePolarity, Ty};
9use rustc_session::{declare_lint_pass, declare_tool_lint};
10use rustc_span::hygiene::{ExpnKind, MacroKind};
11use rustc_span::{Span, sym};
12use tracing::debug;
13use {rustc_ast as ast, rustc_hir as hir};
14
15use crate::lints::{
16 BadOptAccessDiag, DefaultHashTypesDiag, DiagOutOfImpl, ImplicitSysrootCrateImportDiag,
17 LintPassByHand, NonGlobImportTypeIrInherent, QueryInstability, QueryUntracked,
18 SpanUseEqCtxtDiag, SymbolInternStringLiteralDiag, TyQualified, TykindDiag, TykindKind,
19 TypeIrDirectUse, TypeIrInherentUsage, TypeIrTraitUsage, UntranslatableDiag,
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 {
<[_]>::into_vec(::alloc::boxed::box_new([DEFAULT_HASH_TYPES]))
}
}
impl DefaultHashTypes {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([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 {
<[_]>::into_vec(::alloc::boxed::box_new([POTENTIAL_QUERY_INSTABILITY,
UNTRACKED_QUERY_INFORMATION]))
}
}
impl QueryStability {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([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 {
{
'done:
{
for i in cx.tcx.get_all_attrs(def_id) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcLintQueryInstability)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(cx.tcx.get_all_attrs(def_id), AttributeKind::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 {
{
'done:
{
for i in cx.tcx.get_all_attrs(def_id) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcLintUntrackedQueryInformation)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(
110 cx.tcx.get_all_attrs(def_id),
111 AttributeKind::RustcLintUntrackedQueryInformation
112 ) {
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 predicates = cx.tcx.predicates_of(callee_def_id).instantiate(cx.tcx, generic_args);
135 for (predicate, _) in predicates {
136 let Some(trait_pred) = predicate.as_trait_clause() else {
137 continue;
138 };
139 if trait_pred.def_id() != into_iterator_def_id
140 || trait_pred.polarity() != PredicatePolarity::Positive
141 {
142 continue;
143 }
144 let into_iter_fn_args =
146 cx.tcx.instantiate_bound_regions_with_erased(trait_pred).trait_ref.args;
147 let Ok(Some(instance)) = ty::Instance::try_resolve(
148 cx.tcx,
149 cx.typing_env(),
150 into_iter_fn_def_id,
151 into_iter_fn_args,
152 ) else {
153 continue;
154 };
155 if {
{
'done:
{
for i in cx.tcx.get_all_attrs(instance.def_id()) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcLintQueryInstability)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(
158 cx.tcx.get_all_attrs(instance.def_id()),
159 AttributeKind::RustcLintQueryInstability
160 ) {
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((*callee_def_id, callee.span, generic_args, None, args));
179 }
180 if let ExprKind::MethodCall(segment, recv, args, _) = expr.kind
181 && let Some(method_def_id) = cx.typeck_results().type_dependent_def_id(expr.hir_id)
182 {
183 let generic_args = cx.typeck_results().node_args(expr.hir_id);
184 return Some((method_def_id, segment.ident.span, generic_args, Some(recv), args));
185 }
186 None
187}
188
189#[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! {
190 pub rustc::USAGE_OF_TY_TYKIND,
193 Allow,
194 "usage of `ty::TyKind` outside of the `ty::sty` module",
195 report_in_external_macro: true
196}
197
198#[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! {
199 pub rustc::USAGE_OF_QUALIFIED_TY,
202 Allow,
203 "using `ty::{Ty,TyCtxt}` instead of importing it",
204 report_in_external_macro: true
205}
206
207pub 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 {
<[_]>::into_vec(::alloc::boxed::box_new([USAGE_OF_TY_TYKIND,
USAGE_OF_QUALIFIED_TY]))
}
}
impl TyTyKind {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([USAGE_OF_TY_TYKIND,
USAGE_OF_QUALIFIED_TY]))
}
}declare_lint_pass!(TyTyKind => [
208 USAGE_OF_TY_TYKIND,
209 USAGE_OF_QUALIFIED_TY,
210]);
211
212impl<'tcx> LateLintPass<'tcx> for TyTyKind {
213 fn check_path(
214 &mut self,
215 cx: &LateContext<'tcx>,
216 path: &rustc_hir::Path<'tcx>,
217 _: rustc_hir::HirId,
218 ) {
219 if let Some(segment) = path.segments.iter().nth_back(1)
220 && lint_ty_kind_usage(cx, &segment.res)
221 {
222 let span =
223 path.span.with_hi(segment.args.map_or(segment.ident.span, |a| a.span_ext).hi());
224 cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindKind { suggestion: span });
225 }
226 }
227
228 fn check_ty(&mut self, cx: &LateContext<'_>, ty: &'tcx hir::Ty<'tcx, hir::AmbigArg>) {
229 match &ty.kind {
230 hir::TyKind::Path(hir::QPath::Resolved(_, path)) => {
231 if lint_ty_kind_usage(cx, &path.res) {
232 let span = match cx.tcx.parent_hir_node(ty.hir_id) {
233 hir::Node::PatExpr(hir::PatExpr {
234 kind: hir::PatExprKind::Path(qpath),
235 ..
236 })
237 | hir::Node::Pat(hir::Pat {
238 kind:
239 hir::PatKind::TupleStruct(qpath, ..) | hir::PatKind::Struct(qpath, ..),
240 ..
241 })
242 | hir::Node::Expr(
243 hir::Expr { kind: hir::ExprKind::Path(qpath), .. }
244 | &hir::Expr { kind: hir::ExprKind::Struct(qpath, ..), .. },
245 ) => {
246 if let hir::QPath::TypeRelative(qpath_ty, ..) = qpath
247 && qpath_ty.hir_id == ty.hir_id
248 {
249 Some(path.span)
250 } else {
251 None
252 }
253 }
254 _ => None,
255 };
256
257 match span {
258 Some(span) => {
259 cx.emit_span_lint(
260 USAGE_OF_TY_TYKIND,
261 path.span,
262 TykindKind { suggestion: span },
263 );
264 }
265 None => cx.emit_span_lint(USAGE_OF_TY_TYKIND, path.span, TykindDiag),
266 }
267 } else if !ty.span.from_expansion()
268 && path.segments.len() > 1
269 && let Some(ty) = is_ty_or_ty_ctxt(cx, path)
270 {
271 cx.emit_span_lint(
272 USAGE_OF_QUALIFIED_TY,
273 path.span,
274 TyQualified { ty, suggestion: path.span },
275 );
276 }
277 }
278 _ => {}
279 }
280 }
281}
282
283fn lint_ty_kind_usage(cx: &LateContext<'_>, res: &Res) -> bool {
284 if let Some(did) = res.opt_def_id() {
285 cx.tcx.is_diagnostic_item(sym::TyKind, did) || cx.tcx.is_diagnostic_item(sym::IrTyKind, did)
286 } else {
287 false
288 }
289}
290
291fn is_ty_or_ty_ctxt(cx: &LateContext<'_>, path: &hir::Path<'_>) -> Option<String> {
292 match &path.res {
293 Res::Def(_, def_id) => {
294 if let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(*def_id) {
295 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())));
296 }
297 }
298 Res::SelfTyAlias { alias_to: did, is_trait_impl: false, .. } => {
300 if let ty::Adt(adt, args) = cx.tcx.type_of(did).instantiate_identity().kind()
301 && let Some(name @ (sym::Ty | sym::TyCtxt)) = cx.tcx.get_diagnostic_name(adt.did())
302 {
303 return Some(::alloc::__export::must_use({
::alloc::fmt::format(format_args!("{0}<{1}>", name, args[0]))
})format!("{}<{}>", name, args[0]));
304 }
305 }
306 _ => (),
307 }
308
309 None
310}
311
312fn gen_args(segment: &hir::PathSegment<'_>) -> String {
313 if let Some(args) = &segment.args {
314 let lifetimes = args
315 .args
316 .iter()
317 .filter_map(|arg| {
318 if let hir::GenericArg::Lifetime(lt) = arg {
319 Some(lt.ident.to_string())
320 } else {
321 None
322 }
323 })
324 .collect::<Vec<_>>();
325
326 if !lifetimes.is_empty() {
327 return ::alloc::__export::must_use({
::alloc::fmt::format(format_args!("<{0}>", lifetimes.join(", ")))
})format!("<{}>", lifetimes.join(", "));
328 }
329 }
330
331 String::new()
332}
333
334#[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! {
335 pub rustc::NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
338 Allow,
339 "non-glob import of `rustc_type_ir::inherent`",
340 report_in_external_macro: true
341}
342
343#[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! {
344 pub rustc::USAGE_OF_TYPE_IR_INHERENT,
348 Allow,
349 "usage `rustc_type_ir::inherent` outside of trait system",
350 report_in_external_macro: true
351}
352
353#[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! {
354 pub rustc::USAGE_OF_TYPE_IR_TRAITS,
361 Allow,
362 "usage `rustc_type_ir`-specific abstraction traits outside of trait system",
363 report_in_external_macro: true
364}
365#[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! {
366 pub rustc::DIRECT_USE_OF_RUSTC_TYPE_IR,
371 Allow,
372 "usage `rustc_type_ir` abstraction outside of trait system",
373 report_in_external_macro: true
374}
375
376pub 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 {
<[_]>::into_vec(::alloc::boxed::box_new([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 {
<[_]>::into_vec(::alloc::boxed::box_new([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]);
377
378impl<'tcx> LateLintPass<'tcx> for TypeIr {
379 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
380 let res_def_id = match expr.kind {
381 hir::ExprKind::Path(hir::QPath::Resolved(_, path)) => path.res.opt_def_id(),
382 hir::ExprKind::Path(hir::QPath::TypeRelative(..)) | hir::ExprKind::MethodCall(..) => {
383 cx.typeck_results().type_dependent_def_id(expr.hir_id)
384 }
385 _ => return,
386 };
387 let Some(res_def_id) = res_def_id else {
388 return;
389 };
390 if let Some(assoc_item) = cx.tcx.opt_associated_item(res_def_id)
391 && let Some(trait_def_id) = assoc_item.trait_container(cx.tcx)
392 && (cx.tcx.is_diagnostic_item(sym::type_ir_interner, trait_def_id)
393 | cx.tcx.is_diagnostic_item(sym::type_ir_infer_ctxt_like, trait_def_id))
394 {
395 cx.emit_span_lint(USAGE_OF_TYPE_IR_TRAITS, expr.span, TypeIrTraitUsage);
396 }
397 }
398
399 fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx hir::Item<'tcx>) {
400 let rustc_hir::ItemKind::Use(path, kind) = item.kind else { return };
401
402 let is_mod_inherent = |res: Res| {
403 res.opt_def_id()
404 .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir_inherent, def_id))
405 };
406
407 if let Some(seg) = path.segments.iter().find(|seg| is_mod_inherent(seg.res)) {
409 cx.emit_span_lint(USAGE_OF_TYPE_IR_INHERENT, seg.ident.span, TypeIrInherentUsage);
410 }
411 else if let Some(type_ns) = path.res.type_ns
413 && is_mod_inherent(type_ns)
414 {
415 cx.emit_span_lint(
416 USAGE_OF_TYPE_IR_INHERENT,
417 path.segments.last().unwrap().ident.span,
418 TypeIrInherentUsage,
419 );
420 }
421
422 let (lo, hi, snippet) = match path.segments {
423 [.., penultimate, segment] if is_mod_inherent(penultimate.res) => {
424 (segment.ident.span, item.kind.ident().unwrap().span, "*")
425 }
426 [.., segment]
427 if let Some(type_ns) = path.res.type_ns
428 && is_mod_inherent(type_ns)
429 && let rustc_hir::UseKind::Single(ident) = kind =>
430 {
431 let (lo, snippet) =
432 match cx.tcx.sess.source_map().span_to_snippet(path.span).as_deref() {
433 Ok("self") => (path.span, "*"),
434 _ => (segment.ident.span.shrink_to_hi(), "::*"),
435 };
436 (lo, if segment.ident == ident { lo } else { ident.span }, snippet)
437 }
438 _ => return,
439 };
440 cx.emit_span_lint(
441 NON_GLOB_IMPORT_OF_TYPE_IR_INHERENT,
442 path.span,
443 NonGlobImportTypeIrInherent { suggestion: lo.eq_ctxt(hi).then(|| lo.to(hi)), snippet },
444 );
445 }
446
447 fn check_path(
448 &mut self,
449 cx: &LateContext<'tcx>,
450 path: &rustc_hir::Path<'tcx>,
451 _: rustc_hir::HirId,
452 ) {
453 if let Some(seg) = path.segments.iter().find(|seg| {
454 seg.res
455 .opt_def_id()
456 .is_some_and(|def_id| cx.tcx.is_diagnostic_item(sym::type_ir, def_id))
457 }) {
458 cx.emit_span_lint(DIRECT_USE_OF_RUSTC_TYPE_IR, seg.ident.span, TypeIrDirectUse);
459 }
460 }
461}
462
463#[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! {
464 pub rustc::LINT_PASS_IMPL_WITHOUT_MACRO,
467 Allow,
468 "`impl LintPass` without the `declare_lint_pass!` or `impl_lint_pass!` macros"
469}
470
471pub 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 {
<[_]>::into_vec(::alloc::boxed::box_new([LINT_PASS_IMPL_WITHOUT_MACRO]))
}
}
impl LintPassImpl {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([LINT_PASS_IMPL_WITHOUT_MACRO]))
}
}declare_lint_pass!(LintPassImpl => [LINT_PASS_IMPL_WITHOUT_MACRO]);
472
473impl EarlyLintPass for LintPassImpl {
474 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
475 if let ast::ItemKind::Impl(ast::Impl { of_trait: Some(of_trait), .. }) = &item.kind
476 && let Some(last) = of_trait.trait_ref.path.segments.last()
477 && last.ident.name == sym::LintPass
478 {
479 let expn_data = of_trait.trait_ref.path.span.ctxt().outer_expn_data();
480 let call_site = expn_data.call_site;
481 if expn_data.kind != ExpnKind::Macro(MacroKind::Bang, sym::impl_lint_pass)
482 && call_site.ctxt().outer_expn_data().kind
483 != ExpnKind::Macro(MacroKind::Bang, sym::declare_lint_pass)
484 {
485 cx.emit_span_lint(
486 LINT_PASS_IMPL_WITHOUT_MACRO,
487 of_trait.trait_ref.path.span,
488 LintPassByHand,
489 );
490 }
491 }
492 }
493}
494
495#[doc =
r" The `untranslatable_diagnostic` lint detects messages passed to functions with `impl"]
#[doc =
r" Into<{D,Subd}iagMessage` parameters without using translatable Fluent strings."]
#[doc = r""]
#[doc = r" More details on translatable diagnostics can be found"]
#[doc =
r" [here](https://rustc-dev-guide.rust-lang.org/diagnostics/translation.html)."]
pub static UNTRANSLATABLE_DIAGNOSTIC: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: &"rustc::UNTRANSLATABLE_DIAGNOSTIC",
default_level: ::rustc_lint_defs::Allow,
desc: "prevent creation of diagnostics which cannot be translated",
edition_lint_opts: None,
report_in_external_macro: true,
future_incompatible: None,
is_externally_loaded: true,
crate_level_only: false,
eval_always: true,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_tool_lint! {
496 pub rustc::UNTRANSLATABLE_DIAGNOSTIC,
502 Allow,
503 "prevent creation of diagnostics which cannot be translated",
504 report_in_external_macro: true,
505 @eval_always = true
506}
507
508#[doc =
r" The `diagnostic_outside_of_impl` lint detects calls to functions annotated with"]
#[doc =
r" `#[rustc_lint_diagnostics]` that are outside an `Diagnostic`, `Subdiagnostic`, or"]
#[doc = r" `LintDiagnostic` impl (either hand-written or derived)."]
#[doc = r""]
#[doc = r" More details on diagnostics implementations can be found"]
#[doc =
r" [here](https://rustc-dev-guide.rust-lang.org/diagnostics/diagnostic-structs.html)."]
pub static DIAGNOSTIC_OUTSIDE_OF_IMPL: &::rustc_lint_defs::Lint =
&::rustc_lint_defs::Lint {
name: &"rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL",
default_level: ::rustc_lint_defs::Allow,
desc: "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls",
edition_lint_opts: None,
report_in_external_macro: true,
future_incompatible: None,
is_externally_loaded: true,
crate_level_only: false,
eval_always: true,
..::rustc_lint_defs::Lint::default_fields_for_macro()
};declare_tool_lint! {
509 pub rustc::DIAGNOSTIC_OUTSIDE_OF_IMPL,
516 Allow,
517 "prevent diagnostic creation outside of `Diagnostic`/`Subdiagnostic`/`LintDiagnostic` impls",
518 report_in_external_macro: true,
519 @eval_always = true
520}
521
522pub struct Diagnostics;
#[automatically_derived]
impl ::core::marker::Copy for Diagnostics { }
#[automatically_derived]
#[doc(hidden)]
unsafe impl ::core::clone::TrivialClone for Diagnostics { }
#[automatically_derived]
impl ::core::clone::Clone for Diagnostics {
#[inline]
fn clone(&self) -> Diagnostics { *self }
}
impl ::rustc_lint_defs::LintPass for Diagnostics {
fn name(&self) -> &'static str { "Diagnostics" }
fn get_lints(&self) -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([UNTRANSLATABLE_DIAGNOSTIC,
DIAGNOSTIC_OUTSIDE_OF_IMPL]))
}
}
impl Diagnostics {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([UNTRANSLATABLE_DIAGNOSTIC,
DIAGNOSTIC_OUTSIDE_OF_IMPL]))
}
}declare_lint_pass!(Diagnostics => [UNTRANSLATABLE_DIAGNOSTIC, DIAGNOSTIC_OUTSIDE_OF_IMPL]);
523
524impl LateLintPass<'_> for Diagnostics {
525 fn check_expr<'tcx>(&mut self, cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'tcx>) {
526 let collect_args_tys_and_spans = |args: &[hir::Expr<'_>], reserve_one_extra: bool| {
527 let mut result = Vec::with_capacity(args.len() + usize::from(reserve_one_extra));
528 result.extend(args.iter().map(|arg| (cx.typeck_results().expr_ty(arg), arg.span)));
529 result
530 };
531 let Some((def_id, span, fn_gen_args, recv, args)) =
533 get_callee_span_generic_args_and_args(cx, expr)
534 else {
535 return;
536 };
537 let mut arg_tys_and_spans = collect_args_tys_and_spans(args, recv.is_some());
538 if let Some(recv) = recv {
539 arg_tys_and_spans.insert(0, (cx.tcx.types.self_param, recv.span)); }
541
542 Self::diagnostic_outside_of_impl(cx, span, expr.hir_id, def_id, fn_gen_args);
543 Self::untranslatable_diagnostic(cx, def_id, &arg_tys_and_spans);
544 }
545}
546
547impl Diagnostics {
548 fn is_diag_message<'cx>(cx: &LateContext<'cx>, ty: Ty<'cx>) -> bool {
550 if let Some(adt_def) = ty.ty_adt_def()
551 && let Some(name) = cx.tcx.get_diagnostic_name(adt_def.did())
552 && #[allow(non_exhaustive_omitted_patterns)] match name {
sym::DiagMessage | sym::SubdiagMessage => true,
_ => false,
}matches!(name, sym::DiagMessage | sym::SubdiagMessage)
553 {
554 true
555 } else {
556 false
557 }
558 }
559
560 fn untranslatable_diagnostic<'cx>(
561 cx: &LateContext<'cx>,
562 def_id: DefId,
563 arg_tys_and_spans: &[(Ty<'cx>, Span)],
564 ) {
565 let fn_sig = cx.tcx.fn_sig(def_id).instantiate_identity().skip_binder();
566 let predicates = cx.tcx.predicates_of(def_id).instantiate_identity(cx.tcx).predicates;
567 for (i, ¶m_ty) in fn_sig.inputs().iter().enumerate() {
568 if let ty::Param(sig_param) = param_ty.kind() {
569 for pred in predicates.iter() {
571 if let Some(trait_pred) = pred.as_trait_clause()
572 && let trait_ref = trait_pred.skip_binder().trait_ref
573 && trait_ref.self_ty() == param_ty && cx.tcx.is_diagnostic_item(sym::Into, trait_ref.def_id)
575 && let ty1 = trait_ref.args.type_at(1)
576 && Self::is_diag_message(cx, ty1)
577 {
578 let (arg_ty, arg_span) = arg_tys_and_spans[i];
582
583 let is_translatable = Self::is_diag_message(cx, arg_ty)
585 || #[allow(non_exhaustive_omitted_patterns)] match arg_ty.kind() {
ty::Param(arg_param) if arg_param.name == sig_param.name => true,
_ => false,
}matches!(arg_ty.kind(), ty::Param(arg_param) if arg_param.name == sig_param.name);
586 if !is_translatable {
587 cx.emit_span_lint(
588 UNTRANSLATABLE_DIAGNOSTIC,
589 arg_span,
590 UntranslatableDiag,
591 );
592 }
593 }
594 }
595 }
596 }
597 }
598
599 fn diagnostic_outside_of_impl<'cx>(
600 cx: &LateContext<'cx>,
601 span: Span,
602 current_id: HirId,
603 def_id: DefId,
604 fn_gen_args: GenericArgsRef<'cx>,
605 ) {
606 let Some(inst) =
608 ty::Instance::try_resolve(cx.tcx, cx.typing_env(), def_id, fn_gen_args).ok().flatten()
609 else {
610 return;
611 };
612
613 if !{
{
'done:
{
for i in cx.tcx.get_all_attrs(inst.def_id()) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcLintDiagnostics)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(cx.tcx.get_all_attrs(inst.def_id()), AttributeKind::RustcLintDiagnostics) {
614 return;
615 };
616
617 for (hir_id, _parent) in cx.tcx.hir_parent_iter(current_id) {
618 if let Some(owner_did) = hir_id.as_owner()
619 && {
{
'done:
{
for i in cx.tcx.get_all_attrs(owner_did) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcLintDiagnostics)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(cx.tcx.get_all_attrs(owner_did), AttributeKind::RustcLintDiagnostics)
620 {
621 return;
623 }
624 }
625
626 let mut is_inside_appropriate_impl = false;
632 for (_hir_id, parent) in cx.tcx.hir_parent_iter(current_id) {
633 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/internal.rs:633",
"rustc_lint::internal", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/internal.rs"),
::tracing_core::__macro_support::Option::Some(633u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::internal"),
::tracing_core::field::FieldSet::new(&["parent"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&parent) as
&dyn Value))])
});
} else { ; }
};debug!(?parent);
634 if let hir::Node::Item(hir::Item { kind: hir::ItemKind::Impl(impl_), .. }) = parent
635 && let Some(of_trait) = impl_.of_trait
636 && let Some(def_id) = of_trait.trait_ref.trait_def_id()
637 && let Some(name) = cx.tcx.get_diagnostic_name(def_id)
638 && #[allow(non_exhaustive_omitted_patterns)] match name {
sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic => true,
_ => false,
}matches!(name, sym::Diagnostic | sym::Subdiagnostic | sym::LintDiagnostic)
639 {
640 is_inside_appropriate_impl = true;
641 break;
642 }
643 }
644 {
use ::tracing::__macro_support::Callsite as _;
static __CALLSITE: ::tracing::callsite::DefaultCallsite =
{
static META: ::tracing::Metadata<'static> =
{
::tracing_core::metadata::Metadata::new("event compiler/rustc_lint/src/internal.rs:644",
"rustc_lint::internal", ::tracing::Level::DEBUG,
::tracing_core::__macro_support::Option::Some("compiler/rustc_lint/src/internal.rs"),
::tracing_core::__macro_support::Option::Some(644u32),
::tracing_core::__macro_support::Option::Some("rustc_lint::internal"),
::tracing_core::field::FieldSet::new(&["is_inside_appropriate_impl"],
::tracing_core::callsite::Identifier(&__CALLSITE)),
::tracing::metadata::Kind::EVENT)
};
::tracing::callsite::DefaultCallsite::new(&META)
};
let enabled =
::tracing::Level::DEBUG <= ::tracing::level_filters::STATIC_MAX_LEVEL
&&
::tracing::Level::DEBUG <=
::tracing::level_filters::LevelFilter::current() &&
{
let interest = __CALLSITE.interest();
!interest.is_never() &&
::tracing::__macro_support::__is_enabled(__CALLSITE.metadata(),
interest)
};
if enabled {
(|value_set: ::tracing::field::ValueSet|
{
let meta = __CALLSITE.metadata();
::tracing::Event::dispatch(meta, &value_set);
;
})({
#[allow(unused_imports)]
use ::tracing::field::{debug, display, Value};
let mut iter = __CALLSITE.metadata().fields().iter();
__CALLSITE.metadata().fields().value_set(&[(&::tracing::__macro_support::Iterator::next(&mut iter).expect("FieldSet corrupted (this is a bug)"),
::tracing::__macro_support::Option::Some(&debug(&is_inside_appropriate_impl)
as &dyn Value))])
});
} else { ; }
};debug!(?is_inside_appropriate_impl);
645 if !is_inside_appropriate_impl {
646 cx.emit_span_lint(DIAGNOSTIC_OUTSIDE_OF_IMPL, span, DiagOutOfImpl);
647 }
648 }
649}
650
651#[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! {
652 pub rustc::BAD_OPT_ACCESS,
655 Deny,
656 "prevent using options by field access when there is a wrapper function",
657 report_in_external_macro: true
658}
659
660pub 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 {
<[_]>::into_vec(::alloc::boxed::box_new([BAD_OPT_ACCESS]))
}
}
impl BadOptAccess {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([BAD_OPT_ACCESS]))
}
}declare_lint_pass!(BadOptAccess => [BAD_OPT_ACCESS]);
661
662impl LateLintPass<'_> for BadOptAccess {
663 fn check_expr(&mut self, cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
664 let hir::ExprKind::Field(base, target) = expr.kind else { return };
665 let Some(adt_def) = cx.typeck_results().expr_ty(base).ty_adt_def() else { return };
666 if !{
{
'done:
{
for i in cx.tcx.get_all_attrs(adt_def.did()) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcLintOptTy)
=> {
break 'done Some(());
}
_ => {}
}
}
None
}
}.is_some()
}find_attr!(cx.tcx.get_all_attrs(adt_def.did()), AttributeKind::RustcLintOptTy) {
669 return;
670 }
671
672 for field in adt_def.all_fields() {
673 if field.name == target.name
674 && let Some(lint_message) = {
'done:
{
for i in cx.tcx.get_all_attrs(field.did) {
let i: &rustc_hir::Attribute = i;
match i {
rustc_hir::Attribute::Parsed(AttributeKind::RustcLintOptDenyFieldAccess {
lint_message }) => {
break 'done Some(lint_message);
}
_ => {}
}
}
None
}
}find_attr!(cx.tcx.get_all_attrs(field.did), AttributeKind::RustcLintOptDenyFieldAccess { lint_message, } => lint_message)
675 {
676 cx.emit_span_lint(
677 BAD_OPT_ACCESS,
678 expr.span,
679 BadOptAccessDiag { msg: lint_message.as_str() },
680 );
681 }
682 }
683 }
684}
685
686pub 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! {
687 pub rustc::SPAN_USE_EQ_CTXT,
688 Allow,
689 "forbid uses of `==` with `Span::ctxt`, suggest `Span::eq_ctxt` instead",
690 report_in_external_macro: true
691}
692
693pub 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 {
<[_]>::into_vec(::alloc::boxed::box_new([SPAN_USE_EQ_CTXT]))
}
}
impl SpanUseEqCtxt {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([SPAN_USE_EQ_CTXT]))
}
}declare_lint_pass!(SpanUseEqCtxt => [SPAN_USE_EQ_CTXT]);
694
695impl<'tcx> LateLintPass<'tcx> for SpanUseEqCtxt {
696 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &hir::Expr<'_>) {
697 if let hir::ExprKind::Binary(
698 hir::BinOp { node: hir::BinOpKind::Eq | hir::BinOpKind::Ne, .. },
699 lhs,
700 rhs,
701 ) = expr.kind
702 {
703 if is_span_ctxt_call(cx, lhs) && is_span_ctxt_call(cx, rhs) {
704 cx.emit_span_lint(SPAN_USE_EQ_CTXT, expr.span, SpanUseEqCtxtDiag);
705 }
706 }
707 }
708}
709
710fn is_span_ctxt_call(cx: &LateContext<'_>, expr: &hir::Expr<'_>) -> bool {
711 match &expr.kind {
712 hir::ExprKind::MethodCall(..) => cx
713 .typeck_results()
714 .type_dependent_def_id(expr.hir_id)
715 .is_some_and(|call_did| cx.tcx.is_diagnostic_item(sym::SpanCtxt, call_did)),
716
717 _ => false,
718 }
719}
720
721#[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! {
722 pub rustc::SYMBOL_INTERN_STRING_LITERAL,
724 Allow,
727 "Forbid uses of string literals in `Symbol::intern`, suggesting preinterning instead",
728 report_in_external_macro: true
729}
730
731pub 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 {
<[_]>::into_vec(::alloc::boxed::box_new([SYMBOL_INTERN_STRING_LITERAL]))
}
}
impl SymbolInternStringLiteral {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([SYMBOL_INTERN_STRING_LITERAL]))
}
}declare_lint_pass!(SymbolInternStringLiteral => [SYMBOL_INTERN_STRING_LITERAL]);
732
733impl<'tcx> LateLintPass<'tcx> for SymbolInternStringLiteral {
734 fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx rustc_hir::Expr<'tcx>) {
735 if let hir::ExprKind::Call(path, [arg]) = expr.kind
736 && let hir::ExprKind::Path(ref qpath) = path.kind
737 && let Some(def_id) = cx.qpath_res(qpath, path.hir_id).opt_def_id()
738 && cx.tcx.is_diagnostic_item(sym::SymbolIntern, def_id)
739 && let hir::ExprKind::Lit(kind) = arg.kind
740 && let rustc_ast::LitKind::Str(_, _) = kind.node
741 {
742 cx.emit_span_lint(
743 SYMBOL_INTERN_STRING_LITERAL,
744 kind.span,
745 SymbolInternStringLiteralDiag,
746 );
747 }
748 }
749}
750
751#[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! {
752 pub rustc::IMPLICIT_SYSROOT_CRATE_IMPORT,
756 Allow,
757 "Forbid uses of non-sysroot crates in `extern crate`",
758 report_in_external_macro: true
759}
760
761pub 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 {
<[_]>::into_vec(::alloc::boxed::box_new([IMPLICIT_SYSROOT_CRATE_IMPORT]))
}
}
impl ImplicitSysrootCrateImport {
#[allow(unused)]
pub fn lint_vec() -> ::rustc_lint_defs::LintVec {
<[_]>::into_vec(::alloc::boxed::box_new([IMPLICIT_SYSROOT_CRATE_IMPORT]))
}
}declare_lint_pass!(ImplicitSysrootCrateImport => [IMPLICIT_SYSROOT_CRATE_IMPORT]);
762
763impl EarlyLintPass for ImplicitSysrootCrateImport {
764 fn check_item(&mut self, cx: &EarlyContext<'_>, item: &ast::Item) {
765 fn is_whitelisted(crate_name: &str) -> bool {
766 crate_name.starts_with("rustc_")
768 || #[allow(non_exhaustive_omitted_patterns)] match crate_name {
"test" | "self" | "core" | "alloc" | "std" | "proc_macro" |
"tikv_jemalloc_sys" => true,
_ => false,
}matches!(
769 crate_name,
770 "test" | "self" | "core" | "alloc" | "std" | "proc_macro" | "tikv_jemalloc_sys"
771 )
772 }
773
774 if let ast::ItemKind::ExternCrate(original_name, imported_name) = &item.kind {
775 let name = original_name.as_ref().unwrap_or(&imported_name.name).as_str();
776 let externs = &cx.builder.sess().opts.externs;
777 if externs.get(name).is_none() && !is_whitelisted(name) {
778 cx.emit_span_lint(
779 IMPLICIT_SYSROOT_CRATE_IMPORT,
780 item.span,
781 ImplicitSysrootCrateImportDiag { name },
782 );
783 }
784 }
785 }
786}