Skip to content

Commit da0538e

Browse files
committed
Auto merge of #7330 - xFrednet:0000-refactor-map-identity, r=flip1995
Refactoring identity function lints I've noticed that we have several lints that all check for identity functions and each used their own check implementation. I moved the `is_expr_identity_function` function to `clippy_utils` and adapted all lints to reuse that one function. This should make the addition of new lints like this also easier in the future. I've also moved the `map_identity` lint into the `methods` module. It's probably the best to review this PR by checking each commit individually. And that's it, have a great day 🙃 changelog: none
2 parents 07217e3 + 5336f88 commit da0538e

13 files changed

+178
-204
lines changed

clippy_lints/src/lib.rs

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -254,7 +254,6 @@ mod manual_strip;
254254
mod manual_unwrap_or;
255255
mod map_clone;
256256
mod map_err_ignore;
257-
mod map_identity;
258257
mod map_unit_fn;
259258
mod match_on_vec_items;
260259
mod matches;
@@ -705,7 +704,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
705704
manual_unwrap_or::MANUAL_UNWRAP_OR,
706705
map_clone::MAP_CLONE,
707706
map_err_ignore::MAP_ERR_IGNORE,
708-
map_identity::MAP_IDENTITY,
709707
map_unit_fn::OPTION_MAP_UNIT_FN,
710708
map_unit_fn::RESULT_MAP_UNIT_FN,
711709
match_on_vec_items::MATCH_ON_VEC_ITEMS,
@@ -765,6 +763,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
765763
methods::MANUAL_STR_REPEAT,
766764
methods::MAP_COLLECT_RESULT_UNIT,
767765
methods::MAP_FLATTEN,
766+
methods::MAP_IDENTITY,
768767
methods::MAP_UNWRAP_OR,
769768
methods::NEW_RET_NO_SELF,
770769
methods::OK_EXPECT,
@@ -1260,7 +1259,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
12601259
LintId::of(manual_strip::MANUAL_STRIP),
12611260
LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
12621261
LintId::of(map_clone::MAP_CLONE),
1263-
LintId::of(map_identity::MAP_IDENTITY),
12641262
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
12651263
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
12661264
LintId::of(matches::INFALLIBLE_DESTRUCTURING_MATCH),
@@ -1301,6 +1299,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
13011299
LintId::of(methods::MANUAL_SATURATING_ARITHMETIC),
13021300
LintId::of(methods::MANUAL_STR_REPEAT),
13031301
LintId::of(methods::MAP_COLLECT_RESULT_UNIT),
1302+
LintId::of(methods::MAP_IDENTITY),
13041303
LintId::of(methods::NEW_RET_NO_SELF),
13051304
LintId::of(methods::OK_EXPECT),
13061305
LintId::of(methods::OPTION_AS_REF_DEREF),
@@ -1586,7 +1585,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
15861585
LintId::of(loops::WHILE_LET_LOOP),
15871586
LintId::of(manual_strip::MANUAL_STRIP),
15881587
LintId::of(manual_unwrap_or::MANUAL_UNWRAP_OR),
1589-
LintId::of(map_identity::MAP_IDENTITY),
15901588
LintId::of(map_unit_fn::OPTION_MAP_UNIT_FN),
15911589
LintId::of(map_unit_fn::RESULT_MAP_UNIT_FN),
15921590
LintId::of(matches::MATCH_AS_REF),
@@ -1601,6 +1599,7 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
16011599
LintId::of(methods::ITER_COUNT),
16021600
LintId::of(methods::MANUAL_FILTER_MAP),
16031601
LintId::of(methods::MANUAL_FIND_MAP),
1602+
LintId::of(methods::MAP_IDENTITY),
16041603
LintId::of(methods::OPTION_AS_REF_DEREF),
16051604
LintId::of(methods::OPTION_FILTER_MAP),
16061605
LintId::of(methods::SEARCH_IS_SOME),
@@ -2039,7 +2038,6 @@ pub fn register_plugins(store: &mut rustc_lint::LintStore, sess: &Session, conf:
20392038
single_char_binding_names_threshold,
20402039
});
20412040
store.register_late_pass(|| box macro_use::MacroUseImports::default());
2042-
store.register_late_pass(|| box map_identity::MapIdentity);
20432041
store.register_late_pass(|| box pattern_type_mismatch::PatternTypeMismatch);
20442042
store.register_late_pass(|| box stable_sort_primitive::StableSortPrimitive);
20452043
store.register_late_pass(|| box repeat_once::RepeatOnce);

clippy_lints/src/map_identity.rs

Lines changed: 0 additions & 126 deletions
This file was deleted.
Lines changed: 11 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::{is_expr_path_def_path, is_trait_method, path_to_local_id, paths};
3-
use if_chain::if_chain;
2+
use clippy_utils::{is_expr_identity_function, is_trait_method};
43
use rustc_errors::Applicability;
54
use rustc_hir as hir;
65
use rustc_lint::LateContext;
@@ -9,32 +8,15 @@ use rustc_span::{source_map::Span, sym};
98
use super::FILTER_MAP_IDENTITY;
109

1110
pub(super) fn check(cx: &LateContext<'_>, expr: &hir::Expr<'_>, filter_map_arg: &hir::Expr<'_>, filter_map_span: Span) {
12-
if is_trait_method(cx, expr, sym::Iterator) {
13-
let apply_lint = |message: &str| {
14-
span_lint_and_sugg(
15-
cx,
16-
FILTER_MAP_IDENTITY,
17-
filter_map_span.with_hi(expr.span.hi()),
18-
message,
19-
"try",
20-
"flatten()".to_string(),
21-
Applicability::MachineApplicable,
22-
);
23-
};
24-
25-
if_chain! {
26-
if let hir::ExprKind::Closure(_, _, body_id, _, _) = filter_map_arg.kind;
27-
let body = cx.tcx.hir().body(body_id);
28-
29-
if let hir::PatKind::Binding(_, binding_id, ..) = body.params[0].pat.kind;
30-
if path_to_local_id(&body.value, binding_id);
31-
then {
32-
apply_lint("called `filter_map(|x| x)` on an `Iterator`");
33-
}
34-
}
35-
36-
if is_expr_path_def_path(cx, filter_map_arg, &paths::CONVERT_IDENTITY) {
37-
apply_lint("called `filter_map(std::convert::identity)` on an `Iterator`");
38-
}
11+
if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, filter_map_arg) {
12+
span_lint_and_sugg(
13+
cx,
14+
FILTER_MAP_IDENTITY,
15+
filter_map_span.with_hi(expr.span.hi()),
16+
"use of `filter_map` with an identity function",
17+
"try",
18+
"flatten()".to_string(),
19+
Applicability::MachineApplicable,
20+
);
3921
}
4022
}
Lines changed: 11 additions & 33 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,5 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
2-
use clippy_utils::{is_expr_path_def_path, is_trait_method, paths};
3-
use if_chain::if_chain;
2+
use clippy_utils::{is_expr_identity_function, is_trait_method};
43
use rustc_errors::Applicability;
54
use rustc_hir as hir;
65
use rustc_lint::LateContext;
@@ -15,36 +14,15 @@ pub(super) fn check<'tcx>(
1514
flat_map_arg: &'tcx hir::Expr<'_>,
1615
flat_map_span: Span,
1716
) {
18-
if is_trait_method(cx, expr, sym::Iterator) {
19-
let apply_lint = |message: &str| {
20-
span_lint_and_sugg(
21-
cx,
22-
FLAT_MAP_IDENTITY,
23-
flat_map_span.with_hi(expr.span.hi()),
24-
message,
25-
"try",
26-
"flatten()".to_string(),
27-
Applicability::MachineApplicable,
28-
);
29-
};
30-
31-
if_chain! {
32-
if let hir::ExprKind::Closure(_, _, body_id, _, _) = flat_map_arg.kind;
33-
let body = cx.tcx.hir().body(body_id);
34-
35-
if let hir::PatKind::Binding(_, _, binding_ident, _) = body.params[0].pat.kind;
36-
if let hir::ExprKind::Path(hir::QPath::Resolved(_, path)) = body.value.kind;
37-
38-
if path.segments.len() == 1;
39-
if path.segments[0].ident.name == binding_ident.name;
40-
41-
then {
42-
apply_lint("called `flat_map(|x| x)` on an `Iterator`");
43-
}
44-
}
45-
46-
if is_expr_path_def_path(cx, flat_map_arg, &paths::CONVERT_IDENTITY) {
47-
apply_lint("called `flat_map(std::convert::identity)` on an `Iterator`");
48-
}
17+
if is_trait_method(cx, expr, sym::Iterator) && is_expr_identity_function(cx, flat_map_arg) {
18+
span_lint_and_sugg(
19+
cx,
20+
FLAT_MAP_IDENTITY,
21+
flat_map_span.with_hi(expr.span.hi()),
22+
"use of `flat_map` with an identity function",
23+
"try",
24+
"flatten()".to_string(),
25+
Applicability::MachineApplicable,
26+
);
4927
}
5028
}
Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,38 @@
1+
use clippy_utils::diagnostics::span_lint_and_sugg;
2+
use clippy_utils::ty::is_type_diagnostic_item;
3+
use clippy_utils::{is_expr_identity_function, is_trait_method};
4+
use rustc_errors::Applicability;
5+
use rustc_hir as hir;
6+
use rustc_lint::LateContext;
7+
use rustc_span::{source_map::Span, sym};
8+
9+
use super::MAP_IDENTITY;
10+
11+
pub(super) fn check(
12+
cx: &LateContext<'_>,
13+
expr: &hir::Expr<'_>,
14+
caller: &hir::Expr<'_>,
15+
map_arg: &hir::Expr<'_>,
16+
_map_span: Span,
17+
) {
18+
let caller_ty = cx.typeck_results().expr_ty(caller);
19+
20+
if_chain! {
21+
if is_trait_method(cx, expr, sym::Iterator)
22+
|| is_type_diagnostic_item(cx, caller_ty, sym::result_type)
23+
|| is_type_diagnostic_item(cx, caller_ty, sym::option_type);
24+
if is_expr_identity_function(cx, map_arg);
25+
if let Some(sugg_span) = expr.span.trim_start(caller.span);
26+
then {
27+
span_lint_and_sugg(
28+
cx,
29+
MAP_IDENTITY,
30+
sugg_span,
31+
"unnecessary map of the identity function",
32+
"remove the call to `map`",
33+
String::new(),
34+
Applicability::MachineApplicable,
35+
)
36+
}
37+
}
38+
}

clippy_lints/src/methods/mod.rs

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,6 +35,7 @@ mod manual_saturating_arithmetic;
3535
mod manual_str_repeat;
3636
mod map_collect_result_unit;
3737
mod map_flatten;
38+
mod map_identity;
3839
mod map_unwrap_or;
3940
mod ok_expect;
4041
mod option_as_ref_deref;
@@ -1561,6 +1562,29 @@ declare_clippy_lint! {
15611562
"call to `filter_map` where `flatten` is sufficient"
15621563
}
15631564

1565+
declare_clippy_lint! {
1566+
/// **What it does:** Checks for instances of `map(f)` where `f` is the identity function.
1567+
///
1568+
/// **Why is this bad?** It can be written more concisely without the call to `map`.
1569+
///
1570+
/// **Known problems:** None.
1571+
///
1572+
/// **Example:**
1573+
///
1574+
/// ```rust
1575+
/// let x = [1, 2, 3];
1576+
/// let y: Vec<_> = x.iter().map(|x| x).map(|x| 2*x).collect();
1577+
/// ```
1578+
/// Use instead:
1579+
/// ```rust
1580+
/// let x = [1, 2, 3];
1581+
/// let y: Vec<_> = x.iter().map(|x| 2*x).collect();
1582+
/// ```
1583+
pub MAP_IDENTITY,
1584+
complexity,
1585+
"using iterator.map(|x| x)"
1586+
}
1587+
15641588
declare_clippy_lint! {
15651589
/// **What it does:** Checks for the use of `.bytes().nth()`.
15661590
///
@@ -1728,6 +1752,7 @@ impl_lint_pass!(Methods => [
17281752
FILTER_NEXT,
17291753
SKIP_WHILE_NEXT,
17301754
FILTER_MAP_IDENTITY,
1755+
MAP_IDENTITY,
17311756
MANUAL_FILTER_MAP,
17321757
MANUAL_FIND_MAP,
17331758
OPTION_FILTER_MAP,
@@ -2058,6 +2083,7 @@ fn check_methods<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'_>, msrv: Optio
20582083
_ => {},
20592084
}
20602085
}
2086+
map_identity::check(cx, expr, recv, m_arg, span);
20612087
},
20622088
("map_or", [def, map]) => option_map_or_none::check(cx, expr, recv, def, map),
20632089
("next", []) => {

0 commit comments

Comments
 (0)