@@ -44,6 +44,12 @@ declare_lint! {
44
44
"boolean expressions that contain terminals which can be eliminated"
45
45
}
46
46
47
+ // For each pairs, both orders are considered.
48
+ const METHODS_WITH_NEGATION : [ ( & str , & str ) ; 2 ] = [
49
+ ( "is_some" , "is_none" ) ,
50
+ ( "is_err" , "is_ok" ) ,
51
+ ] ;
52
+
47
53
#[ derive( Copy , Clone ) ]
48
54
pub struct NonminimalBool ;
49
55
@@ -153,8 +159,16 @@ impl<'a, 'tcx, 'v> Hir2Qmm<'a, 'tcx, 'v> {
153
159
}
154
160
}
155
161
156
- fn suggest ( cx : & LateContext , suggestion : & Bool , terminals : & [ & Expr ] ) -> String {
157
- fn recurse ( brackets : bool , cx : & LateContext , suggestion : & Bool , terminals : & [ & Expr ] , mut s : String ) -> String {
162
+ // The boolean part of the return indicates whether some simplifications have been applied.
163
+ fn suggest ( cx : & LateContext , suggestion : & Bool , terminals : & [ & Expr ] ) -> ( String , bool ) {
164
+ fn recurse (
165
+ brackets : bool ,
166
+ cx : & LateContext ,
167
+ suggestion : & Bool ,
168
+ terminals : & [ & Expr ] ,
169
+ mut s : String ,
170
+ simplified : & mut bool ,
171
+ ) -> String {
158
172
use quine_mc_cluskey:: Bool :: * ;
159
173
let snip = |e : & Expr | snippet_opt ( cx, e. span ) . expect ( "don't try to improve booleans created by macros" ) ;
160
174
match * suggestion {
@@ -169,49 +183,70 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
169
183
Not ( ref inner) => match * * inner {
170
184
And ( _) | Or ( _) => {
171
185
s. push ( '!' ) ;
172
- recurse ( true , cx, inner, terminals, s)
186
+ recurse ( true , cx, inner, terminals, s, simplified )
173
187
} ,
174
- Term ( n) => if let ExprBinary ( binop, ref lhs, ref rhs) = terminals[ n as usize ] . node {
175
- let op = match binop. node {
176
- BiEq => " != " ,
177
- BiNe => " == " ,
178
- BiLt => " >= " ,
179
- BiGt => " <= " ,
180
- BiLe => " > " ,
181
- BiGe => " < " ,
182
- _ => {
188
+ Term ( n) => match terminals[ n as usize ] . node {
189
+ ExprBinary ( binop, ref lhs, ref rhs) => {
190
+ let op = match binop. node {
191
+ BiEq => " != " ,
192
+ BiNe => " == " ,
193
+ BiLt => " >= " ,
194
+ BiGt => " <= " ,
195
+ BiLe => " > " ,
196
+ BiGe => " < " ,
197
+ _ => {
198
+ s. push ( '!' ) ;
199
+ return recurse ( true , cx, inner, terminals, s, simplified) ;
200
+ } ,
201
+ } ;
202
+ * simplified = true ;
203
+ s. push_str ( & snip ( lhs) ) ;
204
+ s. push_str ( op) ;
205
+ s. push_str ( & snip ( rhs) ) ;
206
+ s
207
+ } ,
208
+ ExprMethodCall ( ref path, _, ref args) if args. len ( ) == 1 => {
209
+ let negation = METHODS_WITH_NEGATION
210
+ . iter ( ) . cloned ( )
211
+ . flat_map ( |( a, b) | vec ! [ ( a, b) , ( b, a) ] )
212
+ . find ( |& ( a, _) | a == path. name . as_str ( ) ) ;
213
+ if let Some ( ( _, negation_method) ) = negation {
214
+ * simplified = true ;
215
+ s. push_str ( & snip ( & args[ 0 ] ) ) ;
216
+ s. push ( '.' ) ;
217
+ s. push_str ( negation_method) ;
218
+ s. push_str ( "()" ) ;
219
+ s
220
+ } else {
183
221
s. push ( '!' ) ;
184
- return recurse ( true , cx, inner, terminals, s) ;
185
- } ,
186
- } ;
187
- s. push_str ( & snip ( lhs) ) ;
188
- s. push_str ( op) ;
189
- s. push_str ( & snip ( rhs) ) ;
190
- s
191
- } else {
192
- s. push ( '!' ) ;
193
- recurse ( false , cx, inner, terminals, s)
222
+ recurse ( false , cx, inner, terminals, s, simplified)
223
+ }
224
+ } ,
225
+ _ => {
226
+ s. push ( '!' ) ;
227
+ recurse ( false , cx, inner, terminals, s, simplified)
228
+ } ,
194
229
} ,
195
230
_ => {
196
231
s. push ( '!' ) ;
197
- recurse ( false , cx, inner, terminals, s)
232
+ recurse ( false , cx, inner, terminals, s, simplified )
198
233
} ,
199
234
} ,
200
235
And ( ref v) => {
201
236
if brackets {
202
237
s. push ( '(' ) ;
203
238
}
204
239
if let Or ( _) = v[ 0 ] {
205
- s = recurse ( true , cx, & v[ 0 ] , terminals, s) ;
240
+ s = recurse ( true , cx, & v[ 0 ] , terminals, s, simplified ) ;
206
241
} else {
207
- s = recurse ( false , cx, & v[ 0 ] , terminals, s) ;
242
+ s = recurse ( false , cx, & v[ 0 ] , terminals, s, simplified ) ;
208
243
}
209
244
for inner in & v[ 1 ..] {
210
245
s. push_str ( " && " ) ;
211
246
if let Or ( _) = * inner {
212
- s = recurse ( true , cx, inner, terminals, s) ;
247
+ s = recurse ( true , cx, inner, terminals, s, simplified ) ;
213
248
} else {
214
- s = recurse ( false , cx, inner, terminals, s) ;
249
+ s = recurse ( false , cx, inner, terminals, s, simplified ) ;
215
250
}
216
251
}
217
252
if brackets {
@@ -223,10 +258,10 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
223
258
if brackets {
224
259
s. push ( '(' ) ;
225
260
}
226
- s = recurse ( false , cx, & v[ 0 ] , terminals, s) ;
261
+ s = recurse ( false , cx, & v[ 0 ] , terminals, s, simplified ) ;
227
262
for inner in & v[ 1 ..] {
228
263
s. push_str ( " || " ) ;
229
- s = recurse ( false , cx, inner, terminals, s) ;
264
+ s = recurse ( false , cx, inner, terminals, s, simplified ) ;
230
265
}
231
266
if brackets {
232
267
s. push ( ')' ) ;
@@ -249,7 +284,9 @@ fn suggest(cx: &LateContext, suggestion: &Bool, terminals: &[&Expr]) -> String {
249
284
} ,
250
285
}
251
286
}
252
- recurse ( false , cx, suggestion, terminals, String :: new ( ) )
287
+ let mut simplified = false ;
288
+ let s = recurse ( false , cx, suggestion, terminals, String :: new ( ) , & mut simplified) ;
289
+ ( s, simplified)
253
290
}
254
291
255
292
fn simple_negate ( b : Bool ) -> Bool {
@@ -359,7 +396,7 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
359
396
db. span_suggestion (
360
397
e. span ,
361
398
"it would look like the following" ,
362
- suggest ( self . cx , suggestion, & h2q. terminals ) ,
399
+ suggest ( self . cx , suggestion, & h2q. terminals ) . 0 ,
363
400
) ;
364
401
} ,
365
402
) ;
@@ -376,22 +413,26 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
376
413
improvements. push ( suggestion) ;
377
414
}
378
415
}
379
- if !improvements . is_empty ( ) {
416
+ let nonminimal_bool_lint = |suggestions| {
380
417
span_lint_and_then (
381
418
self . cx ,
382
419
NONMINIMAL_BOOL ,
383
420
e. span ,
384
421
"this boolean expression can be simplified" ,
385
- |db| {
386
- db. span_suggestions (
387
- e. span ,
388
- "try" ,
389
- improvements
390
- . into_iter ( )
391
- . map ( |suggestion| suggest ( self . cx , suggestion, & h2q. terminals ) )
392
- . collect ( ) ,
393
- ) ;
394
- } ,
422
+ |db| { db. span_suggestions ( e. span , "try" , suggestions) ; } ,
423
+ ) ;
424
+ } ;
425
+ if improvements. is_empty ( ) {
426
+ let suggest = suggest ( self . cx , & expr, & h2q. terminals ) ;
427
+ if suggest. 1 {
428
+ nonminimal_bool_lint ( vec ! [ suggest. 0 ] )
429
+ }
430
+ } else {
431
+ nonminimal_bool_lint (
432
+ improvements
433
+ . into_iter ( )
434
+ . map ( |suggestion| suggest ( self . cx , suggestion, & h2q. terminals ) . 0 )
435
+ . collect ( )
395
436
) ;
396
437
}
397
438
}
0 commit comments