Skip to content

Commit ed0948d

Browse files
committed
Removed checks for user-defined identity functions, added checks for std::convert::identity
1 parent 518a36b commit ed0948d

File tree

4 files changed

+23
-45
lines changed

4 files changed

+23
-45
lines changed

clippy_lints/src/map_identity.rs

Lines changed: 17 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use crate::utils::{
2-
is_adjusted, is_type_diagnostic_item, match_trait_method, match_var, paths, remove_blocks, span_lint_and_sugg,
2+
is_adjusted, is_type_diagnostic_item, match_path, match_trait_method, match_var, paths, remove_blocks, span_lint_and_sugg,
33
};
44
use if_chain::if_chain;
55
use rustc_errors::Applicability;
6-
use rustc_hir::{def, Body, Expr, ExprKind, Pat, PatKind, Path, QPath, StmtKind};
6+
use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_session::{declare_lint_pass, declare_tool_lint};
99

@@ -40,8 +40,7 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MapIdentity {
4040

4141
if_chain! {
4242
if let Some([caller, func]) = get_map_argument(cx, expr);
43-
if let Some(body) = get_body(cx, func);
44-
if is_identity_function(cx, body);
43+
if is_expr_identity_function(cx, func);
4544
then {
4645
span_lint_and_sugg(
4746
cx,
@@ -75,8 +74,19 @@ fn get_map_argument<'a>(cx: &LateContext<'_, '_>, expr: &'a Expr<'a>) -> Option<
7574
}
7675
}
7776

78-
/// Determines if a function is the identity function (in a naive way)
79-
fn is_identity_function(cx: &LateContext<'_, '_>, func: &Body<'_>) -> bool {
77+
/// Checks if an expression represents the identity function
78+
/// Only examines closures and std::convert::identity
79+
fn is_expr_identity_function(cx: &LateContext<'_, '_>, expr: &Expr<'_>) -> bool {
80+
match expr.kind {
81+
ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
82+
ExprKind::Path(QPath::Resolved(_, ref path)) => match_path(path, &paths::STD_CONVERT_IDENTITY),
83+
_ => false,
84+
}
85+
}
86+
87+
/// Checks if a function's body represents the identity function
88+
/// Looks for bodies of the form |x| x, |x| return x, |x| return x;, |x| { return x } or |x| { return x; }
89+
fn is_body_identity_function(cx: &LateContext<'_, '_>, func: &Body<'_>) -> bool {
8090
let params = func.params;
8191
let body = remove_blocks(&func.value);
8292

@@ -104,29 +114,7 @@ fn is_identity_function(cx: &LateContext<'_, '_>, func: &Body<'_>) -> bool {
104114
}
105115
}
106116

107-
/// Returns an associated function/closure body from an expression
108-
fn get_body<'a>(cx: &LateContext<'a, '_>, expr: &'a Expr<'a>) -> Option<&'a Body<'a>> {
109-
match expr.kind {
110-
ExprKind::Closure(_, _, body_id, _, _) => Some(cx.tcx.hir().body(body_id)),
111-
ExprKind::Path(QPath::Resolved(_, ref path)) => path_to_body(cx, path),
112-
_ => None,
113-
}
114-
}
115-
116-
/// Returns the function body associated with a path
117-
fn path_to_body<'a>(cx: &LateContext<'a, '_>, path: &'a Path<'a>) -> Option<&'a Body<'a>> {
118-
if let def::Res::Def(_, def_id) = path.res {
119-
def_id
120-
.as_local()
121-
.and_then(|local_id| cx.tcx.hir().opt_local_def_id_to_hir_id(local_id))
122-
.and_then(|hir_id| cx.tcx.hir().maybe_body_owned_by(hir_id))
123-
.map(|body_id| cx.tcx.hir().body(body_id))
124-
} else {
125-
None
126-
}
127-
}
128-
129-
/// Determines if an expression (syntactically) returns the same thing as a parameter's pattern
117+
/// Returns true iff an expression returns the same thing as a parameter's pattern
130118
fn match_expr_param(cx: &LateContext<'_, '_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
131119
if let PatKind::Binding(_, _, ident, _) = pat.kind {
132120
match_var(expr, ident.name) && !(cx.tables.hir_owner == Some(expr.hir_id.owner) && is_adjusted(cx, expr))

tests/ui/map_identity.fixed

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -18,11 +18,6 @@ fn main() {
1818
});
1919
}
2020

21-
#[allow(dead_code)]
22-
fn identity(x: &u16) -> &u16 {
23-
return x;
24-
}
25-
2621
fn not_identity(x: &u16) -> u16 {
2722
*x
2823
}

tests/ui/map_identity.rs

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ fn main() {
66
let x: [u16; 3] = [1, 2, 3];
77
// should lint
88
let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
9-
let _: Vec<_> = x.iter().map(identity).map(|y| y).collect();
9+
let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
1010
let _: Option<u8> = Some(3).map(|x| x);
1111
let _: Result<i8, f32> = Ok(-3).map(|x| {
1212
return x;
@@ -20,11 +20,6 @@ fn main() {
2020
});
2121
}
2222

23-
#[allow(dead_code)]
24-
fn identity(x: &u16) -> &u16 {
25-
return x;
26-
}
27-
2823
fn not_identity(x: &u16) -> u16 {
2924
*x
3025
}

tests/ui/map_identity.stderr

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -7,16 +7,16 @@ LL | let _: Vec<_> = x.iter().map(not_identity).map(|x| return x).collect();
77
= note: `-D clippy::map-identity` implied by `-D warnings`
88

99
error: unnecessary map of the identity function
10-
--> $DIR/map_identity.rs:9:43
10+
--> $DIR/map_identity.rs:9:57
1111
|
12-
LL | let _: Vec<_> = x.iter().map(identity).map(|y| y).collect();
13-
| ^^^^^^^^^^^ help: remove the call to `map`
12+
LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
13+
| ^^^^^^^^^^^ help: remove the call to `map`
1414

1515
error: unnecessary map of the identity function
1616
--> $DIR/map_identity.rs:9:29
1717
|
18-
LL | let _: Vec<_> = x.iter().map(identity).map(|y| y).collect();
19-
| ^^^^^^^^^^^^^^ help: remove the call to `map`
18+
LL | let _: Vec<_> = x.iter().map(std::convert::identity).map(|y| y).collect();
19+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: remove the call to `map`
2020

2121
error: unnecessary map of the identity function
2222
--> $DIR/map_identity.rs:10:32

0 commit comments

Comments
 (0)