3
3
//! This lint is **warn** by default
4
4
5
5
use crate :: utils:: sugg:: Sugg ;
6
- use crate :: utils:: { higher, parent_node_is_if_expr, span_lint, span_lint_and_sugg} ;
6
+ use crate :: utils:: { higher, parent_node_is_if_expr, snippet_with_applicability, span_lint, span_lint_and_sugg} ;
7
+ use if_chain:: if_chain;
7
8
use rustc_ast:: ast:: LitKind ;
8
9
use rustc_errors:: Applicability ;
9
- use rustc_hir:: { BinOpKind , Block , Expr , ExprKind , StmtKind } ;
10
+ use rustc_hir:: { BinOpKind , Block , Expr , ExprKind , StmtKind , UnOp } ;
10
11
use rustc_lint:: { LateContext , LateLintPass } ;
11
12
use rustc_session:: { declare_lint_pass, declare_tool_lint} ;
12
13
use rustc_span:: source_map:: Spanned ;
14
+ use rustc_span:: Span ;
13
15
14
16
declare_clippy_lint ! {
15
17
/// **What it does:** Checks for expressions of the form `if c { true } else {
@@ -188,6 +190,34 @@ impl<'a, 'tcx> LateLintPass<'a, 'tcx> for BoolComparison {
188
190
}
189
191
}
190
192
193
+ struct ExpressionInfoWithSpan {
194
+ one_side_is_unary_not : bool ,
195
+ left_span : Span ,
196
+ right_span : Span ,
197
+ }
198
+
199
+ fn is_unary_not ( e : & Expr < ' _ > ) -> ( bool , Span ) {
200
+ if_chain ! {
201
+ if let ExprKind :: Unary ( unop, operand) = e. kind;
202
+ if let UnOp :: UnNot = unop;
203
+ then {
204
+ return ( true , operand. span) ;
205
+ }
206
+ } ;
207
+ ( false , e. span )
208
+ }
209
+
210
+ fn one_side_is_unary_not < ' tcx > ( left_side : & ' tcx Expr < ' _ > , right_side : & ' tcx Expr < ' _ > ) -> ExpressionInfoWithSpan {
211
+ let left = is_unary_not ( left_side) ;
212
+ let right = is_unary_not ( right_side) ;
213
+
214
+ ExpressionInfoWithSpan {
215
+ one_side_is_unary_not : left. 0 != right. 0 ,
216
+ left_span : left. 1 ,
217
+ right_span : right. 1 ,
218
+ }
219
+ }
220
+
191
221
fn check_comparison < ' a , ' tcx > (
192
222
cx : & LateContext < ' a , ' tcx > ,
193
223
e : & ' tcx Expr < ' _ > ,
@@ -199,10 +229,30 @@ fn check_comparison<'a, 'tcx>(
199
229
) {
200
230
use self :: Expression :: { Bool , Other } ;
201
231
202
- if let ExprKind :: Binary ( _ , ref left_side, ref right_side) = e. kind {
232
+ if let ExprKind :: Binary ( op , ref left_side, ref right_side) = e. kind {
203
233
let ( l_ty, r_ty) = ( cx. tables . expr_ty ( left_side) , cx. tables . expr_ty ( right_side) ) ;
204
234
if l_ty. is_bool ( ) && r_ty. is_bool ( ) {
205
235
let mut applicability = Applicability :: MachineApplicable ;
236
+
237
+ if let BinOpKind :: Eq = op. node {
238
+ let expression_info = one_side_is_unary_not ( & left_side, & right_side) ;
239
+ if expression_info. one_side_is_unary_not {
240
+ span_lint_and_sugg (
241
+ cx,
242
+ BOOL_COMPARISON ,
243
+ e. span ,
244
+ "This comparison might be written more concisely" ,
245
+ "try simplifying it as shown" ,
246
+ format ! (
247
+ "{} != {}" ,
248
+ snippet_with_applicability( cx, expression_info. left_span, ".." , & mut applicability) ,
249
+ snippet_with_applicability( cx, expression_info. right_span, ".." , & mut applicability)
250
+ ) ,
251
+ applicability,
252
+ )
253
+ }
254
+ }
255
+
206
256
match ( fetch_bool_expr ( left_side) , fetch_bool_expr ( right_side) ) {
207
257
( Bool ( true ) , Other ) => left_true. map_or ( ( ) , |( h, m) | {
208
258
suggest_bool_comparison ( cx, e, right_side, applicability, m, h)
0 commit comments