]> git.proxmox.com Git - rustc.git/blame - src/tools/clippy/clippy_lints/src/methods/option_as_ref_deref.rs
New upstream version 1.64.0+dfsg1
[rustc.git] / src / tools / clippy / clippy_lints / src / methods / option_as_ref_deref.rs
CommitLineData
cdc7bbd5
XL
1use clippy_utils::diagnostics::span_lint_and_sugg;
2use clippy_utils::source::snippet;
3use clippy_utils::ty::is_type_diagnostic_item;
a2a8927a 4use clippy_utils::{match_def_path, meets_msrv, msrvs, path_to_local_id, paths, peel_blocks};
f20569fa
XL
5use if_chain::if_chain;
6use rustc_errors::Applicability;
7use rustc_hir as hir;
8use rustc_lint::LateContext;
9use rustc_middle::ty;
10use rustc_semver::RustcVersion;
11use rustc_span::sym;
12
13use super::OPTION_AS_REF_DEREF;
14
f20569fa
XL
15/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
16pub(super) fn check<'tcx>(
17 cx: &LateContext<'tcx>,
18 expr: &hir::Expr<'_>,
cdc7bbd5
XL
19 as_ref_recv: &hir::Expr<'_>,
20 map_arg: &hir::Expr<'_>,
f20569fa 21 is_mut: bool,
923072b8 22 msrv: Option<RustcVersion>,
f20569fa 23) {
923072b8 24 if !meets_msrv(msrv, msrvs::OPTION_AS_DEREF) {
f20569fa
XL
25 return;
26 }
27
28 let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
29
cdc7bbd5 30 let option_ty = cx.typeck_results().expr_ty(as_ref_recv);
c295e0f8 31 if !is_type_diagnostic_item(cx, option_ty, sym::Option) {
f20569fa
XL
32 return;
33 }
34
35 let deref_aliases: [&[&str]; 9] = [
36 &paths::DEREF_TRAIT_METHOD,
37 &paths::DEREF_MUT_TRAIT_METHOD,
38 &paths::CSTRING_AS_C_STR,
39 &paths::OS_STRING_AS_OS_STR,
40 &paths::PATH_BUF_AS_PATH,
41 &paths::STRING_AS_STR,
42 &paths::STRING_AS_MUT_STR,
43 &paths::VEC_AS_SLICE,
44 &paths::VEC_AS_MUT_SLICE,
45 ];
46
cdc7bbd5 47 let is_deref = match map_arg.kind {
f20569fa 48 hir::ExprKind::Path(ref expr_qpath) => cx
cdc7bbd5 49 .qpath_res(expr_qpath, map_arg.hir_id)
f20569fa
XL
50 .opt_def_id()
51 .map_or(false, |fun_def_id| {
52 deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
53 }),
064997fb 54 hir::ExprKind::Closure(&hir::Closure { body, .. }) => {
923072b8 55 let closure_body = cx.tcx.hir().body(body);
a2a8927a 56 let closure_expr = peel_blocks(&closure_body.value);
f20569fa
XL
57
58 match &closure_expr.kind {
5099ac24 59 hir::ExprKind::MethodCall(_, args, _) => {
f20569fa
XL
60 if_chain! {
61 if args.len() == 1;
62 if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
63 let adj = cx
64 .typeck_results()
65 .expr_adjustments(&args[0])
66 .iter()
67 .map(|x| &x.kind)
68 .collect::<Box<[_]>>();
69 if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
70 then {
71 let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
72 deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
73 } else {
74 false
75 }
76 }
77 },
cdc7bbd5 78 hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, inner) if same_mutability(m) => {
f20569fa 79 if_chain! {
cdc7bbd5
XL
80 if let hir::ExprKind::Unary(hir::UnOp::Deref, inner1) = inner.kind;
81 if let hir::ExprKind::Unary(hir::UnOp::Deref, inner2) = inner1.kind;
f20569fa
XL
82 then {
83 path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
84 } else {
85 false
86 }
87 }
88 },
89 _ => false,
90 }
91 },
92 _ => false,
93 };
94
95 if is_deref {
96 let current_method = if is_mut {
cdc7bbd5 97 format!(".as_mut().map({})", snippet(cx, map_arg.span, ".."))
f20569fa 98 } else {
cdc7bbd5 99 format!(".as_ref().map({})", snippet(cx, map_arg.span, ".."))
f20569fa
XL
100 };
101 let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
cdc7bbd5 102 let hint = format!("{}.{}()", snippet(cx, as_ref_recv.span, ".."), method_hint);
f20569fa
XL
103 let suggestion = format!("try using {} instead", method_hint);
104
105 let msg = format!(
106 "called `{0}` on an Option value. This can be done more directly \
107 by calling `{1}` instead",
108 current_method, hint
109 );
110 span_lint_and_sugg(
111 cx,
112 OPTION_AS_REF_DEREF,
113 expr.span,
114 &msg,
115 &suggestion,
116 hint,
117 Applicability::MachineApplicable,
118 );
119 }
120}