Skip to content

Commit 33a5600

Browse files
committed
Improve method chain pattern
1 parent 0e042d2 commit 33a5600

15 files changed

+176
-113
lines changed

clippy_lints/src/methods/bind_instead_of_map.rs

+7-7
Original file line numberDiff line numberDiff line change
@@ -80,7 +80,7 @@ pub(crate) trait BindInsteadOfMap {
8080
fn lint_closure_autofixable(
8181
cx: &LateContext<'_>,
8282
expr: &hir::Expr<'_>,
83-
args: &[hir::Expr<'_>],
83+
recv: &hir::Expr<'_>,
8484
closure_expr: &hir::Expr<'_>,
8585
closure_args_span: Span,
8686
) -> bool {
@@ -103,7 +103,7 @@ pub(crate) trait BindInsteadOfMap {
103103
};
104104

105105
let closure_args_snip = snippet(cx, closure_args_span, "..");
106-
let option_snip = snippet(cx, args[0].span, "..");
106+
let option_snip = snippet(cx, recv.span, "..");
107107
let note = format!("{}.{}({} {})", option_snip, Self::GOOD_METHOD_NAME, closure_args_snip, some_inner_snip);
108108
span_lint_and_sugg(
109109
cx,
@@ -158,17 +158,17 @@ pub(crate) trait BindInsteadOfMap {
158158
}
159159

160160
/// Lint use of `_.and_then(|x| Some(y))` for `Option`s
161-
fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, args: &[hir::Expr<'_>]) -> bool {
162-
if !match_type(cx, cx.typeck_results().expr_ty(&args[0]), Self::TYPE_QPATH) {
161+
fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) -> bool {
162+
if !match_type(cx, cx.typeck_results().expr_ty(recv), Self::TYPE_QPATH) {
163163
return false;
164164
}
165165

166-
match args[1].kind {
166+
match arg.kind {
167167
hir::ExprKind::Closure(_, _, body_id, closure_args_span, _) => {
168168
let closure_body = cx.tcx.hir().body(body_id);
169169
let closure_expr = remove_blocks(&closure_body.value);
170170

171-
if Self::lint_closure_autofixable(cx, expr, args, closure_expr, closure_args_span) {
171+
if Self::lint_closure_autofixable(cx, expr, recv, closure_expr, closure_args_span) {
172172
true
173173
} else {
174174
Self::lint_closure(cx, expr, closure_expr)
@@ -182,7 +182,7 @@ pub(crate) trait BindInsteadOfMap {
182182
expr.span,
183183
Self::no_op_msg().as_ref(),
184184
"use the expression directly",
185-
snippet(cx, args[0].span, "..").into(),
185+
snippet(cx, recv.span, "..").into(),
186186
Applicability::MachineApplicable,
187187
);
188188
true

clippy_lints/src/methods/expect_used.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -6,8 +6,8 @@ use rustc_span::sym;
66
use super::EXPECT_USED;
77

88
/// lint use of `expect()` for `Option`s and `Result`s
9-
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, expect_args: &[hir::Expr<'_>]) {
10-
let obj_ty = cx.typeck_results().expr_ty(&expect_args[0]).peel_refs();
9+
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>) {
10+
let obj_ty = cx.typeck_results().expr_ty(recv).peel_refs();
1111

1212
let mess = if is_type_diagnostic_item(cx, obj_ty, sym::option_type) {
1313
Some((EXPECT_USED, "an Option", "None"))

clippy_lints/src/methods/filter_map_next.rs

+4-3
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,8 @@ const FILTER_MAP_NEXT_MSRV: RustcVersion = RustcVersion::new(1, 30, 0);
1212
pub(super) fn check<'tcx>(
1313
cx: &LateContext<'tcx>,
1414
expr: &'tcx hir::Expr<'_>,
15-
filter_args: &'tcx [hir::Expr<'_>],
15+
recv: &'tcx hir::Expr<'_>,
16+
arg: &'tcx hir::Expr<'_>,
1617
msrv: Option<&RustcVersion>,
1718
) {
1819
if is_trait_method(cx, expr, sym::Iterator) {
@@ -22,9 +23,9 @@ pub(super) fn check<'tcx>(
2223

2324
let msg = "called `filter_map(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
2425
`.find_map(..)` instead";
25-
let filter_snippet = snippet(cx, filter_args[1].span, "..");
26+
let filter_snippet = snippet(cx, arg.span, "..");
2627
if filter_snippet.lines().count() <= 1 {
27-
let iter_snippet = snippet(cx, filter_args[0].span, "..");
28+
let iter_snippet = snippet(cx, recv.span, "..");
2829
span_lint_and_sugg(
2930
cx,
3031
FILTER_MAP_NEXT,

clippy_lints/src/methods/filter_next.rs

+8-3
Original file line numberDiff line numberDiff line change
@@ -7,14 +7,19 @@ use rustc_span::sym;
77
use super::FILTER_NEXT;
88

99
/// lint use of `filter().next()` for `Iterators`
10-
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, filter_args: &'tcx [hir::Expr<'_>]) {
10+
pub(super) fn check<'tcx>(
11+
cx: &LateContext<'tcx>,
12+
expr: &'tcx hir::Expr<'_>,
13+
recv: &'tcx hir::Expr<'_>,
14+
filter_arg: &'tcx hir::Expr<'_>,
15+
) {
1116
// lint if caller of `.filter().next()` is an Iterator
1217
if is_trait_method(cx, expr, sym::Iterator) {
1318
let msg = "called `filter(..).next()` on an `Iterator`. This is more succinctly expressed by calling \
1419
`.find(..)` instead";
15-
let filter_snippet = snippet(cx, filter_args[1].span, "..");
20+
let filter_snippet = snippet(cx, filter_arg.span, "..");
1621
if filter_snippet.lines().count() <= 1 {
17-
let iter_snippet = snippet(cx, filter_args[0].span, "..");
22+
let iter_snippet = snippet(cx, recv.span, "..");
1823
// add note if not multi-line
1924
span_lint_and_sugg(
2025
cx,

clippy_lints/src/methods/get_unwrap.rs

+11-9
Original file line numberDiff line numberDiff line change
@@ -10,18 +10,20 @@ use rustc_span::sym;
1010

1111
use super::GET_UNWRAP;
1212

13-
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args: &'tcx [hir::Expr<'_>], is_mut: bool) {
13+
pub(super) fn check<'tcx>(
14+
cx: &LateContext<'tcx>,
15+
expr: &hir::Expr<'_>,
16+
recv: &'tcx hir::Expr<'tcx>,
17+
get_arg: &'tcx hir::Expr<'_>,
18+
is_mut: bool,
19+
) {
1420
// Note: we don't want to lint `get_mut().unwrap` for `HashMap` or `BTreeMap`,
1521
// because they do not implement `IndexMut`
1622
let mut applicability = Applicability::MachineApplicable;
17-
let expr_ty = cx.typeck_results().expr_ty(&get_args[0]);
18-
let get_args_str = if get_args.len() > 1 {
19-
snippet_with_applicability(cx, get_args[1].span, "..", &mut applicability)
20-
} else {
21-
return; // not linting on a .get().unwrap() chain or variant
22-
};
23+
let expr_ty = cx.typeck_results().expr_ty(recv);
24+
let get_args_str = snippet_with_applicability(cx, get_arg.span, "..", &mut applicability);
2325
let mut needs_ref;
24-
let caller_type = if derefs_to_slice(cx, &get_args[0], expr_ty).is_some() {
26+
let caller_type = if derefs_to_slice(cx, recv, expr_ty).is_some() {
2527
needs_ref = get_args_str.parse::<usize>().is_ok();
2628
"slice"
2729
} else if is_type_diagnostic_item(cx, expr_ty, sym::vec_type) {
@@ -76,7 +78,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &hir::Expr<'_>, get_args
7678
format!(
7779
"{}{}[{}]",
7880
borrow_str,
79-
snippet_with_applicability(cx, get_args[0].span, "..", &mut applicability),
81+
snippet_with_applicability(cx, recv.span, "..", &mut applicability),
8082
get_args_str
8183
),
8284
applicability,

clippy_lints/src/methods/iter_next_slice.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -10,9 +10,7 @@ use rustc_span::symbol::sym;
1010

1111
use super::ITER_NEXT_SLICE;
1212

13-
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, iter_args: &'tcx [hir::Expr<'_>]) {
14-
let caller_expr = &iter_args[0];
15-
13+
pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx hir::Expr<'_>, caller_expr: &'tcx hir::Expr<'_>) {
1614
// Skip lint if the `iter().next()` expression is a for loop argument,
1715
// since it is already covered by `&loops::ITER_NEXT_LOOP`
1816
let mut parent_expr_opt = get_parent_expr(cx, expr);

clippy_lints/src/methods/iter_skip_next.rs

+11-13
Original file line numberDiff line numberDiff line change
@@ -6,20 +6,18 @@ use rustc_span::sym;
66

77
use super::ITER_SKIP_NEXT;
88

9-
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, skip_args: &[hir::Expr<'_>]) {
9+
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, recv: &hir::Expr<'_>, arg: &hir::Expr<'_>) {
1010
// lint if caller of skip is an Iterator
1111
if is_trait_method(cx, expr, sym::Iterator) {
12-
if let [caller, n] = skip_args {
13-
let hint = format!(".nth({})", snippet(cx, n.span, ".."));
14-
span_lint_and_sugg(
15-
cx,
16-
ITER_SKIP_NEXT,
17-
expr.span.trim_start(caller.span).unwrap(),
18-
"called `skip(..).next()` on an iterator",
19-
"use `nth` instead",
20-
hint,
21-
Applicability::MachineApplicable,
22-
);
23-
}
12+
let hint = format!(".nth({})", snippet(cx, arg.span, ".."));
13+
span_lint_and_sugg(
14+
cx,
15+
ITER_SKIP_NEXT,
16+
expr.span.trim_start(recv.span).unwrap(),
17+
"called `skip(..).next()` on an iterator",
18+
"use `nth` instead",
19+
hint,
20+
Applicability::MachineApplicable,
21+
);
2422
}
2523
}

clippy_lints/src/methods/map_unwrap_or.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -15,22 +15,23 @@ const MAP_UNWRAP_OR_MSRV: RustcVersion = RustcVersion::new(1, 41, 0);
1515
pub(super) fn check<'tcx>(
1616
cx: &LateContext<'tcx>,
1717
expr: &'tcx hir::Expr<'_>,
18-
map_args: &'tcx [hir::Expr<'_>],
19-
unwrap_args: &'tcx [hir::Expr<'_>],
18+
recv: &'tcx hir::Expr<'_>,
19+
map_arg: &'tcx hir::Expr<'_>,
20+
unwrap_arg: &'tcx hir::Expr<'_>,
2021
msrv: Option<&RustcVersion>,
2122
) -> bool {
2223
if !meets_msrv(msrv, &MAP_UNWRAP_OR_MSRV) {
2324
return false;
2425
}
2526
// lint if the caller of `map()` is an `Option`
26-
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::option_type);
27-
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(&map_args[0]), sym::result_type);
27+
let is_option = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::option_type);
28+
let is_result = is_type_diagnostic_item(cx, cx.typeck_results().expr_ty(recv), sym::result_type);
2829

2930
if is_option || is_result {
3031
// Don't make a suggestion that may fail to compile due to mutably borrowing
3132
// the same variable twice.
32-
let map_mutated_vars = mutated_variables(&map_args[0], cx);
33-
let unwrap_mutated_vars = mutated_variables(&unwrap_args[1], cx);
33+
let map_mutated_vars = mutated_variables(recv, cx);
34+
let unwrap_mutated_vars = mutated_variables(unwrap_arg, cx);
3435
if let (Some(map_mutated_vars), Some(unwrap_mutated_vars)) = (map_mutated_vars, unwrap_mutated_vars) {
3536
if map_mutated_vars.intersection(&unwrap_mutated_vars).next().is_some() {
3637
return false;
@@ -48,14 +49,14 @@ pub(super) fn check<'tcx>(
4849
`.map_or_else(<g>, <f>)` instead"
4950
};
5051
// get snippets for args to map() and unwrap_or_else()
51-
let map_snippet = snippet(cx, map_args[1].span, "..");
52-
let unwrap_snippet = snippet(cx, unwrap_args[1].span, "..");
52+
let map_snippet = snippet(cx, map_arg.span, "..");
53+
let unwrap_snippet = snippet(cx, unwrap_arg.span, "..");
5354
// lint, with note if neither arg is > 1 line and both map() and
5455
// unwrap_or_else() have the same span
5556
let multiline = map_snippet.lines().count() > 1 || unwrap_snippet.lines().count() > 1;
56-
let same_span = map_args[1].span.ctxt() == unwrap_args[1].span.ctxt();
57+
let same_span = map_arg.span.ctxt() == unwrap_arg.span.ctxt();
5758
if same_span && !multiline {
58-
let var_snippet = snippet(cx, map_args[0].span, "..");
59+
let var_snippet = snippet(cx, recv.span, "..");
5960
span_lint_and_sugg(
6061
cx,
6162
MAP_UNWRAP_OR,

0 commit comments

Comments
 (0)