11use crate :: utils:: {
2- get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_then, SpanlessEq ,
2+ get_trait_def_id, implements_trait, in_macro, match_type, paths, snippet_opt, span_lint_and_sugg,
3+ span_lint_and_then, SpanlessEq ,
34} ;
45use if_chain:: if_chain;
56use rustc:: hir:: intravisit:: * ;
@@ -159,46 +160,6 @@ struct SuggestContext<'a, 'tcx, 'v> {
159160}
160161
161162impl < ' a , ' tcx , ' v > SuggestContext < ' a , ' tcx , ' v > {
162- fn snip ( & self , e : & Expr ) -> Option < String > {
163- snippet_opt ( self . cx , e. span )
164- }
165-
166- fn simplify_not ( & self , expr : & Expr ) -> Option < String > {
167- match & expr. node {
168- ExprKind :: Binary ( binop, lhs, rhs) => {
169- if !implements_ord ( self . cx , lhs) {
170- return None ;
171- }
172-
173- match binop. node {
174- BinOpKind :: Eq => Some ( " != " ) ,
175- BinOpKind :: Ne => Some ( " == " ) ,
176- BinOpKind :: Lt => Some ( " >= " ) ,
177- BinOpKind :: Gt => Some ( " <= " ) ,
178- BinOpKind :: Le => Some ( " > " ) ,
179- BinOpKind :: Ge => Some ( " < " ) ,
180- _ => None ,
181- }
182- . and_then ( |op| Some ( format ! ( "{}{}{}" , self . snip( lhs) ?, op, self . snip( rhs) ?) ) )
183- } ,
184- ExprKind :: MethodCall ( path, _, args) if args. len ( ) == 1 => {
185- let type_of_receiver = self . cx . tables . expr_ty ( & args[ 0 ] ) ;
186- if !match_type ( self . cx , type_of_receiver, & paths:: OPTION )
187- && !match_type ( self . cx , type_of_receiver, & paths:: RESULT )
188- {
189- return None ;
190- }
191- METHODS_WITH_NEGATION
192- . iter ( )
193- . cloned ( )
194- . flat_map ( |( a, b) | vec ! [ ( a, b) , ( b, a) ] )
195- . find ( |& ( a, _) | a == path. ident . name . as_str ( ) )
196- . and_then ( |( _, neg_method) | Some ( format ! ( "{}.{}()" , self . snip( & args[ 0 ] ) ?, neg_method) ) )
197- } ,
198- _ => None ,
199- }
200- }
201-
202163 fn recurse ( & mut self , suggestion : & Bool ) -> Option < ( ) > {
203164 use quine_mc_cluskey:: Bool :: * ;
204165 match suggestion {
@@ -217,12 +178,12 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
217178 } ,
218179 Term ( n) => {
219180 let terminal = self . terminals [ n as usize ] ;
220- if let Some ( str) = self . simplify_not ( terminal) {
181+ if let Some ( str) = simplify_not ( self . cx , terminal) {
221182 self . simplified = true ;
222183 self . output . push_str ( & str)
223184 } else {
224185 self . output . push ( '!' ) ;
225- let snip = self . snip ( terminal) ?;
186+ let snip = snip ( self . cx , terminal) ?;
226187 self . output . push_str ( & snip) ;
227188 }
228189 } ,
@@ -254,14 +215,52 @@ impl<'a, 'tcx, 'v> SuggestContext<'a, 'tcx, 'v> {
254215 }
255216 } ,
256217 & Term ( n) => {
257- let snip = self . snip ( self . terminals [ n as usize ] ) ?;
218+ let snip = snip ( self . cx , self . terminals [ n as usize ] ) ?;
258219 self . output . push_str ( & snip) ;
259220 } ,
260221 }
261222 Some ( ( ) )
262223 }
263224}
264225
226+ fn snip ( cx : & LateContext < ' _ , ' _ > , e : & Expr ) -> Option < String > {
227+ snippet_opt ( cx, e. span )
228+ }
229+
230+ fn simplify_not ( cx : & LateContext < ' _ , ' _ > , expr : & Expr ) -> Option < String > {
231+ match & expr. node {
232+ ExprKind :: Binary ( binop, lhs, rhs) => {
233+ if !implements_ord ( cx, lhs) {
234+ return None ;
235+ }
236+
237+ match binop. node {
238+ BinOpKind :: Eq => Some ( " != " ) ,
239+ BinOpKind :: Ne => Some ( " == " ) ,
240+ BinOpKind :: Lt => Some ( " >= " ) ,
241+ BinOpKind :: Gt => Some ( " <= " ) ,
242+ BinOpKind :: Le => Some ( " > " ) ,
243+ BinOpKind :: Ge => Some ( " < " ) ,
244+ _ => None ,
245+ }
246+ . and_then ( |op| Some ( format ! ( "{}{}{}" , snip( cx, lhs) ?, op, snip( cx, rhs) ?) ) )
247+ } ,
248+ ExprKind :: MethodCall ( path, _, args) if args. len ( ) == 1 => {
249+ let type_of_receiver = cx. tables . expr_ty ( & args[ 0 ] ) ;
250+ if !match_type ( cx, type_of_receiver, & paths:: OPTION ) && !match_type ( cx, type_of_receiver, & paths:: RESULT ) {
251+ return None ;
252+ }
253+ METHODS_WITH_NEGATION
254+ . iter ( )
255+ . cloned ( )
256+ . flat_map ( |( a, b) | vec ! [ ( a, b) , ( b, a) ] )
257+ . find ( |& ( a, _) | a == path. ident . name . as_str ( ) )
258+ . and_then ( |( _, neg_method) | Some ( format ! ( "{}.{}()" , snip( cx, & args[ 0 ] ) ?, neg_method) ) )
259+ } ,
260+ _ => None ,
261+ }
262+ }
263+
265264// The boolean part of the return indicates whether some simplifications have been applied.
266265fn suggest ( cx : & LateContext < ' _ , ' _ > , suggestion : & Bool , terminals : & [ & Expr ] ) -> ( String , bool ) {
267266 let mut suggest_context = SuggestContext {
@@ -330,7 +329,7 @@ fn terminal_stats(b: &Bool) -> Stats {
330329}
331330
332331impl < ' a , ' tcx > NonminimalBoolVisitor < ' a , ' tcx > {
333- fn bool_expr ( & self , e : & Expr ) {
332+ fn bool_expr ( & self , e : & ' tcx Expr ) {
334333 let mut h2q = Hir2Qmm {
335334 terminals : Vec :: new ( ) ,
336335 cx : self . cx ,
@@ -420,10 +419,8 @@ impl<'a, 'tcx> NonminimalBoolVisitor<'a, 'tcx> {
420419 ) ;
421420 } ;
422421 if improvements. is_empty ( ) {
423- let suggest = suggest ( self . cx , & expr, & h2q. terminals ) ;
424- if suggest. 1 {
425- nonminimal_bool_lint ( vec ! [ suggest. 0 ] )
426- }
422+ let mut visitor = NotSimplificationVisitor { cx : self . cx } ;
423+ visitor. visit_expr ( e) ;
427424 } else {
428425 nonminimal_bool_lint (
429426 improvements
@@ -464,3 +461,30 @@ fn implements_ord<'a, 'tcx>(cx: &'a LateContext<'a, 'tcx>, expr: &Expr) -> bool
464461 let ty = cx. tables . expr_ty ( expr) ;
465462 get_trait_def_id ( cx, & paths:: ORD ) . map_or ( false , |id| implements_trait ( cx, ty, id, & [ ] ) )
466463}
464+
465+ struct NotSimplificationVisitor < ' a , ' tcx > {
466+ cx : & ' a LateContext < ' a , ' tcx > ,
467+ }
468+
469+ impl < ' a , ' tcx > Visitor < ' tcx > for NotSimplificationVisitor < ' a , ' tcx > {
470+ fn visit_expr ( & mut self , expr : & ' tcx Expr ) {
471+ if let ExprKind :: Unary ( UnNot , inner) = & expr. node {
472+ if let Some ( suggestion) = simplify_not ( self . cx , inner) {
473+ span_lint_and_sugg (
474+ self . cx ,
475+ NONMINIMAL_BOOL ,
476+ expr. span ,
477+ "this boolean expression can be simplified" ,
478+ "try" ,
479+ suggestion,
480+ Applicability :: MachineApplicable ,
481+ ) ;
482+ }
483+ }
484+
485+ walk_expr ( self , expr) ;
486+ }
487+ fn nested_visit_map < ' this > ( & ' this mut self ) -> NestedVisitorMap < ' this , ' tcx > {
488+ NestedVisitorMap :: None
489+ }
490+ }
0 commit comments