1
1
use 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 } ;
3
3
use clippy_utils:: is_else_clause;
4
+ use clippy_utils:: source:: { HasSession , indent_of, reindent_multiline, snippet} ;
5
+ use rustc_errors:: Applicability ;
4
6
use rustc_hir:: { BinOpKind , Expr , ExprKind , UnOp } ;
5
7
use rustc_lint:: { LateContext , LateLintPass } ;
6
8
use rustc_session:: declare_lint_pass;
9
+ use rustc_span:: Span ;
10
+ use std:: borrow:: Cow ;
7
11
8
12
declare_clippy_lint ! {
9
13
/// ### What it does
@@ -54,7 +58,7 @@ fn is_zero_const(expr: &Expr<'_>, cx: &LateContext<'_>) -> bool {
54
58
55
59
impl LateLintPass < ' _ > for IfNotElse {
56
60
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
58
62
&& let ExprKind :: DropTemps ( cond) = cond. kind
59
63
&& let ExprKind :: Block ( ..) = els. kind
60
64
{
@@ -79,8 +83,52 @@ impl LateLintPass<'_> for IfNotElse {
79
83
// }
80
84
// ```
81
85
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
+ }
83
98
}
84
99
}
85
100
}
86
101
}
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