about summary refs log tree commit diff
diff options
context:
space:
mode:
authorxFrednet <xFrednet@gmail.com>2021-06-07 22:21:56 +0200
committerxFrednet <xFrednet@gmail.com>2021-06-07 22:42:11 +0200
commit967d815a426dd16354dd42c96ad4b3f2eb036f09 (patch)
treec2ab685d1ce4788745425564af7583d6a5275c4e
parente4a1e8524cb3b03e24be800e5abbf5e5a25d268d (diff)
downloadrust-967d815a426dd16354dd42c96ad4b3f2eb036f09.tar.gz
rust-967d815a426dd16354dd42c96ad4b3f2eb036f09.zip
Extracting `is_expr_identity_function` into `clippy_utils` for reusability
-rw-r--r--clippy_lints/src/map_identity.rs54
-rw-r--r--clippy_utils/src/lib.rs54
2 files changed, 56 insertions, 52 deletions
diff --git a/clippy_lints/src/map_identity.rs b/clippy_lints/src/map_identity.rs
index 41cda23510e..9bcb010ff6d 100644
--- a/clippy_lints/src/map_identity.rs
+++ b/clippy_lints/src/map_identity.rs
@@ -1,9 +1,9 @@
 use clippy_utils::diagnostics::span_lint_and_sugg;
 use clippy_utils::ty::is_type_diagnostic_item;
-use clippy_utils::{is_adjusted, is_qpath_def_path, is_trait_method, match_var, paths, remove_blocks};
+use clippy_utils::{is_expr_identity_function, is_trait_method};
 use if_chain::if_chain;
 use rustc_errors::Applicability;
-use rustc_hir::{Body, Expr, ExprKind, Pat, PatKind, QPath, StmtKind};
+use rustc_hir::{Expr, ExprKind};
 use rustc_lint::{LateContext, LateLintPass};
 use rustc_session::{declare_lint_pass, declare_tool_lint};
 use rustc_span::sym;
@@ -74,53 +74,3 @@ fn get_map_argument<'a>(cx: &LateContext<'_>, expr: &'a Expr<'a>) -> Option<&'a
         }
     }
 }
-
-/// Checks if an expression represents the identity function
-/// Only examines closures and `std::convert::identity`
-fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
-    match expr.kind {
-        ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
-        ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
-        _ => false,
-    }
-}
-
-/// Checks if a function's body represents the identity function
-/// Looks for bodies of the form `|x| x`, `|x| return x`, `|x| { return x }` or `|x| {
-/// return x; }`
-fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
-    let params = func.params;
-    let body = remove_blocks(&func.value);
-
-    // if there's less/more than one parameter, then it is not the identity function
-    if params.len() != 1 {
-        return false;
-    }
-
-    match body.kind {
-        ExprKind::Path(QPath::Resolved(None, _)) => match_expr_param(cx, body, params[0].pat),
-        ExprKind::Ret(Some(ret_val)) => match_expr_param(cx, ret_val, params[0].pat),
-        ExprKind::Block(block, _) => {
-            if_chain! {
-                if block.stmts.len() == 1;
-                if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = block.stmts[0].kind;
-                if let ExprKind::Ret(Some(ret_val)) = expr.kind;
-                then {
-                    match_expr_param(cx, ret_val, params[0].pat)
-                } else {
-                    false
-                }
-            }
-        },
-        _ => false,
-    }
-}
-
-/// Returns true iff an expression returns the same thing as a parameter's pattern
-fn match_expr_param(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
-    if let PatKind::Binding(_, _, ident, _) = pat.kind {
-        match_var(expr, ident.name) && !(cx.typeck_results().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr))
-    } else {
-        false
-    }
-}
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index 769836aaf18..a765abe6b76 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -1399,6 +1399,60 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
     did.map_or(false, |did| must_use_attr(cx.tcx.get_attrs(did)).is_some())
 }
 
+/// Checks if an expression represents the identity function
+/// Only examines closures and `std::convert::identity`
+pub fn is_expr_identity_function(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
+    /// Returns true if the expression is a binding to the given pattern
+    fn is_expr_pat_binding(cx: &LateContext<'_>, expr: &Expr<'_>, pat: &Pat<'_>) -> bool {
+        if let PatKind::Binding(_, _, ident, _) = pat.kind {
+            if match_var(expr, ident.name) {
+                return !(cx.typeck_results().hir_owner == expr.hir_id.owner && is_adjusted(cx, expr));
+            }
+        }
+
+        false
+    }
+
+    /// Checks if a function's body represents the identity function. Looks for bodies of the form:
+    /// * `|x| x`
+    /// * `|x| return x`
+    /// * `|x| { return x }`
+    /// * `|x| { return x; }`
+    fn is_body_identity_function(cx: &LateContext<'_>, func: &Body<'_>) -> bool {
+        let body = remove_blocks(&func.value);
+
+        let value_pat = if let [value_param] = func.params {
+            value_param.pat
+        } else {
+            return false;
+        };
+
+        match body.kind {
+            ExprKind::Path(QPath::Resolved(None, _)) => is_expr_pat_binding(cx, body, value_pat),
+            ExprKind::Ret(Some(ret_val)) => is_expr_pat_binding(cx, ret_val, value_pat),
+            ExprKind::Block(block, _) => {
+                if_chain! {
+                    if let &[block_stmt] = &block.stmts;
+                    if let StmtKind::Semi(expr) | StmtKind::Expr(expr) = block_stmt.kind;
+                    if let ExprKind::Ret(Some(ret_val)) = expr.kind;
+                    then {
+                        is_expr_pat_binding(cx, ret_val, value_pat)
+                    } else {
+                        false
+                    }
+                }
+            },
+            _ => false,
+        }
+    }
+
+    match expr.kind {
+        ExprKind::Closure(_, _, body_id, _, _) => is_body_identity_function(cx, cx.tcx.hir().body(body_id)),
+        ExprKind::Path(ref path) => is_qpath_def_path(cx, path, expr.hir_id, &paths::CONVERT_IDENTITY),
+        _ => false,
+    }
+}
+
 /// Gets the node where an expression is either used, or it's type is unified with another branch.
 pub fn get_expr_use_or_unification_node(tcx: TyCtxt<'tcx>, expr: &Expr<'_>) -> Option<Node<'tcx>> {
     let map = tcx.hir();