Extend disallowed_fields lint on variant fields

This commit is contained in:
Guillaume Gomez
2026-02-09 18:51:44 +01:00
parent 12109e4b2c
commit cb68b21cb3
5 changed files with 98 additions and 29 deletions
+47 -20
View File
@@ -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),
);
}
}
},
_ => {},
}
}
}
+23
View File
@@ -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,
}
}
@@ -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",
]
@@ -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
}
}
@@ -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