about summary refs log tree commit diff
path: root/clippy_utils/src
diff options
context:
space:
mode:
authorCameron Steffen <cam.steffen94@gmail.com>2021-06-09 09:17:34 -0500
committerCameron Steffen <cam.steffen94@gmail.com>2021-06-09 09:47:42 -0500
commitb792bb301c66e271d88d2e579ec79fec153b7b89 (patch)
tree44247c2827821c4bc92f960749c781e195186af5 /clippy_utils/src
parentdd0246813f3f42a6cadc2109cdbda76300495981 (diff)
downloadrust-b792bb301c66e271d88d2e579ec79fec153b7b89.tar.gz
rust-b792bb301c66e271d88d2e579ec79fec153b7b89.zip
Factor out match_var
Diffstat (limited to 'clippy_utils/src')
-rw-r--r--clippy_utils/src/lib.rs94
-rw-r--r--clippy_utils/src/ptr.rs32
2 files changed, 55 insertions, 71 deletions
diff --git a/clippy_utils/src/lib.rs b/clippy_utils/src/lib.rs
index d3efd32d727..66e75b0c206 100644
--- a/clippy_utils/src/lib.rs
+++ b/clippy_utils/src/lib.rs
@@ -72,7 +72,7 @@ use rustc_hir::LangItem::{ResultErr, ResultOk};
 use rustc_hir::{
     def, Arm, BindingAnnotation, Block, Body, Constness, Destination, Expr, ExprKind, FnDecl, GenericArgs, HirId, Impl,
     ImplItem, ImplItemKind, IsAsync, Item, ItemKind, LangItem, Local, MatchSource, Node, Param, Pat, PatKind, Path,
-    PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind,
+    PathSegment, QPath, Stmt, StmtKind, TraitItem, TraitItemKind, TraitRef, TyKind, UnOp,
 };
 use rustc_lint::{LateContext, Level, Lint, LintContext};
 use rustc_middle::hir::exports::Export;
@@ -326,16 +326,6 @@ pub fn is_trait_method(cx: &LateContext<'_>, expr: &Expr<'_>, diag_item: Symbol)
         .map_or(false, |did| is_diag_trait_item(cx, did, diag_item))
 }
 
-/// Checks if an expression references a variable of the given name.
-pub fn match_var(expr: &Expr<'_>, var: Symbol) -> bool {
-    if let ExprKind::Path(QPath::Resolved(None, path)) = expr.kind {
-        if let [p] = path.segments {
-            return p.ident.name == var;
-        }
-    }
-    false
-}
-
 pub fn last_path_segment<'tcx>(path: &QPath<'tcx>) -> &'tcx PathSegment<'tcx> {
     match *path {
         QPath::Resolved(_, path) => path.segments.last().expect("A path must have at least one segment"),
@@ -707,16 +697,6 @@ pub fn get_item_name(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<Symbol> {
     }
 }
 
-/// Gets the name of a `Pat`, if any.
-pub fn get_pat_name(pat: &Pat<'_>) -> Option<Symbol> {
-    match pat.kind {
-        PatKind::Binding(.., ref spname, _) => Some(spname.name),
-        PatKind::Path(ref qpath) => single_segment_path(qpath).map(|ps| ps.ident.name),
-        PatKind::Box(p) | PatKind::Ref(p, _) => get_pat_name(&*p),
-        _ => None,
-    }
-}
-
 pub struct ContainsName {
     pub name: Symbol,
     pub result: bool,
@@ -1404,47 +1384,42 @@ pub fn is_must_use_func_call(cx: &LateContext<'_>, expr: &Expr<'_>) -> bool {
 /// 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;
+        let id = if_chain! {
+            if let [param] = func.params;
+            if let PatKind::Binding(_, id, _, _) = param.pat.kind;
+            then {
+                id
+            } 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
+        let mut expr = &func.value;
+        loop {
+            match expr.kind {
+                #[rustfmt::skip]
+                ExprKind::Block(&Block { stmts: [], expr: Some(e), .. }, _, )
+                | ExprKind::Ret(Some(e)) => expr = e,
+                #[rustfmt::skip]
+                ExprKind::Block(&Block { stmts: [stmt], expr: None, .. }, _) => {
+                    if_chain! {
+                        if let StmtKind::Semi(e) | StmtKind::Expr(e) = stmt.kind;
+                        if let ExprKind::Ret(Some(ret_val)) = e.kind;
+                        then {
+                            expr = ret_val;
+                        } else {
+                            return false;
+                        }
                     }
-                }
-            },
-            _ => false,
+                },
+                _ => return path_to_local_id(expr, id) && cx.typeck_results().expr_adjustments(expr).is_empty(),
+            }
         }
     }
 
@@ -1710,6 +1685,19 @@ pub fn peel_hir_expr_refs(expr: &'a Expr<'a>) -> (&'a Expr<'a>, usize) {
     (e, count)
 }
 
+/// Removes `AddrOf` operators (`&`) or deref operators (`*`), but only if a reference type is
+/// dereferenced. An overloaded deref such as `Vec` to slice would not be removed.
+pub fn peel_ref_operators<'hir>(cx: &LateContext<'_>, mut expr: &'hir Expr<'hir>) -> &'hir Expr<'hir> {
+    loop {
+        match expr.kind {
+            ExprKind::AddrOf(_, _, e) => expr = e,
+            ExprKind::Unary(UnOp::Deref, e) if cx.typeck_results().expr_ty(e).is_ref() => expr = e,
+            _ => break,
+        }
+    }
+    expr
+}
+
 #[macro_export]
 macro_rules! unwrap_cargo_metadata {
     ($cx: ident, $lint: ident, $deps: expr) => {{
diff --git a/clippy_utils/src/ptr.rs b/clippy_utils/src/ptr.rs
index 791688cd194..8adb6915952 100644
--- a/clippy_utils/src/ptr.rs
+++ b/clippy_utils/src/ptr.rs
@@ -1,10 +1,10 @@
 use crate::source::snippet;
-use crate::{get_pat_name, match_var};
+use crate::{path_to_local_id, strip_pat_refs};
 use rustc_hir::intravisit::{walk_expr, NestedVisitorMap, Visitor};
-use rustc_hir::{Body, BodyId, Expr, ExprKind, Param};
+use rustc_hir::{Body, BodyId, Expr, ExprKind, HirId, PatKind};
 use rustc_lint::LateContext;
 use rustc_middle::hir::map::Map;
-use rustc_span::{Span, Symbol};
+use rustc_span::Span;
 use std::borrow::Cow;
 
 pub fn get_spans(
@@ -14,10 +14,11 @@ pub fn get_spans(
     replacements: &[(&'static str, &'static str)],
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     if let Some(body) = opt_body_id.map(|id| cx.tcx.hir().body(id)) {
-        get_binding_name(&body.params[idx]).map_or_else(
-            || Some(vec![]),
-            |name| extract_clone_suggestions(cx, name, replacements, body),
-        )
+        if let PatKind::Binding(_, binding_id, _, _) = strip_pat_refs(body.params[idx].pat).kind {
+            extract_clone_suggestions(cx, binding_id, replacements, body)
+        } else {
+            Some(vec![])
+        }
     } else {
         Some(vec![])
     }
@@ -25,13 +26,13 @@ pub fn get_spans(
 
 fn extract_clone_suggestions<'tcx>(
     cx: &LateContext<'tcx>,
-    name: Symbol,
+    id: HirId,
     replace: &[(&'static str, &'static str)],
     body: &'tcx Body<'_>,
 ) -> Option<Vec<(Span, Cow<'static, str>)>> {
     let mut visitor = PtrCloneVisitor {
         cx,
-        name,
+        id,
         replace,
         spans: vec![],
         abort: false,
@@ -42,7 +43,7 @@ fn extract_clone_suggestions<'tcx>(
 
 struct PtrCloneVisitor<'a, 'tcx> {
     cx: &'a LateContext<'tcx>,
-    name: Symbol,
+    id: HirId,
     replace: &'a [(&'static str, &'static str)],
     spans: Vec<(Span, Cow<'static, str>)>,
     abort: bool,
@@ -55,16 +56,15 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
         if self.abort {
             return;
         }
-        if let ExprKind::MethodCall(seg, _, args, _) = expr.kind {
-            if args.len() == 1 && match_var(&args[0], self.name) {
+        if let ExprKind::MethodCall(seg, _, [recv], _) = expr.kind {
+            if path_to_local_id(recv, self.id) {
                 if seg.ident.name.as_str() == "capacity" {
                     self.abort = true;
                     return;
                 }
                 for &(fn_name, suffix) in self.replace {
                     if seg.ident.name.as_str() == fn_name {
-                        self.spans
-                            .push((expr.span, snippet(self.cx, args[0].span, "_") + suffix));
+                        self.spans.push((expr.span, snippet(self.cx, recv.span, "_") + suffix));
                         return;
                     }
                 }
@@ -77,7 +77,3 @@ impl<'a, 'tcx> Visitor<'tcx> for PtrCloneVisitor<'a, 'tcx> {
         NestedVisitorMap::None
     }
 }
-
-fn get_binding_name(arg: &Param<'_>) -> Option<Symbol> {
-    get_pat_name(arg.pat)
-}