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, cond_inner , Some ( els) ) = e. kind
5862 && let ExprKind :: DropTemps ( cond) = cond. kind
5963 && let ExprKind :: Block ( ..) = els. kind
6064 {
@@ -79,8 +83,52 @@ 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. kind , cond_inner. span , els. span , ".." , 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_kind : & ' a ExprKind < ' a > ,
106+ cond_inner : Span ,
107+ els_span : Span ,
108+ default : & ' a str ,
109+ indent_relative_to : Option < Span > ,
110+ ) -> Cow < ' a , str > {
111+ let cond_inner_snip = snippet ( sess, cond_inner, default) ;
112+ let els_snip = snippet ( sess, els_span, default) ;
113+ let indent = indent_relative_to. and_then ( |s| indent_of ( sess, s) ) ;
114+
115+ let suggestion = match cond_kind {
116+ ExprKind :: Unary ( UnOp :: Not , cond_rest) => {
117+ format ! (
118+ "if {} {} else {}" ,
119+ snippet( sess, cond_rest. span, default ) ,
120+ els_snip,
121+ cond_inner_snip
122+ )
123+ } ,
124+ ExprKind :: Binary ( _, lhs, rhs) => {
125+ let lhs_snip = snippet ( sess, lhs. span , default) ;
126+ let rhs_snip = snippet ( sess, rhs. span , default) ;
127+
128+ format ! ( "if {lhs_snip} == {rhs_snip} {els_snip} else {cond_inner_snip}" )
129+ } ,
130+ _ => String :: new ( ) ,
131+ } ;
132+
133+ reindent_multiline ( suggestion. into ( ) , true , indent)
134+ }
0 commit comments