]> git.lizzy.rs Git - rust.git/blobdiff - clippy_lints/src/mem_replace.rs
mem_replace: match on path.
[rust.git] / clippy_lints / src / mem_replace.rs
index f516fc5085c94e7df1ffb6d6557fca0ec515986f..22460ccb5ea5669ff7900199616c21ba99c2fe97 100644 (file)
@@ -1,7 +1,7 @@
 use crate::rustc::hir::{Expr, ExprKind, MutMutable, QPath};
 use crate::rustc::lint::{LateContext, LateLintPass, LintArray, LintPass};
 use crate::rustc::{declare_tool_lint, lint_array};
-use crate::utils::{match_def_path, match_qpath, match_type, opt_def_id, paths, snippet, span_lint_and_sugg};
+use crate::utils::{match_def_path, match_qpath, opt_def_id, paths, snippet, span_lint_and_sugg};
 use if_chain::if_chain;
 
 /// **What it does:** Checks for `mem::replace()` on an `Option` with
@@ -40,25 +40,42 @@ fn get_lints(&self) -> LintArray {
 impl<'a, 'tcx> LateLintPass<'a, 'tcx> for MemReplace {
     fn check_expr(&mut self, cx: &LateContext<'a, 'tcx>, expr: &'tcx Expr) {
         if_chain! {
+            // Check that `expr` is a call to `mem::replace()`
             if let ExprKind::Call(ref func, ref func_args) = expr.node;
             if func_args.len() == 2;
             if let ExprKind::Path(ref func_qpath) = func.node;
             if let Some(def_id) = opt_def_id(cx.tables.qpath_def(func_qpath, func.hir_id));
             if match_def_path(cx.tcx, def_id, &paths::MEM_REPLACE);
-            if let ExprKind::AddrOf(MutMutable, ref replaced) = func_args[0].node;
-            if match_type(cx, cx.tables.expr_ty(replaced), &paths::OPTION);
+
+            // Check that second argument is `Option::None`
             if let ExprKind::Path(ref replacement_qpath) = func_args[1].node;
             if match_qpath(replacement_qpath, &paths::OPTION_NONE);
-            if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.node;
+
             then {
-                let sugg = format!("{}.take()", snippet(cx, replaced_path.span, ""));
+                // Since this is a late pass (already type-checked),
+                // and we already know that the second argument is an
+                // `Option`, we do not need to check if the first
+                // argument's type. All that's left is to get
+                // replacee's path.
+                let replaced_path = match func_args[0].node {
+                    ExprKind::AddrOf(MutMutable, ref replaced) => {
+                        if let ExprKind::Path(QPath::Resolved(None, ref replaced_path)) = replaced.node {
+                            replaced_path
+                        } else {
+                            return
+                        }
+                    },
+                    ExprKind::Path(QPath::Resolved(None, ref replaced_path)) => replaced_path,
+                    _ => return,
+                };
+
                 span_lint_and_sugg(
                     cx,
                     MEM_REPLACE_OPTION_WITH_NONE,
                     expr.span,
                     "replacing an `Option` with `None`",
                     "consider `Option::take()` instead",
-                    sugg
+                    format!("{}.take()", snippet(cx, replaced_path.span, ""))
                 );
             }
         }