@@ -87,31 +87,115 @@ impl<'tcx> LateLintPass<'tcx> for NonminimalBool {
87
87
}
88
88
89
89
fn check_expr ( & mut self , cx : & LateContext < ' tcx > , expr : & ' tcx Expr < ' tcx > ) {
90
- if let ExprKind :: Unary ( UnOp :: Not , sub) = expr. kind
91
- && !expr. span . from_expansion ( )
92
- && let ExprKind :: Binary ( op, left, right) = sub. kind
93
- {
94
- let new_op = match op. node {
95
- BinOpKind :: Eq => "!=" ,
96
- BinOpKind :: Ne => "==" ,
97
- _ => return ,
90
+ match expr. kind {
91
+ ExprKind :: Unary ( UnOp :: Not , sub) => check_inverted_condition ( cx, expr. span , sub) ,
92
+ // This check the case where an element in a boolean comparison is inverted, like:
93
+ //
94
+ // ```
95
+ // let a = true;
96
+ // !a == false;
97
+ // ```
98
+ ExprKind :: Binary ( op, left, right) if matches ! ( op. node, BinOpKind :: Eq | BinOpKind :: Ne ) => {
99
+ check_inverted_bool_in_condition ( cx, expr. span , op. node , left, right) ;
100
+ } ,
101
+ _ => { } ,
102
+ }
103
+ }
104
+ }
105
+
106
+ fn inverted_bin_op_eq_str ( op : BinOpKind ) -> Option < & ' static str > {
107
+ match op {
108
+ BinOpKind :: Eq => Some ( "!=" ) ,
109
+ BinOpKind :: Ne => Some ( "==" ) ,
110
+ _ => None ,
111
+ }
112
+ }
113
+
114
+ fn bin_op_eq_str ( op : BinOpKind ) -> Option < & ' static str > {
115
+ match op {
116
+ BinOpKind :: Eq => Some ( "==" ) ,
117
+ BinOpKind :: Ne => Some ( "!=" ) ,
118
+ _ => None ,
119
+ }
120
+ }
121
+
122
+ fn check_inverted_condition ( cx : & LateContext < ' _ > , expr_span : Span , sub_expr : & Expr < ' _ > ) {
123
+ if !expr_span. from_expansion ( )
124
+ && let ExprKind :: Binary ( op, left, right) = sub_expr. kind
125
+ && let Some ( left) = snippet_opt ( cx, left. span )
126
+ && let Some ( right) = snippet_opt ( cx, right. span )
127
+ {
128
+ let Some ( op) = inverted_bin_op_eq_str ( op. node ) else {
129
+ return ;
130
+ } ;
131
+ span_lint_and_sugg (
132
+ cx,
133
+ NONMINIMAL_BOOL ,
134
+ expr_span,
135
+ "this boolean expression can be simplified" ,
136
+ "try" ,
137
+ format ! ( "{left} {op} {right}" , ) ,
138
+ Applicability :: MachineApplicable ,
139
+ ) ;
140
+ }
141
+ }
142
+
143
+ fn check_inverted_bool_in_condition (
144
+ cx : & LateContext < ' _ > ,
145
+ expr_span : Span ,
146
+ op : BinOpKind ,
147
+ left : & Expr < ' _ > ,
148
+ right : & Expr < ' _ > ,
149
+ ) {
150
+ if expr_span. from_expansion ( )
151
+ && ( !cx. typeck_results ( ) . node_types ( ) [ left. hir_id ] . is_bool ( )
152
+ || !cx. typeck_results ( ) . node_types ( ) [ right. hir_id ] . is_bool ( ) )
153
+ {
154
+ return ;
155
+ }
156
+
157
+ let suggestion = match ( left. kind , right. kind ) {
158
+ ( ExprKind :: Unary ( UnOp :: Not , left_sub) , ExprKind :: Unary ( UnOp :: Not , right_sub) ) => {
159
+ let Some ( left) = snippet_opt ( cx, left_sub. span ) else {
160
+ return ;
161
+ } ;
162
+ let Some ( right) = snippet_opt ( cx, right_sub. span ) else {
163
+ return ;
164
+ } ;
165
+ let Some ( op) = bin_op_eq_str ( op) else { return } ;
166
+ format ! ( "{left} {op} {right}" )
167
+ } ,
168
+ ( ExprKind :: Unary ( UnOp :: Not , left_sub) , _) => {
169
+ let Some ( left) = snippet_opt ( cx, left_sub. span ) else {
170
+ return ;
98
171
} ;
99
- let Some ( left) = snippet_opt ( cx, left. span ) else { return } ;
100
172
let Some ( right) = snippet_opt ( cx, right. span ) else {
101
173
return ;
102
174
} ;
103
- span_lint_and_sugg (
104
- cx,
105
- NONMINIMAL_BOOL ,
106
- expr. span ,
107
- "this boolean expression can be simplified" ,
108
- "try" ,
109
- format ! ( "{left} {new_op} {right}" ) ,
110
- Applicability :: MachineApplicable ,
111
- ) ;
112
- }
113
- }
175
+ let Some ( op) = inverted_bin_op_eq_str ( op) else { return } ;
176
+ format ! ( "{left} {op} {right}" )
177
+ } ,
178
+ ( _, ExprKind :: Unary ( UnOp :: Not , right_sub) ) => {
179
+ let Some ( left) = snippet_opt ( cx, left. span ) else { return } ;
180
+ let Some ( right) = snippet_opt ( cx, right_sub. span ) else {
181
+ return ;
182
+ } ;
183
+ let Some ( op) = inverted_bin_op_eq_str ( op) else { return } ;
184
+ format ! ( "{left} {op} {right}" )
185
+ } ,
186
+ _ => return ,
187
+ } ;
188
+ span_lint_and_sugg (
189
+ cx,
190
+ NONMINIMAL_BOOL ,
191
+ expr_span,
192
+ "this boolean expression can be simplified" ,
193
+ "try" ,
194
+ suggestion,
195
+ Applicability :: MachineApplicable ,
196
+ ) ;
114
197
}
198
+
115
199
struct NonminimalBoolVisitor < ' a , ' tcx > {
116
200
cx : & ' a LateContext < ' tcx > ,
117
201
}
0 commit comments