@@ -30,12 +30,12 @@ fn is_method(cx: &LateContext<'_>, expr: &hir::Expr<'_>, method_name: Symbol) ->
30
30
match closure_expr.kind {
31
31
hir::ExprKind::MethodCall(hir::PathSegment { ident, .. }, receiver, ..) => {
32
32
if_chain! {
33
- if ident.name == method_name;
34
- if let hir::ExprKind::Path(path) = &receiver.kind;
35
- if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
36
- then {
37
- return arg_id == *local
38
- }
33
+ if ident.name == method_name;
34
+ if let hir::ExprKind::Path(path) = &receiver.kind;
35
+ if let Res::Local(ref local) = cx.qpath_res(path, receiver.hir_id);
36
+ then {
37
+ return arg_id == *local
38
+ }
39
39
}
40
40
false
41
41
},
@@ -92,92 +92,92 @@ pub(super) fn check(
92
92
}
93
93
94
94
if_chain! {
95
- if is_trait_method(cx, map_recv, sym::Iterator);
96
-
97
- // filter(|x| ...is_some())...
98
- if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
99
- let filter_body = cx.tcx.hir().body(filter_body_id);
100
- if let [filter_param] = filter_body.params;
101
- // optional ref pattern: `filter(|&x| ..)`
102
- let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
103
- (ref_pat, true)
104
- } else {
105
- (filter_param.pat, false)
95
+ if is_trait_method(cx, map_recv, sym::Iterator);
96
+
97
+ // filter(|x| ...is_some())...
98
+ if let ExprKind::Closure(&Closure { body: filter_body_id, .. }) = filter_arg.kind;
99
+ let filter_body = cx.tcx.hir().body(filter_body_id);
100
+ if let [filter_param] = filter_body.params;
101
+ // optional ref pattern: `filter(|&x| ..)`
102
+ let (filter_pat, is_filter_param_ref) = if let PatKind::Ref(ref_pat, _) = filter_param.pat.kind {
103
+ (ref_pat, true)
104
+ } else {
105
+ (filter_param.pat, false)
106
+ };
107
+ // closure ends with is_some() or is_ok()
108
+ if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
109
+ if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
110
+ if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
111
+ if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
112
+ Some(false)
113
+ } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
114
+ Some(true)
115
+ } else {
116
+ None
117
+ };
118
+ if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
119
+
120
+ // ...map(|x| ...unwrap())
121
+ if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
122
+ let map_body = cx.tcx.hir().body(map_body_id);
123
+ if let [map_param] = map_body.params;
124
+ if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
125
+ // closure ends with expect() or unwrap()
126
+ if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
127
+ if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
128
+
129
+ // .filter(..).map(|y| f(y).copied().unwrap())
130
+ // ~~~~
131
+ let map_arg_peeled = match map_arg.kind {
132
+ ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
133
+ original_arg
134
+ },
135
+ _ => map_arg,
136
+ };
137
+
138
+ // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
139
+ let simple_equal = path_to_local_id(filter_arg, filter_param_id)
140
+ && path_to_local_id(map_arg_peeled, map_param_id);
141
+
142
+ let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
143
+ // in `filter(|x| ..)`, replace `*x` with `x`
144
+ let a_path = if_chain! {
145
+ if !is_filter_param_ref;
146
+ if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
147
+ then { expr_path } else { a }
106
148
};
107
- // closure ends with is_some() or is_ok()
108
- if let PatKind::Binding(_, filter_param_id, _, None) = filter_pat.kind;
109
- if let ExprKind::MethodCall(path, filter_arg, [], _) = filter_body.value.kind;
110
- if let Some(opt_ty) = cx.typeck_results().expr_ty(filter_arg).peel_refs().ty_adt_def();
111
- if let Some(is_result) = if cx.tcx.is_diagnostic_item(sym::Option, opt_ty.did()) {
112
- Some(false)
113
- } else if cx.tcx.is_diagnostic_item(sym::Result, opt_ty.did()) {
114
- Some(true)
149
+ // let the filter closure arg and the map closure arg be equal
150
+ path_to_local_id(a_path, filter_param_id)
151
+ && path_to_local_id(b, map_param_id)
152
+ && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
153
+ };
154
+
155
+ if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
156
+ then {
157
+ let span = filter_span.with_hi(expr.span.hi());
158
+ let (filter_name, lint) = if is_find {
159
+ ("find", MANUAL_FIND_MAP)
115
160
} else {
116
- None
117
- };
118
- if path.ident.name.as_str() == if is_result { "is_ok" } else { "is_some" };
119
-
120
- // ...map(|x| ...unwrap())
121
- if let ExprKind::Closure(&Closure { body: map_body_id, .. }) = map_arg.kind;
122
- let map_body = cx.tcx.hir().body(map_body_id);
123
- if let [map_param] = map_body.params;
124
- if let PatKind::Binding(_, map_param_id, map_param_ident, None) = map_param.pat.kind;
125
- // closure ends with expect() or unwrap()
126
- if let ExprKind::MethodCall(seg, map_arg, ..) = map_body.value.kind;
127
- if matches!(seg.ident.name, sym::expect | sym::unwrap | sym::unwrap_or);
128
-
129
- // .filter(..).map(|y| f(y).copied().unwrap())
130
- // ~~~~
131
- let map_arg_peeled = match map_arg.kind {
132
- ExprKind::MethodCall(method, original_arg, [], _) if acceptable_methods(method) => {
133
- original_arg
134
- },
135
- _ => map_arg,
161
+ ("filter", MANUAL_FILTER_MAP)
136
162
};
163
+ let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
164
+ let (to_opt, deref) = if is_result {
165
+ (".ok()", String::new())
166
+ } else {
167
+ let derefs = cx.typeck_results()
168
+ .expr_adjustments(map_arg)
169
+ .iter()
170
+ .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
171
+ .count();
137
172
138
- // .filter(|x| x.is_some()).map(|y| y[.acceptable_method()].unwrap())
139
- let simple_equal = path_to_local_id(filter_arg, filter_param_id)
140
- && path_to_local_id(map_arg_peeled, map_param_id);
141
-
142
- let eq_fallback = |a: &Expr<'_>, b: &Expr<'_>| {
143
- // in `filter(|x| ..)`, replace `*x` with `x`
144
- let a_path = if_chain! {
145
- if !is_filter_param_ref;
146
- if let ExprKind::Unary(UnOp::Deref, expr_path) = a.kind;
147
- then { expr_path } else { a }
148
- };
149
- // let the filter closure arg and the map closure arg be equal
150
- path_to_local_id(a_path, filter_param_id)
151
- && path_to_local_id(b, map_param_id)
152
- && cx.typeck_results().expr_ty_adjusted(a) == cx.typeck_results().expr_ty_adjusted(b)
173
+ ("", "*".repeat(derefs))
153
174
};
154
-
155
- if simple_equal || SpanlessEq::new(cx).expr_fallback(eq_fallback).eq_expr(filter_arg, map_arg_peeled);
156
- then {
157
- let span = filter_span.with_hi(expr.span.hi());
158
- let (filter_name, lint) = if is_find {
159
- ("find", MANUAL_FIND_MAP)
160
- } else {
161
- ("filter", MANUAL_FILTER_MAP)
162
- };
163
- let msg = format!("`{filter_name}(..).map(..)` can be simplified as `{filter_name}_map(..)`");
164
- let (to_opt, deref) = if is_result {
165
- (".ok()", String::new())
166
- } else {
167
- let derefs = cx.typeck_results()
168
- .expr_adjustments(map_arg)
169
- .iter()
170
- .filter(|adj| matches!(adj.kind, Adjust::Deref(_)))
171
- .count();
172
-
173
- ("", "*".repeat(derefs))
174
- };
175
- let sugg = format!(
176
- "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
177
- snippet(cx, map_arg.span, ".."),
178
- );
179
- span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
180
- }
175
+ let sugg = format!(
176
+ "{filter_name}_map(|{map_param_ident}| {deref}{}{to_opt})",
177
+ snippet(cx, map_arg.span, ".."),
178
+ );
179
+ span_lint_and_sugg(cx, lint, span, &msg, "try", sugg, Applicability::MachineApplicable);
180
+ }
181
181
}
182
182
}
183
183
0 commit comments