Skip to content

Commit 967d815

Browse files
committed
Extracting is_expr_identity_function into clippy_utils for reusability
1 parent e4a1e85 commit 967d815

File tree

2 files changed

+56
-52
lines changed

2 files changed

+56
-52
lines changed

clippy_lints/src/map_identity.rs

Lines changed: 2 additions & 52 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
11
use clippy_utils::diagnostics::span_lint_and_sugg;
22
use clippy_utils::ty::is_type_diagnostic_item;
3-
use clippy_utils::{is_adjusted, is_qpath_def_path, is_trait_method, match_var, paths, remove_blocks};
3+
use clippy_utils::{is_expr_identity_function, is_trait_method};
44
use if_chain::if_chain;
55
use rustc_errors::Applicability;
6-
use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
6+
use rustc_hir::{Expr, ExprKind};
77
use rustc_lint::{LateContext, LateLintPass};
88
use rustc_session::{declare_lint_pass, declare_tool_lint};
99
use rustc_span::sym;
@@ -74,53 +74,3 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a
7474
}
7575
}
7676
}
77-
78-
/// Checks if an expression represents the identity function
79-
/// Only examines closures and `std::convert::identity`
80-
fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
81-
match expr.kind {
82-
ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
83-
ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
84-
_ => false,
85-
}
86-
}
87-
88-
/// Checks if a function's body represents the identity function
89-
/// Looks for bodies of the form `|x| x`, `|x| return x`, `|x| { return x }` or `|x| {
90-
/// return x; }`
91-
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
92-
let params = func.params;
93-
let body = remove_blocks(&func.value);
94-
95-
// if there's less/more than one parameter, then it is not the identity function
96-
if params.len() != 1 {
97-
return false;
98-
}
99-
100-
match body.kind {
101-
ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat),
102-
ExprKind::Ret(Some(ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
103-
ExprKind::Block(block, _) => {
104-
if_chain! {
105-
if block.stmts.len() == 1;
106-
if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = block.stmts[0].kind;
107-
if let ExprKind::Ret(Some(ret_val)) = expr.kind;
108-
then {
109-
match_expr_param(cx, ret_val, params[0].pat)
110-
} else {
111-
false
112-
}
113-
}
114-
},
115-
_ => false,
116-
}
117-
}
118-
119-
/// Returns true iff an expression returns the same thing as a parameter's pattern
120-
fn match_expr_param(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
121-
if let PatKind::Binding(_, _, ident, _) = pat.kind {
122-
match_var(expr, ident.name) && !(cx.typeck_results().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr))
123-
} else {
124-
false
125-
}
126-
}

clippy_utils/src/lib.rs

Lines changed: 54 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,60 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
13991399
did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
14001400
}
14011401

1402+
/// Checks if an expression represents the identity function
1403+
/// Only examines closures and `std::convert::identity`
1404+
pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
1405+
/// Returns true if the expression is a binding to the given pattern
1406+
fn is_expr_pat_binding(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
1407+
if let PatKind::Binding(_, _, ident, _) = pat.kind {
1408+
if match_var(expr, ident.name) {
1409+
return !(cx.typeck_results().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr));
1410+
}
1411+
}
1412+
1413+
false
1414+
}
1415+
1416+
/// Checks if a function's body represents the identity function. Looks for bodies of the form:
1417+
/// * `|x| x`
1418+
/// * `|x| return x`
1419+
/// * `|x| { return x }`
1420+
/// * `|x| { return x; }`
1421+
fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
1422+
let body = remove_blocks(&func.value);
1423+
1424+
let value_pat = if let [value_param] = func.params {
1425+
value_param.pat
1426+
} else {
1427+
return false;
1428+
};
1429+
1430+
match body.kind {
1431+
ExprKind::Path(QPath::Resolved(None, _)) => is_expr_pat_binding(cx, body, value_pat),
1432+
ExprKind::Ret(Some(ret_val)) => is_expr_pat_binding(cx, ret_val, value_pat),
1433+
ExprKind::Block(block, _) => {
1434+
if_chain! {
1435+
if let &[block_stmt] = &block.stmts;
1436+
if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = block_stmt.kind;
1437+
if let ExprKind::Ret(Some(ret_val)) = expr.kind;
1438+
then {
1439+
is_expr_pat_binding(cx, ret_val, value_pat)
1440+
} else {
1441+
false
1442+
}
1443+
}
1444+
},
1445+
_ => false,
1446+
}
1447+
}
1448+
1449+
match expr.kind {
1450+
ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
1451+
ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
1452+
_ => false,
1453+
}
1454+
}
1455+
14021456
/// Gets the node where an expression is either used, or it's type is unified with another branch.
14031457
pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
14041458
let map = tcx.hir();

0 commit comments

Comments
 (0)