@@ -172,6 +172,7 @@ fn check_manual_swap(cx: &LateContext<'_>, block: &Block<'_>) {
172
172
}
173
173
}
174
174
175
+ #[ allow( clippy:: too_many_lines) ]
175
176
/// Implementation of the `ALMOST_SWAPPED` lint.
176
177
fn check_suspicious_swap ( cx : & LateContext < ' _ > , block : & Block < ' _ > ) {
177
178
for w in block. stmts . windows ( 2 ) {
@@ -220,6 +221,79 @@ fn check_suspicious_swap(cx: &LateContext<'_>, block: &Block<'_>) {
220
221
} ) ;
221
222
}
222
223
}
224
+
225
+ let lint_almost_swapped_note = |span, what : String , sugg, lhs, rhs| {
226
+ span_lint_and_then (
227
+ cx,
228
+ ALMOST_SWAPPED ,
229
+ span,
230
+ & format ! ( "this looks like you are trying to swap{}" , what) ,
231
+ |diag| {
232
+ if !what. is_empty ( ) {
233
+ diag. note ( & format ! (
234
+ "maybe you could use `{sugg}::mem::swap({lhs}, {rhs})` or `{sugg}::mem::replace`?"
235
+ ) ) ;
236
+ }
237
+ } ,
238
+ ) ;
239
+ } ;
240
+
241
+ if let StmtKind :: Local ( first) = w[ 0 ] . kind
242
+ && let StmtKind :: Local ( second) = w[ 1 ] . kind
243
+ && first. span . ctxt ( ) == second. span . ctxt ( )
244
+ && let Some ( rhs0) = first. init
245
+ && let Some ( rhs1) = second. init
246
+ && let ExprKind :: Path ( QPath :: Resolved ( None , path_l) ) = rhs0. kind
247
+ && let ExprKind :: Path ( QPath :: Resolved ( None , path_r) ) = rhs1. kind
248
+ && let PatKind :: Binding ( _, _, ident_l, _) = first. pat . kind
249
+ && let PatKind :: Binding ( _, _, ident_r, _) = second. pat . kind
250
+ && ident_l. name . as_str ( ) == path_r. segments . iter ( ) . map ( |el| el. ident . to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "::" )
251
+ && ident_r. name . as_str ( ) == path_l. segments . iter ( ) . map ( |el| el. ident . to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "::" )
252
+ {
253
+ let rhs0 = Sugg :: hir_opt ( cx, rhs0) ;
254
+ let ( what, lhs, rhs) = if let Some ( second) = rhs0 {
255
+ (
256
+ format ! ( " `{}` and `{}`" , ident_l, second) ,
257
+ format ! ( "&mut {}" , ident_l) ,
258
+ second. mut_addr ( ) . to_string ( ) ,
259
+ )
260
+ } else {
261
+ ( String :: new ( ) , String :: new ( ) , String :: new ( ) )
262
+ } ;
263
+ let span = first. span . to ( second. span ) ;
264
+ let Some ( sugg) = std_or_core ( cx) else { return } ;
265
+
266
+ lint_almost_swapped_note ( span, what, sugg, lhs, rhs) ;
267
+ }
268
+
269
+ if let StmtKind :: Local ( first) = w[ 0 ] . kind
270
+ && let StmtKind :: Semi ( second) = w[ 1 ] . kind
271
+ && first. span . ctxt ( ) == second. span . ctxt ( )
272
+ && let Some ( rhs0) = first. init
273
+ && let ExprKind :: Path ( QPath :: Resolved ( None , path_l) ) = rhs0. kind
274
+ && let PatKind :: Binding ( _, _, ident_l, _) = first. pat . kind
275
+ && let ExprKind :: Assign ( lhs1, rhs1, _) = second. kind
276
+ && let ExprKind :: Path ( QPath :: Resolved ( None , lhs1_path) ) = lhs1. kind
277
+ && let ExprKind :: Path ( QPath :: Resolved ( None , rhs1_path) ) = rhs1. kind
278
+ && ident_l. name . as_str ( ) == rhs1_path. segments . iter ( ) . map ( |el| el. ident . to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "::" )
279
+ && path_l. segments . iter ( ) . map ( |el| el. ident . to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "::" ) == lhs1_path. segments . iter ( ) . map ( |el| el. ident . to_string ( ) ) . collect :: < Vec < _ > > ( ) . join ( "::" )
280
+ {
281
+ let lhs1 = Sugg :: hir_opt ( cx, lhs1) ;
282
+ let rhs1 = Sugg :: hir_opt ( cx, rhs1) ;
283
+ let ( what, lhs, rhs) = if let ( Some ( first) , Some ( second) ) = ( lhs1, rhs1) {
284
+ (
285
+ format ! ( " `{}` and `{}`" , first, second) ,
286
+ first. mut_addr ( ) . to_string ( ) ,
287
+ second. mut_addr ( ) . to_string ( ) ,
288
+ )
289
+ } else {
290
+ ( String :: new ( ) , String :: new ( ) , String :: new ( ) )
291
+ } ;
292
+ let span = first. span . to ( second. span ) ;
293
+ let Some ( sugg) = std_or_core ( cx) else { return } ;
294
+
295
+ lint_almost_swapped_note ( span, what, sugg, lhs, rhs) ;
296
+ }
223
297
}
224
298
}
225
299
0 commit comments