@@ -361,25 +361,22 @@ declare_lint! {
361
361
362
362
fn check_let_unit ( cx : & LateContext , decl : & Decl ) {
363
363
if let DeclLocal ( ref local) = decl. node {
364
- match cx. tables . pat_ty ( & local. pat ) . sty {
365
- ty:: TyTuple ( slice, _) if slice. is_empty ( ) => {
366
- if in_external_macro ( cx, decl. span ) || in_macro ( local. pat . span ) {
367
- return ;
368
- }
369
- if higher:: is_from_for_desugar ( decl) {
370
- return ;
371
- }
372
- span_lint (
373
- cx,
374
- LET_UNIT_VALUE ,
375
- decl. span ,
376
- & format ! (
377
- "this let-binding has unit value. Consider omitting `let {} =`" ,
378
- snippet( cx, local. pat. span, ".." )
379
- ) ,
380
- ) ;
381
- } ,
382
- _ => ( ) ,
364
+ if is_unit ( cx. tables . pat_ty ( & local. pat ) ) {
365
+ if in_external_macro ( cx, decl. span ) || in_macro ( local. pat . span ) {
366
+ return ;
367
+ }
368
+ if higher:: is_from_for_desugar ( decl) {
369
+ return ;
370
+ }
371
+ span_lint (
372
+ cx,
373
+ LET_UNIT_VALUE ,
374
+ decl. span ,
375
+ & format ! (
376
+ "this let-binding has unit value. Consider omitting `let {} =`" ,
377
+ snippet( cx, local. pat. span, ".." )
378
+ ) ,
379
+ ) ;
383
380
}
384
381
}
385
382
}
@@ -434,31 +431,118 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for UnitCmp {
434
431
}
435
432
if let ExprBinary ( ref cmp, ref left, _) = expr. node {
436
433
let op = cmp. node ;
437
- if op. is_comparison ( ) {
438
- match cx. tables . expr_ty ( left) . sty {
439
- ty:: TyTuple ( slice, _) if slice. is_empty ( ) => {
440
- let result = match op {
441
- BiEq | BiLe | BiGe => "true" ,
442
- _ => "false" ,
443
- } ;
444
- span_lint (
445
- cx,
446
- UNIT_CMP ,
447
- expr. span ,
448
- & format ! (
449
- "{}-comparison of unit values detected. This will always be {}" ,
450
- op. as_str( ) ,
451
- result
452
- ) ,
453
- ) ;
454
- } ,
455
- _ => ( ) ,
456
- }
434
+ if op. is_comparison ( ) && is_unit ( cx. tables . expr_ty ( left) ) {
435
+ let result = match op {
436
+ BiEq | BiLe | BiGe => "true" ,
437
+ _ => "false" ,
438
+ } ;
439
+ span_lint (
440
+ cx,
441
+ UNIT_CMP ,
442
+ expr. span ,
443
+ & format ! (
444
+ "{}-comparison of unit values detected. This will always be {}" ,
445
+ op. as_str( ) ,
446
+ result
447
+ ) ,
448
+ ) ;
457
449
}
458
450
}
459
451
}
460
452
}
461
453
454
+ /// **What it does:** Checks for passing a unit value as an argument to a function without using a unit literal (`()`).
455
+ ///
456
+ /// **Why is this bad?** This is likely the result of an accidental semicolon.
457
+ ///
458
+ /// **Known problems:** None.
459
+ ///
460
+ /// **Example:**
461
+ /// ```rust
462
+ /// foo({
463
+ /// let a = bar();
464
+ /// baz(a);
465
+ /// })
466
+ /// ```
467
+ declare_lint ! {
468
+ pub UNIT_ARG ,
469
+ Warn ,
470
+ "passing unit to a function"
471
+ }
472
+
473
+ pub struct UnitArg ;
474
+
475
+ impl LintPass for UnitArg {
476
+ fn get_lints ( & self ) -> LintArray {
477
+ lint_array ! ( UNIT_ARG )
478
+ }
479
+ }
480
+
481
+ impl < ' a , ' tcx > LateLintPass < ' a , ' tcx > for UnitArg {
482
+ fn check_expr ( & mut self , cx : & LateContext < ' a , ' tcx > , expr : & ' tcx Expr ) {
483
+ if in_macro ( expr. span ) {
484
+ return ;
485
+ }
486
+ match expr. node {
487
+ ExprCall ( _, ref args) | ExprMethodCall ( _, _, ref args) => {
488
+ for arg in args {
489
+ if is_unit ( cx. tables . expr_ty ( arg) ) && !is_unit_literal ( arg) {
490
+ let map = & cx. tcx . hir ;
491
+ // apparently stuff in the desugaring of `?` can trigger this
492
+ // so check for that here
493
+ // only the calls to `Try::from_error` is marked as desugared,
494
+ // so we need to check both the current Expr and its parent.
495
+ if !is_questionmark_desugar_marked_call ( expr) {
496
+ if_chain ! {
497
+ let opt_parent_node = map. find( map. get_parent_node( expr. id) ) ;
498
+ if let Some ( hir:: map:: NodeExpr ( parent_expr) ) = opt_parent_node;
499
+ if is_questionmark_desugar_marked_call( parent_expr) ;
500
+ then { }
501
+ else {
502
+ // `expr` and `parent_expr` where _both_ not from
503
+ // desugaring `?`, so lint
504
+ span_lint_and_sugg(
505
+ cx,
506
+ UNIT_ARG ,
507
+ arg. span,
508
+ "passing a unit value to a function" ,
509
+ "if you intended to pass a unit value, use a unit literal instead" ,
510
+ "()" . to_string( ) ,
511
+ ) ;
512
+ }
513
+ }
514
+ }
515
+ }
516
+ }
517
+ } ,
518
+ _ => ( ) ,
519
+ }
520
+ }
521
+ }
522
+
523
+ fn is_questionmark_desugar_marked_call ( expr : & Expr ) -> bool {
524
+ use syntax_pos:: hygiene:: CompilerDesugaringKind ;
525
+ if let ExprCall ( ref callee, _) = expr. node {
526
+ callee. span . is_compiler_desugaring ( CompilerDesugaringKind :: QuestionMark )
527
+ } else {
528
+ false
529
+ }
530
+ }
531
+
532
+ fn is_unit ( ty : Ty ) -> bool {
533
+ match ty. sty {
534
+ ty:: TyTuple ( slice, _) if slice. is_empty ( ) => true ,
535
+ _ => false ,
536
+ }
537
+ }
538
+
539
+ fn is_unit_literal ( expr : & Expr ) -> bool {
540
+ match expr. node {
541
+ ExprTup ( ref slice) if slice. is_empty ( ) => true ,
542
+ _ => false ,
543
+ }
544
+ }
545
+
462
546
pub struct CastPass ;
463
547
464
548
/// **What it does:** Checks for casts from any numerical to a float type where
0 commit comments