Skip to content

Commit 110dac7

Browse files
committed
move option_as_ref_deref to its own module
1 parent 483bac2 commit 110dac7

File tree

2 files changed

+125
-111
lines changed

2 files changed

+125
-111
lines changed

clippy_lints/src/methods/mod.rs

Lines changed: 3 additions & 111 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ mod inspect_for_each;
1010
mod iter_count;
1111
mod manual_saturating_arithmetic;
1212
mod ok_expect;
13+
mod option_as_ref_deref;
1314
mod option_map_unwrap_or;
1415
mod skip_while_next;
1516
mod unnecessary_filter_map;
@@ -1725,10 +1726,10 @@ impl<'tcx> LateLintPass<'tcx> for Methods {
17251726
},
17261727
["is_file", ..] => lint_filetype_is_file(cx, expr, arg_lists[0]),
17271728
["map", "as_ref"] => {
1728-
lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
1729+
option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], false, self.msrv.as_ref())
17291730
},
17301731
["map", "as_mut"] => {
1731-
lint_option_as_ref_deref(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
1732+
option_as_ref_deref::check(cx, expr, arg_lists[1], arg_lists[0], true, self.msrv.as_ref())
17321733
},
17331734
["unwrap_or_else", ..] => unnecessary_lazy_eval::check(cx, expr, arg_lists[0], "unwrap_or"),
17341735
["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<'_>) {
35843585
);
35853586
}
35863587

3587-
const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
3588-
3589-
/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
3590-
fn lint_option_as_ref_deref<'tcx>(
3591-
cx: &LateContext<'tcx>,
3592-
expr: &hir::Expr<'_>,
3593-
as_ref_args: &[hir::Expr<'_>],
3594-
map_args: &[hir::Expr<'_>],
3595-
is_mut: bool,
3596-
msrv: Option<&RustcVersion>,
3597-
) {
3598-
if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) {
3599-
return;
3600-
}
3601-
3602-
let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
3603-
3604-
let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
3605-
if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
3606-
return;
3607-
}
3608-
3609-
let deref_aliases: [&[&str]; 9] = [
3610-
&paths::DEREF_TRAIT_METHOD,
3611-
&paths::DEREF_MUT_TRAIT_METHOD,
3612-
&paths::CSTRING_AS_C_STR,
3613-
&paths::OS_STRING_AS_OS_STR,
3614-
&paths::PATH_BUF_AS_PATH,
3615-
&paths::STRING_AS_STR,
3616-
&paths::STRING_AS_MUT_STR,
3617-
&paths::VEC_AS_SLICE,
3618-
&paths::VEC_AS_MUT_SLICE,
3619-
];
3620-
3621-
let is_deref = match map_args[1].kind {
3622-
hir::ExprKind::Path(ref expr_qpath) => cx
3623-
.qpath_res(expr_qpath, map_args[1].hir_id)
3624-
.opt_def_id()
3625-
.map_or(false, |fun_def_id| {
3626-
deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
3627-
}),
3628-
hir::ExprKind::Closure(_, _, body_id, _, _) => {
3629-
let closure_body = cx.tcx.hir().body(body_id);
3630-
let closure_expr = remove_blocks(&closure_body.value);
3631-
3632-
match &closure_expr.kind {
3633-
hir::ExprKind::MethodCall(_, _, args, _) => {
3634-
if_chain! {
3635-
if args.len() == 1;
3636-
if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
3637-
let adj = cx
3638-
.typeck_results()
3639-
.expr_adjustments(&args[0])
3640-
.iter()
3641-
.map(|x| &x.kind)
3642-
.collect::<Box<[_]>>();
3643-
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
3644-
then {
3645-
let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
3646-
deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
3647-
} else {
3648-
false
3649-
}
3650-
}
3651-
},
3652-
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
3653-
if_chain! {
3654-
if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind;
3655-
if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind;
3656-
then {
3657-
path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
3658-
} else {
3659-
false
3660-
}
3661-
}
3662-
},
3663-
_ => false,
3664-
}
3665-
},
3666-
_ => false,
3667-
};
3668-
3669-
if is_deref {
3670-
let current_method = if is_mut {
3671-
format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
3672-
} else {
3673-
format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
3674-
};
3675-
let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
3676-
let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
3677-
let suggestion = format!("try using {} instead", method_hint);
3678-
3679-
let msg = format!(
3680-
"called `{0}` on an Option value. This can be done more directly \
3681-
by calling `{1}` instead",
3682-
current_method, hint
3683-
);
3684-
span_lint_and_sugg(
3685-
cx,
3686-
OPTION_AS_REF_DEREF,
3687-
expr.span,
3688-
&msg,
3689-
&suggestion,
3690-
hint,
3691-
Applicability::MachineApplicable,
3692-
);
3693-
}
3694-
}
3695-
36963588
fn lint_map_collect(
36973589
cx: &LateContext<'_>,
36983590
expr: &hir::Expr<'_>,
Lines changed: 122 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,122 @@
1+
use crate::utils::{
2+
is_type_diagnostic_item, match_def_path, meets_msrv, path_to_local_id, paths, remove_blocks, snippet,
3+
span_lint_and_sugg,
4+
};
5+
use if_chain::if_chain;
6+
use rustc_errors::Applicability;
7+
use rustc_hir as hir;
8+
use rustc_lint::LateContext;
9+
use rustc_middle::ty;
10+
use rustc_semver::RustcVersion;
11+
use rustc_span::sym;
12+
13+
use super::OPTION_AS_REF_DEREF;
14+
15+
const OPTION_AS_REF_DEREF_MSRV: RustcVersion = RustcVersion::new(1, 40, 0);
16+
17+
/// lint use of `_.as_ref().map(Deref::deref)` for `Option`s
18+
pub(super) fn check<'tcx>(
19+
cx: &LateContext<'tcx>,
20+
expr: &hir::Expr<'_>,
21+
as_ref_args: &[hir::Expr<'_>],
22+
map_args: &[hir::Expr<'_>],
23+
is_mut: bool,
24+
msrv: Option<&RustcVersion>,
25+
) {
26+
if !meets_msrv(msrv, &OPTION_AS_REF_DEREF_MSRV) {
27+
return;
28+
}
29+
30+
let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
31+
32+
let option_ty = cx.typeck_results().expr_ty(&as_ref_args[0]);
33+
if !is_type_diagnostic_item(cx, option_ty, sym::option_type) {
34+
return;
35+
}
36+
37+
let deref_aliases: [&[&str]; 9] = [
38+
&paths::DEREF_TRAIT_METHOD,
39+
&paths::DEREF_MUT_TRAIT_METHOD,
40+
&paths::CSTRING_AS_C_STR,
41+
&paths::OS_STRING_AS_OS_STR,
42+
&paths::PATH_BUF_AS_PATH,
43+
&paths::STRING_AS_STR,
44+
&paths::STRING_AS_MUT_STR,
45+
&paths::VEC_AS_SLICE,
46+
&paths::VEC_AS_MUT_SLICE,
47+
];
48+
49+
let is_deref = match map_args[1].kind {
50+
hir::ExprKind::Path(ref expr_qpath) => cx
51+
.qpath_res(expr_qpath, map_args[1].hir_id)
52+
.opt_def_id()
53+
.map_or(false, |fun_def_id| {
54+
deref_aliases.iter().any(|path| match_def_path(cx, fun_def_id, path))
55+
}),
56+
hir::ExprKind::Closure(_, _, body_id, _, _) => {
57+
let closure_body = cx.tcx.hir().body(body_id);
58+
let closure_expr = remove_blocks(&closure_body.value);
59+
60+
match &closure_expr.kind {
61+
hir::ExprKind::MethodCall(_, _, args, _) => {
62+
if_chain! {
63+
if args.len() == 1;
64+
if path_to_local_id(&args[0], closure_body.params[0].pat.hir_id);
65+
let adj = cx
66+
.typeck_results()
67+
.expr_adjustments(&args[0])
68+
.iter()
69+
.map(|x| &x.kind)
70+
.collect::<Box<[_]>>();
71+
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
72+
then {
73+
let method_did = cx.typeck_results().type_dependent_def_id(closure_expr.hir_id).unwrap();
74+
deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
75+
} else {
76+
false
77+
}
78+
}
79+
},
80+
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
81+
if_chain! {
82+
if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner1) = inner.kind;
83+
if let hir::ExprKind::Unary(hir::UnOp::Deref, ref inner2) = inner1.kind;
84+
then {
85+
path_to_local_id(inner2, closure_body.params[0].pat.hir_id)
86+
} else {
87+
false
88+
}
89+
}
90+
},
91+
_ => false,
92+
}
93+
},
94+
_ => false,
95+
};
96+
97+
if is_deref {
98+
let current_method = if is_mut {
99+
format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
100+
} else {
101+
format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
102+
};
103+
let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
104+
let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
105+
let suggestion = format!("try using {} instead", method_hint);
106+
107+
let msg = format!(
108+
"called `{0}` on an Option value. This can be done more directly \
109+
by calling `{1}` instead",
110+
current_method, hint
111+
);
112+
span_lint_and_sugg(
113+
cx,
114+
OPTION_AS_REF_DEREF,
115+
expr.span,
116+
&msg,
117+
&suggestion,
118+
hint,
119+
Applicability::MachineApplicable,
120+
);
121+
}
122+
}

0 commit comments

Comments
 (0)