@@ -15,7 +15,7 @@ use syntax::print::pprust;
1515use syntax:: symbol:: { kw, sym} ;
1616use syntax:: symbol:: Symbol ;
1717use syntax:: util:: parser;
18- use syntax_pos:: Span ;
18+ use syntax_pos:: { Span , BytePos } ;
1919
2020use rustc:: hir;
2121
@@ -353,31 +353,46 @@ declare_lint! {
353353declare_lint_pass ! ( UnusedParens => [ UNUSED_PARENS ] ) ;
354354
355355impl UnusedParens {
356+
357+ fn is_expr_parens_necessary ( inner : & ast:: Expr , followed_by_block : bool ) -> bool {
358+ followed_by_block && match inner. node {
359+ ast:: ExprKind :: Ret ( _) | ast:: ExprKind :: Break ( ..) => true ,
360+ _ => parser:: contains_exterior_struct_lit ( & inner) ,
361+ }
362+ }
363+
356364 fn check_unused_parens_expr ( & self ,
357- cx : & EarlyContext < ' _ > ,
358- value : & ast:: Expr ,
359- msg : & str ,
360- followed_by_block : bool ) {
365+ cx : & EarlyContext < ' _ > ,
366+ value : & ast:: Expr ,
367+ msg : & str ,
368+ followed_by_block : bool ,
369+ left_pos : Option < BytePos > ,
370+ right_pos : Option < BytePos > ) {
361371 match value. node {
362372 ast:: ExprKind :: Paren ( ref inner) => {
363- let necessary = followed_by_block && match inner. node {
364- ast:: ExprKind :: Ret ( _) | ast:: ExprKind :: Break ( ..) => true ,
365- _ => parser:: contains_exterior_struct_lit ( & inner) ,
366- } ;
367- if !necessary {
373+ if !Self :: is_expr_parens_necessary ( inner, followed_by_block) {
368374 let expr_text = if let Ok ( snippet) = cx. sess ( ) . source_map ( )
369375 . span_to_snippet ( value. span ) {
370376 snippet
371377 } else {
372378 pprust:: expr_to_string ( value)
373379 } ;
374- Self :: remove_outer_parens ( cx, value. span , & expr_text, msg) ;
380+ let keep_space = (
381+ left_pos. map ( |s| s >= value. span . lo ( ) ) . unwrap_or ( false ) ,
382+ right_pos. map ( |s| s <= value. span . hi ( ) ) . unwrap_or ( false ) ,
383+ ) ;
384+ Self :: remove_outer_parens ( cx, value. span , & expr_text, msg, keep_space) ;
375385 }
376386 }
377387 ast:: ExprKind :: Let ( _, ref expr) => {
378388 // FIXME(#60336): Properly handle `let true = (false && true)`
379389 // actually needing the parenthesis.
380- self . check_unused_parens_expr ( cx, expr, "`let` head expression" , followed_by_block) ;
390+ self . check_unused_parens_expr (
391+ cx, expr,
392+ "`let` head expression" ,
393+ followed_by_block,
394+ None , None
395+ ) ;
381396 }
382397 _ => { }
383398 }
@@ -394,11 +409,15 @@ impl UnusedParens {
394409 } else {
395410 pprust:: pat_to_string ( value)
396411 } ;
397- Self :: remove_outer_parens ( cx, value. span , & pattern_text, msg) ;
412+ Self :: remove_outer_parens ( cx, value. span , & pattern_text, msg, ( false , false ) ) ;
398413 }
399414 }
400415
401- fn remove_outer_parens ( cx : & EarlyContext < ' _ > , span : Span , pattern : & str , msg : & str ) {
416+ fn remove_outer_parens ( cx : & EarlyContext < ' _ > ,
417+ span : Span ,
418+ pattern : & str ,
419+ msg : & str ,
420+ keep_space : ( bool , bool ) ) {
402421 let span_msg = format ! ( "unnecessary parentheses around {}" , msg) ;
403422 let mut err = cx. struct_span_lint ( UNUSED_PARENS , span, & span_msg) ;
404423 let mut ate_left_paren = false ;
@@ -424,11 +443,27 @@ impl UnusedParens {
424443 } ,
425444 _ => false ,
426445 }
427- } ) . to_owned ( ) ;
446+ } ) ;
447+
448+ let replace = {
449+ let mut replace = if keep_space. 0 {
450+ let mut s = String :: from ( " " ) ;
451+ s. push_str ( parens_removed) ;
452+ s
453+ } else {
454+ String :: from ( parens_removed)
455+ } ;
456+
457+ if keep_space. 1 {
458+ replace. push ( ' ' ) ;
459+ }
460+ replace
461+ } ;
462+
428463 err. span_suggestion_short (
429464 span,
430465 "remove these parentheses" ,
431- parens_removed ,
466+ replace ,
432467 Applicability :: MachineApplicable ,
433468 ) ;
434469 err. emit ( ) ;
@@ -438,14 +473,35 @@ impl UnusedParens {
438473impl EarlyLintPass for UnusedParens {
439474 fn check_expr ( & mut self , cx : & EarlyContext < ' _ > , e : & ast:: Expr ) {
440475 use syntax:: ast:: ExprKind :: * ;
441- let ( value, msg, followed_by_block) = match e. node {
442- If ( ref cond, ..) => ( cond, "`if` condition" , true ) ,
443- While ( ref cond, ..) => ( cond, "`while` condition" , true ) ,
444- ForLoop ( _, ref cond, ..) => ( cond, "`for` head expression" , true ) ,
445- Match ( ref head, _) => ( head, "`match` head expression" , true ) ,
446- Ret ( Some ( ref value) ) => ( value, "`return` value" , false ) ,
447- Assign ( _, ref value) => ( value, "assigned value" , false ) ,
448- AssignOp ( .., ref value) => ( value, "assigned value" , false ) ,
476+ let ( value, msg, followed_by_block, left_pos, right_pos) = match e. node {
477+ If ( ref cond, ref block, ..) => {
478+ let left = e. span . lo ( ) + syntax_pos:: BytePos ( 2 ) ;
479+ let right = block. span . lo ( ) ;
480+ ( cond, "`if` condition" , true , Some ( left) , Some ( right) )
481+ }
482+
483+ While ( ref cond, ref block, ..) => {
484+ let left = e. span . lo ( ) + syntax_pos:: BytePos ( 5 ) ;
485+ let right = block. span . lo ( ) ;
486+ ( cond, "`while` condition" , true , Some ( left) , Some ( right) )
487+ } ,
488+
489+ ForLoop ( _, ref cond, ref block, ..) => {
490+ ( cond, "`for` head expression" , true , None , Some ( block. span . lo ( ) ) )
491+ }
492+
493+ Match ( ref head, _) => {
494+ let left = e. span . lo ( ) + syntax_pos:: BytePos ( 5 ) ;
495+ ( head, "`match` head expression" , true , Some ( left) , None )
496+ }
497+
498+ Ret ( Some ( ref value) ) => {
499+ let left = e. span . lo ( ) + syntax_pos:: BytePos ( 3 ) ;
500+ ( value, "`return` value" , false , Some ( left) , None )
501+ }
502+
503+ Assign ( _, ref value) => ( value, "assigned value" , false , None , None ) ,
504+ AssignOp ( .., ref value) => ( value, "assigned value" , false , None , None ) ,
449505 // either function/method call, or something this lint doesn't care about
450506 ref call_or_other => {
451507 let ( args_to_check, call_kind) = match * call_or_other {
@@ -467,12 +523,12 @@ impl EarlyLintPass for UnusedParens {
467523 }
468524 let msg = format ! ( "{} argument" , call_kind) ;
469525 for arg in args_to_check {
470- self . check_unused_parens_expr ( cx, arg, & msg, false ) ;
526+ self . check_unused_parens_expr ( cx, arg, & msg, false , None , None ) ;
471527 }
472528 return ;
473529 }
474530 } ;
475- self . check_unused_parens_expr ( cx, & value, msg, followed_by_block) ;
531+ self . check_unused_parens_expr ( cx, & value, msg, followed_by_block, left_pos , right_pos ) ;
476532 }
477533
478534 fn check_pat ( & mut self , cx : & EarlyContext < ' _ > , p : & ast:: Pat ) {
@@ -492,7 +548,7 @@ impl EarlyLintPass for UnusedParens {
492548 fn check_stmt ( & mut self , cx : & EarlyContext < ' _ > , s : & ast:: Stmt ) {
493549 if let ast:: StmtKind :: Local ( ref local) = s. node {
494550 if let Some ( ref value) = local. init {
495- self . check_unused_parens_expr ( cx, & value, "assigned value" , false ) ;
551+ self . check_unused_parens_expr ( cx, & value, "assigned value" , false , None , None ) ;
496552 }
497553 }
498554 }
0 commit comments