Skip to content

Commit cb68b21

Browse files
Extend disallowed_fields lint on variant fields
1 parent 12109e4 commit cb68b21

File tree

5 files changed

+98
-29
lines changed

5 files changed

+98
-29
lines changed

clippy_lints/src/disallowed_fields.rs

Lines changed: 47 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -106,28 +106,55 @@ impl<'tcx> LateLintPass<'tcx> for DisallowedFields {
106106
}
107107

108108
fn check_pat(&mut self, cx: &LateContext<'tcx>, pat: &'tcx Pat<'_>) {
109-
if let PatKind::Struct(struct_path, pat_fields, _) = pat.kind
110-
&& let Res::Def(DefKind::Struct, struct_def_id) = cx.typeck_results().qpath_res(&struct_path, pat.hir_id)
111-
{
112-
let adt_def = cx.tcx.adt_def(struct_def_id);
113-
for field in pat_fields {
114-
if let Some(def_id) = adt_def.all_fields().find_map(|adt_field| {
115-
if field.ident.name == adt_field.name {
116-
Some(adt_field.did)
117-
} else {
118-
None
109+
let PatKind::Struct(struct_path, pat_fields, _) = pat.kind else {
110+
return;
111+
};
112+
match cx.typeck_results().qpath_res(&struct_path, pat.hir_id) {
113+
Res::Def(DefKind::Struct, struct_def_id) => {
114+
let adt_def = cx.tcx.adt_def(struct_def_id);
115+
for field in pat_fields {
116+
if let Some(def_id) = adt_def.all_fields().find_map(|adt_field| {
117+
if field.ident.name == adt_field.name {
118+
Some(adt_field.did)
119+
} else {
120+
None
121+
}
122+
}) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id)
123+
{
124+
span_lint_and_then(
125+
cx,
126+
DISALLOWED_FIELDS,
127+
field.span,
128+
format!("use of a disallowed field `{path}`"),
129+
disallowed_path.diag_amendment(field.span),
130+
);
119131
}
120-
}) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id)
121-
{
122-
span_lint_and_then(
123-
cx,
124-
DISALLOWED_FIELDS,
125-
field.span,
126-
format!("use of a disallowed field `{path}`"),
127-
disallowed_path.diag_amendment(field.span),
128-
);
129132
}
130-
}
133+
},
134+
Res::Def(DefKind::Variant, variant_def_id) => {
135+
let enum_def_id = cx.tcx.parent(variant_def_id);
136+
let variant = cx.tcx.adt_def(enum_def_id).variant_with_id(variant_def_id);
137+
138+
for field in pat_fields {
139+
if let Some(def_id) = variant.fields.iter().find_map(|adt_field| {
140+
if field.ident.name == adt_field.name {
141+
Some(adt_field.did)
142+
} else {
143+
None
144+
}
145+
}) && let Some(&(path, disallowed_path)) = self.disallowed.get(&def_id)
146+
{
147+
span_lint_and_then(
148+
cx,
149+
DISALLOWED_FIELDS,
150+
field.span,
151+
format!("use of a disallowed field `{path}`"),
152+
disallowed_path.diag_amendment(field.span),
153+
);
154+
}
155+
}
156+
},
157+
_ => {},
131158
}
132159
}
133160
}

clippy_utils/src/paths.rs

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,20 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n
288288
&root_mod
289289
},
290290
Node::Item(item) => &item.kind,
291+
Node::Variant(variant) if ns == PathNS::Field => {
292+
return if let rustc_hir::VariantData::Struct { fields, .. } = variant.data
293+
&& let Some(field_def_id) = fields.iter().find_map(|field| {
294+
if field.ident.name == name {
295+
Some(field.def_id.to_def_id())
296+
} else {
297+
None
298+
}
299+
}) {
300+
Some(field_def_id)
301+
} else {
302+
None
303+
};
304+
},
291305
_ => return None,
292306
};
293307

@@ -330,6 +344,15 @@ fn local_item_child_by_name(tcx: TyCtxt<'_>, local_id: LocalDefId, ns: PathNS, n
330344
}
331345
})
332346
},
347+
ItemKind::Enum(_, _, rustc_hir::EnumDef { variants }) if ns == PathNS::Type => {
348+
variants.iter().find_map(|variant| {
349+
if variant.ident.name == name {
350+
Some(variant.def_id.to_def_id())
351+
} else {
352+
None
353+
}
354+
})
355+
},
333356
_ => None,
334357
}
335358
}

tests/ui-toml/toml_disallowed_fields/clippy.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,4 +9,6 @@ disallowed-fields = [
99
"conf_disallowed_fields::X::y",
1010
# re-exports
1111
"conf_disallowed_fields::Y::y",
12+
# field of a variant
13+
"conf_disallowed_fields::Z::B::x",
1214
]

tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,11 @@ struct X {
77
y: u32,
88
}
99

10+
enum Z {
11+
A { x: u32 },
12+
B { x: u32 },
13+
}
14+
1015
use crate::X as Y;
1116

1217
fn b(X { y }: X) {}
@@ -36,4 +41,10 @@ fn main() {
3641
match x {
3742
RangeTo { end } => {}, //~ disallowed_fields
3843
}
44+
45+
let x = Z::B { x: 0 };
46+
match x {
47+
Z::A { x } => {},
48+
Z::B { x } => {}, //~ disallowed_fields
49+
}
3950
}
Lines changed: 15 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
error: use of a disallowed field `conf_disallowed_fields::Y::y`
2-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:12:10
2+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:17:10
33
|
44
LL | fn b(X { y }: X) {}
55
| ^
@@ -8,48 +8,54 @@ LL | fn b(X { y }: X) {}
88
= help: to override `-D warnings` add `#[allow(clippy::disallowed_fields)]`
99

1010
error: use of a disallowed field `conf_disallowed_fields::Y::y`
11-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:17:15
11+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:22:15
1212
|
1313
LL | let _ = x.y;
1414
| ^
1515

1616
error: use of a disallowed field `conf_disallowed_fields::Y::y`
17-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:21:15
17+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:26:15
1818
|
1919
LL | let _ = x.y;
2020
| ^
2121

2222
error: use of a disallowed field `std::ops::Range::start`
23-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:25:15
23+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:30:15
2424
|
2525
LL | let _ = x.start;
2626
| ^^^^^
2727

2828
error: use of a disallowed field `std::ops::Range::end`
29-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:27:15
29+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:32:15
3030
|
3131
LL | let _ = x.end;
3232
| ^^^
3333
|
3434
= note: no end allowed
3535

3636
error: use of a disallowed field `std::ops::Range::start`
37-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:29:17
37+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:34:17
3838
|
3939
LL | let Range { start, .. } = x;
4040
| ^^^^^
4141

4242
error: use of a disallowed field `std::ops::RangeTo::end`
43-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:33:15
43+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:38:15
4444
|
4545
LL | let _ = x.end;
4646
| ^^^
4747

4848
error: use of a disallowed field `std::ops::RangeTo::end`
49-
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:37:19
49+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:42:19
5050
|
5151
LL | RangeTo { end } => {},
5252
| ^^^
5353

54-
error: aborting due to 8 previous errors
54+
error: use of a disallowed field `conf_disallowed_fields::Z::B::x`
55+
--> tests/ui-toml/toml_disallowed_fields/conf_disallowed_fields.rs:48:16
56+
|
57+
LL | Z::B { x } => {},
58+
| ^
59+
60+
error: aborting due to 9 previous errors
5561

0 commit comments

Comments
 (0)