@@ -8,7 +8,7 @@ use clippy_utils::{
8
8
is_default_equivalent, is_expr_used_or_unified, is_res_lang_ctor, path_res, peel_ref_operators, std_or_core,
9
9
} ;
10
10
use rustc_errors:: Applicability ;
11
- use rustc_hir:: LangItem :: OptionNone ;
11
+ use rustc_hir:: LangItem :: { OptionNone , OptionSome } ;
12
12
use rustc_hir:: { Expr , ExprKind } ;
13
13
use rustc_lint:: { LateContext , LateLintPass } ;
14
14
use rustc_session:: impl_lint_pass;
@@ -43,6 +43,31 @@ declare_clippy_lint! {
43
43
"replacing an `Option` with `None` instead of `take()`"
44
44
}
45
45
46
+ declare_clippy_lint ! {
47
+ /// ### What it does
48
+ /// Checks for `mem::replace()` on an `Option` with `Some(…)`.
49
+ ///
50
+ /// ### Why is this bad?
51
+ /// `Option` already has the method `replace()` for
52
+ /// taking its current value (Some(…) or None) and replacing it with
53
+ /// `Some(…)`.
54
+ ///
55
+ /// ### Example
56
+ /// ```no_run
57
+ /// let mut an_option = Some(0);
58
+ /// let replaced = std::mem::replace(&mut an_option, Some(1));
59
+ /// ```
60
+ /// Is better expressed with:
61
+ /// ```no_run
62
+ /// let mut an_option = Some(0);
63
+ /// let taken = an_option.replace(1);
64
+ /// ```
65
+ #[ clippy:: version = "1.86.0" ]
66
+ pub MEM_REPLACE_OPTION_WITH_SOME ,
67
+ style,
68
+ "replacing an `Option` with `Some` instead of `replace()`"
69
+ }
70
+
46
71
declare_clippy_lint ! {
47
72
/// ### What it does
48
73
/// Checks for `mem::replace(&mut _, mem::uninitialized())`
@@ -101,7 +126,7 @@ declare_clippy_lint! {
101
126
}
102
127
103
128
impl_lint_pass ! ( MemReplace =>
104
- [ MEM_REPLACE_OPTION_WITH_NONE , MEM_REPLACE_WITH_UNINIT , MEM_REPLACE_WITH_DEFAULT ] ) ;
129
+ [ MEM_REPLACE_OPTION_WITH_NONE , MEM_REPLACE_OPTION_WITH_SOME , MEM_REPLACE_WITH_UNINIT , MEM_REPLACE_WITH_DEFAULT ] ) ;
105
130
106
131
fn check_replace_option_with_none ( cx : & LateContext < ' _ > , src : & Expr < ' _ > , dest : & Expr < ' _ > , expr_span : Span ) -> bool {
107
132
if is_res_lang_ctor ( cx, path_res ( cx, src) , OptionNone ) {
@@ -130,6 +155,40 @@ fn check_replace_option_with_none(cx: &LateContext<'_>, src: &Expr<'_>, dest: &E
130
155
}
131
156
}
132
157
158
+ fn check_replace_option_with_some (
159
+ cx : & LateContext < ' _ > ,
160
+ src : & Expr < ' _ > ,
161
+ dest : & Expr < ' _ > ,
162
+ expr_span : Span ,
163
+ msrv : & Msrv ,
164
+ ) -> bool {
165
+ if msrv. meets ( msrvs:: OPTION_REPLACE )
166
+ && let ExprKind :: Call ( src_func, [ src_arg] ) = src. kind
167
+ && is_res_lang_ctor ( cx, path_res ( cx, src_func) , OptionSome )
168
+ {
169
+ // We do not have to check for a `const` context here, because `core::mem::replace()` and
170
+ // `Option::replace()` have been const-stabilized simultaneously in version 1.83.0.
171
+ let sugg_expr = peel_ref_operators ( cx, dest) ;
172
+ let mut applicability = Applicability :: MachineApplicable ;
173
+ span_lint_and_sugg (
174
+ cx,
175
+ MEM_REPLACE_OPTION_WITH_SOME ,
176
+ expr_span,
177
+ "replacing an `Option` with `Some(..)`" ,
178
+ "consider `Option::replace()` instead" ,
179
+ format ! (
180
+ "{}.replace({})" ,
181
+ Sugg :: hir_with_context( cx, sugg_expr, expr_span. ctxt( ) , "_" , & mut applicability) . maybe_par( ) ,
182
+ snippet_with_applicability( cx, src_arg. span, "_" , & mut applicability)
183
+ ) ,
184
+ applicability,
185
+ ) ;
186
+ true
187
+ } else {
188
+ false
189
+ }
190
+ }
191
+
133
192
fn check_replace_with_uninit ( cx : & LateContext < ' _ > , src : & Expr < ' _ > , dest : & Expr < ' _ > , expr_span : Span ) {
134
193
if let Some ( method_def_id) = cx. typeck_results ( ) . type_dependent_def_id ( src. hir_id )
135
194
// check if replacement is mem::MaybeUninit::uninit().assume_init()
@@ -249,6 +308,7 @@ impl<'tcx> LateLintPass<'tcx> for MemReplace {
249
308
{
250
309
// Check that second argument is `Option::None`
251
310
if !check_replace_option_with_none ( cx, src, dest, expr. span )
311
+ && !check_replace_option_with_some ( cx, src, dest, expr. span , & self . msrv )
252
312
&& !check_replace_with_default ( cx, src, dest, expr, & self . msrv )
253
313
{
254
314
check_replace_with_uninit ( cx, src, dest, expr. span ) ;
0 commit comments