11use clippy_utils:: consts:: { ConstEvalCtxt , Constant } ;
2- use clippy_utils:: diagnostics:: span_lint_and_help;
2+ use clippy_utils:: diagnostics:: { span_lint_and_help, span_lint_and_sugg } ;
33use clippy_utils:: is_else_clause;
4+ use clippy_utils:: source:: { HasSession , indent_of, reindent_multiline, snippet} ;
5+ use rustc_errors:: Applicability ;
46use rustc_hir:: { BinOpKind , Expr , ExprKind , UnOp } ;
57use rustc_lint:: { LateContext , LateLintPass } ;
68use rustc_session:: declare_lint_pass;
9+ use rustc_span:: Span ;
10+ use std:: borrow:: Cow ;
711
812declare_clippy_lint ! {
913 /// ### What it does
@@ -54,7 +58,7 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
5458
5559impl LateLintPass < ' _ > for IfNotElse {
5660 fn check_expr ( & mut self , cx : & LateContext < ' _ > , e : & Expr < ' _ > ) {
57- if let ExprKind :: If ( cond, _ , Some ( els) ) = e. kind
61+ if let ExprKind :: If ( cond, inter , Some ( els) ) = e. kind
5862 && let ExprKind :: DropTemps ( cond) = cond. kind
5963 && let ExprKind :: Block ( ..) = els. kind
6064 {
@@ -79,8 +83,60 @@ impl LateLintPass<'_> for IfNotElse {
7983 // }
8084 // ```
8185 if !e. span . from_expansion ( ) && !is_else_clause ( cx. tcx , e) {
82- span_lint_and_help ( cx, IF_NOT_ELSE , e. span , msg, None , help) ;
86+ match cond. kind {
87+ ExprKind :: Unary ( UnOp :: Not , _) | ExprKind :: Binary ( _, _, _) => span_lint_and_sugg (
88+ cx,
89+ IF_NOT_ELSE ,
90+ e. span ,
91+ msg,
92+ "try" ,
93+ make_sugg ( cx, cond. span , inter. span , els. span , & cond. kind , ".." , Some ( e. span ) ) . to_string ( ) ,
94+ Applicability :: MachineApplicable ,
95+ ) ,
96+ _ => span_lint_and_help ( cx, IF_NOT_ELSE , e. span , msg, None , help) ,
97+ }
8398 }
8499 }
85100 }
86101}
102+
103+ fn make_sugg < ' a > (
104+ sess : & impl HasSession ,
105+ cond : Span ,
106+ cond_rest : Span ,
107+ els_span : Span ,
108+ cond_kind : & ' a ExprKind < ' a > ,
109+ default : & ' a str ,
110+ indent_relative_to : Option < Span > ,
111+ ) -> Cow < ' a , str > {
112+ let cond_snip = snippet ( sess, cond, default) ;
113+ let cond_rest_snip = snippet ( sess, cond_rest, default) ;
114+ let els_snip = snippet ( sess, els_span, default) ;
115+ let indent = indent_relative_to. and_then ( |s| indent_of ( sess, s) ) ;
116+
117+ let suggestion = match cond_kind {
118+ ExprKind :: Unary ( UnOp :: Not , _) => format ! (
119+ "if {} {} else {}" ,
120+ Cow :: Borrowed ( & cond_snip[ 1 ..] ) ,
121+ els_snip,
122+ cond_rest_snip
123+ ) ,
124+ ExprKind :: Binary ( op, lhs, rhs) => {
125+ let lhs_snip = snippet ( sess, lhs. span , default) ;
126+ let rhs_snip = snippet ( sess, rhs. span , default) ;
127+
128+ format ! (
129+ "if {} {} else {}" ,
130+ match op. node {
131+ BinOpKind :: Ne => format!( "{lhs_snip} == {rhs_snip}" ) ,
132+ _ => unreachable!( ) ,
133+ } ,
134+ els_snip,
135+ cond_rest_snip
136+ )
137+ } ,
138+ _ => unreachable ! ( ) ,
139+ } ;
140+
141+ reindent_multiline ( suggestion. into ( ) , true , indent)
142+ }
0 commit comments