Skip to content

Commit f178316

Browse files
committed
Refactor excessive_bools:
* Check HIR tree before checking for macros. * Check item count before checking for bools.
1 parent 1b0230c commit f178316

File tree

1 file changed

+43
-52
lines changed

1 file changed

+43
-52
lines changed

clippy_lints/src/excessive_bools.rs

Lines changed: 43 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -87,12 +87,6 @@ pub struct ExcessiveBools {
8787
max_fn_params_bools: u64,
8888
}
8989

90-
#[derive(Eq, PartialEq, Debug, Copy, Clone)]
91-
enum Kind {
92-
Struct,
93-
Fn,
94-
}
95-
9690
impl ExcessiveBools {
9791
#[must_use]
9892
pub fn new(max_struct_bools: u64, max_fn_params_bools: u64) -> Self {
@@ -101,64 +95,60 @@ impl ExcessiveBools {
10195
max_fn_params_bools,
10296
}
10397
}
98+
}
10499

105-
fn too_many_bools<'tcx>(&self, tys: impl Iterator<Item = &'tcx Ty<'tcx>>, kind: Kind) -> bool {
106-
if let Ok(bools) = tys.filter(|ty| is_bool(ty)).count().try_into() {
107-
(if Kind::Fn == kind {
108-
self.max_fn_params_bools
109-
} else {
110-
self.max_struct_bools
111-
}) < bools
112-
} else {
113-
false
114-
}
115-
}
100+
impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
116101

117-
fn check_fn_sig(&self, cx: &LateContext<'_>, fn_decl: &FnDecl<'_>, span: Span) {
118-
if !span.from_expansion() && self.too_many_bools(fn_decl.inputs.iter(), Kind::Fn) {
119-
span_lint_and_help(
120-
cx,
121-
FN_PARAMS_EXCESSIVE_BOOLS,
122-
span,
123-
format!("more than {} bools in function parameters", self.max_fn_params_bools),
124-
None,
125-
"consider refactoring bools into two-variant enums",
126-
);
127-
}
128-
}
102+
fn has_n_bools<'tcx>(iter: impl Iterator<Item = &'tcx Ty<'tcx>>, mut count: u64) -> bool {
103+
iter.filter(|ty| is_bool(ty)).any(|_| {
104+
let (x, overflow) = count.overflowing_sub(1);
105+
count = x;
106+
overflow
107+
})
129108
}
130109

131-
impl_lint_pass!(ExcessiveBools => [STRUCT_EXCESSIVE_BOOLS, FN_PARAMS_EXCESSIVE_BOOLS]);
110+
fn check_fn_decl(cx: &LateContext<'_>, decl: &FnDecl<'_>, sp: Span, max: u64) {
111+
if has_n_bools(decl.inputs.iter(), max) && !sp.from_expansion() {
112+
span_lint_and_help(
113+
cx,
114+
FN_PARAMS_EXCESSIVE_BOOLS,
115+
sp,
116+
format!("more than {max} bools in function parameters"),
117+
None,
118+
"consider refactoring bools into two-variant enums",
119+
);
120+
}
121+
}
132122

133123
impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
134124
fn check_item(&mut self, cx: &LateContext<'tcx>, item: &'tcx Item<'tcx>) {
135-
if item.span.from_expansion() {
136-
return;
137-
}
138-
if let ItemKind::Struct(variant_data, _) = &item.kind {
139-
if has_repr_attr(cx, item.hir_id()) {
140-
return;
141-
}
142-
143-
if self.too_many_bools(variant_data.fields().iter().map(|field| field.ty), Kind::Struct) {
144-
span_lint_and_help(
145-
cx,
146-
STRUCT_EXCESSIVE_BOOLS,
147-
item.span,
148-
format!("more than {} bools in a struct", self.max_struct_bools),
149-
None,
150-
"consider using a state machine or refactoring bools into two-variant enums",
151-
);
152-
}
125+
if let ItemKind::Struct(variant_data, _) = &item.kind
126+
&& variant_data.fields().len() as u64 > self.max_struct_bools
127+
&& has_n_bools(
128+
variant_data.fields().iter().map(|field| field.ty),
129+
self.max_struct_bools,
130+
)
131+
&& !has_repr_attr(cx, item.hir_id())
132+
&& !item.span.from_expansion()
133+
{
134+
span_lint_and_help(
135+
cx,
136+
STRUCT_EXCESSIVE_BOOLS,
137+
item.span,
138+
format!("more than {} bools in a struct", self.max_struct_bools),
139+
None,
140+
"consider using a state machine or refactoring bools into two-variant enums",
141+
);
153142
}
154143
}
155144

156145
fn check_trait_item(&mut self, cx: &LateContext<'tcx>, trait_item: &'tcx TraitItem<'tcx>) {
157146
// functions with a body are already checked by `check_fn`
158147
if let TraitItemKind::Fn(fn_sig, TraitFn::Required(_)) = &trait_item.kind
159148
&& fn_sig.header.abi == Abi::Rust
149+
&& fn_sig.decl.inputs.len() as u64 > self.max_fn_params_bools
160150
{
161-
self.check_fn_sig(cx, fn_sig.decl, fn_sig.span);
151+
check_fn_decl(cx, fn_sig.decl, fn_sig.span, self.max_fn_params_bools);
162152
}
163153
}
164154

@@ -171,12 +161,13 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools {
171161
span: Span,
172162
def_id: LocalDefId,
173163
) {
174-
let hir_id = cx.tcx.local_def_id_to_hir_id(def_id);
175164
if let Some(fn_header) = fn_kind.header()
176165
&& fn_header.abi == Abi::Rust
177-
&& get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none())
166+
&& fn_decl.inputs.len() as u64 > self.max_fn_params_bools
167+
&& get_parent_as_impl(cx.tcx, cx.tcx.local_def_id_to_hir_id(def_id))
168+
.map_or(true, |impl_item| impl_item.of_trait.is_none())
178169
{
179-
self.check_fn_sig(cx, fn_decl, span);
170+
check_fn_decl(cx, fn_decl, span, self.max_fn_params_bools);
180171
}
181172
}
182173
}

0 commit comments

Comments
 (0)