Skip to content

Commit 79d1521

Browse files
authored
Rollup merge of rust-lang#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 rust-lang#5367. changelog: lint on opt.as_ref().map(|x| &**x)
2 parents 8fc592a + d7056f8 commit 79d1521

File tree

5 files changed

+73
-36
lines changed

5 files changed

+73
-36
lines changed

clippy_lints/src/loops.rs

+2-2
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

+38-19
Original file line numberDiff line numberDiff line change
@@ -3233,6 +3233,8 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
32333233
map_args: &[hir::Expr<'_>],
32343234
is_mut: bool,
32353235
) {
3236+
let same_mutability = |m| (is_mut && m == &hir::Mutability::Mut) || (!is_mut && m == &hir::Mutability::Not);
3237+
32363238
let option_ty = cx.tables.expr_ty(&as_ref_args[0]);
32373239
if !match_type(cx, option_ty, &paths::OPTION) {
32383240
return;
@@ -3255,39 +3257,56 @@ fn lint_option_as_ref_deref<'a, 'tcx>(
32553257
hir::ExprKind::Closure(_, _, body_id, _, _) => {
32563258
let closure_body = cx.tcx.hir().body(body_id);
32573259
let closure_expr = remove_blocks(&closure_body.value);
3258-
if_chain! {
3259-
if let hir::ExprKind::MethodCall(_, _, args) = &closure_expr.kind;
3260-
if args.len() == 1;
3261-
if let hir::ExprKind::Path(qpath) = &args[0].kind;
3262-
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id);
3263-
if closure_body.params[0].pat.hir_id == local_id;
3264-
let adj = cx.tables.expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
3265-
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
3266-
then {
3267-
let method_did = cx.tables.type_dependent_def_id(closure_expr.hir_id).unwrap();
3268-
deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
3269-
} else {
3270-
false
3271-
}
3260+
3261+
match &closure_expr.kind {
3262+
hir::ExprKind::MethodCall(_, _, args) => {
3263+
if_chain! {
3264+
if args.len() == 1;
3265+
if let hir::ExprKind::Path(qpath) = &args[0].kind;
3266+
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, args[0].hir_id);
3267+
if closure_body.params[0].pat.hir_id == local_id;
3268+
let adj = cx.tables.expr_adjustments(&args[0]).iter().map(|x| &x.kind).collect::<Box<[_]>>();
3269+
if let [ty::adjustment::Adjust::Deref(None), ty::adjustment::Adjust::Borrow(_)] = *adj;
3270+
then {
3271+
let method_did = cx.tables.type_dependent_def_id(closure_expr.hir_id).unwrap();
3272+
deref_aliases.iter().any(|path| match_def_path(cx, method_did, path))
3273+
} else {
3274+
false
3275+
}
3276+
}
3277+
},
3278+
hir::ExprKind::AddrOf(hir::BorrowKind::Ref, m, ref inner) if same_mutability(m) => {
3279+
if_chain! {
3280+
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner1) = inner.kind;
3281+
if let hir::ExprKind::Unary(hir::UnOp::UnDeref, ref inner2) = inner1.kind;
3282+
if let hir::ExprKind::Path(ref qpath) = inner2.kind;
3283+
if let hir::def::Res::Local(local_id) = cx.tables.qpath_res(qpath, inner2.hir_id);
3284+
then {
3285+
closure_body.params[0].pat.hir_id == local_id
3286+
} else {
3287+
false
3288+
}
3289+
}
3290+
},
3291+
_ => false,
32723292
}
32733293
},
3274-
32753294
_ => false,
32763295
};
32773296

32783297
if is_deref {
32793298
let current_method = if is_mut {
3280-
".as_mut().map(DerefMut::deref_mut)"
3299+
format!(".as_mut().map({})", snippet(cx, map_args[1].span, ".."))
32813300
} else {
3282-
".as_ref().map(Deref::deref)"
3301+
format!(".as_ref().map({})", snippet(cx, map_args[1].span, ".."))
32833302
};
32843303
let method_hint = if is_mut { "as_deref_mut" } else { "as_deref" };
32853304
let hint = format!("{}.{}()", snippet(cx, as_ref_args[0].span, ".."), method_hint);
32863305
let suggestion = format!("try using {} instead", method_hint);
32873306

32883307
let msg = format!(
3289-
"called `{0}` (or with one of deref aliases) on an Option value. \
3290-
This can be done more directly by calling `{1}` instead",
3308+
"called `{0}` on an Option value. This can be done more directly \
3309+
by calling `{1}` instead",
32913310
current_method, hint
32923311
);
32933312
span_lint_and_sugg(

tests/ui/option_as_ref_deref.fixed

+3
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

+3
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

+27-15
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)