Skip to content

Commit 635518f

Browse files
authored
Rollup merge of #5425 - xiongmao86:issue5367, r=flip1995
Ehance opt_as_ref_deref lint. - [x] Added passing UI tests (including committed `.stderr` file) - [x] `cargo test` passes locally - [x] Run `cargo dev fmt` Lint on opt.as_ref().map(|x| &**x). Fixes #5367. changelog: lint on opt.as_ref().map(|x| &**x)
2 parents 1242808 + d7056f8 commit 635518f

File tree

5 files changed

+73
-36
lines changed

5 files changed

+73
-36
lines changed

clippy_lints/src/loops.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -654,15 +654,15 @@ fn combine_branches(b1: NeverLoopResult, b2: NeverLoopResult) -> NeverLoopResult
654654

655655
fn never_loop_block(block: &Block<'_>, main_loop_id: HirId) -> NeverLoopResult {
656656
let stmts = block.stmts.iter().map(stmt_to_expr);
657-
let expr = once(block.expr.as_ref().map(|p| &**p));
657+
let expr = once(block.expr.as_deref());
658658
let mut iter = stmts.chain(expr).filter_map(|e| e);
659659
never_loop_expr_seq(&mut iter, main_loop_id)
660660
}
661661

662662
fn stmt_to_expr<'tcx>(stmt: &Stmt<'tcx>) -> Option<&'tcx Expr<'tcx>> {
663663
match stmt.kind {
664664
StmtKind::Semi(ref e, ..) | StmtKind::Expr(ref e, ..) => Some(e),
665-
StmtKind::Local(ref local) => local.init.as_ref().map(|p| &**p),
665+
StmtKind::Local(ref local) => local.init.as_deref(),
666666
_ => None,
667667
}
668668
}

clippy_lints/src/methods/mod.rs

Lines changed: 38 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -3226,6 +3226,8 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
32263226
map_args: &[hir::Expr<'_>],
32273227
is_mut: bool,
32283228
) {
3229+
let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
3230+
32293231
let option_ty = cx.tables.expr_ty(&as_ref_args[0]);
32303232
if !match_type(cx, option_ty, &paths::OPTION) {
32313233
return;
@@ -3248,39 +3250,56 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
32483250
hir::ExprKind::Closure(_, _, body_id, _, _) => {
32493251
let closure_body = cx.tcx.hir().body(body_id);
32503252
let closure_expr = remove_blocks(&closure_body.value);
3251-
if_chain! {
3252-
if let hir::ExprKind::MethodCall(_, _, args) = &closure_expr.kind;
3253-
if args.len() == 1;
3254-
if let hir::ExprKind::Path(qpath) = &args[0].kind;
3255-
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id);
3256-
if closure_body.params[0].pat.hir_id == local_id;
3257-
let adj = cx.tables.expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
3258-
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
3259-
then {
3260-
let method_did = cx.tables.type_dependent_def_id(closure_expr.hir_id).unwrap();
3261-
deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
3262-
} else {
3263-
false
3264-
}
3253+
3254+
match &closure_expr.kind {
3255+
hir::ExprKind::MethodCall(_, _, args) => {
3256+
if_chain! {
3257+
if args.len() == 1;
3258+
if let hir::ExprKind::Path(qpath) = &args[0].kind;
3259+
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id);
3260+
if closure_body.params[0].pat.hir_id == local_id;
3261+
let adj = cx.tables.expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
3262+
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
3263+
then {
3264+
let method_did = cx.tables.type_dependent_def_id(closure_expr.hir_id).unwrap();
3265+
deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
3266+
} else {
3267+
false
3268+
}
3269+
}
3270+
},
3271+
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
3272+
if_chain! {
3273+
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
3274+
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
3275+
if let hir::ExprKind::Path(ref qpath) = inner2.kind;
3276+
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, inner2.hir_id);
3277+
then {
3278+
closure_body.params[0].pat.hir_id == local_id
3279+
} else {
3280+
false
3281+
}
3282+
}
3283+
},
3284+
_ => false,
32653285
}
32663286
},
3267-
32683287
_ => false,
32693288
};
32703289

32713290
if is_deref {
32723291
let current_method = if is_mut {
3273-
".as_mut().map(DerefMut::deref_mut)"
3292+
format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
32743293
} else {
3275-
".as_ref().map(Deref::deref)"
3294+
format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
32763295
};
32773296
let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
32783297
let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
32793298
let suggestion = format!("try using {} instead", method_hint);
32803299

32813300
let msg = format!(
3282-
"called `{0}` (or with one of deref aliases) on an Option value. \
3283-
This can be done more directly by calling `{1}` instead",
3301+
"called `{0}` on an Option value. This can be done more directly \
3302+
by calling `{1}` instead",
32843303
current_method, hint
32853304
);
32863305
span_lint_and_sugg(

tests/ui/option_as_ref_deref.fixed

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -35,4 +35,7 @@ fn main() {
3535
let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted
3636

3737
let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted
38+
39+
let _ = opt.as_deref();
40+
let _ = opt.as_deref_mut();
3841
}

tests/ui/option_as_ref_deref.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -38,4 +38,7 @@ fn main() {
3838
let _ = Some(1_usize).as_ref().map(|x| vc[*x].as_str()); // should not be linted
3939

4040
let _: Option<&str> = Some(&String::new()).as_ref().map(|x| x.as_str()); // should not be linted
41+
42+
let _ = opt.as_ref().map(|x| &**x);
43+
let _ = opt.as_mut().map(|x| &mut **x);
4144
}

tests/ui/option_as_ref_deref.stderr

Lines changed: 27 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
1-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
1+
error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
22
--> $DIR/option_as_ref_deref.rs:13:13
33
|
44
LL | let _ = opt.clone().as_ref().map(Deref::deref).map(str::len);
55
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.clone().as_deref()`
66
|
77
= note: `-D clippy::option-as-ref-deref` implied by `-D warnings`
88

9-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
9+
error: called `.as_ref().map(Deref::deref)` on an Option value. This can be done more directly by calling `opt.clone().as_deref()` instead
1010
--> $DIR/option_as_ref_deref.rs:16:13
1111
|
1212
LL | let _ = opt.clone()
@@ -16,77 +16,89 @@ LL | | Deref::deref
1616
LL | | )
1717
| |_________^ help: try using as_deref instead: `opt.clone().as_deref()`
1818

19-
error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
19+
error: called `.as_mut().map(DerefMut::deref_mut)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
2020
--> $DIR/option_as_ref_deref.rs:22:13
2121
|
2222
LL | let _ = opt.as_mut().map(DerefMut::deref_mut);
2323
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
2424

25-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref()` instead
25+
error: called `.as_ref().map(String::as_str)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
2626
--> $DIR/option_as_ref_deref.rs:24:13
2727
|
2828
LL | let _ = opt.as_ref().map(String::as_str);
2929
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
3030

31-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref()` instead
31+
error: called `.as_ref().map(|x| x.as_str())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
3232
--> $DIR/option_as_ref_deref.rs:25:13
3333
|
3434
LL | let _ = opt.as_ref().map(|x| x.as_str());
3535
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
3636

37-
error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
37+
error: called `.as_mut().map(String::as_mut_str)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
3838
--> $DIR/option_as_ref_deref.rs:26:13
3939
|
4040
LL | let _ = opt.as_mut().map(String::as_mut_str);
4141
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
4242

43-
error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
43+
error: called `.as_mut().map(|x| x.as_mut_str())` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
4444
--> $DIR/option_as_ref_deref.rs:27:13
4545
|
4646
LL | let _ = opt.as_mut().map(|x| x.as_mut_str());
4747
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
4848

49-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead
49+
error: called `.as_ref().map(CString::as_c_str)` on an Option value. This can be done more directly by calling `Some(CString::new(vec![]).unwrap()).as_deref()` instead
5050
--> $DIR/option_as_ref_deref.rs:28:13
5151
|
5252
LL | let _ = Some(CString::new(vec![]).unwrap()).as_ref().map(CString::as_c_str);
5353
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(CString::new(vec![]).unwrap()).as_deref()`
5454

55-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead
55+
error: called `.as_ref().map(OsString::as_os_str)` on an Option value. This can be done more directly by calling `Some(OsString::new()).as_deref()` instead
5656
--> $DIR/option_as_ref_deref.rs:29:13
5757
|
5858
LL | let _ = Some(OsString::new()).as_ref().map(OsString::as_os_str);
5959
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(OsString::new()).as_deref()`
6060

61-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead
61+
error: called `.as_ref().map(PathBuf::as_path)` on an Option value. This can be done more directly by calling `Some(PathBuf::new()).as_deref()` instead
6262
--> $DIR/option_as_ref_deref.rs:30:13
6363
|
6464
LL | let _ = Some(PathBuf::new()).as_ref().map(PathBuf::as_path);
6565
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(PathBuf::new()).as_deref()`
6666

67-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead
67+
error: called `.as_ref().map(Vec::as_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref()` instead
6868
--> $DIR/option_as_ref_deref.rs:31:13
6969
|
7070
LL | let _ = Some(Vec::<()>::new()).as_ref().map(Vec::as_slice);
7171
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `Some(Vec::<()>::new()).as_deref()`
7272

73-
error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead
73+
error: called `.as_mut().map(Vec::as_mut_slice)` on an Option value. This can be done more directly by calling `Some(Vec::<()>::new()).as_deref_mut()` instead
7474
--> $DIR/option_as_ref_deref.rs:32:13
7575
|
7676
LL | let _ = Some(Vec::<()>::new()).as_mut().map(Vec::as_mut_slice);
7777
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `Some(Vec::<()>::new()).as_deref_mut()`
7878

79-
error: called `.as_ref().map(Deref::deref)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.as_deref()` instead
79+
error: called `.as_ref().map(|x| x.deref())` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
8080
--> $DIR/option_as_ref_deref.rs:34:13
8181
|
8282
LL | let _ = opt.as_ref().map(|x| x.deref());
8383
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
8484

85-
error: called `.as_mut().map(DerefMut::deref_mut)` (or with one of deref aliases) on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead
85+
error: called `.as_mut().map(|x| x.deref_mut())` on an Option value. This can be done more directly by calling `opt.clone().as_deref_mut()` instead
8686
--> $DIR/option_as_ref_deref.rs:35:13
8787
|
8888
LL | let _ = opt.clone().as_mut().map(|x| x.deref_mut()).map(|x| x.len());
8989
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.clone().as_deref_mut()`
9090

91-
error: aborting due to 14 previous errors
91+
error: called `.as_ref().map(|x| &**x)` on an Option value. This can be done more directly by calling `opt.as_deref()` instead
92+
--> $DIR/option_as_ref_deref.rs:42:13
93+
|
94+
LL | let _ = opt.as_ref().map(|x| &**x);
95+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref instead: `opt.as_deref()`
96+
97+
error: called `.as_mut().map(|x| &mut **x)` on an Option value. This can be done more directly by calling `opt.as_deref_mut()` instead
98+
--> $DIR/option_as_ref_deref.rs:43:13
99+
|
100+
LL | let _ = opt.as_mut().map(|x| &mut **x);
101+
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: try using as_deref_mut instead: `opt.as_deref_mut()`
102+
103+
error: aborting due to 16 previous errors
92104

0 commit comments

Comments
 (0)