about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--clippy_lints/src/methods/mod.rs114
-rw-r--r--clippy_lints/src/methods/option_as_ref_deref.rs122
2 files changed, 125 insertions, 111 deletions
diff --git a/clippy_lints/src/methods/mod.rs b/clippy_lints/src/methods/mod.rs
index 34def45a8dd..c6b6ef34bc4 100644
--- a/clippy_lints/src/methods/mod.rs
+++ b/clippy_lints/src/methods/mod.rs
@@ -10,6 +10,7 @@ mod inspect_for_each;
 mod iter_count;
 mod manual_saturating_arithmetic;
 mod ok_expect;
+mod option_as_ref_deref;
 mod option_map_unwrap_or;
 mod skip_while_next;
 mod unnecessary_filter_map;
@@ -1725,10 +1726,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
             },
             ["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
             ["map", "as_ref"] => {
-                lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
+                option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
             },
             ["map", "as_mut"] => {
-                lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
+                option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
             },
             ["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"),
             ["get_or_insert_with", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "get_or_insert"),
@@ -3584,115 +3585,6 @@ fn lint_suspicious_map(cx: &LateContext<'_>, expr: &hir::Expr<'_>) {
     );
 }
 
-const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
-
-/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
-fn lint_option_as_ref_deref<'tcx>(
-    cx: &LateContext<'tcx>,
-    expr: &hir::Expr<'_>,
-    as_ref_args: &[hir::Expr<'_>],
-    map_args: &[hir::Expr<'_>],
-    is_mut: bool,
-    msrv: Option<&RustcVersion>,
-) {
-    if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) {
-        return;
-    }
-
-    let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
-
-    let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
-    if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
-        return;
-    }
-
-    let deref_aliases: [&[&str]; 9] = [
-        &paths::DEREF_TRAIT_METHOD,
-        &paths::DEREF_MUT_TRAIT_METHOD,
-        &paths::CSTRING_AS_C_STR,
-        &paths::OS_STRING_AS_OS_STR,
-        &paths::PATH_BUF_AS_PATH,
-        &paths::STRING_AS_STR,
-        &paths::STRING_AS_MUT_STR,
-        &paths::VEC_AS_SLICE,
-        &paths::VEC_AS_MUT_SLICE,
-    ];
-
-    let is_deref = match map_args[1].kind {
-        hir::ExprKind::Path(ref expr_qpath) => cx
-            .qpath_res(expr_qpath, map_args[1].hir_id)
-            .opt_def_id()
-            .map_or(false, |fun_def_id| {
-                deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
-            }),
-        hir::ExprKind::Closure(_, _, body_id, _, _) => {
-            let closure_body = cx.tcx.hir().body(body_id);
-            let closure_expr = remove_blocks(&closure_body.value);
-
-            match &closure_expr.kind {
-                hir::ExprKind::MethodCall(_, _, args, _) => {
-                    if_chain! {
-                        if args.len() == 1;
-                        if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
-                        let adj = cx
-                            .typeck_results()
-                            .expr_adjustments(&args[0])
-                            .iter()
-                            .map(|x| &x.kind)
-                            .collect::<Box<[_]>>();
-                        if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
-                        then {
-                            let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
-                            deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
-                        } else {
-                            false
-                        }
-                    }
-                },
-                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
-                    if_chain! {
-                        if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind;
-                        if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind;
-                        then {
-                            path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
-                        } else {
-                            false
-                        }
-                    }
-                },
-                _ => false,
-            }
-        },
-        _ => false,
-    };
-
-    if is_deref {
-        let current_method = if is_mut {
-            format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
-        } else {
-            format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
-        };
-        let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
-        let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
-        let suggestion = format!("try using {} instead", method_hint);
-
-        let msg = format!(
-            "called `{0}` on an Option value. This can be done more directly \
-            by calling `{1}` instead",
-            current_method, hint
-        );
-        span_lint_and_sugg(
-            cx,
-            OPTION_AS_REF_DEREF,
-            expr.span,
-            &msg,
-            &suggestion,
-            hint,
-            Applicability::MachineApplicable,
-        );
-    }
-}
-
 fn lint_map_collect(
     cx: &LateContext<'_>,
     expr: &hir::Expr<'_>,
diff --git a/clippy_lints/src/methods/option_as_ref_deref.rs b/clippy_lints/src/methods/option_as_ref_deref.rs
new file mode 100644
index 00000000000..89067dbfe0e
--- /dev/null
+++ b/clippy_lints/src/methods/option_as_ref_deref.rs
@@ -0,0 +1,122 @@
+use crate::utils::{
+    is_type_diagnostic_item, match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, snippet,
+    span_lint_and_sugg,
+};
+use if_chain::if_chain;
+use rustc_errors::Applicability;
+use rustc_hir as hir;
+use rustc_lint::LateContext;
+use rustc_middle::ty;
+use rustc_semver::RustcVersion;
+use rustc_span::sym;
+
+use super::OPTION_AS_REF_DEREF;
+
+const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
+
+/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
+pub(super) fn check<'tcx>(
+    cx: &LateContext<'tcx>,
+    expr: &hir::Expr<'_>,
+    as_ref_args: &[hir::Expr<'_>],
+    map_args: &[hir::Expr<'_>],
+    is_mut: bool,
+    msrv: Option<&RustcVersion>,
+) {
+    if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) {
+        return;
+    }
+
+    let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
+
+    let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
+    if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
+        return;
+    }
+
+    let deref_aliases: [&[&str]; 9] = [
+        &paths::DEREF_TRAIT_METHOD,
+        &paths::DEREF_MUT_TRAIT_METHOD,
+        &paths::CSTRING_AS_C_STR,
+        &paths::OS_STRING_AS_OS_STR,
+        &paths::PATH_BUF_AS_PATH,
+        &paths::STRING_AS_STR,
+        &paths::STRING_AS_MUT_STR,
+        &paths::VEC_AS_SLICE,
+        &paths::VEC_AS_MUT_SLICE,
+    ];
+
+    let is_deref = match map_args[1].kind {
+        hir::ExprKind::Path(ref expr_qpath) => cx
+            .qpath_res(expr_qpath, map_args[1].hir_id)
+            .opt_def_id()
+            .map_or(false, |fun_def_id| {
+                deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
+            }),
+        hir::ExprKind::Closure(_, _, body_id, _, _) => {
+            let closure_body = cx.tcx.hir().body(body_id);
+            let closure_expr = remove_blocks(&closure_body.value);
+
+            match &closure_expr.kind {
+                hir::ExprKind::MethodCall(_, _, args, _) => {
+                    if_chain! {
+                        if args.len() == 1;
+                        if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
+                        let adj = cx
+                            .typeck_results()
+                            .expr_adjustments(&args[0])
+                            .iter()
+                            .map(|x| &x.kind)
+                            .collect::<Box<[_]>>();
+                        if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
+                        then {
+                            let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
+                            deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
+                        } else {
+                            false
+                        }
+                    }
+                },
+                hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
+                    if_chain! {
+                        if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind;
+                        if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind;
+                        then {
+                            path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
+                        } else {
+                            false
+                        }
+                    }
+                },
+                _ => false,
+            }
+        },
+        _ => false,
+    };
+
+    if is_deref {
+        let current_method = if is_mut {
+            format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
+        } else {
+            format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
+        };
+        let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
+        let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
+        let suggestion = format!("try using {} instead", method_hint);
+
+        let msg = format!(
+            "called `{0}` on an Option value. This can be done more directly \
+            by calling `{1}` instead",
+            current_method, hint
+        );
+        span_lint_and_sugg(
+            cx,
+            OPTION_AS_REF_DEREF,
+            expr.span,
+            &msg,
+            &suggestion,
+            hint,
+            Applicability::MachineApplicable,
+        );
+    }
+}