1+ use  clippy_config:: Conf ; 
2+ use  clippy_config:: msrvs:: { self ,  Msrv } ; 
13use  clippy_utils:: diagnostics:: { span_lint_and_sugg,  span_lint_hir_and_then} ; 
24use  clippy_utils:: eq_expr_value; 
35use  clippy_utils:: source:: SpanRangeExt ; 
@@ -7,7 +9,7 @@ use rustc_errors::Applicability;
79use  rustc_hir:: intravisit:: { FnKind ,  Visitor ,  walk_expr} ; 
810use  rustc_hir:: { BinOpKind ,  Body ,  Expr ,  ExprKind ,  FnDecl ,  UnOp } ; 
911use  rustc_lint:: { LateContext ,  LateLintPass ,  Level } ; 
10- use  rustc_session:: declare_lint_pass ; 
12+ use  rustc_session:: { RustcVersion ,  impl_lint_pass } ; 
1113use  rustc_span:: def_id:: LocalDefId ; 
1214use  rustc_span:: { Span ,  sym} ; 
1315
@@ -69,9 +71,25 @@ declare_clippy_lint! {
6971} 
7072
7173// For each pairs, both orders are considered. 
72- const  METHODS_WITH_NEGATION :  [ ( & str ,  & str ) ;  2 ]  = [ ( "is_some" ,  "is_none" ) ,  ( "is_err" ,  "is_ok" ) ] ; 
74+ const  METHODS_WITH_NEGATION :  [ ( Option < RustcVersion > ,  & str ,  & str ) ;  3 ]  = [ 
75+     ( None ,  "is_some" ,  "is_none" ) , 
76+     ( None ,  "is_err" ,  "is_ok" ) , 
77+     ( Some ( msrvs:: IS_NONE_OR ) ,  "is_some_and" ,  "is_none_or" ) , 
78+ ] ; 
79+ 
80+ pub  struct  NonminimalBool  { 
81+     msrv :  Msrv , 
82+ } 
83+ 
84+ impl  NonminimalBool  { 
85+     pub  fn  new ( conf :  & ' static  Conf )  -> Self  { 
86+         Self  { 
87+             msrv :  conf. msrv . clone ( ) , 
88+         } 
89+     } 
90+ } 
7391
74- declare_lint_pass ! ( NonminimalBool  => [ NONMINIMAL_BOOL ,  OVERLY_COMPLEX_BOOL_EXPR ] ) ; 
92+ impl_lint_pass ! ( NonminimalBool  => [ NONMINIMAL_BOOL ,  OVERLY_COMPLEX_BOOL_EXPR ] ) ; 
7593
7694impl < ' tcx >  LateLintPass < ' tcx >  for  NonminimalBool  { 
7795    fn  check_fn ( 
@@ -83,7 +101,7 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
83101        _:  Span , 
84102        _:  LocalDefId , 
85103    )  { 
86-         NonminimalBoolVisitor  {  cx } . visit_body ( body) ; 
104+         NonminimalBoolVisitor  {  cx,   msrv :   & self . msrv  } . visit_body ( body) ; 
87105    } 
88106
89107    fn  check_expr ( & mut  self ,  cx :  & LateContext < ' tcx > ,  expr :  & ' tcx  Expr < ' tcx > )  { 
@@ -100,6 +118,8 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
100118            _ => { } , 
101119        } 
102120    } 
121+ 
122+     extract_msrv_attr ! ( LateContext ) ; 
103123} 
104124
105125fn  inverted_bin_op_eq_str ( op :  BinOpKind )  -> Option < & ' static  str >  { 
@@ -176,11 +196,11 @@ fn check_inverted_bool_in_condition(
176196    ) ; 
177197} 
178198
179- fn  check_simplify_not ( cx :  & LateContext < ' _ > ,  expr :  & Expr < ' _ > )  { 
199+ fn  check_simplify_not ( cx :  & LateContext < ' _ > ,  msrv :   & Msrv ,   expr :  & Expr < ' _ > )  { 
180200    if  let  ExprKind :: Unary ( UnOp :: Not ,  inner)  = & expr. kind 
181201        && !expr. span . from_expansion ( ) 
182202        && !inner. span . from_expansion ( ) 
183-         && let  Some ( suggestion)  = simplify_not ( cx,  inner) 
203+         && let  Some ( suggestion)  = simplify_not ( cx,  msrv ,   inner) 
184204        && cx. tcx . lint_level_at_node ( NONMINIMAL_BOOL ,  expr. hir_id ) . 0  != Level :: Allow 
185205    { 
186206        span_lint_and_sugg ( 
@@ -197,6 +217,7 @@ fn check_simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) {
197217
198218struct  NonminimalBoolVisitor < ' a ,  ' tcx >  { 
199219    cx :  & ' a  LateContext < ' tcx > , 
220+     msrv :  & ' a  Msrv , 
200221} 
201222
202223use  quine_mc_cluskey:: Bool ; 
@@ -289,6 +310,7 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
289310struct  SuggestContext < ' a ,  ' tcx ,  ' v >  { 
290311    terminals :  & ' v  [ & ' v  Expr < ' v > ] , 
291312    cx :  & ' a  LateContext < ' tcx > , 
313+     msrv :  & ' a  Msrv , 
292314    output :  String , 
293315} 
294316
@@ -311,7 +333,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
311333                } , 
312334                Term ( n)  => { 
313335                    let  terminal = self . terminals [ n as  usize ] ; 
314-                     if  let  Some ( str)  = simplify_not ( self . cx ,  terminal)  { 
336+                     if  let  Some ( str)  = simplify_not ( self . cx ,  self . msrv ,   terminal)  { 
315337                        self . output . push_str ( & str) ; 
316338                    }  else  { 
317339                        self . output . push ( '!' ) ; 
@@ -358,7 +380,7 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
358380    } 
359381} 
360382
361- fn  simplify_not ( cx :  & LateContext < ' _ > ,  expr :  & Expr < ' _ > )  -> Option < String >  { 
383+ fn  simplify_not ( cx :  & LateContext < ' _ > ,  curr_msrv :   & Msrv ,   expr :  & Expr < ' _ > )  -> Option < String >  { 
362384    match  & expr. kind  { 
363385        ExprKind :: Binary ( binop,  lhs,  rhs)  => { 
364386            if  !implements_ord ( cx,  lhs)  { 
@@ -389,7 +411,7 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
389411                Some ( format ! ( "{lhs_snippet}{op}{rhs_snippet}" ) ) 
390412            } ) 
391413        } , 
392-         ExprKind :: MethodCall ( path,  receiver,  [ ] ,  _)  => { 
414+         ExprKind :: MethodCall ( path,  receiver,  args ,  _)  => { 
393415            let  type_of_receiver = cx. typeck_results ( ) . expr_ty ( receiver) ; 
394416            if  !is_type_diagnostic_item ( cx,  type_of_receiver,  sym:: Option ) 
395417                && !is_type_diagnostic_item ( cx,  type_of_receiver,  sym:: Result ) 
@@ -399,21 +421,42 @@ fn simplify_not(cx: &LateContext<'_>, expr: &Expr<'_>) -> Option<String> {
399421            METHODS_WITH_NEGATION 
400422                . iter ( ) 
401423                . copied ( ) 
402-                 . flat_map ( |( a,  b) | vec ! [ ( a,  b) ,  ( b,  a) ] ) 
403-                 . find ( |& ( a,  _) | { 
404-                     let  path:  & str  = path. ident . name . as_str ( ) ; 
405-                     a == path
424+                 . flat_map ( |( msrv,  a,  b) | vec ! [ ( msrv,  a,  b) ,  ( msrv,  b,  a) ] ) 
425+                 . find ( |& ( msrv,  a,  _) | msrv. is_none_or ( |msrv| curr_msrv. meets ( msrv) )  && a == path. ident . name . as_str ( ) ) 
426+                 . and_then ( |( _,  _,  neg_method) | { 
427+                     let  negated_args = args
428+                         . iter ( ) 
429+                         . map ( |arg| simplify_not ( cx,  curr_msrv,  arg) ) 
430+                         . collect :: < Option < Vec < _ > > > ( ) ?
431+                         . join ( ", " ) ; 
432+                     Some ( format ! ( 
433+                         "{}.{neg_method}({negated_args})" , 
434+                         receiver. span. get_source_text( cx) ?
435+                     ) ) 
406436                } ) 
407-                 . and_then ( |( _,  neg_method) | Some ( format ! ( "{}.{neg_method}()" ,  receiver. span. get_source_text( cx) ?) ) ) 
408437        } , 
438+ 
439+         ExprKind :: Closure ( closure)  => { 
440+             let  body = cx. tcx . hir ( ) . body ( closure. body ) ; 
441+             let  params = body
442+                 . params 
443+                 . iter ( ) 
444+                 . map ( |param| param. span . get_source_text ( cx) . map ( |t| t. to_string ( ) ) ) 
445+                 . collect :: < Option < Vec < _ > > > ( ) ?
446+                 . join ( ", " ) ; 
447+             let  negated = simplify_not ( cx,  curr_msrv,  body. value ) ?; 
448+             Some ( format ! ( "|{params}| {negated}" ) ) 
449+         } , 
450+         ExprKind :: Unary ( UnOp :: Not ,  expr)  => expr. span . get_source_text ( cx) . map ( |t| t. to_string ( ) ) , 
409451        _ => None , 
410452    } 
411453} 
412454
413- fn  suggest ( cx :  & LateContext < ' _ > ,  suggestion :  & Bool ,  terminals :  & [ & Expr < ' _ > ] )  -> String  { 
455+ fn  suggest ( cx :  & LateContext < ' _ > ,  msrv :   & Msrv ,   suggestion :  & Bool ,  terminals :  & [ & Expr < ' _ > ] )  -> String  { 
414456    let  mut  suggest_context = SuggestContext  { 
415457        terminals, 
416458        cx, 
459+         msrv, 
417460        output :  String :: new ( ) , 
418461    } ; 
419462    suggest_context. recurse ( suggestion) ; 
@@ -526,7 +569,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
526569                                diag. span_suggestion ( 
527570                                    e. span , 
528571                                    "it would look like the following" , 
529-                                     suggest ( self . cx ,  suggestion,  & h2q. terminals ) , 
572+                                     suggest ( self . cx ,  self . msrv ,   suggestion,  & h2q. terminals ) , 
530573                                    // nonminimal_bool can produce minimal but 
531574                                    // not human readable expressions (#3141) 
532575                                    Applicability :: Unspecified , 
@@ -569,12 +612,12 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
569612                } 
570613            } ; 
571614            if  improvements. is_empty ( )  { 
572-                 check_simplify_not ( self . cx ,  e) ; 
615+                 check_simplify_not ( self . cx ,  self . msrv ,   e) ; 
573616            }  else  { 
574617                nonminimal_bool_lint ( 
575618                    improvements
576619                        . into_iter ( ) 
577-                         . map ( |suggestion| suggest ( self . cx ,  suggestion,  & h2q. terminals ) ) 
620+                         . map ( |suggestion| suggest ( self . cx ,  self . msrv ,   suggestion,  & h2q. terminals ) ) 
578621                        . collect ( ) , 
579622                ) ; 
580623            } 
0 commit comments