@@ -12,6 +12,7 @@ use rustc_hir::{
12
12
use rustc_lint:: { LateContext , LateLintPass , LintContext } ;
13
13
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
14
14
use rustc_span:: symbol:: { Ident , Symbol } ;
15
+ use std:: cell:: Cell ;
15
16
use std:: fmt:: { Display , Formatter , Write as _} ;
16
17
17
18
declare_clippy_lint ! {
@@ -37,15 +38,13 @@ declare_clippy_lint! {
37
38
///
38
39
/// ```rust,ignore
39
40
/// // ./tests/ui/new_lint.stdout
40
- /// if_chain! {
41
- /// if let ExprKind::If(ref cond, ref then, None) = item.kind,
42
- /// if let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind,
43
- /// if let ExprKind::Path(ref path) = left.kind,
44
- /// if let ExprKind::Lit(ref lit) = right.kind,
45
- /// if let LitKind::Int(42, _) = lit.node,
46
- /// then {
47
- /// // report your lint here
48
- /// }
41
+ /// if ExprKind::If(ref cond, ref then, None) = item.kind
42
+ /// && let ExprKind::Binary(BinOp::Eq, ref left, ref right) = cond.kind
43
+ /// && let ExprKind::Path(ref path) = left.kind
44
+ /// && let ExprKind::Lit(ref lit) = right.kind
45
+ /// && let LitKind::Int(42, _) = lit.node
46
+ /// {
47
+ /// // report your lint here
49
48
/// }
50
49
/// ```
51
50
pub LINT_AUTHOR ,
@@ -91,15 +90,16 @@ macro_rules! field {
91
90
} ;
92
91
}
93
92
94
- fn prelude ( ) {
95
- println ! ( "if_chain! {{" ) ;
96
- }
97
-
98
- fn done ( ) {
99
- println ! ( " then {{" ) ;
100
- println ! ( " // report your lint here" ) ;
101
- println ! ( " }}" ) ;
102
- println ! ( "}}" ) ;
93
+ /// Print a condition of a let chain, `chain!(self, "let Some(x) = y")` will print
94
+ /// `if let Some(x) = y` on the first call and ` && let Some(x) = y` thereafter
95
+ macro_rules! chain {
96
+ ( $self: ident, $( $t: tt) * ) => {
97
+ if $self. first. take( ) {
98
+ println!( "if {}" , format_args!( $( $t) * ) ) ;
99
+ } else {
100
+ println!( " && {}" , format_args!( $( $t) * ) ) ;
101
+ }
102
+ }
103
103
}
104
104
105
105
impl < ' tcx > LateLintPass < ' tcx > for Author {
@@ -149,9 +149,10 @@ fn check_item(cx: &LateContext<'_>, hir_id: HirId) {
149
149
150
150
fn check_node ( cx : & LateContext < ' _ > , hir_id : HirId , f : impl Fn ( & PrintVisitor < ' _ , ' _ > ) ) {
151
151
if has_attr ( cx, hir_id) {
152
- prelude ( ) ;
153
152
f ( & PrintVisitor :: new ( cx) ) ;
154
- done ( ) ;
153
+ println ! ( "{{" ) ;
154
+ println ! ( " // report your lint here" ) ;
155
+ println ! ( "}}" ) ;
155
156
}
156
157
}
157
158
@@ -195,15 +196,18 @@ struct PrintVisitor<'a, 'tcx> {
195
196
cx : & ' a LateContext < ' tcx > ,
196
197
/// Fields are the current index that needs to be appended to pattern
197
198
/// binding names
198
- ids : std:: cell:: Cell < FxHashMap < & ' static str , u32 > > ,
199
+ ids : Cell < FxHashMap < & ' static str , u32 > > ,
200
+ /// Currently at the first condition in the if chain
201
+ first : Cell < bool > ,
199
202
}
200
203
201
204
#[ allow( clippy:: unused_self) ]
202
205
impl < ' a , ' tcx > PrintVisitor < ' a , ' tcx > {
203
206
fn new ( cx : & ' a LateContext < ' tcx > ) -> Self {
204
207
Self {
205
208
cx,
206
- ids : std:: cell:: Cell :: default ( ) ,
209
+ ids : Cell :: default ( ) ,
210
+ first : Cell :: new ( true ) ,
207
211
}
208
212
}
209
213
@@ -226,20 +230,20 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
226
230
227
231
fn option < T : Copy > ( & self , option : & Binding < Option < T > > , name : & ' static str , f : impl Fn ( & Binding < T > ) ) {
228
232
match option. value {
229
- None => out ! ( "if {option}.is_none(); ") ,
233
+ None => chain ! ( self , " {option}.is_none()") ,
230
234
Some ( value) => {
231
235
let value = & self . bind ( name, value) ;
232
- out ! ( "if let Some({value}) = {option}; ") ;
236
+ chain ! ( self , " let Some({value}) = {option}") ;
233
237
f ( value) ;
234
238
} ,
235
239
}
236
240
}
237
241
238
242
fn slice < T > ( & self , slice : & Binding < & [ T ] > , f : impl Fn ( & Binding < & T > ) ) {
239
243
if slice. value . is_empty ( ) {
240
- out ! ( "if {slice}.is_empty(); ") ;
244
+ chain ! ( self , " {slice}.is_empty()") ;
241
245
} else {
242
- out ! ( "if {slice}.len() == {}; ", slice. value. len( ) ) ;
246
+ chain ! ( self , " {slice}.len() == {}", slice. value. len( ) ) ;
243
247
for ( i, value) in slice. value . iter ( ) . enumerate ( ) {
244
248
let name = format ! ( "{slice}[{i}]" ) ;
245
249
f ( & Binding { name, value } ) ;
@@ -254,23 +258,23 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
254
258
}
255
259
256
260
fn ident ( & self , ident : & Binding < Ident > ) {
257
- out ! ( "if {ident}.as_str() == {:?}; ", ident. value. as_str( ) ) ;
261
+ chain ! ( self , " {ident}.as_str() == {:?}", ident. value. as_str( ) ) ;
258
262
}
259
263
260
264
fn symbol ( & self , symbol : & Binding < Symbol > ) {
261
- out ! ( "if {symbol}.as_str() == {:?}; ", symbol. value. as_str( ) ) ;
265
+ chain ! ( self , " {symbol}.as_str() == {:?}", symbol. value. as_str( ) ) ;
262
266
}
263
267
264
268
fn qpath ( & self , qpath : & Binding < & QPath < ' _ > > ) {
265
269
if let QPath :: LangItem ( lang_item, ..) = * qpath. value {
266
- out ! ( "if matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _)); ") ;
270
+ chain ! ( self , " matches!({qpath}, QPath::LangItem(LangItem::{lang_item:?}, _))") ;
267
271
} else {
268
- out ! ( "if match_qpath({qpath}, &[{}]); ", path_to_string( qpath. value) ) ;
272
+ chain ! ( self , " match_qpath({qpath}, &[{}])", path_to_string( qpath. value) ) ;
269
273
}
270
274
}
271
275
272
276
fn lit ( & self , lit : & Binding < & Lit > ) {
273
- let kind = |kind| out ! ( "if let LitKind::{kind} = {lit}.node; ") ;
277
+ let kind = |kind| chain ! ( self , " let LitKind::{kind} = {lit}.node") ;
274
278
macro_rules! kind {
275
279
( $( $t: tt) * ) => ( kind( format_args!( $( $t) * ) ) ) ;
276
280
}
@@ -298,7 +302,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
298
302
LitKind :: ByteStr ( ref vec) => {
299
303
bind ! ( self , vec) ;
300
304
kind ! ( "ByteStr(ref {vec})" ) ;
301
- out ! ( "if let [{:?}] = **{vec}; ", vec. value) ;
305
+ chain ! ( self , " let [{:?}] = **{vec}", vec. value) ;
302
306
} ,
303
307
LitKind :: Str ( s, _) => {
304
308
bind ! ( self , s) ;
@@ -311,15 +315,15 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
311
315
fn arm ( & self , arm : & Binding < & hir:: Arm < ' _ > > ) {
312
316
self . pat ( field ! ( arm. pat) ) ;
313
317
match arm. value . guard {
314
- None => out ! ( "if {arm}.guard.is_none(); ") ,
318
+ None => chain ! ( self , " {arm}.guard.is_none()") ,
315
319
Some ( hir:: Guard :: If ( expr) ) => {
316
320
bind ! ( self , expr) ;
317
- out ! ( "if let Some(Guard::If({expr})) = {arm}.guard; ") ;
321
+ chain ! ( self , " let Some(Guard::If({expr})) = {arm}.guard") ;
318
322
self . expr ( expr) ;
319
323
} ,
320
324
Some ( hir:: Guard :: IfLet ( let_expr) ) => {
321
325
bind ! ( self , let_expr) ;
322
- out ! ( "if let Some(Guard::IfLet({let_expr}) = {arm}.guard; ") ;
326
+ chain ! ( self , " let Some(Guard::IfLet({let_expr}) = {arm}.guard") ;
323
327
self . pat ( field ! ( let_expr. pat) ) ;
324
328
self . expr ( field ! ( let_expr. init) ) ;
325
329
} ,
@@ -331,9 +335,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
331
335
fn expr ( & self , expr : & Binding < & hir:: Expr < ' _ > > ) {
332
336
if let Some ( higher:: While { condition, body } ) = higher:: While :: hir ( expr. value ) {
333
337
bind ! ( self , condition, body) ;
334
- out ! (
335
- "if let Some(higher::While {{ condition: {condition}, body: {body} }}) \
336
- = higher::While::hir({expr});"
338
+ chain ! (
339
+ self ,
340
+ "let Some(higher::While {{ condition: {condition}, body: {body} }}) \
341
+ = higher::While::hir({expr})"
337
342
) ;
338
343
self . expr ( condition) ;
339
344
self . expr ( body) ;
@@ -347,9 +352,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
347
352
} ) = higher:: WhileLet :: hir ( expr. value )
348
353
{
349
354
bind ! ( self , let_pat, let_expr, if_then) ;
350
- out ! (
351
- "if let Some(higher::WhileLet {{ let_pat: {let_pat}, let_expr: {let_expr}, if_then: {if_then} }}) \
352
- = higher::WhileLet::hir({expr});"
355
+ chain ! (
356
+ self ,
357
+ "let Some(higher::WhileLet {{ let_pat: {let_pat}, let_expr: {let_expr}, if_then: {if_then} }}) \
358
+ = higher::WhileLet::hir({expr})"
353
359
) ;
354
360
self . pat ( let_pat) ;
355
361
self . expr ( let_expr) ;
@@ -359,17 +365,18 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
359
365
360
366
if let Some ( higher:: ForLoop { pat, arg, body, .. } ) = higher:: ForLoop :: hir ( expr. value ) {
361
367
bind ! ( self , pat, arg, body) ;
362
- out ! (
363
- "if let Some(higher::ForLoop {{ pat: {pat}, arg: {arg}, body: {body}, .. }}) \
364
- = higher::ForLoop::hir({expr});"
368
+ chain ! (
369
+ self ,
370
+ "let Some(higher::ForLoop {{ pat: {pat}, arg: {arg}, body: {body}, .. }}) \
371
+ = higher::ForLoop::hir({expr})"
365
372
) ;
366
373
self . pat ( pat) ;
367
374
self . expr ( arg) ;
368
375
self . expr ( body) ;
369
376
return ;
370
377
}
371
378
372
- let kind = |kind| out ! ( "if let ExprKind::{kind} = {expr}.kind; ") ;
379
+ let kind = |kind| chain ! ( self , " let ExprKind::{kind} = {expr}.kind") ;
373
380
macro_rules! kind {
374
381
( $( $t: tt) * ) => ( kind( format_args!( $( $t) * ) ) ) ;
375
382
}
@@ -383,7 +390,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
383
390
// if it's a path
384
391
if let Some ( TyKind :: Path ( ref qpath) ) = let_expr. value . ty . as_ref ( ) . map ( |ty| & ty. kind ) {
385
392
bind ! ( self , qpath) ;
386
- out ! ( "if let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind; ") ;
393
+ chain ! ( self , " let TyKind::Path(ref {qpath}) = {let_expr}.ty.kind") ;
387
394
self . qpath ( qpath) ;
388
395
}
389
396
self . expr ( field ! ( let_expr. init) ) ;
@@ -419,7 +426,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
419
426
ExprKind :: Binary ( op, left, right) => {
420
427
bind ! ( self , op, left, right) ;
421
428
kind ! ( "Binary({op}, {left}, {right})" ) ;
422
- out ! ( "if BinOpKind::{:?} == {op}.node; ", op. value. node) ;
429
+ chain ! ( self , " BinOpKind::{:?} == {op}.node", op. value. node) ;
423
430
self . expr ( left) ;
424
431
self . expr ( right) ;
425
432
} ,
@@ -438,7 +445,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
438
445
kind ! ( "Cast({expr}, {cast_ty})" ) ;
439
446
if let TyKind :: Path ( ref qpath) = cast_ty. value . kind {
440
447
bind ! ( self , qpath) ;
441
- out ! ( "if let TyKind::Path(ref {qpath}) = {cast_ty}.kind; ") ;
448
+ chain ! ( self , " let TyKind::Path(ref {qpath}) = {cast_ty}.kind") ;
442
449
self . qpath ( qpath) ;
443
450
}
444
451
self . expr ( expr) ;
@@ -485,7 +492,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
485
492
486
493
bind ! ( self , fn_decl, body_id) ;
487
494
kind ! ( "Closure(CaptureBy::{capture_clause:?}, {fn_decl}, {body_id}, _, {movability})" ) ;
488
- out ! ( "if let {ret_ty} = {fn_decl}.output; ") ;
495
+ chain ! ( self , " let {ret_ty} = {fn_decl}.output") ;
489
496
self . body ( body_id) ;
490
497
} ,
491
498
ExprKind :: Yield ( sub, source) => {
@@ -509,7 +516,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
509
516
ExprKind :: AssignOp ( op, target, value) => {
510
517
bind ! ( self , op, target, value) ;
511
518
kind ! ( "AssignOp({op}, {target}, {value})" ) ;
512
- out ! ( "if BinOpKind::{:?} == {op}.node; ", op. value. node) ;
519
+ chain ! ( self , " BinOpKind::{:?} == {op}.node", op. value. node) ;
513
520
self . expr ( target) ;
514
521
self . expr ( value) ;
515
522
} ,
@@ -573,10 +580,10 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
573
580
kind ! ( "Repeat({value}, {length})" ) ;
574
581
self . expr ( value) ;
575
582
match length. value {
576
- ArrayLen :: Infer ( ..) => out ! ( "if let ArrayLen::Infer(..) = length; ") ,
583
+ ArrayLen :: Infer ( ..) => chain ! ( self , " let ArrayLen::Infer(..) = length") ,
577
584
ArrayLen :: Body ( anon_const) => {
578
585
bind ! ( self , anon_const) ;
579
- out ! ( "if let ArrayLen::Body({anon_const}) = {length}; ") ;
586
+ chain ! ( self , " let ArrayLen::Body({anon_const}) = {length}") ;
580
587
self . body ( field ! ( anon_const. body) ) ;
581
588
} ,
582
589
}
@@ -600,12 +607,12 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
600
607
fn body ( & self , body_id : & Binding < hir:: BodyId > ) {
601
608
let expr = self . cx . tcx . hir ( ) . body ( body_id. value ) . value ;
602
609
bind ! ( self , expr) ;
603
- out ! ( "let {expr} = &cx.tcx.hir().body({body_id}).value; ") ;
610
+ chain ! ( self , " {expr} = &cx.tcx.hir().body({body_id}).value") ;
604
611
self . expr ( expr) ;
605
612
}
606
613
607
614
fn pat ( & self , pat : & Binding < & hir:: Pat < ' _ > > ) {
608
- let kind = |kind| out ! ( "if let PatKind::{kind} = {pat}.kind; ") ;
615
+ let kind = |kind| chain ! ( self , " let PatKind::{kind} = {pat}.kind") ;
609
616
macro_rules! kind {
610
617
( $( $t: tt) * ) => ( kind( format_args!( $( $t) * ) ) ) ;
611
618
}
@@ -688,7 +695,7 @@ impl<'a, 'tcx> PrintVisitor<'a, 'tcx> {
688
695
}
689
696
690
697
fn stmt ( & self , stmt : & Binding < & hir:: Stmt < ' _ > > ) {
691
- let kind = |kind| out ! ( "if let StmtKind::{kind} = {stmt}.kind; ") ;
698
+ let kind = |kind| chain ! ( self , " let StmtKind::{kind} = {stmt}.kind") ;
692
699
macro_rules! kind {
693
700
( $( $t: tt) * ) => ( kind( format_args!( $( $t) * ) ) ) ;
694
701
}
0 commit comments