Skip to content

Commit b4cbbd5

Browse files
committed
change is_call_max_min pattern to avoid usage of def_path_res
1 parent a3ce7e9 commit b4cbbd5

File tree

1 file changed

+86
-93
lines changed

1 file changed

+86
-93
lines changed

clippy_lints/src/manual_clamp.rs

Lines changed: 86 additions & 93 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
use itertools::Itertools;
22
use rustc_hir::{
3-
def::Res, Arm, BinOpKind, Block, BlockCheckMode, Expr, ExprKind, Guard, HirId, PatKind, QPath, StmtKind,
3+
def::Res, Arm, BinOpKind, Block, BlockCheckMode, Expr, ExprKind, Guard, HirId, PatKind, PathSegment, PrimTy, QPath,
4+
StmtKind,
45
};
56
use rustc_lint::{LateContext, LateLintPass};
67
use rustc_middle::ty::Ty;
@@ -10,8 +11,8 @@ use rustc_span::{symbol::sym, Span};
1011
use std::ops::Deref;
1112

1213
use clippy_utils::{
13-
consts::constant, def_path_res, diagnostics::span_lint_and_then, eq_expr_value, get_trait_def_id, higher::If,
14-
is_trait_method, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks_with_stmt, sugg::Sugg,
14+
consts::constant, diagnostics::span_lint_and_then, eq_expr_value, get_trait_def_id, higher::If, is_diag_trait_item,
15+
is_trait_method, meets_msrv, msrvs, path_res, path_to_local_id, paths, peel_blocks_with_stmt, sugg::Sugg,
1516
ty::implements_trait,
1617
};
1718
use rustc_errors::Applicability;
@@ -278,101 +279,97 @@ fn is_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> O
278279
/// # ;
279280
/// ```
280281
fn is_call_max_min_pattern<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>) -> Option<ClampSuggestion<'tcx>> {
281-
fn for_methods<'tcx>(
282+
fn segment<'tcx>(cx: &LateContext<'_>, func: &Expr<'tcx>) -> Option<FunctionType<'tcx>> {
283+
match func.kind {
284+
ExprKind::Path(QPath::Resolved(None, path)) => {
285+
let id = path.res.opt_def_id()?;
286+
match cx.tcx.get_diagnostic_name(id) {
287+
Some(sym::cmp_min) => Some(FunctionType::CmpMin),
288+
Some(sym::cmp_max) => Some(FunctionType::CmpMax),
289+
_ if is_diag_trait_item(cx, id, sym::Ord) => {
290+
Some(FunctionType::OrdOrFloat(path.segments.last().expect("infallible")))
291+
},
292+
_ => None,
293+
}
294+
},
295+
ExprKind::Path(QPath::TypeRelative(ty, seg)) => {
296+
matches!(path_res(cx, ty), Res::PrimTy(PrimTy::Float(_))).then(|| FunctionType::OrdOrFloat(seg))
297+
},
298+
_ => None,
299+
}
300+
}
301+
302+
enum FunctionType<'tcx> {
303+
CmpMin,
304+
CmpMax,
305+
OrdOrFloat(&'tcx PathSegment<'tcx>),
306+
}
307+
308+
fn extract_call_data(e: ExprRef<'_>, is_first: bool) -> Option<(ExprRef<'_>, ExprRef<'_>, ExprRef<'_>, bool)> {
309+
if let ExprKind::Call(inner_fn, &[ref third, ref fourth]) = &e.kind {
310+
Some((inner_fn, third, fourth, is_first))
311+
} else {
312+
None
313+
}
314+
}
315+
316+
fn check<'tcx>(
282317
cx: &LateContext<'tcx>,
283-
expr: &'tcx Expr<'tcx>,
284-
max_is_first: bool,
285-
first_res: Res,
286-
second_res: Res,
287-
is_float: bool,
318+
outer_fn: ExprRef<'tcx>,
319+
first: ExprRef<'tcx>,
320+
second: ExprRef<'tcx>,
321+
span: Span,
288322
) -> Option<ClampSuggestion<'tcx>> {
289-
let mut min = None;
290-
let mut max = None;
291-
let mut input = None;
292-
let (mut_one, mut_two) = if max_is_first {
293-
(&mut min, &mut max)
294-
} else {
295-
(&mut max, &mut min)
296-
};
297-
let mut process_consts = |arg_third, arg_fourth| {
298-
let third_is_const = constant(cx, cx.typeck_results(), simplify_kind(arg_third)).is_some();
299-
let fourth_is_const = constant(cx, cx.typeck_results(), simplify_kind(arg_fourth)).is_some();
323+
if let Ok((inner_fn, third, fourth, is_first)) =
324+
extract_call_data(first, true).into_iter().chain(extract_call_data(second, false)).exactly_one()
325+
&& let Some(inner_seg) = segment(cx, inner_fn)
326+
&& let Some(outer_seg) = segment(cx, outer_fn) {
327+
let third_is_const = constant(cx, cx.typeck_results(), simplify_kind(third)).is_some();
328+
let fourth_is_const = constant(cx, cx.typeck_results(), simplify_kind(fourth)).is_some();
329+
let input;
330+
let new_arg;
300331
match (third_is_const, fourth_is_const) {
301-
(true, false) => (input, *mut_two) = (Some(arg_fourth), Some(arg_third)),
302-
(false, true) => (input, *mut_two) = (Some(arg_third), Some(arg_fourth)),
303-
_ => {},
332+
(true, false) => (input, new_arg) = (fourth, third),
333+
(false, true) => (input, new_arg) = (third, fourth),
334+
_ => return None,
304335
}
305-
};
306-
if let ExprKind::Call(
307-
Expr { kind: ExprKind::Path(path), hir_id, .. }, &[ref arg_first, ref arg_second]
308-
) = &expr.kind
309-
&& cx.qpath_res(path, *hir_id) == first_res {
310-
if let ExprKind::Call(
311-
Expr { kind: ExprKind::Path(path_first), hir_id, .. }, &[ref arg_third, ref arg_fourth]
312-
) = &simplify_kind(arg_first).kind
313-
&& cx.qpath_res(path_first, *hir_id) == second_res {
314-
*mut_one = Some(arg_second);
315-
process_consts(arg_third, arg_fourth);
316-
} else if let ExprKind::Call(
317-
Expr { kind: ExprKind::Path(path_second), hir_id, .. }, &[ref arg_third, ref arg_fourth]
318-
) = &simplify_kind(arg_second).kind
319-
&& cx.qpath_res(path_second, *hir_id) == second_res {
320-
*mut_one = Some(arg_first);
321-
process_consts(arg_third, arg_fourth);
336+
let other_new_arg = if is_first {
337+
second
338+
} else {
339+
first
340+
};
341+
let is_float = cx.typeck_results().expr_ty_adjusted(input).is_floating_point();
342+
let min_max_suggestion = Some(ClampSuggestion {
343+
params: InputMinMax { input, min: other_new_arg, max: new_arg, is_float },
344+
span,
345+
make_assignment: None,
346+
});
347+
let max_min_suggestion = Some(ClampSuggestion {
348+
params: InputMinMax { input, min: new_arg, max: other_new_arg, is_float },
349+
span,
350+
make_assignment: None,
351+
});
352+
match (inner_seg, outer_seg) {
353+
(FunctionType::CmpMin, FunctionType::CmpMax) => min_max_suggestion,
354+
(FunctionType::CmpMax, FunctionType::CmpMin) => max_min_suggestion,
355+
(FunctionType::OrdOrFloat(first_segment), FunctionType::OrdOrFloat(second_segment)) => {
356+
match (first_segment.ident.as_str(), second_segment.ident.as_str()) {
357+
("min", "max") => min_max_suggestion,
358+
("max", "min") => max_min_suggestion,
359+
_ => None,
360+
}
361+
}
362+
_ => None,
322363
}
364+
} else {
365+
None
323366
}
324-
let input = input?;
325-
let min = min?;
326-
let max = max?;
327-
Some(ClampSuggestion {
328-
params: InputMinMax {
329-
input,
330-
min,
331-
max,
332-
is_float,
333-
},
334-
span: expr.span,
335-
make_assignment: None,
336-
})
337367
}
338-
// Lots of expensive queries coming up which we don't want to repeat for every expr, so short
339-
// circuit this a bit.
340-
let is_dual_call = |e| {
341-
matches!(
342-
&simplify_kind(e).kind,
343-
ExprKind::Call(
344-
Expr {
345-
kind: ExprKind::Path(_),
346-
..
347-
},
348-
&[_, _]
349-
)
350-
)
351-
};
352-
let type_clampability = if let ExprKind::Call(
353-
Expr {
354-
kind: ExprKind::Path(_),
355-
..
356-
},
357-
&[ref arg_first, ref arg_second],
358-
) = &expr.kind
359-
&& (is_dual_call(arg_first) ^ is_dual_call(arg_second)) {
360-
TypeClampability::is_clampable(cx, cx.typeck_results().expr_ty(arg_first))
368+
369+
if let ExprKind::Call(outer_fn, [first, second]) = &expr.kind {
370+
check(cx, outer_fn, first, second, expr.span).or_else(|| check(cx, outer_fn, second, first, expr.span))
361371
} else {
362372
None
363-
}?;
364-
let is_float = type_clampability.is_float();
365-
let for_each_combo_of = |min, max| {
366-
for_methods(cx, expr, true, max, min, is_float).or_else(|| for_methods(cx, expr, false, min, max, is_float))
367-
};
368-
if is_float {
369-
let (f32_min_res, f32_max_res) = for_min_max(|m| def_path_res(cx, &["f32", m]));
370-
let (f64_min_res, f64_max_res) = for_min_max(|m| def_path_res(cx, &["f64", m]));
371-
for_each_combo_of(f32_min_res, f32_max_res).or_else(|| for_each_combo_of(f64_min_res, f64_max_res))
372-
} else {
373-
let (core_min_res, core_max_res) = for_min_max(|m| def_path_res(cx, &["core", "cmp", m]));
374-
let (core_ord_min_res, core_ord_max_res) = for_min_max(|m| def_path_res(cx, &["core", "cmp", "Ord", m]));
375-
for_each_combo_of(core_min_res, core_max_res).or_else(|| for_each_combo_of(core_ord_min_res, core_ord_max_res))
376373
}
377374
}
378375

@@ -720,10 +717,6 @@ fn ord_op_same_direction(a: BinOpKind, b: BinOpKind) -> bool {
720717
}
721718
}
722719

723-
fn for_min_max<T>(mut f: impl FnMut(&str) -> T) -> (T, T) {
724-
(f("min"), f("max"))
725-
}
726-
727720
/// Really similar to Cow, but doesn't have a `Clone` requirement.
728721
#[derive(Debug)]
729722
enum MaybeBorrowedStmtKind<'a> {

0 commit comments

Comments
 (0)