diff --git a/clippy_lints/src/question_mark.rs b/clippy_lints/src/question_mark.rs index 95f79219105..c7501ccf2d7 100644 --- a/clippy_lints/src/question_mark.rs +++ b/clippy_lints/src/question_mark.rs @@ -84,6 +84,8 @@ impl Pass { replacement_str = format!("Some({}?)", receiver_str); } } + } else if Self::moves_by_default(cx, subject) { + replacement_str = format!("{}.as_ref()?;", receiver_str); } else { replacement_str = format!("{}?;", receiver_str); } @@ -105,6 +107,12 @@ impl Pass { } } + fn moves_by_default(cx: &LateContext<'_, '_>, expression: &Expr) -> bool { + let expr_ty = cx.tables.expr_ty(expression); + + expr_ty.moves_by_default(cx.tcx, cx.param_env, expression.span) + } + fn is_option(cx: &LateContext<'_, '_>, expression: &Expr) -> bool { let expr_ty = cx.tables.expr_ty(expression); diff --git a/tests/ui/question_mark.rs b/tests/ui/question_mark.rs index b1edec32eee..c6726ee567c 100644 --- a/tests/ui/question_mark.rs +++ b/tests/ui/question_mark.rs @@ -37,11 +37,11 @@ fn returns_something_similar_to_option(a: SeemsOption) -> SeemsOption a } -pub struct SomeStruct { +pub struct CopyStruct { pub opt: Option, } -impl SomeStruct { +impl CopyStruct { #[rustfmt::skip] pub fn func(&self) -> Option { if (self.opt).is_none() { @@ -62,12 +62,49 @@ impl SomeStruct { } } +#[derive(Clone)] +pub struct MoveStruct { + pub opt: Option>, +} + +impl MoveStruct { + pub fn ref_func(&self) -> Option> { + if self.opt.is_none() { + return None; + } + + self.opt.clone() + } + + pub fn mov_func_reuse(self) -> Option> { + if self.opt.is_none() { + return None; + } + + self.opt + } + + pub fn mov_func_no_use(self) -> Option> { + if self.opt.is_none() { + return None; + } + Some(Vec::new()) + } +} + fn main() { some_func(Some(42)); some_func(None); - let some_struct = SomeStruct { opt: Some(54) }; - some_struct.func(); + let copy_struct = CopyStruct { opt: Some(54) }; + copy_struct.func(); + + let move_struct = MoveStruct { + opt: Some(vec![42, 1337]), + }; + move_struct.ref_func(); + move_struct.clone().mov_func_reuse(); + move_struct.clone().mov_func_no_use(); let so = SeemsOption::Some(45); returns_something_similar_to_option(so); diff --git a/tests/ui/question_mark.stderr b/tests/ui/question_mark.stderr index c9d5538f36f..4f3b2c65de5 100644 --- a/tests/ui/question_mark.stderr +++ b/tests/ui/question_mark.stderr @@ -35,5 +35,29 @@ error: this block may be rewritten with the `?` operator 59 | | }; | |_________^ help: replace_it_with: `Some(self.opt?)` -error: aborting due to 4 previous errors +error: this block may be rewritten with the `?` operator + --> $DIR/question_mark.rs:72:9 + | +72 | / if self.opt.is_none() { +73 | | return None; +74 | | } + | |_________^ help: replace_it_with: `self.opt.as_ref()?;` + +error: this block may be rewritten with the `?` operator + --> $DIR/question_mark.rs:80:9 + | +80 | / if self.opt.is_none() { +81 | | return None; +82 | | } + | |_________^ help: replace_it_with: `self.opt.as_ref()?;` + +error: this block may be rewritten with the `?` operator + --> $DIR/question_mark.rs:88:9 + | +88 | / if self.opt.is_none() { +89 | | return None; +90 | | } + | |_________^ help: replace_it_with: `self.opt.as_ref()?;` + +error: aborting due to 7 previous errors