Skip to content

Commit 3c4abb5

Browse files
committed
Auto merge of #3561 - fuerstenau:master, r=oli-obk
Suggest `.as_ref()?` instead of `?` in certain circumstances.
2 parents f7bdf50 + 8be7050 commit 3c4abb5

File tree

3 files changed

+107
-39
lines changed

3 files changed

+107
-39
lines changed

clippy_lints/src/question_mark.rs

+29-31
Original file line numberDiff line numberDiff line change
@@ -72,52 +72,50 @@ impl Pass {
7272
if Self::is_option(cx, subject);
7373

7474
then {
75+
let receiver_str = &Sugg::hir(cx, subject, "..");
76+
let mut replacement: Option<String> = None;
7577
if let Some(else_) = else_ {
7678
if_chain! {
7779
if let ExprKind::Block(block, None) = &else_.node;
7880
if block.stmts.len() == 0;
7981
if let Some(block_expr) = &block.expr;
8082
if SpanlessEq::new(cx).ignore_fn().eq_expr(subject, block_expr);
8183
then {
82-
span_lint_and_then(
83-
cx,
84-
QUESTION_MARK,
85-
expr.span,
86-
"this block may be rewritten with the `?` operator",
87-
|db| {
88-
db.span_suggestion_with_applicability(
89-
expr.span,
90-
"replace_it_with",
91-
format!("Some({}?)", Sugg::hir(cx, subject, "..")),
92-
Applicability::MaybeIncorrect, // snippet
93-
);
94-
}
95-
)
84+
replacement = Some(format!("Some({}?)", receiver_str));
9685
}
9786
}
98-
return;
87+
} else if Self::moves_by_default(cx, subject) {
88+
replacement = Some(format!("{}.as_ref()?;", receiver_str));
89+
} else {
90+
replacement = Some(format!("{}?;", receiver_str));
9991
}
10092

101-
span_lint_and_then(
102-
cx,
103-
QUESTION_MARK,
104-
expr.span,
105-
"this block may be rewritten with the `?` operator",
106-
|db| {
107-
let receiver_str = &Sugg::hir(cx, subject, "..");
108-
109-
db.span_suggestion_with_applicability(
110-
expr.span,
111-
"replace_it_with",
112-
format!("{}?;", receiver_str),
113-
Applicability::MaybeIncorrect, // snippet
114-
);
115-
}
116-
)
93+
if let Some(replacement_str) = replacement {
94+
span_lint_and_then(
95+
cx,
96+
QUESTION_MARK,
97+
expr.span,
98+
"this block may be rewritten with the `?` operator",
99+
|db| {
100+
db.span_suggestion_with_applicability(
101+
expr.span,
102+
"replace_it_with",
103+
replacement_str,
104+
Applicability::MaybeIncorrect, // snippet
105+
);
106+
}
107+
)
108+
}
117109
}
118110
}
119111
}
120112

113+
fn moves_by_default(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
114+
let expr_ty = cx.tables.expr_ty(expression);
115+
116+
expr_ty.moves_by_default(cx.tcx, cx.param_env, expression.span)
117+
}
118+
121119
fn is_option(cx: &LateContext<'_, '_>, expression: &Expr) -> bool {
122120
let expr_ty = cx.tables.expr_ty(expression);
123121

tests/ui/question_mark.rs

+50-4
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,15 @@ fn some_func(a: Option<u32>) -> Option<u32> {
1515
a
1616
}
1717

18+
fn some_other_func(a: Option<u32>) -> Option<u32> {
19+
if a.is_none() {
20+
return None;
21+
} else {
22+
return Some(0);
23+
}
24+
unreachable!()
25+
}
26+
1827
pub enum SeemsOption<T> {
1928
Some(T),
2029
None,
@@ -37,11 +46,11 @@ fn returns_something_similar_to_option(a: SeemsOption<u32>) -> SeemsOption<u32>
3746
a
3847
}
3948

40-
pub struct SomeStruct {
49+
pub struct CopyStruct {
4150
pub opt: Option<u32>,
4251
}
4352

44-
impl SomeStruct {
53+
impl CopyStruct {
4554
#[rustfmt::skip]
4655
pub fn func(&self) -> Option<u32> {
4756
if (self.opt).is_none() {
@@ -62,12 +71,49 @@ impl SomeStruct {
6271
}
6372
}
6473

74+
#[derive(Clone)]
75+
pub struct MoveStruct {
76+
pub opt: Option<Vec<u32>>,
77+
}
78+
79+
impl MoveStruct {
80+
pub fn ref_func(&self) -> Option<Vec<u32>> {
81+
if self.opt.is_none() {
82+
return None;
83+
}
84+
85+
self.opt.clone()
86+
}
87+
88+
pub fn mov_func_reuse(self) -> Option<Vec<u32>> {
89+
if self.opt.is_none() {
90+
return None;
91+
}
92+
93+
self.opt
94+
}
95+
96+
pub fn mov_func_no_use(self) -> Option<Vec<u32>> {
97+
if self.opt.is_none() {
98+
return None;
99+
}
100+
Some(Vec::new())
101+
}
102+
}
103+
65104
fn main() {
66105
some_func(Some(42));
67106
some_func(None);
68107

69-
let some_struct = SomeStruct { opt: Some(54) };
70-
some_struct.func();
108+
let copy_struct = CopyStruct { opt: Some(54) };
109+
copy_struct.func();
110+
111+
let move_struct = MoveStruct {
112+
opt: Some(vec![42, 1337]),
113+
};
114+
move_struct.ref_func();
115+
move_struct.clone().mov_func_reuse();
116+
move_struct.clone().mov_func_no_use();
71117

72118
let so = SeemsOption::Some(45);
73119
returns_something_similar_to_option(so);

tests/ui/question_mark.stderr

+28-4
Original file line numberDiff line numberDiff line change
@@ -9,23 +9,23 @@ LL | | }
99
= note: `-D clippy::question-mark` implied by `-D warnings`
1010

1111
error: this block may be rewritten with the `?` operator
12-
--> $DIR/question_mark.rs:47:9
12+
--> $DIR/question_mark.rs:56:9
1313
|
1414
LL | / if (self.opt).is_none() {
1515
LL | | return None;
1616
LL | | }
1717
| |_________^ help: replace_it_with: `(self.opt)?;`
1818

1919
error: this block may be rewritten with the `?` operator
20-
--> $DIR/question_mark.rs:51:9
20+
--> $DIR/question_mark.rs:60:9
2121
|
2222
LL | / if self.opt.is_none() {
2323
LL | | return None
2424
LL | | }
2525
| |_________^ help: replace_it_with: `self.opt?;`
2626

2727
error: this block may be rewritten with the `?` operator
28-
--> $DIR/question_mark.rs:55:17
28+
--> $DIR/question_mark.rs:64:17
2929
|
3030
LL | let _ = if self.opt.is_none() {
3131
| _________________^
@@ -35,5 +35,29 @@ LL | | self.opt
3535
LL | | };
3636
| |_________^ help: replace_it_with: `Some(self.opt?)`
3737

38-
error: aborting due to 4 previous errors
38+
error: this block may be rewritten with the `?` operator
39+
--> $DIR/question_mark.rs:81:9
40+
|
41+
LL | / if self.opt.is_none() {
42+
LL | | return None;
43+
LL | | }
44+
| |_________^ help: replace_it_with: `self.opt.as_ref()?;`
45+
46+
error: this block may be rewritten with the `?` operator
47+
--> $DIR/question_mark.rs:89:9
48+
|
49+
LL | / if self.opt.is_none() {
50+
LL | | return None;
51+
LL | | }
52+
| |_________^ help: replace_it_with: `self.opt.as_ref()?;`
53+
54+
error: this block may be rewritten with the `?` operator
55+
--> $DIR/question_mark.rs:97:9
56+
|
57+
LL | / if self.opt.is_none() {
58+
LL | | return None;
59+
LL | | }
60+
| |_________^ help: replace_it_with: `self.opt.as_ref()?;`
61+
62+
error: aborting due to 7 previous errors
3963

0 commit comments

Comments
 (0)