diff --git a/clippy_lints/src/disallowed_fields.rs b/clippy_lints/src/disallowed_fields.rs index 24bea4cd2729..f1136556e2ed 100644 --- a/clippy_lints/src/disallowed_fields.rs +++ b/clippy_lints/src/disallowed_fields.rs @@ -106,28 +106,55 @@ fn check_expr(&mut self, cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>) { } fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) { - if let PatKind::Struct(struct_path, pat_fields, _) = pat.kind - && let Res::Def(DefKind::Struct, struct_def_id) = cx.typeck_results().qpath_res(&struct_path, pat.hir_id) - { - let adt_def = cx.tcx.adt_def(struct_def_id); - for field in pat_fields { - if let Some(def_id) = adt_def.all_fields().find_map(|adt_field| { - if field.ident.name == adt_field.name { - Some(adt_field.did) - } else { - None + let PatKind::Struct(struct_path, pat_fields, _) = pat.kind else { + return; + }; + match cx.typeck_results().qpath_res(&struct_path, pat.hir_id) { + Res::Def(DefKind::Struct, struct_def_id) => { + let adt_def = cx.tcx.adt_def(struct_def_id); + for field in pat_fields { + if let Some(def_id) = adt_def.all_fields().find_map(|adt_field| { + if field.ident.name == adt_field.name { + Some(adt_field.did) + } else { + None + } + }) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id) + { + span_lint_and_then( + cx, + DISALLOWED_FIELDS, + field.span, + format!("use of a disallowed field `{path}`"), + disallowed_path.diag_amendment(field.span), + ); } - }) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id) - { - span_lint_and_then( - cx, - DISALLOWED_FIELDS, - field.span, - format!("use of a disallowed field `{path}`"), - disallowed_path.diag_amendment(field.span), - ); } - } + }, + Res::Def(DefKind::Variant, variant_def_id) => { + let enum_def_id = cx.tcx.parent(variant_def_id); + let variant = cx.tcx.adt_def(enum_def_id).variant_with_id(variant_def_id); + + for field in pat_fields { + if let Some(def_id) = variant.fields.iter().find_map(|adt_field| { + if field.ident.name == adt_field.name { + Some(adt_field.did) + } else { + None + } + }) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id) + { + span_lint_and_then( + cx, + DISALLOWED_FIELDS, + field.span, + format!("use of a disallowed field `{path}`"), + disallowed_path.diag_amendment(field.span), + ); + } + } + }, + _ => {}, } } } diff --git a/clippy_utils/src/paths.rs b/clippy_utils/src/paths.rs index 1255b05b8e1e..b9173b14a6cb 100644 --- a/clippy_utils/src/paths.rs +++ b/clippy_utils/src/paths.rs @@ -288,6 +288,20 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n &root_mod }, Node::Item(item) => &item.kind, + Node::Variant(variant) if ns == PathNS::Field => { + return if let rustc_hir::VariantData::Struct { fields, .. } = variant.data + && let Some(field_def_id) = fields.iter().find_map(|field| { + if field.ident.name == name { + Some(field.def_id.to_def_id()) + } else { + None + } + }) { + Some(field_def_id) + } else { + None + }; + }, _ => return None, }; @@ -330,6 +344,15 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n } }) }, + ItemKind::Enum(_, _, rustc_hir::EnumDef { variants }) if ns == PathNS::Type => { + variants.iter().find_map(|variant| { + if variant.ident.name == name { + Some(variant.def_id.to_def_id()) + } else { + None + } + }) + }, _ => None, } } diff --git a/tests/ui-toml/toml_disallowed_fields/clippy.toml b/tests/ui-toml/toml_disallowed_fields/clippy.toml index 0dc494815a34..615d405a87a4 100644 --- a/tests/ui-toml/toml_disallowed_fields/clippy.toml +++ b/tests/ui-toml/toml_disallowed_fields/clippy.toml @@ -9,4 +9,6 @@ disallowed-fields = [ "conf_disallowed_fields::X::y", # re-exports "conf_disallowed_fields::Y::y", + # field of a variant + "conf_disallowed_fields::Z::B::x", ] diff --git a/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs b/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs index 359c861baf66..7804b605a67a 100644 --- a/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs +++ b/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs @@ -7,6 +7,11 @@ struct X { y: u32, } +enum Z { + A { x: u32 }, + B { x: u32 }, +} + use crate::X as Y; fn b(X { y }: X) {} @@ -36,4 +41,10 @@ fn main() { match x { RangeTo { end } => {}, //~ disallowed_fields } + + let x = Z::B { x: 0 }; + match x { + Z::A { x } => {}, + Z::B { x } => {}, //~ disallowed_fields + } } diff --git a/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.stderr b/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.stderr index 3cc22a55ab9c..ac43c702bbdc 100644 --- a/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.stderr +++ b/tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.stderr @@ -1,5 +1,5 @@ error: use of a disallowed field `conf_disallowed_fields::Y::y` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:12:10 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:17:10 | LL | fn b(X { y }: X) {} | ^ @@ -8,25 +8,25 @@ LL | fn b(X { y }: X) {} = help: to override `-D warnings` add `#[allow(clippy::disallowed_fields)]` error: use of a disallowed field `conf_disallowed_fields::Y::y` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:17:15 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:22:15 | LL | let _ = x.y; | ^ error: use of a disallowed field `conf_disallowed_fields::Y::y` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:21:15 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:26:15 | LL | let _ = x.y; | ^ error: use of a disallowed field `std::ops::Range::start` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:25:15 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:30:15 | LL | let _ = x.start; | ^^^^^ error: use of a disallowed field `std::ops::Range::end` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:27:15 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:32:15 | LL | let _ = x.end; | ^^^ @@ -34,22 +34,28 @@ LL | let _ = x.end; = note: no end allowed error: use of a disallowed field `std::ops::Range::start` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:29:17 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:34:17 | LL | let Range { start, .. } = x; | ^^^^^ error: use of a disallowed field `std::ops::RangeTo::end` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:33:15 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:38:15 | LL | let _ = x.end; | ^^^ error: use of a disallowed field `std::ops::RangeTo::end` - --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:37:19 + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:42:19 | LL | RangeTo { end } => {}, | ^^^ -error: aborting due to 8 previous errors +error: use of a disallowed field `conf_disallowed_fields::Z::B::x` + --> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:48:16 + | +LL | Z::B { x } => {}, + | ^ + +error: aborting due to 9 previous errors